From 730d4e8ac9acb1bad68a314dbb9e1b74337708da Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Mon, 19 Jul 2021 14:42:29 -0300 Subject: [PATCH] [KEYCLOAK-18807] - Fixing claims in JARM responses --- .../java/org/keycloak/OAuth2Constants.java | 2 ++ .../oidc/utils/OIDCRedirectUriBuilder.java | 30 ++++++++++++++----- .../AuthorizationTokenResponseModeTest.java | 27 +++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java index ba864ae9fd..79d4393910 100755 --- a/core/src/main/java/org/keycloak/OAuth2Constants.java +++ b/core/src/main/java/org/keycloak/OAuth2Constants.java @@ -24,6 +24,8 @@ public interface OAuth2Constants { String CODE = "code"; + String TOKEN = "token"; + String CLIENT_ID = "client_id"; String CLIENT_SECRET = "client_secret"; diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java index 2df5f18f96..455dc1be3e 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java @@ -17,14 +17,19 @@ package org.keycloak.protocol.oidc.utils; +import org.keycloak.OAuth2Constants; import org.keycloak.common.util.Encode; import org.keycloak.common.util.HtmlUtils; import org.keycloak.common.util.KeycloakUriBuilder; import org.keycloak.common.util.Time; import org.keycloak.models.AuthenticatedClientSessionModel; +import org.keycloak.models.ClientModel; +import org.keycloak.models.KeycloakContext; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.representations.AuthorizationResponseToken; +import org.keycloak.services.Urls; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -183,10 +188,10 @@ public abstract class OIDCRedirectUriBuilder { // https://openid.net/specs/openid-financial-api-jarm-ID1.html private static class JWTRedirectUriBuilder extends OIDCRedirectUriBuilder { - private OIDCResponseMode responseMode; - private AuthorizationResponseToken responseJWT; - private KeycloakSession session; - private AuthenticatedClientSessionModel clientSession; + private final OIDCResponseMode responseMode; + private final AuthorizationResponseToken responseJWT; + private final KeycloakSession session; + private final AuthenticatedClientSessionModel clientSession; public JWTRedirectUriBuilder(KeycloakUriBuilder uriBuilder, OIDCResponseMode responseMode, KeycloakSession session, AuthenticatedClientSessionModel clientSession) { super(uriBuilder); @@ -204,12 +209,23 @@ public abstract class OIDCRedirectUriBuilder { @Override public Response build() { + KeycloakContext context = session.getContext(); + ClientModel client = context.getClient(); + RealmModel realm = client.getRealm(); + + responseJWT.issuer(Urls.realmIssuer(context.getUri().getBaseUri(), realm.getName())); + responseJWT.audience(client.getClientId()); + responseJWT.exp((long) (Time.currentTime() + realm.getAccessCodeLifespan())); + if(clientSession != null) { responseJWT.issuer(clientSession.getNote(OIDCLoginProtocol.ISSUER)); - responseJWT.audience(clientSession.getClient().getClientId()); - responseJWT.setOtherClaims("scope", clientSession.getNote(OIDCLoginProtocol.SCOPE_PARAM)); - responseJWT.exp((long) (Time.currentTime() + clientSession.getRealm().getAccessCodeLifespan())); + String responseType = clientSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM); + + if (OAuth2Constants.TOKEN.equals(responseType)) { + responseJWT.setOtherClaims(OAuth2Constants.SCOPE, clientSession.getNote(OIDCLoginProtocol.SCOPE_PARAM)); + } } + switch (responseMode) { case QUERY_JWT: return buildQueryResponse(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AuthorizationTokenResponseModeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AuthorizationTokenResponseModeTest.java index eb8619621e..fdd103be02 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AuthorizationTokenResponseModeTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AuthorizationTokenResponseModeTest.java @@ -19,6 +19,7 @@ package org.keycloak.testsuite.oidc; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; +import org.keycloak.OAuth2Constants; import org.keycloak.OAuthErrorException; import org.keycloak.events.Details; import org.keycloak.events.Errors; @@ -38,6 +39,9 @@ import java.io.IOException; import java.net.URI; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; public class AuthorizationTokenResponseModeTest extends AbstractTestRealmKeycloakTest { @@ -76,6 +80,8 @@ public class AuthorizationTokenResponseModeTest extends AbstractTestRealmKeycloa assertEquals("test-app", responseToken.getAudience()[0]); Assert.assertNotNull(responseToken.getOtherClaims().get("code")); + // should not return code when response_type not 'token' + assertFalse(responseToken.getOtherClaims().containsKey(OAuth2Constants.SCOPE)); assertEquals("OpenIdConnect.AuthenticationProperties=2302984sdlk", responseToken.getOtherClaims().get("state")); Assert.assertNull(responseToken.getOtherClaims().get("error")); @@ -212,6 +218,27 @@ public class AuthorizationTokenResponseModeTest extends AbstractTestRealmKeycloa events.expectLogin().error(Errors.INVALID_REQUEST).user((String) null).session((String) null).clearDetails().assertEvent(); } + @Test + public void testErrorObjectExpectedClaims() throws Exception { + ClientManager.realm(adminClient.realm("test")).clientId("test-app").implicitFlow(true); + oauth.responseMode("query.jwt"); + oauth.responseType("code id_token"); + oauth.stateParamHardcoded("OpenIdConnect.AuthenticationProperties=2302984sdlk"); + oauth.nonce("123456"); + UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl()); + driver.navigate().to(b.build().toURL()); + + OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth); + AuthorizationResponseToken responseToken = oauth.verifyAuthorizationResponseToken(errorResponse.getResponse()); + + assertNotNull(responseToken.getIssuer()); + assertNotNull(responseToken.getExp()); + assertNotNull(responseToken.getAudience()); + assertNotEquals(0, responseToken.getAudience().length); + assertTrue(responseToken.getOtherClaims().containsKey("error")); + assertTrue(responseToken.getOtherClaims().containsKey("error_description")); + } + @Override public void configureTestRealm(RealmRepresentation testRealm) { }