Skip to content

Commit

Permalink
Merge pull request #79 from nr23730/authorization
Browse files Browse the repository at this point in the history
Use authorization from cBioPortal
  • Loading branch information
nr23730 committed Mar 31, 2021
2 parents 8294088 + 9d1ed56 commit 39b77ff
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 3 deletions.
122 changes: 120 additions & 2 deletions src/main/java/fhirspark/FhirSpark.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import fhirspark.resolver.HgncGeneName;
import fhirspark.resolver.OncoKbDrug;
import fhirspark.restmodel.CbioportalRest;
Expand All @@ -11,8 +14,15 @@
import fhirspark.restmodel.Mtb;
import java.io.FileInputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.ws.rs.core.Cookie;
import org.eclipse.jetty.http.HttpStatus;
import spark.Request;

import static spark.Spark.delete;
import static spark.Spark.get;
Expand All @@ -30,6 +40,8 @@ public final class FhirSpark {

private static JsonFhirMapper jsonFhirMapper;
private static JsonHl7v2Mapper jsonHl7v2Mapper;
private static Settings settings;
private static Client client = new Client();
private static ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());

private FhirSpark() {
Expand All @@ -46,7 +58,7 @@ public static void main(final String[] args) throws Exception {
settingsYaml = new FileInputStream(args[0]);
}
ConfigurationLoader configLoader = new ConfigurationLoader();
final Settings settings = configLoader.loadConfiguration(settingsYaml, Settings.class);
settings = configLoader.loadConfiguration(settingsYaml, Settings.class);
HgncGeneName.initialize(settings.getHgncPath());
OncoKbDrug.initalize(settings.getOncokbPath());
jsonFhirMapper = new JsonFhirMapper(settings);
Expand All @@ -68,7 +80,33 @@ public static void main(final String[] args) throws Exception {
return res;
});

/**
*
* Checks whether the client has permission to view and manipulate the data of the given patientId
*
* @param req Incoming Java Spark Request
* @param patientId requested patientId
* @return FORBIDDEN_403 if not authorized
* @return OK_200 if authorized
*/
get("/mtb/:patientId/permission", (req, res) -> {
if (settings.getLoginRequired()
&& (!validateRequest(req) || !validateManipulation(req))) {
res.status(HttpStatus.FORBIDDEN_403);
return res;
}
res.status(HttpStatus.ACCEPTED_202);
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Origin", req.headers("Origin"));
res.header("Cache-Control", "no-cache, no-store, max-age=0");
return res;
});

get("/mtb/:patientId", (req, res) -> {
if (settings.getLoginRequired() && !validateRequest(req)) {
res.status(HttpStatus.FORBIDDEN_403);
return res;
}
res.status(HttpStatus.OK_200);
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Origin", req.headers("Origin"));
Expand All @@ -79,6 +117,11 @@ public static void main(final String[] args) throws Exception {
});

put("/mtb/:patientId", (req, res) -> {
if (settings.getLoginRequired()
&& (!validateRequest(req) || !validateManipulation(req))) {
res.status(HttpStatus.FORBIDDEN_403);
return res;
}
res.status(HttpStatus.CREATED_201);
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Origin", req.headers("Origin"));
Expand All @@ -95,6 +138,11 @@ public static void main(final String[] args) throws Exception {
});

delete("/mtb/:patientId", (req, res) -> {
if (settings.getLoginRequired()
&& (!validateRequest(req) || !validateManipulation(req))) {
res.status(HttpStatus.FORBIDDEN_403);
return res;
}
res.status(HttpStatus.OK_200);
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Origin", req.headers("Origin"));
Expand Down Expand Up @@ -128,7 +176,8 @@ public static void main(final String[] args) throws Exception {
new TypeReference<List<GeneticAlteration>>() {
});
res.body(
objectMapper.writeValueAsString(jsonFhirMapper.getTherapyRecommendationsByAlteration(alterations)));
objectMapper.writeValueAsString(jsonFhirMapper
.getTherapyRecommendationsByAlteration(alterations)));
return res.body();
});

Expand Down Expand Up @@ -159,4 +208,73 @@ public static void main(final String[] args) throws Exception {

}

/**
* Checks if the session id is authorized to access the clinical data of the patient.
*
* @param req Incoming Java Spark Request
* @return Boolean if the session if able to access the data
*/
private static boolean validateRequest(Request req) {
String portalDomain = settings.getPortalUrl();
String validatePath = "api/studies/" + settings.getMtbStudy() + "/patients/"
+ req.params(":patientId");
String requestUrl = portalDomain + validatePath;

WebResource webResource = client.resource(requestUrl);
WebResource.Builder builder = webResource.getRequestBuilder();
builder = builder.cookie(new Cookie("JSESSIONID", req.cookies().get("JSESSIONID")));
ClientResponse response = builder.accept("application/json").get(ClientResponse.class);

System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
System.out.println("Validation request for study:");
System.out.println("Sending request at requestUrl: " + requestUrl);

if (response.getStatus() == HttpStatus.OK_200) {
System.out.println("Response code was good: " + response.getStatus() + "\n");
return true;
}
System.out.println("Response code was: " + response.getStatus() + "\n");
return false;
}

/**
* Checks if the session id is authorized to manipulate the clinical data of the patients in the MTB study.
*
* @param req Incoming Java Spark Request
* @return Boolean if the session is able to access the data
*/
private static boolean validateManipulation(Request req) {
String requestedPatientId = req.params(":patientId");
String mtbStudy = settings.getMtbStudy();
String userRoles = req.headers("X-USERROLES");
String userLoginName = req.headers("X-USERLOGIN");

System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
System.out.println("Manipulation permission request:\nfrom user: " + userLoginName + ", for patientId: "
+ requestedPatientId + "\nfound header X-USERROLES: " + userRoles);

if (userRoles == null || userRoles.isEmpty()) {
System.out.println("Incoming user roles are null or empty - returning false\n");
return false;
}

ArrayList<String> roleList = new ArrayList<String>();
Pattern p = Pattern.compile("\"([^\"]*)\"");
Matcher m = p.matcher(userRoles);
while (m.find()) {
roleList.add(m.group(1));
}

for (String s : roleList) {
if (s.equals(mtbStudy) || s.equals(requestedPatientId)) {
System.out.println("permission granted with role: " + s + "\n");
return true;
}
}

System.out.println("no matching role could be found - returning false\n");
return false;

}

}
39 changes: 39 additions & 0 deletions src/main/java/fhirspark/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
"observationSystem",
"patientSystem",
"hgncPath",
"portalUrl",
"mtbStudy",
"loginRequired",
"oncokbPath",
"hl7v2config"
})
Expand All @@ -37,6 +40,12 @@ public final class Settings {
private String patientSystem;
@JsonProperty("hgncPath")
private String hgncPath;
@JsonProperty("portalUrl")
private String portalUrl;
@JsonProperty("mtbStudy")
private String mtbStudy;
@JsonProperty("loginRequired")
private Boolean loginRequired;
@JsonProperty("oncokbPath")
private String oncokbPath;
@JsonProperty("hl7v2config")
Expand Down Expand Up @@ -112,6 +121,36 @@ public void setHgncPath(String hgncPath) {
this.hgncPath = hgncPath;
}

@JsonProperty("portalUrl")
public String getPortalUrl() {
return portalUrl;
}

@JsonProperty("portalUrl")
public void setPortalUrl(String portalUrl) {
this.portalUrl = portalUrl;
}

@JsonProperty("mtbStudy")
public String getMtbStudy() {
return mtbStudy;
}

@JsonProperty("mtbStudy")
public void setMtbStudy(String mtbStudy) {
this.mtbStudy = mtbStudy;
}

@JsonProperty("loginRequired")
public Boolean getLoginRequired() {
return loginRequired;
}

@JsonProperty("loginRequired")
public void setLoginRequired(Boolean loginRequired) {
this.loginRequired = loginRequired;
}

@JsonProperty("oncokbPath")
public String getOncokbPath() {
return oncokbPath;
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ specimenSystem: ${FHIRSPARK_SPECIMENSYSTEM:-https://cbioportal.org/specimen/}
diagnosticReportSystem: ${FHIRSPARK_DIAGNOSTICREPORTSYSTEM:-https://cbioportal.org/mtb/}
observationSystem: ${FHIRSPARK_OBSERVATIONSYSTEM:-https://cbioportal.org/therapyrecommendation/}
patientSystem: ${FHIRSPARK_PATIENTSYSTEM:-https://cbioportal.org/patient/}
portalUrl: ${FHIRSPARK_PORTALURL:-http://cbioportal/}
mtbStudy: ${FHIRSPARK_MTBSTUDY:-MTB}
loginRequired: ${FHIRSPARK_LOGINREQUIRED:-true}
hgncPath: ${FHIRSPARK_HGNCPATH:-hgnc.csv}
oncokbPath: ${FHIRSPARK_ONCOKBPATH:-drugs.json}
hl7v2config:
- sendv2: ${FHIRSPARK_SENDHL7V2:-true}
- sendv2: ${FHIRSPARK_SENDHL7V2:-false}
server: ${FHIRSPARK_HL7V2SERVER:-localhost}
port: ${FHIRSPARK_HL7V2PORT:-1011}

0 comments on commit 39b77ff

Please sign in to comment.