diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java index ab5b69d43f..d989492f81 100644 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java @@ -74,8 +74,9 @@ public class AdapterTokenVerifier { IDToken idToken = TokenVerifier.create(idTokenString, IDToken.class).getToken(); TokenVerifier idTokenVerifier = TokenVerifier.createWithoutSignature(idToken); - // Always verify audience on IDToken + // Always verify audience and azp on IDToken idTokenVerifier.audience(deployment.getResourceName()); + idTokenVerifier.issuedFor(deployment.getResourceName()); idTokenVerifier.verify(); return new VerifiedTokens(accessToken, idToken); diff --git a/core/src/main/java/org/keycloak/TokenVerifier.java b/core/src/main/java/org/keycloak/TokenVerifier.java index 71e125f159..d45e0b2878 100755 --- a/core/src/main/java/org/keycloak/TokenVerifier.java +++ b/core/src/main/java/org/keycloak/TokenVerifier.java @@ -153,10 +153,8 @@ public class TokenVerifier { throw new VerificationException("No audience in the token"); } - for (String aud : audience) { - if (expectedAudience.equals(aud)) { - return true; - } + if (t.hasAudience(expectedAudience)) { + return true; } throw new VerificationException("Expected audience not available in the token"); @@ -164,6 +162,29 @@ public class TokenVerifier { }; + public static class IssuedForCheck implements Predicate { + + private final String expectedIssuedFor; + + public IssuedForCheck(String expectedIssuedFor) { + this.expectedIssuedFor = expectedIssuedFor; + } + + @Override + public boolean test(JsonWebToken jsonWebToken) throws VerificationException { + if (expectedIssuedFor == null) { + throw new VerificationException("Missing expectedIssuedFor"); + } + + if (expectedIssuedFor.equals(jsonWebToken.getIssuedFor())) { + return true; + } + + throw new VerificationException("Expected issuedFor doesn't match"); + } + } + + private String tokenString; private Class clazz; private PublicKey publicKey; @@ -352,6 +373,16 @@ public class TokenVerifier { return this.replaceCheck(AudienceCheck.class, true, new AudienceCheck(expectedAudience)); } + /** + * Add check for verifying that token issuedFor (azp claim) is the expected value + * + * @param expectedIssuedFor issuedFor, which needs to be in the target token. Can't be null + * @return This token verifier + */ + public TokenVerifier issuedFor(String expectedIssuedFor) { + return this.replaceCheck(IssuedForCheck.class, true, new IssuedForCheck(expectedIssuedFor)); + } + public TokenVerifier parse() throws VerificationException { if (jws == null) { if (tokenString == null) { diff --git a/core/src/main/java/org/keycloak/representations/RefreshToken.java b/core/src/main/java/org/keycloak/representations/RefreshToken.java index ddb28aa32f..4a8547c5b2 100755 --- a/core/src/main/java/org/keycloak/representations/RefreshToken.java +++ b/core/src/main/java/org/keycloak/representations/RefreshToken.java @@ -46,7 +46,7 @@ public class RefreshToken extends AccessToken { this.issuedFor = token.issuedFor; this.sessionState = token.sessionState; this.nonce = token.nonce; - this.audience = token.audience; + this.audience = new String[] { token.issuer }; this.scope = token.scope; if (token.realmAccess != null) { realmAccess = token.realmAccess.clone(); diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java index 42d64eccf0..a973eef1f4 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java @@ -258,10 +258,13 @@ public class PolicyEvaluationService { } - AccessToken.Access realmAccess = accessToken.getRealmAccess(); + if (representation.getRoleIds() != null && !representation.getRoleIds().isEmpty()) { + if (accessToken.getRealmAccess() == null) { + accessToken.setRealmAccess(new AccessToken.Access()); + } + AccessToken.Access realmAccess = accessToken.getRealmAccess(); - if (representation.getRoleIds() != null) { - representation.getRoleIds().forEach(roleName -> realmAccess.addRole(roleName)); + representation.getRoleIds().forEach(realmAccess::addRole); } return new CloseableKeycloakIdentity(accessToken, keycloakSession, userSession); diff --git a/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java index 13bc812297..5e06676414 100755 --- a/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java +++ b/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java @@ -64,7 +64,8 @@ public class KeycloakOIDCIdentityProvider extends OIDCIdentityProvider { @Override protected void processAccessTokenResponse(BrokeredIdentityContext context, AccessTokenResponse response) { - JsonWebToken access = validateToken(response.getToken()); + // Don't verify audience on accessToken as it may not be there. It was verified on IDToken already + JsonWebToken access = validateToken(response.getToken(), true); context.getContextData().put(VALIDATED_ACCESS_TOKEN, access); } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java index d5ee3e9fc8..ba36588215 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java @@ -640,7 +640,6 @@ public class TokenManager { token.id(KeycloakModelUtils.generateId()); token.type(TokenUtil.TOKEN_TYPE_BEARER); token.subject(user.getId()); - token.audience(client.getClientId()); token.issuedNow(); token.issuedFor(client.getClientId()); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java index 872fd4c578..2447afa115 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java @@ -854,6 +854,10 @@ public class TokenEndpoint { .generateAccessToken(); responseBuilder.getAccessToken().issuedFor(client.getClientId()); + if (audience != null) { + responseBuilder.getAccessToken().addAudience(audience); + } + if (requestedTokenType.equals(OAuth2Constants.REFRESH_TOKEN_TYPE)) { responseBuilder.generateRefreshToken(); responseBuilder.getRefreshToken().issuedFor(client.getClientId()); diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java index 5dd5056081..66278a703d 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -439,12 +439,15 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal if (authResult != null) { AccessToken token = authResult.getToken(); - String[] audience = token.getAudience(); - ClientModel clientModel = this.realmModel.getClientByClientId(audience[0]); + String issuedFor = token.getIssuedFor(); + ClientModel clientModel = this.realmModel.getClientByClientId(issuedFor); if (clientModel == null) { return badRequest("Invalid client."); } + if (!clientModel.isEnabled()) { + return badRequest("Client is disabled"); + } session.getContext().setClient(clientModel); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java index 56e5f5316f..c38cdae145 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java @@ -96,8 +96,8 @@ class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManage } private void initIdentity(KeycloakSession session, AdminAuth auth) { - if (auth.getToken().hasAudience(Constants.ADMIN_CLI_CLIENT_ID) - || auth.getToken().hasAudience(Constants.ADMIN_CONSOLE_CLIENT_ID)) { + if (Constants.ADMIN_CLI_CLIENT_ID.equals(auth.getToken().getIssuedFor()) + || Constants.ADMIN_CONSOLE_CLIENT_ID.equals(auth.getToken().getIssuedFor())) { this.identity = new UserModelIdentity(auth.getRealm(), auth.getUser()); } else { diff --git a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/ClientInitiatedAccountLinkServlet.java b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/ClientInitiatedAccountLinkServlet.java index f8849b09a6..9bc68df0bd 100644 --- a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/ClientInitiatedAccountLinkServlet.java +++ b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/ClientInitiatedAccountLinkServlet.java @@ -47,7 +47,7 @@ public class ClientInitiatedAccountLinkServlet extends HttpServlet { String realm = request.getParameter("realm"); KeycloakSecurityContext session = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName()); AccessToken token = session.getToken(); - String clientId = token.getAudience()[0]; + String clientId = token.getIssuedFor(); String nonce = UUID.randomUUID().toString(); MessageDigest md = null; try { diff --git a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/LinkAndExchangeServlet.java b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/LinkAndExchangeServlet.java index 44ebb6dfec..c43ef97062 100644 --- a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/LinkAndExchangeServlet.java +++ b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/LinkAndExchangeServlet.java @@ -126,7 +126,7 @@ public class LinkAndExchangeServlet extends HttpServlet { AccessToken token = session.getToken(); String tokenString = session.getTokenString(); - String clientId = token.getAudience()[0]; + String clientId = token.getIssuedFor(); String linkUrl = null; try { AccessTokenResponse response = doTokenExchange(realm, tokenString, provider, clientId, "password"); @@ -176,7 +176,7 @@ public class LinkAndExchangeServlet extends HttpServlet { String realm = request.getParameter("realm"); KeycloakSecurityContext session = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName()); AccessToken token = session.getToken(); - String clientId = token.getAudience()[0]; + String clientId = token.getIssuedFor(); String tokenString = session.getTokenString(); AccessTokenResponse response = doTokenExchange(realm, tokenString, provider, clientId, "password"); error = (String)response.getOtherClaims().get("error"); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java index 8ce0632be7..fe2e886411 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java @@ -307,7 +307,7 @@ public class OIDCJwksClientRegistrationTest extends AbstractClientRegistrationTe OAuthClient.AccessTokenResponse accessTokenResponse = doClientCredentialsGrantRequest(signedJwt); Assert.assertEquals(200, accessTokenResponse.getStatusCode()); AccessToken accessToken = oauth.verifyToken(accessTokenResponse.getAccessToken()); - Assert.assertEquals(response.getClientId(), accessToken.getAudience()[0]); + Assert.assertEquals(response.getClientId(), accessToken.getIssuedFor()); } private void assertAuthenticateClientError(Map generatedKeys, OIDCClientRepresentation response, String kid) throws Exception { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCPairwiseClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCPairwiseClientRegistrationTest.java index da9d484f05..3edc3e2346 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCPairwiseClientRegistrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCPairwiseClientRegistrationTest.java @@ -397,9 +397,6 @@ public class OIDCPairwiseClientRegistrationTest extends AbstractClientRegistrati // its iat Claim MUST represent the time that the new ID Token is issued Assert.assertEquals(refreshedIdToken.getIssuedAt(), refreshedRefreshToken.getIssuedAt()); - // its aud Claim Value MUST be the same as in the ID Token issued when the original authentication occurred - Assert.assertArrayEquals(idToken.getAudience(), refreshedRefreshToken.getAudience()); - // if the ID Token contains an auth_time Claim, its value MUST represent the time of the original authentication // - not the time that the new ID token is issued Assert.assertEquals(idToken.getAuthTime(), refreshedIdToken.getAuthTime()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java index 167cbf489c..67200906cc 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java @@ -143,6 +143,16 @@ public class AccessTokenTest extends AbstractKeycloakTest { .password("password"); realm.getUsers().add(user.build()); + realm.getClients().stream().filter(clientRepresentation -> { + + return "test-app".equals(clientRepresentation.getClientId()); + + }).forEach(clientRepresentation -> { + + clientRepresentation.setFullScopeAllowed(false); + + }); + testRealms.add(realm); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientTokenExchangeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientTokenExchangeTest.java index f506bdb2b8..db3dd9cc62 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientTokenExchangeTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientTokenExchangeTest.java @@ -301,7 +301,7 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest { TokenVerifier verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class); AccessToken exchangedToken = verifier.parse().getToken(); Assert.assertEquals("client-exchanger", exchangedToken.getIssuedFor()); - Assert.assertEquals("client-exchanger", exchangedToken.getAudience()[0]); + Assert.assertNull(exchangedToken.getAudience()); Assert.assertEquals(exchangedToken.getPreferredUsername(), "impersonated-user"); Assert.assertNull(exchangedToken.getRealmAccess()); } @@ -409,7 +409,7 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest { TokenVerifier verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class); AccessToken exchangedToken = verifier.parse().getToken(); Assert.assertEquals("direct-exchanger", exchangedToken.getIssuedFor()); - Assert.assertEquals("direct-exchanger", exchangedToken.getAudience()[0]); + Assert.assertNull(exchangedToken.getAudience()); Assert.assertEquals(exchangedToken.getPreferredUsername(), "impersonated-user"); Assert.assertNull(exchangedToken.getRealmAccess()); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java index 416a743090..25efa56c1c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java @@ -228,7 +228,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest { assertEquals(Arrays.asList("A","B"), accessToken.getOtherClaims().get("multiValued-via-script")); // Assert audiences added through AudienceResolve mapper - Assert.assertThat(accessToken.getAudience(), arrayContainingInAnyOrder("test-app", "app", "account")); + Assert.assertThat(accessToken.getAudience(), arrayContainingInAnyOrder( "app", "account")); // Assert allowed origins String expectedOrigin = UriUtils.getOrigin(oauth.getRedirectUri()); @@ -415,7 +415,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest { List roles = (List) cst1.get("roles"); Assert.assertNames(roles, "offline_access", "user", "customer-user", "hardcoded", AccountRoles.VIEW_PROFILE, AccountRoles.MANAGE_ACCOUNT, AccountRoles.MANAGE_ACCOUNT_LINKS); - // Assert audience + // Assert audience - "test-app" is added due the AudienceResolveProtocolMapper Assert.assertNames(Arrays.asList(accessToken.getAudience()), "account", "test-app"); } finally { // Revert @@ -430,13 +430,15 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest { @Test - public void testAllowedOriginsRemovedFromAccessToken() throws Exception { + public void testRolesAndAllowedOriginsRemovedFromAccessToken() throws Exception { RealmResource realm = adminClient.realm("test"); ClientScopeRepresentation allowedOriginsScope = ApiUtil.findClientScopeByName(realm, OIDCLoginProtocolFactory.WEB_ORIGINS_SCOPE).toRepresentation(); + ClientScopeRepresentation rolesScope = ApiUtil.findClientScopeByName(realm, OIDCLoginProtocolFactory.ROLES_SCOPE).toRepresentation(); - // Remove 'web-origins' scope from the client + // Remove 'roles' and 'web-origins' scope from the client ClientResource testApp = ApiUtil.findClientByClientId(realm, "test-app"); testApp.removeDefaultClientScope(allowedOriginsScope.getId()); + testApp.removeDefaultClientScope(rolesScope.getId()); try { OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password"); @@ -445,9 +447,22 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest { // Assert web origins are not in the token Assert.assertNull(accessToken.getAllowedOrigins()); + // Assert roles are not in the token + Assert.assertNull(accessToken.getRealmAccess()); + Assert.assertTrue(accessToken.getResourceAccess().isEmpty()); + + // Assert client not in the token audience. Just in "issuedFor" + Assert.assertEquals("test-app", accessToken.getIssuedFor()); + Assert.assertFalse(accessToken.hasAudience("test-app")); + + // Assert IDToken still has "test-app" as an audience + IDToken idToken = oauth.verifyIDToken(response.getIdToken()); + Assert.assertEquals("test-app", idToken.getIssuedFor()); + Assert.assertTrue(idToken.hasAudience("test-app")); } finally { // Revert testApp.addDefaultClientScope(allowedOriginsScope.getId()); + testApp.addDefaultClientScope(rolesScope.getId()); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java index bd249d0688..8facb4127c 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java @@ -179,6 +179,10 @@ public class RefreshTokenTest extends AbstractKeycloakTest { Assert.assertThat(refreshedToken.getExpiration() - token.getExpiration(), allOf(greaterThanOrEqualTo(1), lessThanOrEqualTo(10))); Assert.assertThat(refreshedRefreshToken.getExpiration() - refreshToken.getExpiration(), allOf(greaterThanOrEqualTo(1), lessThanOrEqualTo(10))); + // "test-app" should not be an audience in the refresh token + assertEquals("test-app", refreshedRefreshToken.getIssuedFor()); + Assert.assertFalse(refreshedRefreshToken.hasAudience("test-app")); + Assert.assertNotEquals(token.getId(), refreshedToken.getId()); Assert.assertNotEquals(refreshToken.getId(), refreshedRefreshToken.getId()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AudienceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AudienceTest.java index a810f5da37..7527e05ef0 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AudienceTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AudienceTest.java @@ -19,6 +19,7 @@ package org.keycloak.testsuite.oidc; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import javax.ws.rs.core.Response; @@ -136,8 +137,8 @@ public class AudienceTest extends AbstractOIDCScopeTest { .user(userId) .assertEvent(); Tokens tokens = sendTokenRequest(loginEvent, userId,"openid profile email audience-scope", "test-app"); - // TODO: Frontend client itself should not be in the audiences of access token. Will be fixed in the future - assertAudiences(tokens.accessToken, "test-app", "service-client"); + + assertAudiences(tokens.accessToken, "service-client"); assertAudiences(tokens.idToken, "test-app"); // Revert @@ -168,8 +169,8 @@ public class AudienceTest extends AbstractOIDCScopeTest { .user(userId) .assertEvent(); Tokens tokens = sendTokenRequest(loginEvent, userId,"openid profile email audience-scope", "test-app"); - // TODO: Frontend client itself should not be in the audiences of access token. Will be fixed in the future - assertAudiences(tokens.accessToken, "test-app", "http://host/service/ctx1", "http://host/service/ctx2"); + + assertAudiences(tokens.accessToken, "http://host/service/ctx1", "http://host/service/ctx2"); assertAudiences(tokens.idToken, "test-app", "http://host/service/ctx2"); // Revert @@ -192,7 +193,7 @@ public class AudienceTest extends AbstractOIDCScopeTest { .user(userId) .assertEvent(); Tokens tokens = sendTokenRequest(loginEvent, userId,"openid profile email", "test-app"); - assertAudiences(tokens.accessToken, "test-app"); + assertAudiences(tokens.accessToken); assertAudiences(tokens.idToken, "test-app"); Assert.assertFalse(tokens.accessToken.getResourceAccess().containsKey("service-client")); @@ -215,7 +216,7 @@ public class AudienceTest extends AbstractOIDCScopeTest { .user(userId) .assertEvent(); tokens = sendTokenRequest(loginEvent, userId,"openid profile email service-client", "test-app"); - assertAudiences(tokens.accessToken, "test-app", "service-client"); + assertAudiences(tokens.accessToken, "service-client"); assertAudiences(tokens.idToken, "test-app"); Assert.assertTrue(tokens.accessToken.getResourceAccess().containsKey("service-client")); Assert.assertNames(tokens.accessToken.getResourceAccess().get("service-client").getRoles(), "role1"); @@ -228,7 +229,7 @@ public class AudienceTest extends AbstractOIDCScopeTest { private void assertAudiences(JsonWebToken token, String... expectedAudience) { - Collection audiences = Arrays.asList(token.getAudience()); + Collection audiences = token.getAudience() == null ? Collections.emptyList() : Arrays.asList(token.getAudience()); Collection expectedAudiences = Arrays.asList(expectedAudience); Assert.assertTrue("Not matched. expectedAudiences: " + expectedAudiences + ", audiences: " + audiences, expectedAudiences.containsAll(audiences) && audiences.containsAll(expectedAudiences));