NIFI-9322 Refactored OIDC and SAML Access Resources
- Removed parent AccessResource from OIDCAccessResource and SAMLAccessResource to avoid unexpected inherited methods
- Moved Token Expiration validation from AccessResource to StandardBearerTokenProvider
Signed-off-by: Nathan Gough <thenatog@gmail.com>
This closes #5489.
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
index b184518..4f29cde 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
@@ -106,7 +106,7 @@
private BearerTokenResolver bearerTokenResolver;
private KnoxService knoxService;
private KerberosService kerberosService;
- protected LogoutRequestManager logoutRequestManager;
+ private LogoutRequestManager logoutRequestManager;
/**
* Retrieves the access configuration for this NiFi.
@@ -348,8 +348,7 @@
final String expirationFromProperties = properties.getKerberosAuthenticationExpiration();
long expiration = Math.round(FormatUtils.getPreciseTimeDuration(expirationFromProperties, TimeUnit.MILLISECONDS));
final String rawIdentity = authentication.getName();
- String mappedIdentity = IdentityMappingUtil.mapIdentity(rawIdentity, IdentityMappingUtil.getIdentityMappings(properties));
- expiration = validateTokenExpiration(expiration, mappedIdentity);
+ final String mappedIdentity = IdentityMappingUtil.mapIdentity(rawIdentity, IdentityMappingUtil.getIdentityMappings(properties));
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(mappedIdentity, expiration, "KerberosService");
final String token = bearerTokenProvider.getBearerToken(loginAuthenticationToken);
@@ -416,8 +415,8 @@
// attempt to authenticate
final AuthenticationResponse authenticationResponse = loginIdentityProvider.authenticate(new LoginCredentials(username, password));
final String rawIdentity = authenticationResponse.getIdentity();
- String mappedIdentity = IdentityMappingUtil.mapIdentity(rawIdentity, IdentityMappingUtil.getIdentityMappings(properties));
- long expiration = validateTokenExpiration(authenticationResponse.getExpiration(), mappedIdentity);
+ final String mappedIdentity = IdentityMappingUtil.mapIdentity(rawIdentity, IdentityMappingUtil.getIdentityMappings(properties));
+ final long expiration = authenticationResponse.getExpiration();
// create the authentication token
loginAuthenticationToken = new LoginAuthenticationToken(mappedIdentity, expiration, authenticationResponse.getIssuer());
@@ -506,7 +505,7 @@
httpServletResponse.sendRedirect(getNiFiLogoutCompleteUri());
}
- LogoutRequest completeLogoutRequest(final HttpServletResponse httpServletResponse) {
+ private LogoutRequest completeLogoutRequest(final HttpServletResponse httpServletResponse) {
LogoutRequest logoutRequest = null;
final Optional<String> cookieValue = getLogoutRequestIdentifier();
@@ -522,24 +521,7 @@
return logoutRequest;
}
- long validateTokenExpiration(long proposedTokenExpiration, String identity) {
- final long maxExpiration = TimeUnit.MILLISECONDS.convert(12, TimeUnit.HOURS);
- final long minExpiration = TimeUnit.MILLISECONDS.convert(1, TimeUnit.MINUTES);
-
- if (proposedTokenExpiration > maxExpiration) {
- logger.warn(String.format("Max token expiration exceeded. Setting expiration to %s from %s for %s", maxExpiration,
- proposedTokenExpiration, identity));
- proposedTokenExpiration = maxExpiration;
- } else if (proposedTokenExpiration < minExpiration) {
- logger.warn(String.format("Min token expiration not met. Setting expiration to %s from %s for %s", minExpiration,
- proposedTokenExpiration, identity));
- proposedTokenExpiration = minExpiration;
- }
-
- return proposedTokenExpiration;
- }
-
- String getNiFiLogoutCompleteUri() {
+ private String getNiFiLogoutCompleteUri() {
return getNiFiUri() + "logout-complete";
}
@@ -548,7 +530,7 @@
*
* @param httpServletResponse HTTP Servlet Response
*/
- protected void removeLogoutRequestCookie(final HttpServletResponse httpServletResponse) {
+ private void removeLogoutRequestCookie(final HttpServletResponse httpServletResponse) {
applicationCookieService.removeCookie(getCookieResourceUri(), httpServletResponse, ApplicationCookieName.LOGOUT_REQUEST_IDENTIFIER);
}
@@ -557,7 +539,7 @@
*
* @return Optional Logout Request Identifier
*/
- protected Optional<String> getLogoutRequestIdentifier() {
+ private Optional<String> getLogoutRequestIdentifier() {
return applicationCookieService.getCookieValue(httpServletRequest, ApplicationCookieName.LOGOUT_REQUEST_IDENTIFIER);
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OIDCAccessResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OIDCAccessResource.java
index 673e529..cc952a7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OIDCAccessResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OIDCAccessResource.java
@@ -74,7 +74,7 @@
value = OIDCEndpoints.OIDC_ACCESS_ROOT,
description = "Endpoints for obtaining an access token or checking access status."
)
-public class OIDCAccessResource extends AccessResource {
+public class OIDCAccessResource extends ApplicationResource {
private static final Logger logger = LoggerFactory.getLogger(OIDCAccessResource.class);
private static final String OIDC_ID_TOKEN_AUTHN_ERROR = "Unable to exchange authorization for ID token: ";
@@ -115,7 +115,7 @@
public void oidcRequest(@Context HttpServletRequest httpServletRequest, @Context HttpServletResponse httpServletResponse) throws Exception {
// only consider user specific access over https
if (!httpServletRequest.isSecure()) {
- forwardToLoginMessagePage(httpServletRequest, httpServletResponse, AUTHENTICATION_NOT_ENABLED_MSG);
+ forwardToLoginMessagePage(httpServletRequest, httpServletResponse, AccessResource.AUTHENTICATION_NOT_ENABLED_MSG);
return;
}
@@ -199,7 +199,7 @@
public Response oidcExchange(@Context HttpServletRequest httpServletRequest, @Context HttpServletResponse httpServletResponse) {
// only consider user specific access over https
if (!httpServletRequest.isSecure()) {
- throw new AuthenticationNotSupportedException(AUTHENTICATION_NOT_ENABLED_MSG);
+ throw new AuthenticationNotSupportedException(AccessResource.AUTHENTICATION_NOT_ENABLED_MSG);
}
// ensure oidc is enabled
@@ -238,7 +238,7 @@
)
public void oidcLogout(@Context HttpServletRequest httpServletRequest, @Context HttpServletResponse httpServletResponse) throws Exception {
if (!httpServletRequest.isSecure()) {
- throw new IllegalStateException(AUTHENTICATION_NOT_ENABLED_MSG);
+ throw new IllegalStateException(AccessResource.AUTHENTICATION_NOT_ENABLED_MSG);
}
if (!oidcService.isOidcEnabled()) {
@@ -468,7 +468,7 @@
// only consider user specific access over https
if (!httpServletRequest.isSecure()) {
- forwardToMessagePage(httpServletRequest, httpServletResponse, pageTitle, AUTHENTICATION_NOT_ENABLED_MSG);
+ forwardToMessagePage(httpServletRequest, httpServletResponse, pageTitle, AccessResource.AUTHENTICATION_NOT_ENABLED_MSG);
return null;
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SAMLAccessResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SAMLAccessResource.java
index a374428..537aa0b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SAMLAccessResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SAMLAccessResource.java
@@ -27,6 +27,7 @@
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.api.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.logout.LogoutRequest;
+import org.apache.nifi.web.security.logout.LogoutRequestManager;
import org.apache.nifi.web.security.saml.SAMLCredentialStore;
import org.apache.nifi.web.security.saml.SAMLEndpoints;
import org.apache.nifi.web.security.saml.SAMLService;
@@ -61,7 +62,7 @@
value = SAMLEndpoints.SAML_ACCESS_ROOT,
description = "Endpoints for authenticating, obtaining an access token or logging out of a configured SAML authentication provider."
)
-public class SAMLAccessResource extends AccessResource {
+public class SAMLAccessResource extends ApplicationResource {
private static final Logger logger = LoggerFactory.getLogger(SAMLAccessResource.class);
private static final String SAML_METADATA_MEDIA_TYPE = "application/samlmetadata+xml";
@@ -73,6 +74,7 @@
private SAMLStateManager samlStateManager;
private SAMLCredentialStore samlCredentialStore;
private IdpUserGroupService idpUserGroupService;
+ private LogoutRequestManager logoutRequestManager;
@GET
@Consumes(MediaType.WILDCARD)
@@ -85,7 +87,7 @@
public Response samlMetadata(@Context HttpServletRequest httpServletRequest, @Context HttpServletResponse httpServletResponse) {
// only consider user specific access over https
if (!httpServletRequest.isSecure()) {
- throw new AuthenticationNotSupportedException(AUTHENTICATION_NOT_ENABLED_MSG);
+ throw new AuthenticationNotSupportedException(AccessResource.AUTHENTICATION_NOT_ENABLED_MSG);
}
// ensure saml is enabled
@@ -212,7 +214,7 @@
// create the login token
final String rawIdentity = samlService.getUserIdentity(samlCredential);
final String mappedIdentity = IdentityMappingUtil.mapIdentity(rawIdentity, IdentityMappingUtil.getIdentityMappings(properties));
- final long expiration = validateTokenExpiration(samlService.getAuthExpiration(), mappedIdentity);
+ final long expiration = samlService.getAuthExpiration();
final String issuer = samlCredential.getRemoteEntityID();
final LoginAuthenticationToken loginToken = new LoginAuthenticationToken(mappedIdentity, mappedIdentity, expiration, issuer);
@@ -255,7 +257,7 @@
// only consider user specific access over https
if (!httpServletRequest.isSecure()) {
- throw new AuthenticationNotSupportedException(AUTHENTICATION_NOT_ENABLED_MSG);
+ throw new AuthenticationNotSupportedException(AccessResource.AUTHENTICATION_NOT_ENABLED_MSG);
}
// ensure saml is enabled
@@ -446,19 +448,21 @@
assert(isSamlEnabled(httpServletRequest, httpServletResponse, !LOGGING_IN));
// complete the logout request if one exists
- final LogoutRequest completedLogoutRequest = completeLogoutRequest(httpServletResponse);
+ final Optional<String> cookieValue = getLogoutRequestIdentifier();
+ if (cookieValue.isPresent()) {
+ final String logoutRequestIdentifier = cookieValue.get();
+ final LogoutRequest logoutRequest = logoutRequestManager.complete(logoutRequestIdentifier);
- // if a logout request was completed, then delete the stored SAMLCredential for that user
- if (completedLogoutRequest != null) {
- final String userIdentity = completedLogoutRequest.getMappedUserIdentity();
+ final String mappedUserIdentity = logoutRequest.getMappedUserIdentity();
+ samlCredentialStore.delete(mappedUserIdentity);
+ idpUserGroupService.deleteUserGroups(mappedUserIdentity);
- logger.info("Removing cached SAML information for " + userIdentity);
- samlCredentialStore.delete(userIdentity);
-
- logger.info("Removing cached SAML Groups for " + userIdentity);
- idpUserGroupService.deleteUserGroups(userIdentity);
+ logger.info("Logout Request [{}] Identity [{}] SAML Local Logout Completed", logoutRequestIdentifier, mappedUserIdentity);
+ } else {
+ logger.warn("Logout Request Cookie [{}] not found", ApplicationCookieName.LOGOUT_REQUEST_IDENTIFIER.getCookieName());
}
+ removeLogoutRequestCookie(httpServletResponse);
// redirect to logout landing page
httpServletResponse.sendRedirect(getNiFiLogoutCompleteUri());
}
@@ -488,7 +492,7 @@
// only consider user specific access over https
if (!httpServletRequest.isSecure()) {
- forwardToMessagePage(httpServletRequest, httpServletResponse, pageTitle, AUTHENTICATION_NOT_ENABLED_MSG);
+ forwardToMessagePage(httpServletRequest, httpServletResponse, pageTitle, AccessResource.AUTHENTICATION_NOT_ENABLED_MSG);
return false;
}
@@ -508,6 +512,18 @@
return applicationCookieService.getCookieValue(httpServletRequest, ApplicationCookieName.SAML_REQUEST_IDENTIFIER);
}
+ private void removeLogoutRequestCookie(final HttpServletResponse httpServletResponse) {
+ applicationCookieService.removeCookie(getCookieResourceUri(), httpServletResponse, ApplicationCookieName.LOGOUT_REQUEST_IDENTIFIER);
+ }
+
+ private Optional<String> getLogoutRequestIdentifier() {
+ return applicationCookieService.getCookieValue(httpServletRequest, ApplicationCookieName.LOGOUT_REQUEST_IDENTIFIER);
+ }
+
+ private String getNiFiLogoutCompleteUri() {
+ return getNiFiUri() + "logout-complete";
+ }
+
public void setSamlService(SAMLService samlService) {
this.samlService = samlService;
}
@@ -531,4 +547,8 @@
protected NiFiProperties getProperties() {
return properties;
}
+
+ public void setLogoutRequestManager(LogoutRequestManager logoutRequestManager) {
+ this.logoutRequestManager = logoutRequestManager;
+ }
}
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/provider/StandardBearerTokenProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/provider/StandardBearerTokenProvider.java
index 95185b6..aca6e40 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/provider/StandardBearerTokenProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/provider/StandardBearerTokenProvider.java
@@ -32,6 +32,8 @@
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
@@ -44,6 +46,10 @@
private static final String URL_ENCODED_CHARACTER_SET = StandardCharsets.UTF_8.name();
+ private static final Duration MAXIMUM_EXPIRATION = Duration.ofHours(12);
+
+ private static final Duration MINIMUM_EXPIRATION = Duration.ofMinutes(1);
+
private final JwsSignerProvider jwsSignerProvider;
public StandardBearerTokenProvider(final JwsSignerProvider jwsSignerProvider) {
@@ -64,7 +70,7 @@
final String issuer = getUrlEncoded(loginAuthenticationToken.getIssuer());
final Date now = new Date();
- final Date expirationTime = new Date(loginAuthenticationToken.getExpiration());
+ final Date expirationTime = getExpirationTime(loginAuthenticationToken);
final JWTClaimsSet claims = new JWTClaimsSet.Builder()
.jwtID(UUID.randomUUID().toString())
.subject(subject)
@@ -78,6 +84,24 @@
return getSignedBearerToken(claims);
}
+ private Date getExpirationTime(final LoginAuthenticationToken loginAuthenticationToken) {
+ Instant expiration = Instant.ofEpochMilli(loginAuthenticationToken.getExpiration());
+
+ final Instant maximumExpiration = Instant.now().plus(MAXIMUM_EXPIRATION);
+ final Instant minimumExpiration = Instant.now().plus(MINIMUM_EXPIRATION);
+
+ final String identity = loginAuthenticationToken.getName();
+ if (expiration.isAfter(maximumExpiration)) {
+ LOGGER.warn("Identity [{}] Token Expiration [{}] greater than maximum [{}]", identity, expiration, MAXIMUM_EXPIRATION);
+ expiration = maximumExpiration;
+ } else if (expiration.isBefore(minimumExpiration)) {
+ LOGGER.warn("Identity [{}] Token Expiration [{}] less than minimum [{}]", identity, expiration, MINIMUM_EXPIRATION);
+ expiration = minimumExpiration;
+ }
+
+ return Date.from(expiration);
+ }
+
private String getSignedBearerToken(final JWTClaimsSet claims) {
final Date expirationTime = claims.getExpirationTime();
final JwsSignerContainer jwsSignerContainer = jwsSignerProvider.getJwsSignerContainer(expirationTime.toInstant());
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationToken.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationToken.java
index 3591239..c0e895c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationToken.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationToken.java
@@ -19,8 +19,7 @@
import org.apache.nifi.security.util.CertificateUtils;
import org.springframework.security.authentication.AbstractAuthenticationToken;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
+import java.time.Instant;
/**
* This is an Authentication Token for logging in. Once a user is authenticated, they can be issued an ID token.
@@ -57,8 +56,7 @@
this.identity = identity;
this.username = username;
this.issuer = issuer;
- Calendar now = Calendar.getInstance();
- this.expiration = now.getTimeInMillis() + expiration;
+ this.expiration = Instant.now().plusMillis(expiration).toEpochMilli();
}
@Override
@@ -98,20 +96,15 @@
@Override
public String toString() {
- Calendar expirationTime = Calendar.getInstance();
- expirationTime.setTimeInMillis(getExpiration());
- long remainingTime = expirationTime.getTimeInMillis() - Calendar.getInstance().getTimeInMillis();
-
- SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS");
- dateFormat.setTimeZone(expirationTime.getTimeZone());
- String expirationTimeString = dateFormat.format(expirationTime.getTime());
+ final Instant expirationTime = Instant.ofEpochMilli(expiration);
+ long remainingTime = expirationTime.toEpochMilli() - Instant.now().toEpochMilli();
return new StringBuilder("LoginAuthenticationToken for ")
.append(getName())
.append(" issued by ")
.append(getIssuer())
.append(" expiring at ")
- .append(expirationTimeString)
+ .append(expirationTime)
.append(" [")
.append(getExpiration())
.append(" ms, ")
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/jwt/provider/StandardBearerTokenProviderTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/jwt/provider/StandardBearerTokenProviderTest.java
index 668d04c..da3bb20 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/jwt/provider/StandardBearerTokenProviderTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/jwt/provider/StandardBearerTokenProviderTest.java
@@ -27,34 +27,41 @@
import org.apache.nifi.web.security.jwt.jws.JwsSignerContainer;
import org.apache.nifi.web.security.jwt.jws.JwsSignerProvider;
import org.apache.nifi.web.security.token.LoginAuthenticationToken;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.jupiter.MockitoExtension;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.text.ParseException;
+import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
+import java.util.Date;
import java.util.UUID;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.when;
-@RunWith(MockitoJUnitRunner.class)
+@ExtendWith(MockitoExtension.class)
public class StandardBearerTokenProviderTest {
private static final String USERNAME = "USERNAME";
private static final String IDENTITY = "IDENTITY";
- private static final long EXPIRATION = 60;
+ private static final Duration EXPIRATION = Duration.ofHours(1);
+
+ private static final Duration MAXIMUM_DURATION_EXCEEDED = Duration.parse("PT12H5M");
+
+ private static final Duration MINIMUM_DURATION_EXCEEDED = Duration.parse("PT30S");
private static final String ISSUER = "ISSUER";
@@ -73,7 +80,7 @@
private JWSSigner jwsSigner;
- @Before
+ @BeforeEach
public void setProvider() throws NoSuchAlgorithmException {
provider = new StandardBearerTokenProvider(jwsSignerProvider);
@@ -86,24 +93,76 @@
@Test
public void testGetBearerToken() throws ParseException, JOSEException {
- final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, EXPIRATION, ISSUER);
- final String keyIdentifier = UUID.randomUUID().toString();
- final JwsSignerContainer jwsSignerContainer = new JwsSignerContainer(keyIdentifier, JWS_ALGORITHM, jwsSigner);
- when(jwsSignerProvider.getJwsSignerContainer(isA(Instant.class))).thenReturn(jwsSignerContainer);
+ final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, EXPIRATION.toMillis(), ISSUER);
+ setSignerProvider();
final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
- final SignedJWT signedJwt = SignedJWT.parse(bearerToken);
- assertTrue("Verification Failed", signedJwt.verify(jwsVerifier));
-
+ final SignedJWT signedJwt = assertTokenVerified(bearerToken);
final JWTClaimsSet claims = signedJwt.getJWTClaimsSet();
- assertNotNull("Issue Time not found", claims.getIssueTime());
- assertNotNull("Not Before Time Time not found", claims.getNotBeforeTime());
- assertNotNull("Expiration Time Time not found", claims.getExpirationTime());
+ assertNotNull(claims.getIssueTime(), "Issue Time not found");
+ assertNotNull(claims.getNotBeforeTime(), "Not Before Time not found");
+
+ final Date claimExpirationTime = claims.getExpirationTime();
+ assertNotNull(claimExpirationTime, "Expiration Time not found");
+
+ final Date loginExpirationTime = new Date(loginAuthenticationToken.getExpiration());
+ assertEquals(loginExpirationTime.toString(), claimExpirationTime.toString(), "Expiration Time not matched");
+
assertEquals(ISSUER, claims.getIssuer());
assertEquals(Collections.singletonList(ISSUER), claims.getAudience());
assertEquals(IDENTITY, claims.getSubject());
assertEquals(USERNAME, claims.getClaim(SupportedClaim.PREFERRED_USERNAME.getClaim()));
assertNotNull("JSON Web Token Identifier not found", claims.getJWTID());
}
+
+ @Test
+ public void testGetBearerTokenExpirationMaximum() throws ParseException, JOSEException {
+ final long expiration = MAXIMUM_DURATION_EXCEEDED.toMillis();
+ final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, expiration, ISSUER);
+ setSignerProvider();
+
+ final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
+
+ final SignedJWT signedJwt = assertTokenVerified(bearerToken);
+ final JWTClaimsSet claims = signedJwt.getJWTClaimsSet();
+ final Date claimExpirationTime = claims.getExpirationTime();
+ assertNotNull(claimExpirationTime, "Expiration Time not found");
+
+ final Date loginExpirationTime = new Date(loginAuthenticationToken.getExpiration());
+ assertNotSame(loginExpirationTime.toString(), claimExpirationTime.toString(), "Expiration Time matched");
+
+ assertTrue(claimExpirationTime.toInstant().isBefore(loginExpirationTime.toInstant()), "Claim Expiration after Login Expiration");
+ }
+
+ @Test
+ public void testGetBearerTokenExpirationMinimum() throws ParseException, JOSEException {
+ final long expiration = MINIMUM_DURATION_EXCEEDED.toMillis();
+ final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, expiration, ISSUER);
+ setSignerProvider();
+
+ final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
+
+ final SignedJWT signedJwt = assertTokenVerified(bearerToken);
+ final JWTClaimsSet claims = signedJwt.getJWTClaimsSet();
+ final Date claimExpirationTime = claims.getExpirationTime();
+ assertNotNull(claimExpirationTime, "Expiration Time not found");
+
+ final Date loginExpirationTime = new Date(loginAuthenticationToken.getExpiration());
+ assertNotSame(loginExpirationTime.toString(), claimExpirationTime.toString(), "Expiration Time matched");
+
+ assertTrue(claimExpirationTime.toInstant().isAfter(loginExpirationTime.toInstant()), "Claim Expiration before Login Expiration");
+ }
+
+ private void setSignerProvider() {
+ final String keyIdentifier = UUID.randomUUID().toString();
+ final JwsSignerContainer jwsSignerContainer = new JwsSignerContainer(keyIdentifier, JWS_ALGORITHM, jwsSigner);
+ when(jwsSignerProvider.getJwsSignerContainer(isA(Instant.class))).thenReturn(jwsSignerContainer);
+ }
+
+ private SignedJWT assertTokenVerified(final String bearerToken) throws ParseException, JOSEException {
+ final SignedJWT signedJwt = SignedJWT.parse(bearerToken);
+ assertTrue(signedJwt.verify(jwsVerifier), "Verification Failed");
+ return signedJwt;
+ }
}