diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..e43402f --- /dev/null +++ b/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..54056e6 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + ckan-connector + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..ec4300d --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/distro/LICENSE b/distro/LICENSE new file mode 100644 index 0000000..cdf50bd --- /dev/null +++ b/distro/LICENSE @@ -0,0 +1,4 @@ +gCube System - License +------------------------------------------------------------ + +${gcube.license} \ No newline at end of file diff --git a/distro/README b/distro/README new file mode 100644 index 0000000..a61347f --- /dev/null +++ b/distro/README @@ -0,0 +1,66 @@ +The gCube System - ${name} +-------------------------------------------------- + +${description} + + +${gcube.description} + +${gcube.funding} + + +Version +-------------------------------------------------- + +${version} (${buildDate}) + +Please see the file named "changelog.xml" in this directory for the release notes. + + +Authors +-------------------------------------------------- + +* Lucio Lelii (lucio.lelii@isti.cnr.it), CNR, Italy + + +Maintainers +----------- + +* Lucio Lelii (lucio.lelii@isti.cnr.it), CNR, Italy + + +Download information +-------------------------------------------------- + +Source code is available from SVN: + ${scm.url} + +Binaries can be downloaded from the gCube website: + ${gcube.website} + + +Installation +-------------------------------------------------- + +Installation documentation is available on-line in the gCube Wiki: + ${gcube.wikiRoot} + + +Documentation +-------------------------------------------------- + +Documentation is available on-line in the gCube Wiki: + ${gcube.wikiRoot} + + +Support +-------------------------------------------------- + +Bugs and support requests can be reported in the gCube issue tracking tool: + ${gcube.issueTracking} + + +Licensing +-------------------------------------------------- + +This software is licensed under the terms you may find in the file named "LICENSE" in this directory. \ No newline at end of file diff --git a/distro/changelog.xml b/distro/changelog.xml new file mode 100644 index 0000000..5365517 --- /dev/null +++ b/distro/changelog.xml @@ -0,0 +1,6 @@ + + + First Release + + \ No newline at end of file diff --git a/distro/descriptor.xml b/distro/descriptor.xml new file mode 100644 index 0000000..e395580 --- /dev/null +++ b/distro/descriptor.xml @@ -0,0 +1,32 @@ + + servicearchive + + tar.gz + + / + + + ${distroDirectory} + / + true + + README + LICENSE + changelog.xml + profile.xml + + 755 + true + + + + + target/${build.finalName}.${project.packaging} + /${artifactId} + + + + \ No newline at end of file diff --git a/distro/profile.xml b/distro/profile.xml new file mode 100644 index 0000000..a96f3dc --- /dev/null +++ b/distro/profile.xml @@ -0,0 +1,26 @@ + + + + Service + + ${description} + DataAccess + ${artifactId} + 1.0.0 + + + ${artifactId} + ${version} + + ${groupId} + ${artifactId} + ${version} + + + ${build.finalName}.war + + + + + + diff --git a/java/org/gcube/data/analysis/rconnector/TEstAcazzo.java b/java/org/gcube/data/analysis/rconnector/TEstAcazzo.java new file mode 100644 index 0000000..d210021 --- /dev/null +++ b/java/org/gcube/data/analysis/rconnector/TEstAcazzo.java @@ -0,0 +1,97 @@ +package org.gcube.data.analysis.rconnector; + +import java.security.MessageDigest; + +import org.junit.Test; +import org.python.core.PyCode; +import org.python.core.PyObject; +import org.python.core.PyString; +import org.python.util.PythonInterpreter; + +import java.io.*; +public class TEstAcazzo { + + @Test + public void test() throws Exception{ + String secret = "Ew2DCqvvavzBx7fKFPWwKhNKN"; + String digest0 = encodeTimestamp("0.0.0.0", 1458818509l)+secret+"user_vre_two_editor"+'\0'+'\0'+"userid_type:unicode"; + String timestamp16 = Long.toString(1458818509l, 16); + System.out.println(digest0); + System.out.println(digest0.length()); + MessageDigest mg = MessageDigest.getInstance("MD5"); + String digestResult = toHexString(mg.digest(digest0.getBytes())); + System.out.println(digestResult); + String finalDigest = toHexString(mg.digest((digestResult+secret).getBytes())); + System.out.println(finalDigest); + System.out.println(finalDigest.length()); + System.out.println(timestamp16); + } + + @Test + public void python() throws Exception{ + PythonInterpreter interpreter = new PythonInterpreter(); + interpreter.execfile(new FileInputStream(new File(this.getClass().getClassLoader().getResource("digest.py").getFile()))); + PyObject someFunc = interpreter.get("calculate_digest"); + System.out.println(" someFunc is null ?"+(someFunc==null)); + PyObject ret = someFunc.__call__(new PyObject[]{new PyString("0.0.0.0"), new PyString("1458818509"), new PyString("Ew2DCqvvavzBx7fKFPWwKhNKN"), + new PyString("user_vre_two_editor"), new PyString(""), new PyString("userid_type:unicode")} ); + String realResult = (String) ret.__tojava__(String.class); + System.out.println("result is "+realResult); + } + + + public String encodeTimestamp(String ip, long timestamp ){ + String[] splitIp = ip.split("\\."); + + //bho + String toConvertIp =""; + for (String ipPart: splitIp) + toConvertIp += UnicodeFormatter.byteToHex((byte)Integer.parseInt(ipPart)); + + + int t = (int) timestamp; + String tsString = UnicodeFormatter.byteToHex((byte)((t & 0xff000000) >> 24))+ + UnicodeFormatter.byteToHex((byte)((t & 0xff0000) >> 16))+ + UnicodeFormatter.byteToHex((byte)((t & 0xff00) >> 8))+ + UnicodeFormatter.byteToHex((byte)((t & 0xff))); + System.out.println("ts string is "+toConvertIp+tsString); + return toConvertIp+tsString; + } + + public static String toHexString(byte[] bytes) { + StringBuilder hexString = new StringBuilder(); + + for (int i = 0; i < bytes.length; i++) { + String hex = Integer.toHexString(0xFF & bytes[i]); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + + return hexString.toString(); + } + + + + public static class UnicodeFormatter { + + static public String byteToHex(byte b) { + // Returns hex String representation of byte b + char hexDigit[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] }; + return new String(array); + } + + static public String charToHex(char c) { + // Returns hex String representation of char c + byte hi = (byte) (c >>> 8); + byte lo = (byte) (c & 0xff); + return byteToHex(hi) + byteToHex(lo); + } + + } +} diff --git a/java/org/gcube/data/analysis/rconnector/TestCall.java b/java/org/gcube/data/analysis/rconnector/TestCall.java new file mode 100644 index 0000000..de90a70 --- /dev/null +++ b/java/org/gcube/data/analysis/rconnector/TestCall.java @@ -0,0 +1,22 @@ +package org.gcube.data.analysis.rconnector; + +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.Test; + +public class TestCall extends JerseyTest{ + + @Override + protected Application configure() { + return new ResourceConfig(Resource.class, DisconnectResource.class); + } + + @Test + public void disconnect() { + final String ret = target("disconnect").request().get(String.class); + System.out.println("return is "+ret); + } + +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..cc3b75e --- /dev/null +++ b/pom.xml @@ -0,0 +1,141 @@ + + 4.0.0 + org.gcube.data.access + ckan-connector + 1.0.0-SNAPSHOT + war + ckan connector + a ckan connector for automatic login + + + distro + + + + + + org.gcube.distribution + maven-smartgears-bom + LATEST + pom + import + + + + + + + + org.python + jython-standalone + 2.5.2 + + + + eu.trentorise.opendata + jackan + 0.4.2 + + + + + org.gcube.core + common-smartgears + + + + + com.google.code.gson + gson + 2.3.1 + + + + + + javax.ws.rs + javax.ws.rs-api + 2.0 + + + org.glassfish.jersey.containers + jersey-container-servlet + 2.13 + + + + javax.servlet + javax.servlet-api + 3.0.1 + + + + org.slf4j + slf4j-api + + + + + com.google.guava + guava + 18.0 + + + + + org.projectlombok + lombok + 0.11.6 + + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-simple + 2.13 + test + + + + + ${artifactId} + + + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-war-plugin + 2.4 + + ckan-connector + false + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.2 + + + ${distroDirectory}/descriptor.xml + + + + + servicearchive + install + + single + + + + + + + \ No newline at end of file diff --git a/resources/digest.py b/resources/digest.py new file mode 100644 index 0000000..e2cf932 --- /dev/null +++ b/resources/digest.py @@ -0,0 +1,35 @@ +from hashlib import md5 + +def calculate_digest(ip, timestamp, secret, userid, tokens, user_data): + secret = maybe_encode(secret) + userid = maybe_encode(userid) + tokens = maybe_encode(tokens) + user_data = maybe_encode(user_data) + digest0 = md5(encode_ip_timestamp(ip, timestamp) + secret + userid + '\0' + tokens + '\0' + user_data).hexdigest() + digest = md5(maybe_encode(digest0) + secret).hexdigest() + return digest + + +if type(chr(1)) == type(''): #pragma NO COVER Python < 3.0 + def ints2bytes(ints): + return ''.join(map(chr, ints)) +else: #pragma NO COVER Python >= 3.0 + def ints2bytes(ints): + return bytes(ints) + +def encode_ip_timestamp(ip, timestamp): + ip_chars = ints2bytes(map(int, ip.split('.'))) + t = int(timestamp) + ts = ((t & 0xff000000) >> 24, + (t & 0xff0000) >> 16, + (t & 0xff00) >> 8, + t & 0xff) + ts_chars = ints2bytes(ts) + return ip_chars + ts_chars + + +def maybe_encode(s, encoding='utf8'): + if not isinstance(s, type('')): + s = s.encode(encoding) + return s + diff --git a/resources/logback.xml b/resources/logback.xml new file mode 100644 index 0000000..4f36cc8 --- /dev/null +++ b/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{0}: %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/data/access/ckanconnector/CKanConnector.java b/src/main/java/org/gcube/data/access/ckanconnector/CKanConnector.java new file mode 100644 index 0000000..54398c5 --- /dev/null +++ b/src/main/java/org/gcube/data/access/ckanconnector/CKanConnector.java @@ -0,0 +1,15 @@ +package org.gcube.data.access.ckanconnector; + +import javax.ws.rs.ApplicationPath; + +import org.glassfish.jersey.server.ResourceConfig; + +@ApplicationPath("/gcube/service/") +public class CKanConnector extends ResourceConfig { + + public CKanConnector(){ + packages("org.gcube.data.access.ckanconnector"); + } + + +} diff --git a/src/main/java/org/gcube/data/access/ckanconnector/ConnectorManager.java b/src/main/java/org/gcube/data/access/ckanconnector/ConnectorManager.java new file mode 100644 index 0000000..536eea5 --- /dev/null +++ b/src/main/java/org/gcube/data/access/ckanconnector/ConnectorManager.java @@ -0,0 +1,203 @@ +package org.gcube.data.access.ckanconnector; + +import java.io.File; +import java.io.FileInputStream; +import java.net.URI; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.NewCookie; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import lombok.extern.slf4j.Slf4j; + +import org.gcube.common.authorization.library.provider.AuthorizationProvider; +import org.gcube.common.scope.api.ScopeProvider; +import org.python.core.PyLong; +import org.python.core.PyObject; +import org.python.core.PyString; +import org.python.util.PythonInterpreter; + +import eu.trentorise.opendata.jackan.CkanClient; +import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse; +import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpStatus; +import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpPost; +import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.StringEntity; +import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.CloseableHttpClient; +import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.HttpClientBuilder; +import eu.trentorise.opendata.jackan.model.CkanOrganization; +import eu.trentorise.opendata.jackan.model.CkanUser; + +@Path("/") +@Slf4j +public class ConnectorManager { + + @Context ServletContext context; + + RandomString randomString = new RandomString(12); + + + @Path("disconnect") + @DELETE + public Response disconnect() { + log.info("disconnect called "); + String hostname = context.getInitParameter("hostname"); + try{ + return Response.ok() + .header( + "Set-Cookie", + String.format("auth_tkt=deleted;Domain=.%s;Path=/;Expires=Thu, 01-Jan-1970 00:00:01 GMT",hostname) + ).build(); + }catch(Exception e){ + e.printStackTrace(); + return null; + } + } + + + @Path("connect{pathInfo:(/[^?$]+)?}") + @GET + public Response connect(@PathParam(value = "pathInfo") String path, @Context HttpServletRequest req, @QueryParam(value="listOfVres") String vres ) { + try{ + if (AuthorizationProvider.instance.get()==null || AuthorizationProvider.instance.get().getUserName() == null ) return Response.status(Status.UNAUTHORIZED).build(); + log.info("passed path is {}",path); + String ckanKey = context.getInitParameter("ckanKey"); + String originalUserName = AuthorizationProvider.instance.get().getUserName(); + String changedUserName = originalUserName.replace(".", "_"); + int internalPort = Integer.parseInt(context.getInitParameter("internalPort")); + String localhostName = "http://127.0.0.1:"+internalPort; + CkanClient ckanClient = new CkanClient(localhostName, ckanKey); + CkanUser user = null; + try{ + user = ckanClient.getUser(changedUserName); + }catch(Exception e){ + log.warn("user {} doesn't exist, the system will create it",originalUserName, e); + } + if (user==null) + user = ckanClient.createUser(new CkanUser(changedUserName, originalUserName+"@gcube.ckan.org" , randomString.nextString() )); + + addUserToVres(vres, changedUserName, ckanClient, ckanKey, localhostName); + + log.info("logging {} in scope {}",originalUserName, ScopeProvider.instance.get()); + return createResponse(changedUserName, path, req.getQueryString()); + }catch(Exception e){ + log.info("error trying to connect to CKAN",e); + return Response.serverError().entity(e.getMessage()).build(); + } + } + + private void addUserToVres(String vres, String changedUserName, + CkanClient ckanClient, String ckanKey, String localhostName) { + if (vres!=null && !vres.isEmpty()) + for (String vre: vres.split(",")){ + try{ + CkanOrganization org = ckanClient.getOrganization(vre); + boolean userAlreadyRegistered = false; + for (CkanUser vreUser : org.getUsers()){ + log.info("found user {} in organization {}",vreUser.getId(), org.getTitle()); + if (vreUser.getId().equals(changedUserName)){ + userAlreadyRegistered= true; + break; + } + + } + if (userAlreadyRegistered){ + log.warn("user {} already registered to vre {} ",changedUserName, vre); + } else{ + boolean added = addUserToOrganization(changedUserName, vre, ckanKey, localhostName); + log.info("{} {} added to vre {} for a remote service problem",changedUserName, added?"":"not", vre); + } + }catch(Exception e){ + log.warn("organization {} not found ",vre); + } + } + + } + + private Response createResponse(String userName, String path, String query){ + try{ + String secret = context.getInitParameter("secret"); + String hostIp = context.getInitParameter("hostIp"); + String hostname = context.getInitParameter("hostname"); + String fixedData = "userid_type:unicode"; + PythonInterpreter interpreter = new PythonInterpreter(); + interpreter.execfile(new FileInputStream(new File(this.getClass().getClassLoader().getResource("digest.py").getFile()))); + PyObject someFunc = interpreter.get("calculate_digest"); + long currentMillis = System.currentTimeMillis()/1000; + PyObject ret = someFunc.__call__(new PyObject[]{new PyString(hostIp), new PyLong(currentMillis), new PyString(secret), + new PyString(userName), new PyString(""), new PyString(fixedData)} ); + String realResult = (String) ret.__tojava__(String.class); + + String timestamp16 = Long.toString(currentMillis, 16); + + String cookieValue = realResult+timestamp16+userName+"!"+fixedData; + NewCookie cookie = new NewCookie("auth_tkt", + cookieValue, + "/", hostname, "", -1, false, true ); + + + NewCookie cookieHideHeader = new NewCookie("ckan_hide_header", "true", + "/", hostname, "", -1, false, true ); + + + String newQueryString = query.replaceFirst("&?gcube-token=[^&$]*&?", "").replace("&?listOfVres=[^&$]*&?", ""); + String baseUrl = "https://"+hostname; + if (path!=null && !path.isEmpty()) + baseUrl+=path.startsWith("/")?path:"/"+path; + + if (newQueryString!=null && !newQueryString.isEmpty()) + baseUrl+="?"+newQueryString; + + log.info("redirecting to "+baseUrl); + + return Response.seeOther(new URI(baseUrl)) + .cookie(cookie).cookie(cookieHideHeader).build(); + }catch(Exception e){ + e.printStackTrace(); + return Response.serverError().build(); + } + } + + + private boolean addUserToOrganization(String ckanUsername, String organizationName, String ckanKey, String hostAddress ){ + // we need to use the apis to make it + String path = "/api/3/action/organization_member_create"; + + // Request parameters to be replaced + String parameter = "{" + + "\"id\":\"ORGANIZATION_ID_NAME\"," + + "\"username\":\"USERNAME_ID_NAME\"," + + "\"role\":\"ROLE\"" + + "}"; + + // replace those values + parameter = parameter.replace("ORGANIZATION_ID_NAME", organizationName.toLowerCase()); + parameter = parameter.replace("USERNAME_ID_NAME", ckanUsername); + parameter = parameter.replace("ROLE", "member"); + + log.debug("API request for organization membership is going to be " + parameter); + + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { + HttpPost request = new HttpPost(hostAddress + path); + request.addHeader("Authorization", ckanKey); // sys token + StringEntity params = new StringEntity(parameter); + request.setEntity(params); + HttpResponse response = httpClient.execute(request); + log.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase()); + + return (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK); + + }catch (Exception ex) { + log.error("Error while trying to change the role for this user ", ex); + return false; + } + } + +} diff --git a/src/main/java/org/gcube/data/access/ckanconnector/OrganizationManager.java b/src/main/java/org/gcube/data/access/ckanconnector/OrganizationManager.java new file mode 100644 index 0000000..68c86c0 --- /dev/null +++ b/src/main/java/org/gcube/data/access/ckanconnector/OrganizationManager.java @@ -0,0 +1,84 @@ +package org.gcube.data.access.ckanconnector; + +import javax.servlet.ServletContext; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import lombok.extern.slf4j.Slf4j; + +import org.gcube.common.authorization.library.provider.AuthorizationProvider; +import org.gcube.common.scope.api.ScopeProvider; + +import com.google.gson.Gson; + +import eu.trentorise.opendata.jackan.CkanClient; +import eu.trentorise.opendata.jackan.exceptions.CkanNotFoundException; +import eu.trentorise.opendata.jackan.model.CkanOrganization; + + +@Path("organization") +@Slf4j +public class OrganizationManager { + + @Context ServletContext context; + + @PUT + @Path("/{name}") + public Response create(@PathParam("name") String organizationName) { + log.info("create called"); + try{ + if (AuthorizationProvider.instance.get()==null || AuthorizationProvider.instance.get().getUserName() == null ) return Response.status(Status.UNAUTHORIZED).build(); + + String ckanKey = context.getInitParameter("ckanKey"); + int internalPort = Integer.parseInt(context.getInitParameter("internalPort")); + CkanClient ckanClient = new CkanClient("http://127.0.0.1:"+internalPort, ckanKey); + + CkanOrganization org = new CkanOrganization(organizationName.replaceAll(" ", "_").replace(".", "_").toLowerCase()); + org.setDisplayName(organizationName); + org.setTitle(organizationName); + ckanClient.createOrganization(org); + + log.info("create organizzation {} called from user {} in scope {}",organizationName, AuthorizationProvider.instance.get().getUserName(), ScopeProvider.instance.get()); + return Response.ok().build(); + }catch(Exception e){ + log.error("error trying to create organization "+organizationName,e); + return Response.serverError().entity(e.getMessage()).build(); + } + } + + @GET + @Path("/{name}") + @Produces(MediaType.APPLICATION_JSON) + public String get(@PathParam("name") String organizationName) { + log.info("get called with name {}", organizationName); + + if (AuthorizationProvider.instance.get()==null || AuthorizationProvider.instance.get().getUserName() == null ) throw new WebApplicationException("user authentication needed",Response.Status.UNAUTHORIZED); + + String ckanKey = context.getInitParameter("ckanKey"); + int internalPort = Integer.parseInt(context.getInitParameter("internalPort")); + + try{ + CkanClient ckanClient = new CkanClient("http://127.0.0.1:"+internalPort, ckanKey); + CkanOrganization org = ckanClient.getOrganization(organizationName.replaceAll(" ", "_").replace(".", "_").toLowerCase()); + log.trace("organization {} found",organizationName); + return new Gson().toJson(org); + }catch(CkanNotFoundException e){ + log.error("organization {} doesn't exist",organizationName); + throw new WebApplicationException("organization "+organizationName+" doesn't exist",Response.Status.NOT_FOUND); + } catch (Exception e) { + log.error("error trying to contect ckan",e); + throw new WebApplicationException("error trying to contect ckan",Response.Status.INTERNAL_SERVER_ERROR); + } + + + } + +} diff --git a/src/main/java/org/gcube/data/access/ckanconnector/RandomString.java b/src/main/java/org/gcube/data/access/ckanconnector/RandomString.java new file mode 100644 index 0000000..03c44b0 --- /dev/null +++ b/src/main/java/org/gcube/data/access/ckanconnector/RandomString.java @@ -0,0 +1,33 @@ +package org.gcube.data.access.ckanconnector; + +import java.util.Random; + +public class RandomString { + + private static final char[] symbols; + + static { + StringBuilder tmp = new StringBuilder(); + for (char ch = '0'; ch <= '9'; ++ch) + tmp.append(ch); + for (char ch = 'a'; ch <= 'z'; ++ch) + tmp.append(ch); + symbols = tmp.toString().toCharArray(); + } + + private final Random random = new Random(); + + private final char[] buf; + + public RandomString(int length) { + if (length < 1) + throw new IllegalArgumentException("length < 1: " + length); + buf = new char[length]; + } + + public String nextString() { + for (int idx = 0; idx < buf.length; ++idx) + buf[idx] = symbols[random.nextInt(symbols.length)]; + return new String(buf); + } +} diff --git a/src/main/resources/digest.py b/src/main/resources/digest.py new file mode 100644 index 0000000..e2cf932 --- /dev/null +++ b/src/main/resources/digest.py @@ -0,0 +1,35 @@ +from hashlib import md5 + +def calculate_digest(ip, timestamp, secret, userid, tokens, user_data): + secret = maybe_encode(secret) + userid = maybe_encode(userid) + tokens = maybe_encode(tokens) + user_data = maybe_encode(user_data) + digest0 = md5(encode_ip_timestamp(ip, timestamp) + secret + userid + '\0' + tokens + '\0' + user_data).hexdigest() + digest = md5(maybe_encode(digest0) + secret).hexdigest() + return digest + + +if type(chr(1)) == type(''): #pragma NO COVER Python < 3.0 + def ints2bytes(ints): + return ''.join(map(chr, ints)) +else: #pragma NO COVER Python >= 3.0 + def ints2bytes(ints): + return bytes(ints) + +def encode_ip_timestamp(ip, timestamp): + ip_chars = ints2bytes(map(int, ip.split('.'))) + t = int(timestamp) + ts = ((t & 0xff000000) >> 24, + (t & 0xff0000) >> 16, + (t & 0xff00) >> 8, + t & 0xff) + ts_chars = ints2bytes(ts) + return ip_chars + ts_chars + + +def maybe_encode(s, encoding='utf8'): + if not isinstance(s, type('')): + s = s.encode(encoding) + return s + diff --git a/src/main/webapp/WEB-INF/gcube-app.xml b/src/main/webapp/WEB-INF/gcube-app.xml new file mode 100644 index 0000000..6948378 --- /dev/null +++ b/src/main/webapp/WEB-INF/gcube-app.xml @@ -0,0 +1,8 @@ + + CkanConnector + DataAccess + 1.0.0-SNAPSHOT + ckan connector webapp + + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..49ebb87 --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,29 @@ + + + secret + Ew2DCqvvavzBx7fKFPWwKhNKN + + + hostIp + 0.0.0.0 + + + hostname + ckan-d-d4s.d4science.org + + + internalPort + 8080 + + + ckanKey + 803ada7f-2080-493f-8a99-3e593e880d94 + + + org.gcube.data.access.ckanconnector.CkanConnector + + + org.gcube.data.access.ckanconnector.CkanConnector + /* + + \ No newline at end of file diff --git a/src/test/java/org/gcube/data/access/ckanconnector/TestCall.java b/src/test/java/org/gcube/data/access/ckanconnector/TestCall.java new file mode 100644 index 0000000..e08a6ef --- /dev/null +++ b/src/test/java/org/gcube/data/access/ckanconnector/TestCall.java @@ -0,0 +1,44 @@ +package org.gcube.data.access.ckanconnector; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.Random; + +import javax.net.ssl.HttpsURLConnection; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; + +import org.gcube.common.authorization.client.Constants; +import org.gcube.common.scope.api.ScopeProvider; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.Test; + +public class TestCall extends JerseyTest{ + + @Override + protected Application configure() { + return new ResourceConfig(ConnectorManager.class); + } + + @Test + public void connect() { + final Response ret = target("connect").request().get(Response.class); + System.out.println("return is "+ret); + } + + @Test + public void createOrganization() throws Exception{ + String callUrl = "https://ckan-d-d4s.d4science.org/ckan-connector/organization/CreationTest?gcube-token=34c34146-ab38-42d5-9332-f325e8b2b930"; + URL url = new URL(callUrl); + HttpsURLConnection connection = (HttpsURLConnection)url.openConnection(); + connection.setRequestMethod("PUT"); + + System.out.println(connection.getResponseCode()); + } + + + +} diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml new file mode 100644 index 0000000..4f36cc8 --- /dev/null +++ b/src/test/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{0}: %msg%n + + + + + + + + + + + \ No newline at end of file