diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/JAXRSConfiguration.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/JAXRSConfiguration.java
index d0f7a11e3..54756508e 100755
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/JAXRSConfiguration.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/JAXRSConfiguration.java
@@ -2,7 +2,6 @@
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.type.MapType;
import edu.harvard.hms.dbmi.avillach.auth.data.entity.Connection;
import edu.harvard.hms.dbmi.avillach.auth.data.entity.Privilege;
import edu.harvard.hms.dbmi.avillach.auth.data.entity.Role;
@@ -11,7 +10,6 @@
import edu.harvard.hms.dbmi.avillach.auth.data.repository.RoleRepository;
import edu.harvard.hms.dbmi.avillach.auth.rest.TokenService;
import io.swagger.jaxrs.config.BeanConfig;
-import org.apache.commons.io.IOUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
@@ -28,13 +26,10 @@
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.SecurityContext;
-import java.io.InputStream;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.*;
-import javax.net.ssl.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import static edu.harvard.hms.dbmi.avillach.auth.utils.AuthNaming.AuthRoleNaming.ADMIN;
import static edu.harvard.hms.dbmi.avillach.auth.utils.AuthNaming.AuthRoleNaming.SUPER_ADMIN;
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/data/repository/UserRepository.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/data/repository/UserRepository.java
index a627ccd5f..2188daa24 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/data/repository/UserRepository.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/data/repository/UserRepository.java
@@ -13,152 +13,194 @@
import javax.persistence.NonUniqueResultException;
import javax.persistence.criteria.*;
import javax.transaction.Transactional;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
+import java.util.*;
import java.util.stream.Collectors;
/**
*
Provides operations for the User entity to interact with a database.
+ *
* @see User
*/
@Transactional
@ApplicationScoped
public class UserRepository extends BaseRepository {
- private Logger logger = LoggerFactory.getLogger(UserRepository.class);
-
- protected UserRepository() {
- super(User.class);
- }
-
- public User findBySubject(String subject) {
- CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
- Root queryRoot = query.from(User.class);
- query.select(queryRoot);
- CriteriaBuilder cb = cb();
- return em.createQuery(query
- .where(
- eq(cb, queryRoot, "subject", subject)))
- .getSingleResult();
- }
-
- public User findBySubjectAndConnection(String subject, String connectionId){
- CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
- Root queryRoot = query.from(User.class);
- query.select(queryRoot);
- CriteriaBuilder cb = cb();
- try {
+ private Logger logger = LoggerFactory.getLogger(UserRepository.class);
+
+ protected UserRepository() {
+ super(User.class);
+ }
+
+ public User findBySubject(String subject) {
+ CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
+ Root queryRoot = query.from(User.class);
+ query.select(queryRoot);
+ CriteriaBuilder cb = cb();
+ return em.createQuery(query
+ .where(
+ eq(cb, queryRoot, "subject", subject)))
+ .getSingleResult();
+ }
+
+ public User findBySubjectAndConnection(String subject, String connectionId) {
+ CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
+ Root queryRoot = query.from(User.class);
+ query.select(queryRoot);
+ CriteriaBuilder cb = cb();
+ try {
return em.createQuery(query
- .where(
- cb.and(
- cb.equal(queryRoot.join("connection")
- .get("id"), connectionId),
- eq(cb, queryRoot, "subject", subject))))
+ .where(
+ cb.and(
+ cb.equal(queryRoot.join("connection")
+ .get("id"), connectionId),
+ eq(cb, queryRoot, "subject", subject))))
.getSingleResult();
- } catch (NoResultException e){
- return null;
+ } catch (NoResultException e) {
+ return null;
+ }
+ }
+
+ public List listUnmatchedByConnectionId(Connection connection) {
+ CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
+ Root queryRoot = query.from(User.class);
+ query.select(queryRoot);
+ CriteriaBuilder cb = cb();
+ return em.createQuery(query
+ .where(
+ cb.and(
+ eq(cb, queryRoot, "connection", connection),
+ eq(cb, queryRoot, "matched", false))))
+ .getResultList();
+ }
+
+ /**
+ * @return
+ */
+ public User findOrCreate(User inputUser) {
+ User user = null;
+ String subject = inputUser.getSubject();
+ try {
+ user = findBySubject(subject);
+ logger.info("findOrCreate(), trying to find user: {subject: " + subject +
+ "}, and found a user with uuid: " + user.getUuid()
+ + ", subject: " + user.getSubject());
+ } catch (NoResultException e) {
+ logger.debug("findOrCreate() subject " + subject +
+ " could not be found by `entityManager`, going to create a new user.");
+ user = createUser(inputUser);
+ } catch (NonUniqueResultException e) {
+ logger.error("findOrCreate() " + e.getClass().getSimpleName() + ": " + e.getMessage());
+ }
+ return user;
+ }
+
+ private User createUser(User inputUser) {
+ String subject = inputUser.getSubject();
+ logger.debug("createUser() creating user, subject: " + subject + " ......");
+ em().persist(inputUser);
+
+ User result = getById(inputUser.getUuid());
+ if (result != null)
+ logger.info("createUser() created user, uuid: " + result.getUuid()
+ + ", subject: " + subject
+ + ", role: " + result.getRoleString()
+ + ", privilege: " + result.getPrivilegeString());
+
+ return result;
+ }
+
+ public User changeRole(User user, Set roles) {
+ logger.info("Starting changing the role of user: " + user.getUuid()
+ + ", with subject: " + user.getSubject() + ", to " + roles.stream().map(role -> role.getName()).collect(Collectors.joining(",")));
+ user.setRoles(roles);
+ em().merge(user);
+ User updatedUser = getById(user.getUuid());
+ logger.info("User: " + updatedUser.getUuid() + ", with subject: " +
+ updatedUser.getSubject() + ", now has a new role: " + updatedUser.getRoleString());
+ return updatedUser;
+ }
+
+ @Override
+ public void persist(User user) {
+ findOrCreate(user);
+ }
+
+ public User findByEmail(String email) {
+ CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
+ Root queryRoot = query.from(User.class);
+ query.select(queryRoot);
+ CriteriaBuilder cb = cb();
+ return em.createQuery(query
+ .where(
+ eq(cb, queryRoot, "email", email)))
+ .getSingleResult();
+ }
+
+ public boolean checkAgainstTOSDate(String userId) {
+ CriteriaQuery query = cb().createQuery(User.class);
+ Root queryRoot = query.from(User.class);
+ query.select(queryRoot);
+ CriteriaBuilder cb = cb();
+
+ Subquery subquery = query.subquery(Date.class);
+ Root tosRoot = subquery.from(TermsOfService.class);
+ subquery.select(cb.greatest(tosRoot.get("dateUpdated")));
+
+ return !em.createQuery(query
+ .where(
+ cb.and(
+ eq(cb, queryRoot, "subject", userId),
+ cb.greaterThanOrEqualTo(queryRoot.get("acceptedTOS"), subquery))))
+ .getResultList().isEmpty();
+ }
+
+ /**
+ * @param uuid the uuid of the user to find
+ * @return the user with the given uuid, or null if no user is found
+ */
+ public User findByUUID(UUID uuid) {
+ CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
+ Root queryRoot = query.from(User.class);
+ query.select(queryRoot);
+ CriteriaBuilder cb = cb();
+ try {
+ return em.createQuery(query
+ .where(
+ eq(cb, queryRoot, "uuid", uuid)))
+ .getSingleResult();
+ } catch (NoResultException e) {
+ logger.error("findByUUID() " + e.getClass().getSimpleName() + ": " + e.getMessage());
}
- }
-
- public List listUnmatchedByConnectionId(Connection connection) {
- CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
- Root queryRoot = query.from(User.class);
- query.select(queryRoot);
- CriteriaBuilder cb = cb();
- return em.createQuery(query
- .where(
- cb.and(
- eq(cb, queryRoot, "connection", connection),
- eq(cb, queryRoot, "matched", false))))
- .getResultList();
- }
-
- /**
- *
- * @return
- */
- public User findOrCreate(User inputUser) {
- User user = null;
- String subject = inputUser.getSubject();
- try{
- user = findBySubject(subject);
- logger.info("findOrCreate(), trying to find user: {subject: " + subject+
- "}, and found a user with uuid: " + user.getUuid()
- + ", subject: " + user.getSubject());
- } catch (NoResultException e) {
- logger.debug("findOrCreate() subject " + subject +
- " could not be found by `entityManager`, going to create a new user.");
- user = createUser(inputUser);
- }catch(NonUniqueResultException e){
- logger.error("findOrCreate() " + e.getClass().getSimpleName() + ": " + e.getMessage());
- }
- return user;
- }
-
- private User createUser(User inputUser) {
- String subject = inputUser.getSubject();
-// if (subject == null && userId == null){
-// logger.error("createUser() cannot create user when both subject and userId are null");
-// return null;
-// }
- logger.debug("createUser() creating user, subject: " + subject + " ......");
- em().persist(inputUser);
-
- User result = getById(inputUser.getUuid());
- if (result != null)
- logger.info("createUser() created user, uuid: " + result.getUuid()
- + ", subject: " + subject
- + ", role: " + result.getRoleString()
- + ", privilege: "+ result.getPrivilegeString());
-
- return result;
- }
-
- public User changeRole(User user, Set roles){
- logger.info("Starting changing the role of user: " + user.getUuid()
- + ", with subject: " + user.getSubject() + ", to " + roles.stream().map(role -> role.getName()).collect(Collectors.joining(",")));
- user.setRoles(roles);
- em().merge(user);
- User updatedUser = getById(user.getUuid());
- logger.info("User: " + updatedUser.getUuid() + ", with subject: " +
- updatedUser.getSubject() + ", now has a new role: " + updatedUser.getRoleString());
- return updatedUser;
- }
-
- @Override
- public void persist(User user) {
- findOrCreate(user);
- }
-
- public User findByEmail(String email) {
- CriteriaQuery query = em.getCriteriaBuilder().createQuery(User.class);
- Root queryRoot = query.from(User.class);
- query.select(queryRoot);
- CriteriaBuilder cb = cb();
- return em.createQuery(query
- .where(
- eq(cb, queryRoot, "email", email)))
- .getSingleResult();
- }
-
- public boolean checkAgainstTOSDate(String userId){
- CriteriaQuery query = cb().createQuery(User.class);
- Root queryRoot = query.from(User.class);
- query.select(queryRoot);
- CriteriaBuilder cb = cb();
-
- Subquery subquery = query.subquery(Date.class);
- Root tosRoot = subquery.from(TermsOfService.class);
- subquery.select(cb.greatest(tosRoot.get("dateUpdated")));
-
- return !em.createQuery(query
- .where(
- cb.and(
- eq(cb, queryRoot, "subject", userId),
- cb.greaterThanOrEqualTo(queryRoot.get("acceptedTOS"), subquery))))
- .getResultList().isEmpty();
- }
+ return null;
+ }
+
+ /**
+ * Creates a user with a subject of "open_access|{uuid}"
+ * and an email of "{uuid}@open_access.com"
+ *
+ * @return the created user
+ */
+ public User createOpenAccessUser(Role openAccessRole) {
+ User user = new User();
+ em().persist(user);
+
+ user = getById(user.getUuid());
+ user.setSubject("open_access|" + user.getUuid().toString());
+ if (openAccessRole != null) {
+ user.setRoles(new HashSet<>(List.of(openAccessRole)));
+ } else {
+ logger.error("createOpenAccessUser() openAccessRole is null");
+ user.setRoles(new HashSet<>());
+ }
+ user.setEmail(user.getUuid() + "@open_access.com");
+ em().merge(user);
+
+ logger.info("createOpenAccessUser() created user, uuid: " + user.getUuid()
+ + ", subject: " + user.getSubject()
+ + ", role: " + user.getRoleString()
+ + ", privilege: " + user.getPrivilegeString()
+ + ", email: " + user.getEmail());
+ return user;
+ }
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthService.java
index 1abf0938e..b304af1d3 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthService.java
@@ -31,10 +31,7 @@
@Produces("application/json")
public class AuthService {
- private Logger logger = LoggerFactory.getLogger(this.getClass());
-
- @Inject
- AuthorizationService authorizationService;
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Inject
AuthenticationService authenticationService;
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OpenAuthService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OpenAuthService.java
new file mode 100644
index 000000000..35b059512
--- /dev/null
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OpenAuthService.java
@@ -0,0 +1,49 @@
+package edu.harvard.hms.dbmi.avillach.auth.rest;
+
+import edu.harvard.hms.dbmi.avillach.auth.JAXRSConfiguration;
+import edu.harvard.hms.dbmi.avillach.auth.service.auth.OpenAuthenticationService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import java.util.Map;
+
+/**
+ * The authentication endpoint for PSAMA.
+ */
+@Api
+@Path("/open")
+@Consumes("application/json")
+@Produces("application/json")
+public class OpenAuthService {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Inject
+ private OpenAuthenticationService openAuthenticationService;
+
+ @ApiOperation(value = "The authentication endpoint for retrieving a valid user token")
+ @POST
+ @Path("/authentication")
+ public Response authentication(@ApiParam(required = true, value = "A json object that includes all Oauth authentication needs, for example, access_token and redirectURI") Map authRequest) {
+ logger.debug("authentication() starting...");
+
+ // idp_provider also has default value of "default" if not set in the config file
+ // This is a temporary solution to ensure that a user cannot authenticate against fence using the open endpoint
+ if (!JAXRSConfiguration.idp_provider.equalsIgnoreCase("fence")) {
+ return openAuthenticationService.authenticate(authRequest);
+ }
+
+ // Fence authentication is not supported by the open endpoint
+ return Response.status(Response.Status.FORBIDDEN).build();
+ }
+
+}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/UserService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/UserService.java
index 4b6bb1d4b..e6b775af1 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/UserService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/UserService.java
@@ -281,7 +281,8 @@ public Response getCurrentUser(
.setPrivileges(user.getPrivilegeNameSet())
.setUuid(user.getUuid().toString())
.setAcceptedTOS(true); //FENCE only returns valid users who have agreed to their terms
-
+
+ logger.debug("getCurrentUser() userForDisplay: " + userForDisplay.toString());
// currently, the queryScopes are simple combination of queryScope string together as a set.
// We are expecting the queryScope string as plain string. If it is a JSON, we could change the
@@ -313,6 +314,8 @@ public Response getCurrentUser(
}
}
+ logger.debug("getCurrentUser() returning userForDisplay: " + userForDisplay.toString());
+
return PICSUREResponse.success(userForDisplay);
}
@@ -519,5 +522,4 @@ private void checkAssociation(List users) throws ProtocolException{
}
}
-
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/AuthenticationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/AuthenticationService.java
index d17e60d80..c4c551750 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/AuthenticationService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/AuthenticationService.java
@@ -86,7 +86,6 @@ public Response getToken(Map authRequest){
throw new ApplicationException("cannot get sufficient user information. Please contact admin.");
}
- //Do we have this user already?
User user = userRepository.findBySubjectAndConnection(userId, connectionId);
if (user == null){
//Try to match
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/FENCEAuthenticationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/FENCEAuthenticationService.java
index b0791b519..5bdadd09b 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/FENCEAuthenticationService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/FENCEAuthenticationService.java
@@ -8,6 +8,8 @@
import java.io.File;
import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
@@ -148,6 +150,12 @@ public Response getFENCEProfile(String callback_url, Map authReq
logger.debug("getFENCEProfile() starting...");
String fence_code = authRequest.get("code");
+ // Validate that the fence code is alphanumeric
+ if (!fence_code.matches("[a-zA-Z0-9]+")) {
+ logger.error("getFENCEProfile() fence code is not alphanumeric");
+ throw new NotAuthorizedException("The fence code is not alphanumeric");
+ }
+
JsonNode fence_user_profile = null;
// Get the Gen3/FENCE user profile. It is a JsonNode object
try {
@@ -192,54 +200,10 @@ public Response getFENCEProfile(String callback_url, Map authReq
// Update the user's roles (or create them if none exists)
//Set actual_user_roles = u.getRoles();
- Iterator access_role_names = fence_user_profile.get("project_access").fieldNames();
- while (access_role_names.hasNext()) {
- String access_role_name = access_role_names.next();
- logger.debug("getFENCEProfile() AccessRole:"+access_role_name);
-
- // These two special access does not matter. We are not using it.
- if (access_role_name.equals("admin") || access_role_name.equals("parent")) {
- logger.info("SKIPPING ACCESS ROLE: " + access_role_name);
- continue;
- }
- //topmed ==> access to all studies (not just topmed)
- if (access_role_name.equals("topmed") ) {
- Map projects = getFENCEMapping();
- for(Map projectMetadata : projects.values()) {
- String projectId = (String) projectMetadata.get("study_identifier");
- String consentCode = (String) projectMetadata.get("consent_group_code");
- String newRoleName = "FENCE_"+projectId+"_"+consentCode;
-
- if (upsertRole(current_user, newRoleName, "FENCE role "+newRoleName)) {
- logger.info("getFENCEProfile() Updated TOPMED user role. Now it includes `"+newRoleName+"`");
- } else {
- logger.error("getFENCEProfile() could not add roles to TOPMED user's profile");
- }
- }
- continue;
- }
-
-
- String[] parts = access_role_name.split("\\.");
-
- String newRoleName;
- if (parts.length > 1) {
- newRoleName = "FENCE_"+parts[0]+"_"+parts[parts.length-1];
- } else {
- newRoleName = "FENCE_"+access_role_name;
- }
- logger.info("getFENCEProfile() New PSAMA role name:"+newRoleName);
-
- if (upsertRole(current_user, newRoleName, "FENCE role "+newRoleName)) {
- logger.info("getFENCEProfile() Updated user role. Now it includes `"+newRoleName+"`");
- } else {
- logger.error("getFENCEProfile() could not add roles to user's profile");
- }
-
- // TODO: In case we need to do something with this part, we can uncomment it.
- //JsonNode role_object = fence_user_profile.get("project_access").get(newRoleName);
- //It is a an array of strings, like this: ["read-storage","read"]
- //logger.debug("getFENCEProfile() object:"+role_object.toString());
+ Iterator project_access_names = fence_user_profile.get("authz").fieldNames();
+ while (project_access_names.hasNext()) {
+ String access_role_name = project_access_names.next();
+ createAndUpsertRole(access_role_name, current_user);
}
final String idp = extractIdp(current_user);
@@ -271,6 +235,31 @@ public Response getFENCEProfile(String callback_url, Map authReq
return PICSUREResponse.success(responseMap);
}
+ private void createAndUpsertRole(String access_role_name, User current_user) {
+ logger.debug("createAndUpsertRole() starting...");
+ Map projectMetadata = getFENCEMapping().values().stream()
+ .filter(map -> access_role_name.equals(
+ map.get("authZ").toString().replace("\\/", "/"))
+ ).findFirst().orElse(null);
+
+ if (projectMetadata == null) {
+ logger.error("getFENCEProfile() -> createAndUpsertRole could not find study in FENCE mapping SKIPPING: " + access_role_name);
+ return;
+ }
+
+ String projectId = (String) projectMetadata.get("study_identifier");
+ String consentCode = (String) projectMetadata.get("consent_group_code");
+ String newRoleName = (consentCode != null && consentCode != "") ? "FENCE_"+projectId+"_"+consentCode : "FENCE_"+projectId;
+
+ logger.info("getFENCEProfile() New PSAMA role name:"+newRoleName);
+
+ if (upsertRole(current_user, newRoleName, "FENCE role "+newRoleName)) {
+ logger.info("getFENCEProfile() Updated user role. Now it includes `"+newRoleName+"`");
+ } else {
+ logger.error("getFENCEProfile() could not add roles to user's profile");
+ }
+ }
+
private String extractIdp(User current_user) {
try {
final ObjectNode node;
@@ -323,7 +312,7 @@ private User createUserFromFENCEProfile(JsonNode node) {
* @param roleDescription Description of the Role
* @return boolean Whether the Role was successfully added to the User or not
*/
- private boolean upsertRole(User u, String roleName, String roleDescription) {
+ public boolean upsertRole(User u, String roleName, String roleDescription) {
boolean status = false;
logger.debug("upsertRole() starting for user subject:"+u.getSubject());
@@ -369,13 +358,18 @@ private Set addFENCEPrivileges(User u, Role r) {
//Topmed has up to three ARs for topmed / topmed + parent / topmed + harmonized
Set privs = r.getPrivileges();
if (privs == null) { privs = new HashSet();}
-
- //e.g. FENCE_phs0000xx_c2
- String[] parts = roleName.split("_");
- String project_name = parts[1];
- String consent_group = parts.length > 2 ? parts[2] : "";
-
-
+
+ //e.g. FENCE_phs0000xx_c2 or FENCE_tutorial-biolinc_camp
+ String project_name = extractProject(roleName);
+ if (project_name.length() <= 0) {
+ logger.warn("addFENCEPrivileges() role name: "+roleName+" returned an empty project name");
+ }
+ String consent_group = extractConsentGroup(roleName);
+ if (consent_group.length() <= 0) {
+ logger.warn("addFENCEPrivileges() role name: "+roleName+" returned an empty consent group");
+ }
+ logger.info("addFENCEPrivileges() project name: "+project_name+" consent group: "+consent_group);
+
// Look up the metadata by consent group.
Map projectMetadata = getFENCEMappingforProjectAndConsent(project_name, consent_group);
@@ -401,7 +395,7 @@ private Set addFENCEPrivileges(User u, Role r) {
if(concept_path != null) {
concept_path = concept_path.replaceAll("\\\\", "\\\\\\\\");
}
-
+
if(dataType != null && dataType.contains("G")) {
//insert genomic/topmed privs - this will also add rules for including harmonized & parent data if applicable
privs.add(upsertTopmedPrivilege(project_name, projectAlias, consent_group, concept_path, isHarmonized));
@@ -420,13 +414,41 @@ private Set addFENCEPrivileges(User u, Role r) {
//projects without G or P in data_type are skipped
if(dataType == null || (!dataType.contains("P") && !dataType.contains("G"))){
- logger.warn("Missing study type for " + project_name + " " + consent_group);
+ logger.warn("Missing study type for " + project_name + " " + consent_group + ". Skipping.");
}
logger.info("addPrivileges() Finished");
return privs;
}
+ private static String extractProject(String roleName) {
+ String projectPattern = "FENCE_(.*?)(?:_c\\d+)?$";
+ Pattern projectRegex = Pattern.compile(projectPattern);
+ Matcher projectMatcher = projectRegex.matcher(roleName);
+ String project = "";
+ if (projectMatcher.find()) {
+ project = projectMatcher.group(1).trim();
+ } else {
+ String[] parts = roleName.split("_", 1);
+ if (parts.length > 0) {
+ project = parts[1];
+ }
+ }
+ return project;
+ }
+
+ private static String extractConsentGroup(String roleName) {
+ String consentPattern = "FENCE_.*?_c(\\d+)$";
+
+ Pattern consentRegex = Pattern.compile(consentPattern);
+ Matcher consentMatcher = consentRegex.matcher(roleName);
+ String consentGroup = "";
+ if (consentMatcher.find()) {
+ consentGroup = "c" + consentMatcher.group(1).trim();
+ }
+ return consentGroup;
+ }
+
/**
* Creates a privilege with a set of access rules that allow queries containing a consent group to pass if the query only contains valid entries that match conceptPath. If the study is harmonized,
* this also creates an access rule to allow access when using the harmonized consent concept path.
@@ -441,8 +463,8 @@ private Set addFENCEPrivileges(User u, Role r) {
*/
private Privilege upsertClinicalPrivilege(String studyIdentifier, String projectAlias, String consent_group, String conceptPath, boolean isHarmonized) {
- String privilegeName = "PRIV_FENCE_"+studyIdentifier+"_"+consent_group+(isHarmonized?"_HARMONIZED":"");
- Privilege priv = privilegeRepo.getUniqueResultByColumn("name", privilegeName);
+ String privilegeName = (consent_group != null && consent_group != "") ? "PRIV_FENCE_"+studyIdentifier+"_"+consent_group+(isHarmonized?"_HARMONIZED":"") : "PRIV_FENCE_"+studyIdentifier+(isHarmonized?"_HARMONIZED":"") ;
+ Privilege priv = privilegeRepo.getUniqueResultByColumn("name", privilegeName);
if(priv != null) {
logger.info("upsertClinicalPrivilege() " + privilegeName + " already exists");
return priv;
@@ -469,10 +491,11 @@ private Privilege upsertClinicalPrivilege(String studyIdentifier, String project
// TOOD: Change this to a mustache template
+ String studyIdentifierField = (consent_group != null && consent_group != "") ? studyIdentifier+"."+consent_group: studyIdentifier;
String queryTemplateText = "{\"categoryFilters\": {\""
+consent_concept_path
+"\":[\""
- +studyIdentifier+"."+consent_group
+ +studyIdentifierField
+"\"]},"
+"\"numericFilters\":{},\"requiredFields\":[],"
+"\"fields\":[\"" + parentAccessionField + "\"],"
@@ -946,7 +969,7 @@ private Privilege upsertTopmedPrivilege(String studyIdentifier, String projectAl
// prentRule should be null if this is the main rule, or the appropriate value if this is a sub rule
private AccessRule createConsentAccessRule(String studyIdentifier, String consent_group, String label, String consent_path) {
logger.debug("upsertConsentAccessRule() starting");
- String ar_name = "AR_CONSENT_" + studyIdentifier+"_"+consent_group+ "_" +label;
+ String ar_name = (consent_group != null && consent_group != "") ? "AR_CONSENT_" + studyIdentifier+"_"+consent_group+ "_" +label : "AR_CONSENT_" + studyIdentifier;
AccessRule ar = accessruleRepo.getUniqueResultByColumn("name", ar_name);
if(ar != null) {
@@ -959,14 +982,16 @@ private AccessRule createConsentAccessRule(String studyIdentifier, String consen
logger.info("upsertConsentAccessRule() Creating new access rule "+ar_name);
ar = new AccessRule();
ar.setName(ar_name);
- ar.setDescription("FENCE AR for "+studyIdentifier+"."+consent_group + " clinical concepts");
+ String description = (consent_group != null && consent_group != "") ? "FENCE AR for "+studyIdentifier+"."+consent_group + " clinical concepts" : "FENCE AR for "+studyIdentifier+" clinical concepts";
+ ar.setDescription(description);
StringBuilder ruleText = new StringBuilder();
ruleText.append("$.query.query.categoryFilters.");
ruleText.append(consent_path);
ruleText.append("[*]");
ar.setRule(ruleText.toString());
ar.setType(AccessRule.TypeNaming.ALL_CONTAINS);
- ar.setValue(studyIdentifier+"."+consent_group);
+ String arValue = (consent_group != null && consent_group != "") ? studyIdentifier+"."+consent_group : studyIdentifier;
+ ar.setValue(arValue);
ar.setCheckMapKeyOnly(false);
ar.setCheckMapNode(false);
ar.setEvaluateOnlyByGates(false);
@@ -981,7 +1006,7 @@ private AccessRule createConsentAccessRule(String studyIdentifier, String consen
// Generates Main Rule only; gates & sub rules attached by calling method
private AccessRule upsertTopmedAccessRule(String project_name, String consent_group, String label ) {
logger.debug("upsertTopmedAccessRule() starting");
- String ar_name = "AR_TOPMED_"+project_name+"_"+consent_group + "_" + label;
+ String ar_name = (consent_group != null && consent_group != "") ? "AR_TOPMED_"+project_name+"_"+consent_group + "_" + label : "AR_TOPMED_"+project_name+"_"+label;
AccessRule ar = accessruleRepo.getUniqueResultByColumn("name", ar_name);
if (ar != null) {
logger.info("upsertTopmedAccessRule() AccessRule "+ar_name+" already exists.");
@@ -998,7 +1023,8 @@ private AccessRule upsertTopmedAccessRule(String project_name, String consent_gr
ruleText.append("[*]");
ar.setRule(ruleText.toString());
ar.setType(AccessRule.TypeNaming.ALL_CONTAINS);
- ar.setValue(project_name+"."+consent_group);
+ String arValue = (consent_group != null && consent_group != "") ? project_name+"."+consent_group : project_name;
+ ar.setValue(arValue);
ar.setCheckMapKeyOnly(false);
ar.setCheckMapNode(false);
ar.setEvaluateOnlyByGates(false);
@@ -1075,7 +1101,7 @@ private AccessRule upsertConsentGate(String gateName, String rule, boolean is_pr
private Map getFENCEMappingforProjectAndConsent(String projectId, String consent_group) {
- String consentVal = projectId + "." + consent_group;
+ String consentVal = (consent_group != null && consent_group != "") ? projectId + "." + consent_group : projectId;
logger.info("getFENCEMappingforProjectAndConsent() looking up "+consentVal);
Object projectMetadata = getFENCEMapping().get(consentVal);
@@ -1098,7 +1124,9 @@ private Map getFENCEMapping(){
logger.debug("getFENCEMapping: found FENCE mapping with " + projects.size() + " entries");
_projectMap = new HashMap(projects.size());
for(Map project : projects) {
- String consentVal = "" + project.get("study_identifier") + "." + project.get("consent_group_code");
+ String consentVal = (project.get("consent_group_code") != null && project.get("consent_group_code") != "") ?
+ "" + project.get("study_identifier") + "." + project.get("consent_group_code") :
+ "" + project.get("study_identifier");
logger.debug("adding study " + consentVal);
_projectMap.put(consentVal, project);
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/OpenAuthenticationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/OpenAuthenticationService.java
new file mode 100644
index 000000000..ed9e41620
--- /dev/null
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/OpenAuthenticationService.java
@@ -0,0 +1,67 @@
+package edu.harvard.hms.dbmi.avillach.auth.service.auth;
+
+import edu.harvard.dbmi.avillach.util.response.PICSUREResponse;
+import edu.harvard.hms.dbmi.avillach.auth.data.entity.Role;
+import edu.harvard.hms.dbmi.avillach.auth.data.entity.User;
+import edu.harvard.hms.dbmi.avillach.auth.data.repository.RoleRepository;
+import edu.harvard.hms.dbmi.avillach.auth.data.repository.UserRepository;
+import edu.harvard.hms.dbmi.avillach.auth.rest.UserService;
+import edu.harvard.hms.dbmi.avillach.auth.utils.AuthUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class OpenAuthenticationService {
+
+ private final Logger logger = LoggerFactory.getLogger(OpenAuthenticationService.class);
+
+ @Inject
+ private UserRepository userRepository;
+
+ @Inject
+ private RoleRepository roleRepository;
+
+ @Inject
+ AuthUtils authUtil;
+
+ public Response authenticate(Map authRequest) {
+ String userUUID = authRequest.get("UUID");
+ User current_user = null;
+
+ // Try to get the user by UUID
+ if (StringUtils.isNotBlank(userUUID)) {
+ try {
+ UUID uuid = UUID.fromString(userUUID);
+ current_user = userRepository.findByUUID(uuid);
+ } catch (IllegalArgumentException e) {
+ logger.error("Invalid UUID: " + userUUID);
+ }
+ }
+
+ // If we can't find the user by UUID, create a new one
+ if (current_user == null) {
+ Role openAccessRole = roleRepository.getUniqueResultByColumn("name", FENCEAuthenticationService.fence_open_access_role_name);
+ current_user = userRepository.createOpenAccessUser(openAccessRole);
+
+ //clear some cache entries if we register a new login
+ AuthorizationService.clearCache(current_user);
+ UserService.clearCache(current_user);
+ }
+
+ HashMap claims = new HashMap<>();
+ claims.put("sub", current_user.getSubject());
+ claims.put("email", current_user.getUuid() + "@open_access.com");
+ claims.put("uuid", current_user.getUuid().toString());
+ HashMap responseMap = authUtil.getUserProfileResponse(claims);
+
+ logger.info("LOGIN SUCCESS ___ " + current_user.getEmail() + ":" + current_user.getUuid().toString() + " ___ Authorization will expire at ___ " + responseMap.get("expirationDate") + "___");
+
+ return PICSUREResponse.success(responseMap);
+ }
+}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/utils/AuthUtils.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/utils/AuthUtils.java
index 85ddd170e..48bb53213 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/utils/AuthUtils.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/utils/AuthUtils.java
@@ -106,15 +106,20 @@ public HashMap getUserProfileResponse(Map claims
logger.debug("getUserProfileResponse() acceptedTOS is set");
- boolean acceptedTOS = JAXRSConfiguration.tosEnabled.startsWith("true") ?
- tosService.getLatest() == null || tosService.hasUserAcceptedLatest(claims.get("subject").toString()) : true;
+ boolean acceptedTOS = !JAXRSConfiguration.tosEnabled.startsWith("true") || tosService.getLatest() == null || tosService.hasUserAcceptedLatest(claims.get("subject").toString());
- responseMap.put("acceptedTOS", ""+acceptedTOS);
+ responseMap.put("acceptedTOS", String.valueOf(acceptedTOS));
logger.debug("getUserProfileResponse() expirationDate is set");
Date expirationDate = new Date(Calendar.getInstance().getTimeInMillis() + JAXRSConfiguration.tokenExpirationTime);
responseMap.put("expirationDate", ZonedDateTime.ofInstant(expirationDate.toInstant(), ZoneOffset.UTC).toString());
+ // This is required for open access, but optional otherwise
+ if (claims.get("uuid") != null) {
+ logger.debug("getUserProfileResponse() uuid field is set");
+ responseMap.put("uuid", claims.get("uuid").toString());
+ }
+
logger.debug("getUserProfileResponse() finished");
return responseMap;
}