This commit is contained in:
Lucio Lelii 2019-04-08 15:09:18 +00:00
parent af91624406
commit 6b0b45c988
11 changed files with 139 additions and 71 deletions

View File

@ -15,11 +15,13 @@
<attributes> <attributes>
<attribute name="optional" value="true"/> <attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes> <attributes>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
@ -30,6 +32,7 @@
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes> <attributes>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="output" path="target/classes"/>

View File

@ -5,11 +5,21 @@
<projects> <projects>
</projects> </projects>
<buildSpec> <buildSpec>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name> <name>org.eclipse.jdt.core.javabuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name> <name>org.eclipse.m2e.core.maven2Builder</name>
<arguments> <arguments>
@ -17,7 +27,11 @@
</buildCommand> </buildCommand>
</buildSpec> </buildSpec>
<natures> <natures>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature> <nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures> </natures>
</projectDescription> </projectDescription>

View File

@ -1,5 +1,8 @@
<ReleaseNotes> <ReleaseNotes>
<Changeset component="org.gcube.data-analysis.r-connector.2.1.2" date="2017-03-27"> <Changeset component="org.gcube.data-analysis.r-connector.2.1.4" date="2019-03-27">
<Change>integration with storageHub</Change>
</Changeset>
<Changeset component="org.gcube.data-analysis.r-connector.2.1.3" date="2017-03-27">
<Change>add user script is executed also when configfile.csv is not present</Change> <Change>add user script is executed also when configfile.csv is not present</Change>
</Changeset> </Changeset>
<Changeset component="org.gcube.data-analysis.r-connector.2.1.2" date="2017-02-22"> <Changeset component="org.gcube.data-analysis.r-connector.2.1.2" date="2017-02-22">

View File

@ -11,6 +11,10 @@
<param-name>addUserScript</param-name> <param-name>addUserScript</param-name>
<param-value>/usr/local/bin/rusersadd</param-value> <param-value>/usr/local/bin/rusersadd</param-value>
</context-param> </context-param>
<context-param>
<param-name>unmountScript</param-name>
<param-value>/usr/local/bin/rconnector_unmount</param-value>
</context-param>
<context-param> <context-param>
<param-name>storedKeyPath</param-name> <param-name>storedKeyPath</param-name>
<param-value>/var/lib/rstudio-server/secure-cookie-key</param-value> <param-value>/var/lib/rstudio-server/secure-cookie-key</param-value>

12
pom.xml
View File

@ -1,9 +1,10 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.gcube.data.analysis</groupId> <groupId>org.gcube.data.analysis</groupId>
<artifactId>r-connector</artifactId> <artifactId>r-connector</artifactId>
<version>2.1.3-SNAPSHOT</version> <version>2.1.4-SNAPSHOT</version>
<name>RConnector</name> <name>RConnector</name>
<description>makes R available in the infrastructure</description> <description>makes R available in the infrastructure</description>
@ -64,7 +65,12 @@
<artifactId>tabulardata-client-library</artifactId> <artifactId>tabulardata-client-library</artifactId>
<version>[2.0.0-SNAPSHOT, 3.0.0-SNAPSHOT)</version> <version>[2.0.0-SNAPSHOT, 3.0.0-SNAPSHOT)</version>
</dependency> </dependency>
<dependency>
<groupId>org.gcube.data-access</groupId>
<artifactId>sh-fuse-integration</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- jersey --> <!-- jersey -->
<dependency> <dependency>
<groupId>javax.ws.rs</groupId> <groupId>javax.ws.rs</groupId>

View File

@ -1,13 +1,13 @@
package org.gcube.data.analysis.rconnector; package org.gcube.data.analysis.rconnector;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.api.ScopeProvider;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -21,38 +21,10 @@ public class ConfigFileWriter {
usersHome=usersHome+"/"; usersHome=usersHome+"/";
File userDir = new File(usersHome+login); File userDir = new File(usersHome+login);
File configFile= new File(userDir, fileName); File configFile= new File(userDir, fileName);
executeCommandLine(scriptToExecute,login); Utils.executeCommandLine(scriptToExecute,login, SecurityTokenProvider.instance.get(), ScopeProvider.instance.get());
return writeFile(info, configFile); return writeFile(info, configFile);
} }
private String executeCommandLine(String cmd, String login){
log.debug("executing command "+cmd+" "+login);
Process process = null;
String lastline = "";
try {
ProcessBuilder pb = new ProcessBuilder(cmd, login);
process = pb.start();
try {
process.waitFor();
} catch (InterruptedException e) {
log.warn("interrupt Exception on process",e);
}
BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = br.readLine();
while (line!=null){
lastline += line;
line = br.readLine();
}
} catch (IOException e) {
log.error("error executing command line",e);
}
log.debug("command result line is "+lastline);
return lastline;
}
private boolean writeFile(Info info, File pathToFile){ private boolean writeFile(Info info, File pathToFile){
log.debug("writing config file"); log.debug("writing config file");
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();

View File

@ -1,5 +1,6 @@
package org.gcube.data.analysis.rconnector; package org.gcube.data.analysis.rconnector;
import javax.inject.Inject;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -10,21 +11,39 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Path("disconnect") @Path("disconnect")
@Slf4j @Slf4j
public class DisconnectResource { public class DisconnectResource {
@Context ServletContext context; @Context ServletContext context;
@Inject
InfoRetriever infoRetriever;
@GET @GET
@Produces(MediaType.TEXT_HTML) @Produces(MediaType.TEXT_HTML)
public Response disconnect(@Context HttpServletRequest req) { public Response disconnect(@Context HttpServletRequest req) {
log.info("disconnect called "); log.info("disconnect called ");
String rStudioServerAddress = context==null?"":context.getInitParameter("rStudioAddress"); String rStudioServerAddress = context==null?"":context.getInitParameter("rStudioAddress");
log.info(rStudioServerAddress); String scriptToExecute = context.getInitParameter("unmountScript");
String login = null;
for (Cookie cookie : req.getCookies())
if (cookie.getName().equals("user-id"))
login = cookie.getValue();
if (login==null)
return Response.serverError().build();
try{ try{
Utils.executeCommandLine(scriptToExecute, login);
boolean found = false; boolean found = false;
for (Cookie cookie : req.getCookies()) for (Cookie cookie : req.getCookies())
if (cookie.getName().equals("user-id")){ if (cookie.getName().equals("user-id")){
@ -39,8 +58,8 @@ public class DisconnectResource {
).build(); ).build();
else return Response.ok(context.getClassLoader().getResourceAsStream("inactivesession.html")).build(); else return Response.ok(context.getClassLoader().getResourceAsStream("inactivesession.html")).build();
}catch(Exception e){ }catch(Exception e){
e.printStackTrace(); log.error("erorr disconnecting from Rstudio",e);
return null; return Response.serverError().build();
} }
} }

View File

@ -10,8 +10,6 @@ import java.util.regex.Pattern;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.database.DatabaseEndpointIdentifier; import org.gcube.common.database.DatabaseEndpointIdentifier;
import org.gcube.common.database.DatabaseProvider; import org.gcube.common.database.DatabaseProvider;
@ -25,6 +23,8 @@ import org.gcube.data.analysis.tabulardata.model.metadata.common.NamesMetadata;
import org.gcube.data.analysis.tabulardata.model.metadata.table.DatasetViewTableMetadata; import org.gcube.data.analysis.tabulardata.model.metadata.table.DatasetViewTableMetadata;
import org.gcube.data.analysis.tabulardata.model.table.Table; import org.gcube.data.analysis.tabulardata.model.table.Table;
import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@Singleton @Singleton
public class InfoRetriever { public class InfoRetriever {
@ -32,7 +32,6 @@ public class InfoRetriever {
@Inject @Inject
DatabaseProvider databaseProvider; DatabaseProvider databaseProvider;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Info retrieve(String userName, Long tabularResourceId){ public Info retrieve(String userName, Long tabularResourceId){
try { try {

View File

@ -1,9 +1,11 @@
package org.gcube.data.analysis.rconnector; package org.gcube.data.analysis.rconnector;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.Locale; import java.util.Locale;
@ -20,11 +22,12 @@ import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
import lombok.extern.slf4j.Slf4j;
import org.gcube.common.authorization.library.provider.AuthorizationProvider; import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.data.access.storagehub.fs.StorageHubFS;
import lombok.extern.slf4j.Slf4j;
@Path("connect/") @Path("connect/")
@Slf4j @Slf4j
@ -35,85 +38,89 @@ public class Resource {
@Inject @Inject
InfoRetriever infoRetriever; InfoRetriever infoRetriever;
@Context ServletContext context; @Context ServletContext context;
@Path("/{trId}") @Path("/{trId}")
@GET @GET
public Response connect(@PathParam("trId") Long tabularResourceId) { public Response connect(@PathParam("trId") Long tabularResourceId) {
log.info("connect called with user {} and trID {} in scope {}",AuthorizationProvider.instance.get().getClient().getId(), tabularResourceId, ScopeProvider.instance.get()); log.info("connect called with user {} and trID {} in scope {}",AuthorizationProvider.instance.get().getClient().getId(), tabularResourceId, ScopeProvider.instance.get());
String login = AuthorizationProvider.instance.get().getClient().getId();
String usersHome = context.getInitParameter("usersHome"); String usersHome = context.getInitParameter("usersHome");
String filename = context.getInitParameter("filename"); String filename = context.getInitParameter("filename");
String scriptToExecute = context.getInitParameter("addUserScript"); String scriptToExecute = context.getInitParameter("addUserScript");
if (ScopeProvider.instance.get()==null || AuthorizationProvider.instance.get().getClient().getId() == null || tabularResourceId ==null ) return Response.serverError().build(); if (ScopeProvider.instance.get()==null || login == null || tabularResourceId ==null ) return Response.serverError().build();
Info info; Info info;
try{ try{
info = infoRetriever.retrieve(AuthorizationProvider.instance.get().getClient().getId(), tabularResourceId); info = infoRetriever.retrieve(login, tabularResourceId);
log.debug("retrieved info: "+info); log.debug("retrieved info: "+info);
}catch(Exception e){ }catch(Exception e){
log.error("error connecting to r",e); log.error("error connecting to r",e);
return Response.serverError().build(); return Response.serverError().build();
} }
if (!writer.write(info, AuthorizationProvider.instance.get().getClient().getId(), usersHome, filename, scriptToExecute)) return Response.serverError().build(); if (!writer.write(info, login, usersHome, filename, scriptToExecute)) return Response.serverError().build();
return createResponse(AuthorizationProvider.instance.get().getClient().getId()); return createResponse(login);
} }
@GET @GET
public Response connect() { public Response connect() {
log.info("connect called with user {} in scope {}",AuthorizationProvider.instance.get().getClient().getId(), ScopeProvider.instance.get()); log.info("connect called with user {} in scope {}",AuthorizationProvider.instance.get().getClient().getId(), ScopeProvider.instance.get());
String login = AuthorizationProvider.instance.get().getClient().getId();
String usersHome = context.getInitParameter("usersHome"); String usersHome = context.getInitParameter("usersHome");
String filename = context.getInitParameter("filename"); String filename = context.getInitParameter("filename");
String scriptToExecute = context.getInitParameter("addUserScript"); String scriptToExecute = context.getInitParameter("addUserScript");
if (AuthorizationProvider.instance.get().getClient().getId() == null ) return Response.serverError().build(); if (login == null ) return Response.serverError().build();
Info info = new Info(); Info info = new Info();
info.setUsername(AuthorizationProvider.instance.get().getClient().getId()); info.setUsername(login);
info.setToken(SecurityTokenProvider.instance.get()); info.setToken(SecurityTokenProvider.instance.get());
if (!writer.write(info, AuthorizationProvider.instance.get().getClient().getId(), usersHome, filename, scriptToExecute)) return Response.serverError().build(); if (!writer.write(info, login, usersHome, filename, scriptToExecute)) return Response.serverError().build();
return createResponse(AuthorizationProvider.instance.get().getClient().getId()); return createResponse(AuthorizationProvider.instance.get().getClient().getId());
} }
private Response createResponse(String userName){ private Response createResponse(String userName){
try{ try{
String keyFilePath = context.getInitParameter("storedKeyPath"); String keyFilePath = context.getInitParameter("storedKeyPath");
String rStudioServerAddress = context.getInitParameter("rStudioAddress"); String rStudioServerAddress = context.getInitParameter("rStudioAddress");
log.debug("key file path: "+keyFilePath); log.debug("key file path: "+keyFilePath);
log.debug("rstudio server address: "+rStudioServerAddress); log.debug("rstudio server address: "+rStudioServerAddress);
Calendar now = Calendar.getInstance(); Calendar now = Calendar.getInstance();
now.add(Calendar.YEAR, 10); now.add(Calendar.YEAR, 10);
now.add(Calendar.DAY_OF_YEAR, -1); now.add(Calendar.DAY_OF_YEAR, -1);
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH); SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
String format = sdf.format(now.getTime()); String format = sdf.format(now.getTime());
File keyFile = new File(keyFilePath); File keyFile = new File(keyFilePath);
if (!keyFile.exists()) if (!keyFile.exists())
return Response.serverError().build(); return Response.serverError().build();
byte[] keyByte = Files.readAllBytes(keyFile.toPath()); byte[] keyByte = Files.readAllBytes(keyFile.toPath());
SecretKeySpec keySpec = new SecretKeySpec(keyByte, SecretKeySpec keySpec = new SecretKeySpec(keyByte,
"HmacSHA256"); "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256"); Mac mac = Mac.getInstance("HmacSHA256");
mac.init(keySpec); mac.init(keySpec);
byte[] result = mac.doFinal((userName+format).getBytes()); byte[] result = mac.doFinal((userName+format).getBytes());
String encoded = URLEncoder.encode(DatatypeConverter.printBase64Binary(result)); String encoded = URLEncoder.encode(DatatypeConverter.printBase64Binary(result));
String cookieValue = userName+"|"+URLEncoder.encode(format).replaceAll("\\+", "%20")+"|"+encoded; String cookieValue = userName+"|"+URLEncoder.encode(format).replaceAll("\\+", "%20")+"|"+encoded;
NewCookie cookie = new NewCookie("user-id", NewCookie cookie = new NewCookie("user-id",
cookieValue, cookieValue,
"/", rStudioServerAddress, "", -1, false, true ); "/", rStudioServerAddress, "", -1, false, true );
return Response.seeOther(new URI("http://"+rStudioServerAddress)) return Response.seeOther(new URI("http://"+rStudioServerAddress))
.cookie(cookie).build(); .cookie(cookie).build();
}catch(Exception e){ }catch(Exception e){
log.error("error creating response", e); log.error("error creating response", e);
return Response.serverError().build();} return Response.serverError().build();}
} }
} }

View File

@ -0,0 +1,43 @@
package org.gcube.data.analysis.rconnector;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Utils {
private static Logger log = LoggerFactory.getLogger(Utils.class);
protected static String executeCommandLine(String ... args){
log.debug("executing command {}",Arrays.asList(args));
Process process = null;
String lastline = "";
try {
ProcessBuilder pb = new ProcessBuilder(args);
process = pb.start();
try {
process.waitFor();
} catch (InterruptedException e) {
log.warn("interrupt Exception on process",e);
}
BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = br.readLine();
while (line!=null){
lastline += line;
line = br.readLine();
}
} catch (IOException e) {
log.error("error executing command line",e);
}
log.debug("command result line is {} ",lastline);
return lastline;
}
}

View File

@ -1,5 +1,3 @@
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" <?xml version="1.0" encoding="UTF-8"?>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
</beans> </beans>