Skip to content

Commit

Permalink
Merge pull request chpladmin#1775 from kekey1/OCD-4782
Browse files Browse the repository at this point in the history
OCD-4782: Move user role from Cognito group to custom attribute
  • Loading branch information
kekey1 authored Jan 23, 2025
2 parents 7410a9c + 64a72bc commit 6703fdb
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,14 @@
"raw": "{\"id\":1,\"acbCode\":\"02\",\"name\":\"UL LLC\",\"website\":\"https://testwebsite.com\",\"address\":{\"addressId\":1,\"line1\":\"address\",\"line2\":null,\"city\":\"city\",\"state\":\"state\",\"zipcode\":\"111111\",\"country\":\"country\"},\"retired\":false,\"retirementDay\":null}"
},
"url": {
"raw": "{{url}}/rest/acbs/1",
"raw": "{{url}}/rest/acbs/3",
"host": [
"{{url}}"
],
"path": [
"rest",
"acbs",
"1"
"3"
]
}
},
Expand Down Expand Up @@ -254,14 +254,14 @@
}
],
"url": {
"raw": "{{url}}/rest/acbs/1/users",
"raw": "{{url}}/rest/acbs/3/users",
"host": [
"{{url}}"
],
"path": [
"rest",
"acbs",
"1",
"3",
"users"
]
}
Expand Down Expand Up @@ -513,14 +513,14 @@
}
],
"url": {
"raw": "{{url}}/rest/acbs/1/users",
"raw": "{{url}}/rest/acbs/3/users",
"host": [
"{{url}}"
],
"path": [
"rest",
"acbs",
"1",
"3",
"users"
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package gov.healthit.chpl.auth.authentication;

import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.NotImplementedException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
Expand All @@ -25,39 +22,25 @@
public class CognitoJwtUserConverter implements JWTUserConverter {
private String region;
private String userPoolId;
private String clientId;
private String tokenizeRsaKeyUrl;

public CognitoJwtUserConverter(@Value("${cognito.region}") String region, @Value("${cognito.userPoolId}") String userPoolId,
@Value("${cognito.clientId}") String clientId, @Value("${cognito.tokenizezRsaKeyUrl}") String tokenizeRsaKeyUrl) {
public CognitoJwtUserConverter(@Value("${cognito.region}") String region,
@Value("${cognito.userPoolId}") String userPoolId,
@Value("${cognito.tokenizezRsaKeyUrl}") String tokenizeRsaKeyUrl) {
this.region = region;
this.userPoolId = userPoolId;
this.clientId = clientId;
this.tokenizeRsaKeyUrl = tokenizeRsaKeyUrl;
}

@Override
public JWTAuthenticatedUser getAuthenticatedUser(String jwt) throws JWTValidationException, MultipleUserAccountsException {
try {
DecodedJWT decodeJwt = decodeJwt(jwt);
if (decodeJwt.getClaims().size() != 0) {
DecodedJWT decodedJwt = decodeJwt(jwt);
if (decodedJwt.getClaims().size() != 0) {
return JWTAuthenticatedUser.builder()
.authenticationSystem(AuthenticationSystem.COGNITO)
.authenticated(true)
.cognitoId(UUID.fromString(decodeJwt.getSubject()))
.subjectName(decodeJwt.getClaim("email").asString())
.fullName(decodeJwt.getClaim("name").asString())
.email(decodeJwt.getClaim("email").asString())
.organizationIds(
decodeJwt.getClaims().containsKey("custom:organizations")
? Stream.of(decodeJwt.getClaim("custom:organizations").asString().split(","))
.map(Long::valueOf)
.toList()
: null)
.authorities(decodeJwt.getClaim("cognito:groups").asList(String.class).stream()
.filter(group -> !group.endsWith("-env")) //Remove environment related groups
.map(group -> new SimpleGrantedAuthority(group))
.collect(Collectors.toSet()))
.cognitoId(UUID.fromString(decodedJwt.getSubject()))
.build();
} else {
throw new JWTValidationException("Invalid authentication token.");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package gov.healthit.chpl.auth.authentication;

import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.ff4j.FF4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import gov.healthit.chpl.FeatureList;
Expand All @@ -25,11 +31,15 @@ public class JWTUserConverterFacade implements JWTUserConverter {

private FF4j ff4j;

public JWTUserConverterFacade(JWTConsumer jwtConsumer, UserDAO userDAO, @Value("${cognito.region}") String region,
@Value("${cognito.userPoolId}") String userPoolId, @Value("${cognito.clientId}") String clientId,
@Value("${cognito.tokenizezRsaKeyUrl}") String tokenizeRsaKeyUrl, FF4j ff4j, CognitoApiWrapper cognitoApiWrapper) {
public JWTUserConverterFacade(JWTConsumer jwtConsumer,
UserDAO userDAO,
@Value("${cognito.region}") String region,
@Value("${cognito.userPoolId}") String userPoolId,
@Value("${cognito.tokenizezRsaKeyUrl}") String tokenizeRsaKeyUrl,
FF4j ff4j,
CognitoApiWrapper cognitoApiWrapper) {
chplJwtUserConverter = new ChplJWTUserConverter(jwtConsumer, userDAO);
cognitoJwtUserConverter = new CognitoJwtUserConverter(region, userPoolId, clientId, tokenizeRsaKeyUrl);
cognitoJwtUserConverter = new CognitoJwtUserConverter(region, userPoolId, tokenizeRsaKeyUrl);
this.ff4j = ff4j;
this.cognitoApiWrapper = cognitoApiWrapper;
}
Expand All @@ -42,11 +52,20 @@ public JWTAuthenticatedUser getAuthenticatedUser(String jwt) throws JWTValidatio
user = cognitoJwtUserConverter.getAuthenticatedUser(jwt);
if (user != null) {
try {
//Set some values not avail in the Cognito Access Token that were avail in the CHPL token
//Many values are not available from the Cognito Access Token so we have to set them
//manually here from the Cognito user data
User cognitoUser = cognitoApiWrapper.getUserInfo(user.getCognitoId());
user.setEmail(cognitoUser.getEmail());
user.setSubjectName(cognitoUser.getEmail());
user.setFullName(cognitoUser.getFullName());
if (!StringUtils.isEmpty(cognitoUser.getRole())) {
user.setAuthorities(Stream.of(new SimpleGrantedAuthority(cognitoUser.getRole())).collect(Collectors.toSet()));
}
if (!CollectionUtils.isEmpty(cognitoUser.getOrganizations())) {
user.setOrganizationIds(cognitoUser.getOrganizations().stream()
.map(org -> org.getId())
.toList());
}
} catch (UserRetrievalException e) {
throw new JWTValidationException("Could not locate the Cognito user id");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,19 @@ public final class CognitoGroups {
private CognitoGroups() {}
public static final String CHPL_ADMIN = "chpl-admin";
public static final String CHPL_ONC = "chpl-onc";
public static final String CHPL_USER_CREATOR = "chpl-user-creator";
public static final String CHPL_ACB = "chpl-onc-acb";
public static final String CHPL_CMS_STAFF = "chpl-cms-staff";
public static final String CHPL_DEVELOPER = "chpl-developer";
public static final String CHPL_USER_AUTHENTICATOR = "chpl-user-authenticator";
public static final String CHPL_INVITED_USER_CREATOR = "chpl-invited-user-creator";
public static final String CHPL_STARTUP = "chpl-startup";
public static final String CHPL_SYSTEM = "chpl-system";

public static List<String> getAll() {
return List.of(
CHPL_ADMIN,
CHPL_ONC,
CHPL_USER_CREATOR,
CHPL_ACB,
CHPL_CMS_STAFF,
CHPL_DEVELOPER,
CHPL_USER_AUTHENTICATOR,
CHPL_INVITED_USER_CREATOR,
CHPL_STARTUP,
CHPL_SYSTEM);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatusCode;
Expand Down Expand Up @@ -61,6 +62,9 @@ private JsonNode fetchInsightSubmissionsForDeveloper(Long developerId) throws In
try {
response = insightRestTemplate.getForEntity(url, String.class);
LOGGER.debug("Response: " + response.getBody());
if (response == null || StringUtils.isEmpty(response.getBody())) {
LOGGER.warn("A null or empty response was received from the Insights API.");
}
} catch (Exception ex) {
HttpStatusCode statusCode = (response != null ? response.getStatusCode() : null);
if (statusCode == null && ex instanceof RestClientResponseException) {
Expand All @@ -69,7 +73,7 @@ private JsonNode fetchInsightSubmissionsForDeveloper(Long developerId) throws In
LOGGER.error("Unable to connect to the URL " + url + ". Got response status code " + statusCode);
throw new InsightRequestFailedException(ex.getMessage(), ex, statusCode);
}
String responseBody = response == null ? "" : response.getBody();
String responseBody = ((response == null || StringUtils.isEmpty(response.getBody())) ? "{}" : response.getBody());
JsonNode root = null;
try {
root = objectMapper.readTree(responseBody);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ public CertificationBody create(CertificationBody acb) throws EntityCreationExce

@Transactional
@PreAuthorize("@permissions.hasAccess(T(gov.healthit.chpl.permissions.Permissions).CERTIFICATION_BODY, "
+ "T(gov.healthit.chpl.permissions.domains.CertificationBodyDomainPermissions).UPDATE, #acb)")
+ "T(gov.healthit.chpl.permissions.domains.CertificationBodyDomainPermissions).UPDATE, #acbToUpdate)")
@CacheEvict(value = {
CacheNames.GET_DECERTIFIED_DEVELOPERS,
CacheNames.COLLECTIONS_DEVELOPERS,
CacheNames.COLLECTIONS_LISTINGS,
CacheNames.COMPLAINTS
}, allEntries = true)
@ListingStoreRemove(removeBy = RemoveBy.ACB_ID, id = "#acb.id")
@ListingStoreRemove(removeBy = RemoveBy.ACB_ID, id = "#acbToUpdate.id")
@ListingSearchCacheRefresh
// no other caches have ACB data so we do not need to clear all
public CertificationBody update(CertificationBody acbToUpdate) throws EntityRetrievalException, SchedulerException, ValidationException, ActivityException, InvalidArgumentsException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,17 +200,17 @@ public boolean isUserRoleDeveloperAdmin() {

@Override
public boolean isUserRoleUserCreator() {
return doesAuditUserHaveRole(CognitoGroups.CHPL_USER_CREATOR);
return false;
}

@Override
public boolean isUserRoleUserAuthenticator() {
return doesAuditUserHaveRole(CognitoGroups.CHPL_USER_AUTHENTICATOR);
return false;
}

@Override
public boolean isUserRoleInvitedUserCreator() {
return doesAuditUserHaveRole(CognitoGroups.CHPL_INVITED_USER_CREATOR);
return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,16 @@ public interface ResourcePermissions {

boolean isUserRoleDeveloperAdmin();

//Not used with Cognito users
@Deprecated
boolean isUserRoleUserCreator();

//Not used with Cognito users
@Deprecated
boolean isUserRoleUserAuthenticator();

//Not used with Cognito users
@Deprecated
boolean isUserRoleInvitedUserCreator();

boolean isUserRoleStartup();
Expand Down
Loading

0 comments on commit 6703fdb

Please sign in to comment.