diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/TurnOffConsentForPairwiseOpenIdOnlyConsentTest.java b/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/TurnOffConsentForPairwiseOpenIdOnlyConsentTest.java new file mode 100644 index 00000000000..17976c81917 --- /dev/null +++ b/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/TurnOffConsentForPairwiseOpenIdOnlyConsentTest.java @@ -0,0 +1,97 @@ +package io.jans.as.client.ws.rs; + +import io.jans.as.client.*; +import io.jans.as.model.common.ResponseType; +import io.jans.as.model.common.SubjectType; +import io.jans.as.model.crypto.signature.SignatureAlgorithm; +import io.jans.as.model.jwt.JwtClaimName; +import io.jans.as.model.register.ApplicationType; +import io.jans.as.model.util.StringUtils; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + * Turn off consent for pairwise / openid-only scope + * + * @author Javier Rojas Blum + * @version January 24, 2022 + */ +public class TurnOffConsentForPairwiseOpenIdOnlyConsentTest extends BaseTest { + + /** + * If a client is configured for pairwise identifiers, and the openid scope is the only scope requested, + * there is no need to present the consent page, because the AS is not releasing any PII. + */ + @Parameters({"redirectUris", "redirectUri", "userId", "userSecret", "sectorIdentifierUri"}) + @Test + public void turnOffConsentForPairwiseOpenIdOnlyConsentTest( + final String redirectUris, final String redirectUri, final String userId, final String userSecret, + final String sectorIdentifierUri) { + showTitle("turnOffConsentForPairwiseOpenIdOnlyConsentTest"); + + List responseTypes = Arrays.asList( + ResponseType.TOKEN, + ResponseType.ID_TOKEN); + + // 1. Dynamic Registration + RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "jans test app", + StringUtils.spaceSeparatedToList(redirectUris)); + registerRequest.setResponseTypes(responseTypes); + registerRequest.setUserInfoSignedResponseAlg(SignatureAlgorithm.RS256); + registerRequest.setSubjectType(SubjectType.PAIRWISE); + registerRequest.setSectorIdentifierUri(sectorIdentifierUri); + + RegisterClient registerClient = new RegisterClient(registrationEndpoint); + registerClient.setRequest(registerRequest); + RegisterResponse registerResponse = registerClient.exec(); + + showClient(registerClient); + assertEquals(registerResponse.getStatus(), 201); + assertNotNull(registerResponse.getClientId()); + assertNotNull(registerResponse.getClientSecret()); + assertNotNull(registerResponse.getRegistrationAccessToken()); + assertNotNull(registerResponse.getClientSecretExpiresAt()); + + String clientId = registerResponse.getClientId(); + + // 2. Request Authorization + List scopes = Arrays.asList("openid"); + String nonce = UUID.randomUUID().toString(); + String state = UUID.randomUUID().toString(); + + AuthorizationRequest authorizationRequest = new AuthorizationRequest( + responseTypes, clientId, scopes, redirectUri, nonce); + authorizationRequest.setState(state); + + AuthorizationResponse authorizationResponse = authenticateResourceOwner( + authorizationEndpoint, authorizationRequest, userId, userSecret, false); + + assertNotNull(authorizationResponse.getLocation()); + assertNotNull(authorizationResponse.getAccessToken()); + assertNotNull(authorizationResponse.getState()); + assertNotNull(authorizationResponse.getTokenType()); + assertNotNull(authorizationResponse.getExpiresIn()); + assertNotNull(authorizationResponse.getScope()); + assertNotNull(authorizationResponse.getIdToken()); + + String accessToken = authorizationResponse.getAccessToken(); + + // 3. Request user info + UserInfoClient userInfoClient = new UserInfoClient(userInfoEndpoint); + userInfoClient.setJwksUri(jwksUri); + UserInfoResponse userInfoResponse = userInfoClient.execUserInfo(accessToken); + + showClient(userInfoClient); + assertEquals(userInfoResponse.getStatus(), 200); + assertNotNull(userInfoResponse.getClaim(JwtClaimName.SUBJECT_IDENTIFIER)); + assertNotNull(userInfoResponse.getClaim(JwtClaimName.ISSUER)); + assertNotNull(userInfoResponse.getClaim(JwtClaimName.AUDIENCE)); + } +} diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeAction.java b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeAction.java index 61725c04438..61f0be66ad8 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeAction.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeAction.java @@ -27,21 +27,14 @@ import io.jans.as.server.model.authorize.JwtAuthorizationRequest; import io.jans.as.server.model.authorize.ScopeChecker; import io.jans.as.server.model.common.CibaRequestCacheControl; +import io.jans.as.server.model.common.DefaultScope; import io.jans.as.server.model.common.SessionId; import io.jans.as.server.model.common.SessionIdState; import io.jans.as.server.model.config.Constants; import io.jans.as.server.model.exception.AcrChangedException; import io.jans.as.server.model.ldap.ClientAuthorization; import io.jans.as.server.security.Identity; -import io.jans.as.server.service.AuthenticationService; -import io.jans.as.server.service.AuthorizeService; -import io.jans.as.server.service.ClientAuthorizationsService; -import io.jans.as.server.service.ClientService; -import io.jans.as.server.service.CookieService; -import io.jans.as.server.service.ErrorHandlerService; -import io.jans.as.server.service.RedirectionUriService; -import io.jans.as.server.service.RequestParameterService; -import io.jans.as.server.service.SessionIdService; +import io.jans.as.server.service.*; import io.jans.as.server.service.ciba.CibaRequestService; import io.jans.as.server.service.external.ExternalAuthenticationService; import io.jans.as.server.service.external.ExternalConsentGatheringService; @@ -75,15 +68,7 @@ import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import static io.jans.as.server.service.DeviceAuthorizationService.SESSION_USER_CODE; import static org.apache.commons.lang3.BooleanUtils.isTrue; @@ -91,7 +76,7 @@ /** * @author Javier Rojas Blum * @author Yuriy Movchan - * @version March 4, 2020 + * @version January 24, 2022 */ @RequestScoped @Named @@ -414,7 +399,16 @@ public void checkPermissionGranted() throws IOException { final boolean isTrusted = isTrue(appConfiguration.getTrustedClientEnabled()) && client.getTrustedClient(); final boolean canGrantAccess = isTrue(appConfiguration.getSkipAuthorizationForOpenIdScopeAndPairwiseId()) && SubjectType.PAIRWISE.equals(client.getSubjectType()) && hasOnlyOpenidScope(); - if (isTrusted || canGrantAccess) { + // There is no need to present the consent page: + // If Client is a Trusted Client. + // If a client is configured for pairwise identifiers, and the openid scope is the only scope requested. + // Also, we should make sure that the claims request is not enabled. + final boolean isPairwiseWithOnlyOpenIdScope = client.getSubjectType() == SubjectType.PAIRWISE + && grantedScopes.size() == 1 + && grantedScopes.contains(DefaultScope.OPEN_ID.toString()) + && scope.equals(DefaultScope.OPEN_ID.toString()) + && claims == null && request == null; + if (isTrusted || canGrantAccess || isPairwiseWithOnlyOpenIdScope) { permissionGranted(session); return; } diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java index c19146c8087..cd67003b6f9 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java @@ -91,7 +91,7 @@ * Implementation for request authorization through REST web services. * * @author Javier Rojas Blum - * @version December 15, 2021 + * @version January 24, 2022 */ @Path("/") public class AuthorizeRestWebServiceImpl implements AuthorizeRestWebService { @@ -591,7 +591,16 @@ private Response requestAuthorization( idTokenHint, loginHint, acrValues, amrValues, request, requestUri, originHeaders, codeChallenge, codeChallengeMethod, sessionId, claims, authReqId, customParameters, oAuth2AuditLog, httpRequest); } - if (client.getTrustedClient()) { + // There is no need to present the consent page: + // If Client is a Trusted Client. + // If a client is configured for pairwise identifiers, and the openid scope is the only scope requested. + // Also, we should make sure that the claims request is not enabled. + final boolean isPairwiseWithOnlyOpenIdScope = client.getSubjectType() == SubjectType.PAIRWISE + && scopes.size() == 1 + && scopes.contains(DefaultScope.OPEN_ID.toString()) + && claims == null + && (jwtRequest == null || (jwtRequest.getUserInfoMember() == null && jwtRequest.getIdTokenMember() == null)); + if (client.getTrustedClient() || isPairwiseWithOnlyOpenIdScope) { sessionUser.addPermission(clientId, true); sessionIdService.updateSessionId(sessionUser); } else {