From d5199501c796d19ffcfc9b6c98d997492bb1799f Mon Sep 17 00:00:00 2001 From: mposolda Date: Wed, 13 Jul 2016 10:17:45 +0200 Subject: [PATCH] KEYCLOAK-3219 Added claims info to OIDCWellKnownProvider. More tests --- .../oidc/OIDCLoginProtocolService.java | 5 +++ .../protocol/oidc/OIDCWellKnownProvider.java | 10 +++++ .../OIDCConfigurationRepresentation.java | 33 ++++++++++++++ .../keycloak/testsuite/util/OAuthClient.java | 2 +- .../testsuite/util/UserInfoClientUtil.java | 4 +- .../oidc/OIDCWellKnownProviderTest.java | 45 ++++++++++++++++++- 6 files changed, 95 insertions(+), 4 deletions(-) diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java index fad4aeb2cd..c5e86ea541 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java @@ -104,6 +104,11 @@ public class OIDCLoginProtocolService { return uriBuilder.path(OIDCLoginProtocolService.class, "certs"); } + public static UriBuilder userInfoUrl(UriBuilder baseUriBuilder) { + UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder); + return uriBuilder.path(OIDCLoginProtocolService.class, "issueUserInfo"); + } + public static UriBuilder tokenIntrospectionUrl(UriBuilder baseUriBuilder) { return tokenUrl(baseUriBuilder).path(TokenEndpoint.class, "introspect"); } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java index 3dbbbee60e..daff056113 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java @@ -24,6 +24,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.protocol.oidc.endpoints.TokenEndpoint; import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation; import org.keycloak.protocol.oidc.utils.OIDCResponseType; +import org.keycloak.representations.IDToken; import org.keycloak.services.clientregistration.ClientRegistrationService; import org.keycloak.services.clientregistration.oidc.OIDCClientRegistrationProviderFactory; import org.keycloak.services.resources.RealmsResource; @@ -55,6 +56,11 @@ public class OIDCWellKnownProvider implements WellKnownProvider { public static final List DEFAULT_CLIENT_AUTH_SIGNING_ALG_VALUES_SUPPORTED = list(Algorithm.RS256.toString()); + // The exact list depends on protocolMappers + public static final List DEFAULT_CLAIMS_SUPPORTED= list("sub", "iss", IDToken.AUTH_TIME, IDToken.NAME, IDToken.GIVEN_NAME, IDToken.FAMILY_NAME, IDToken.PREFERRED_USERNAME, IDToken.EMAIL); + + public static final List DEFAULT_CLAIM_TYPES_SUPPORTED= list("normal"); + private KeycloakSession session; public OIDCWellKnownProvider(KeycloakSession session) { @@ -87,6 +93,10 @@ public class OIDCWellKnownProvider implements WellKnownProvider { config.setTokenEndpointAuthMethodsSupported(DEFAULT_CLIENT_AUTH_METHODS_SUPPORTED); config.setTokenEndpointAuthSigningAlgValuesSupported(DEFAULT_CLIENT_AUTH_SIGNING_ALG_VALUES_SUPPORTED); + config.setClaimsSupported(DEFAULT_CLAIMS_SUPPORTED); + config.setClaimTypesSupported(DEFAULT_CLAIM_TYPES_SUPPORTED); + config.setClaimsParameterSupported(false); + return config; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java b/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java index 1fc349affe..bae3b52280 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java @@ -76,6 +76,15 @@ public class OIDCConfigurationRepresentation { @JsonProperty("token_endpoint_auth_signing_alg_values_supported") private List tokenEndpointAuthSigningAlgValuesSupported; + @JsonProperty("claims_supported") + private List claimsSupported; + + @JsonProperty("claim_types_supported") + private List claimTypesSupported; + + @JsonProperty("claims_parameter_supported") + private Boolean claimsParameterSupported; + protected Map otherClaims = new HashMap(); public String getIssuer() { @@ -198,6 +207,30 @@ public class OIDCConfigurationRepresentation { this.tokenEndpointAuthSigningAlgValuesSupported = tokenEndpointAuthSigningAlgValuesSupported; } + public List getClaimsSupported() { + return claimsSupported; + } + + public void setClaimsSupported(List claimsSupported) { + this.claimsSupported = claimsSupported; + } + + public List getClaimTypesSupported() { + return claimTypesSupported; + } + + public void setClaimTypesSupported(List claimTypesSupported) { + this.claimTypesSupported = claimTypesSupported; + } + + public Boolean getClaimsParameterSupported() { + return claimsParameterSupported; + } + + public void setClaimsParameterSupported(Boolean claimsParameterSupported) { + this.claimsParameterSupported = claimsParameterSupported; + } + @JsonAnyGetter public Map getOtherClaims() { return otherClaims; diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java index c406e2e6f9..cbfcc5beba 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java @@ -485,7 +485,7 @@ public class OAuthClient { } public String getLoginFormUrl() { - UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(SERVER_ROOT + "/auth")); + UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(AUTH_SERVER_ROOT)); b.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE); if (clientId != null) { b.queryParam(OAuth2Constants.CLIENT_ID, clientId); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UserInfoClientUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UserInfoClientUtil.java index 3d6033d10e..dd6a3db2c9 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UserInfoClientUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UserInfoClientUtil.java @@ -44,8 +44,8 @@ public class UserInfoClientUtil { public static WebTarget getUserInfoWebTarget(Client client) { UriBuilder builder = UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT); - UriBuilder uriBuilder = OIDCLoginProtocolService.tokenServiceBaseUrl(builder); - URI userInfoUri = uriBuilder.path(OIDCLoginProtocolService.class, "issueUserInfo").build("test"); + UriBuilder uriBuilder = OIDCLoginProtocolService.userInfoUrl(builder); + URI userInfoUri = uriBuilder.build("test"); return client.target(userInfoUri); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java index 61d8c877b4..c8ced0fd2c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java @@ -26,17 +26,21 @@ import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; +import org.junit.Before; import org.junit.Test; import org.keycloak.OAuth2Constants; import org.keycloak.jose.jws.Algorithm; +import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.OIDCWellKnownProviderFactory; import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation; import org.keycloak.protocol.oidc.utils.OIDCResponseType; +import org.keycloak.representations.IDToken; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.services.resources.RealmsResource; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.admin.AbstractAdminTest; +import org.keycloak.testsuite.util.ClientManager; import org.keycloak.testsuite.util.OAuthClient; /** @@ -50,6 +54,18 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest { testRealms.add(realm); } + @Before + public void clientConfiguration() { + ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true); + /* + * Configure the default client ID. Seems like OAuthClient is keeping the state of clientID + * For example: If some test case configure oauth.clientId("sample-public-client"), other tests + * will faile and the clientID will always be "sample-public-client + * @see AccessTokenTest#testAuthorizationNegotiateHeaderIgnored() + */ + oauth.clientId("test-app"); + } + @Test public void testDiscovery() { @@ -57,6 +73,12 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest { try { OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryConfiguration(client); + // URIs are filled + Assert.assertEquals(oidcConfig.getAuthorizationEndpoint(), OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT)).build("test").toString()); + Assert.assertEquals(oidcConfig.getTokenEndpoint(), oauth.getAccessTokenUrl()); + Assert.assertEquals(oidcConfig.getUserinfoEndpoint(), OIDCLoginProtocolService.userInfoUrl(UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT)).build("test").toString()); + Assert.assertEquals(oidcConfig.getJwksUri(), oauth.getCertsUrl("test")); + // Support standard + implicit + hybrid flow assertContains(oidcConfig.getResponseTypesSupported(), OAuth2Constants.CODE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token"); assertContains(oidcConfig.getGrantTypesSupported(), OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT); @@ -68,7 +90,28 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest { // Client authentication Assert.assertNames(oidcConfig.getTokenEndpointAuthMethodsSupported(), "client_secret_basic", "client_secret_post", "private_key_jwt"); Assert.assertNames(oidcConfig.getTokenEndpointAuthSigningAlgValuesSupported(), Algorithm.RS256.toString()); - System.out.println("Fopo"); + + // Claims + assertContains(oidcConfig.getClaimsSupported(), IDToken.NAME, IDToken.EMAIL, IDToken.PREFERRED_USERNAME, IDToken.FAMILY_NAME); + Assert.assertNames(oidcConfig.getClaimTypesSupported(), "normal"); + Assert.assertFalse(oidcConfig.getClaimsParameterSupported()); + } finally { + client.close(); + } + } + + @Test + public void testIssuerMatches() throws Exception { + OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password"); + Assert.assertEquals(200, response.getStatusCode()); + IDToken idToken = oauth.verifyIDToken(response.getIdToken()); + + Client client = ClientBuilder.newClient(); + try { + OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryConfiguration(client); + + // assert issuer matches + Assert.assertEquals(idToken.getIssuer(), oidcConfig.getIssuer()); } finally { client.close(); }