diff --git a/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/AudienceValidator.java b/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/AudienceValidator.java index 937a5673..10562086 100644 --- a/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/AudienceValidator.java +++ b/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/AudienceValidator.java @@ -52,8 +52,8 @@ public OAuth2TokenValidatorResult validate(Jwt jwt) { Transaction transaction = auditService.createTransaction(request.getRemoteAddr(), TransactionType.UNKNOWN); auditService.createTransactionEvent(transaction, TransactionEventType.UNAUTHORIZED); - logger.debug(error.getDescription()); + logger.warn("User {} is missing aud claim {} ", jwt.getClaim(SecurityUtil.CLAIM_USERNAME).toString(), audience); return OAuth2TokenValidatorResult.failure(error); } } -} +} \ No newline at end of file diff --git a/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/OrganizationValidator.java b/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/OrganizationValidator.java new file mode 100644 index 00000000..63a9110e --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/OrganizationValidator.java @@ -0,0 +1,53 @@ +package ca.bc.gov.hlth.hnweb.security; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.OAuth2TokenValidator; +import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import ca.bc.gov.hlth.hnweb.persistence.entity.Transaction; +import ca.bc.gov.hlth.hnweb.persistence.entity.TransactionEventType; +import ca.bc.gov.hlth.hnweb.service.AuditService; + +@Component +public class OrganizationValidator implements OAuth2TokenValidator { + + private static final Logger logger = LoggerFactory.getLogger(OrganizationValidator.class); + + private static final OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST, " User has no org_details", + "https://tools.ietf.org/html/rfc6750#section-3.1"); + + @Autowired + private AuditService auditService; + + @Override + public OAuth2TokenValidatorResult validate(Jwt jwt) { + Assert.notNull(jwt, "Token cannot be null"); + + String org = jwt.getClaim(SecurityUtil.CLAIM_ORGANIZATION); + + if (StringUtils.isNotEmpty(org)) { + return OAuth2TokenValidatorResult.success(); + } else { + // Audit the failure. Only users with defined Organization should be considered as authorized and able to access MSP Direct. + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + + Transaction transaction = auditService.createTransaction(request.getRemoteAddr(), TransactionType.UNKNOWN); + auditService.createTransactionEvent(transaction, TransactionEventType.UNAUTHORIZED); + + logger.warn("User {} has no org_details (Organization)", jwt.getClaim(SecurityUtil.CLAIM_USERNAME).toString()); + return OAuth2TokenValidatorResult.failure(error); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/SecurityConfig.java b/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/SecurityConfig.java index 451654e1..ebedc642 100644 --- a/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/SecurityConfig.java +++ b/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/SecurityConfig.java @@ -40,6 +40,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AudienceValidator audienceValidator; + @Autowired + private OrganizationValidator organizationValidator; + @Autowired private CustomAccessDeniedHandler accessDeniedHandler; @@ -73,8 +76,9 @@ public JwtDecoder jwtDecoder() { OAuth2TokenValidator withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri); OAuth2TokenValidator withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator); + OAuth2TokenValidator withOrganization = new DelegatingOAuth2TokenValidator<>(withAudience, organizationValidator); - jwtDecoder.setJwtValidator(withAudience); + jwtDecoder.setJwtValidator(withOrganization); return jwtDecoder; } diff --git a/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/SecurityUtil.java b/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/SecurityUtil.java index 3a765291..6f594c92 100644 --- a/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/SecurityUtil.java +++ b/backend/src/main/java/ca/bc/gov/hlth/hnweb/security/SecurityUtil.java @@ -22,8 +22,8 @@ public class SecurityUtil { private static final String CLAIM_RESOURCE_ACCESS = "resource_access"; private static final String CLAIM_SESSION_STATE = "session_state"; - private static final String CLAIM_USERNAME = "preferred_username"; - private static final String CLAIM_ORGANIZATION = "org_details"; + public static final String CLAIM_USERNAME = "preferred_username"; + public static final String CLAIM_ORGANIZATION = "org_details"; private static final String ORGANIZATION_ID = "id";