From df2a5f598cf6004dcf58c5120847498adfef2dd9 Mon Sep 17 00:00:00 2001 From: gcolon021 Date: Thu, 3 Aug 2023 15:20:57 -0400 Subject: [PATCH] [ALS-4793] Initial impl for open access auth --- .../avillach/auth/JAXRSConfiguration.java | 13 ++--- .../auth/data/repository/UserRepository.java | 47 ++++++++++++--- .../avillach/auth/rest/OpenAuthService.java | 46 +++++++++++++++ .../dbmi/avillach/auth/rest/UserService.java | 1 - .../auth/OpenAuthenticationService.java | 57 +++++++++++++++++++ 5 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OpenAuthService.java create mode 100644 pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/OpenAuthenticationService.java 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..fbabba07c 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,10 +13,7 @@ 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; /** @@ -99,10 +96,6 @@ public User findOrCreate(User inputUser) { 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); @@ -161,4 +154,42 @@ public boolean checkAgainstTOSDate(String userId){ .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()); + } + + return null; + } + + public User createOpenAccessUser() { + // I can either use the user subject combined with a random string, or I can use the uuid of the user + // after I create the user. I think I will use the uuid of the user after I create the user. + + // create a new user + User user = new User(); + em().persist(user); + + // We should have a user now, so get the user by uuid + User result = getById(user.getUuid()); + result.setSubject("open_access|" + result.getUuid().toString()); + result.setRoles(new HashSet<>()); + em().merge(result); + + return null; + } } 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..34413cbed --- /dev/null +++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OpenAuthService.java @@ -0,0 +1,46 @@ +package edu.harvard.hms.dbmi.avillach.auth.rest; + +import edu.harvard.hms.dbmi.avillach.auth.service.auth.OpenAuthenticationService; +import edu.harvard.hms.dbmi.avillach.auth.service.auth.AuthenticationService; +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.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +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; + + // I went with a new endpoint instead of setting a new idp_provider because open_access isn't really an idp_provider. + // Secondly there was already a default authentication endpoint, so I didn't want to change that. + @ApiOperation(value = "The authentication endpoint for retrieving a valid user token") + @POST + @Path("/authentication") + public Response authentication(@Context UriInfo uriInfo, @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..."); + + return openAuthenticationService.authenticate(uriInfo, authRequest); + } + +} 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..8d1806a92 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 @@ -519,5 +519,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/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..699278075 --- /dev/null +++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/auth/OpenAuthenticationService.java @@ -0,0 +1,57 @@ +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.User; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +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 + AuthUtils authUtil; + + public Response authenticate(UriInfo uriInfo, Map authRequest) { + String userUUID = authRequest.get("UUID"); + User current_user = null; + + if (userUUID == null || userUUID.isEmpty()) { + UUID uuid = UUID.fromString(userUUID); + + // Get the user from the database + current_user = userRepository.findByUUID(uuid); + } + + + if (current_user == null) { + current_user = userRepository.createOpenAccessUser(); + + //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.getUuid().toString()); + claims.put("email", current_user.getSubject()); + 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); + } +}