From 90842cf7ef7f19930c0c505a8c545d1ab3fcccd0 Mon Sep 17 00:00:00 2001 From: mposolda Date: Tue, 26 Jan 2016 10:59:17 +0100 Subject: [PATCH 1/3] Minor change in message --- .../authenticators/client/JWTClientAuthenticator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java index 4cb728f67a..a1a847dd07 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java @@ -2,6 +2,7 @@ package org.keycloak.authentication.authenticators.client; import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -120,7 +121,7 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator { // Validate other things String expectedAudience = Urls.realmIssuer(context.getUriInfo().getBaseUri(), realm.getName()); if (!token.hasAudience(expectedAudience)) { - throw new RuntimeException("Token audience doesn't match domain. Realm audience is '" + expectedAudience + "' but audience from token is '" + token.getAudience() + "'"); + throw new RuntimeException("Token audience doesn't match domain. Realm audience is '" + expectedAudience + "' but audience from token is '" + Arrays.asList(token.getAudience()).toString() + "'"); } if (!token.isActive()) { From 3731964a2a9fcc26db17c1f29a093826edadcec8 Mon Sep 17 00:00:00 2001 From: mposolda Date: Tue, 26 Jan 2016 13:01:57 +0100 Subject: [PATCH 2/3] KEYCLOAK-2351 Support for response_type=token to be OAuth2 compliant --- .../protocol/oidc/OIDCWellKnownProvider.java | 2 +- .../protocol/oidc/utils/OIDCResponseType.java | 10 ++++++---- .../java/org/keycloak/test/ResponseTypeTest.java | 14 +++++++------- .../client/OIDCClientRegistrationTest.java | 2 +- .../testsuite/oauth/AuthorizationCodeTest.java | 4 ++-- 5 files changed, 17 insertions(+), 15 deletions(-) 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 8e0cdbf0e2..4f6a5cc20b 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java @@ -26,7 +26,7 @@ public class OIDCWellKnownProvider implements WellKnownProvider { public static final List DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS); - public static final List DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE, OIDCResponseType.NONE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token"); + public static final List DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE, OIDCResponseType.NONE, OIDCResponseType.ID_TOKEN, OIDCResponseType.TOKEN, "id_token token", "code id_token", "code token", "code id_token token"); public static final List DEFAULT_SUBJECT_TYPES_SUPPORTED = list("public"); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java index 9313aa60bc..e8327ecd50 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java @@ -63,9 +63,11 @@ public class OIDCResponseType { if (responseTypes.contains(NONE) && responseTypes.size() > 1) { throw new IllegalArgumentException("None not allowed with some other response_type"); } - if (responseTypes.contains(TOKEN) && responseTypes.size() == 1) { - throw new IllegalArgumentException("Not supported to use response_type=token alone"); - } + + // response_type value "token" alone is not mentioned in OIDC specification, however it is supported by OAuth2. We allow it just to be compatible with pure OAuth2 clients like swagger.ui +// if (responseTypes.contains(TOKEN) && responseTypes.size() == 1) { +// throw new IllegalArgumentException("Not supported to use response_type=token alone"); +// } } @@ -79,7 +81,7 @@ public class OIDCResponseType { } public boolean isImplicitFlow() { - return hasResponseType(ID_TOKEN) && !hasResponseType(CODE); + return (hasResponseType(TOKEN) || hasResponseType(ID_TOKEN)) && !hasResponseType(CODE); } diff --git a/services/src/test/java/org/keycloak/test/ResponseTypeTest.java b/services/src/test/java/org/keycloak/test/ResponseTypeTest.java index dd15aa90e9..42d852a17d 100644 --- a/services/src/test/java/org/keycloak/test/ResponseTypeTest.java +++ b/services/src/test/java/org/keycloak/test/ResponseTypeTest.java @@ -20,7 +20,7 @@ public class ResponseTypeTest { assertSuccess("code"); assertSuccess("none"); assertSuccess("id_token"); - assertFail("token"); + assertSuccess("token"); assertFail("refresh_token"); assertSuccess("id_token token"); assertSuccess("code token"); @@ -32,13 +32,13 @@ public class ResponseTypeTest { @Test public void testMultipleResponseTypes() { - try { - OIDCResponseType.parse(Arrays.asList("code", "token")); - Assert.fail("Not expected to parse with success"); - } catch (IllegalArgumentException iae) { - } + OIDCResponseType responseType = OIDCResponseType.parse(Arrays.asList("code", "token")); + Assert.assertTrue(responseType.hasResponseType("code")); + Assert.assertFalse(responseType.hasResponseType("none")); + Assert.assertTrue(responseType.isImplicitOrHybridFlow()); + Assert.assertFalse(responseType.isImplicitFlow()); - OIDCResponseType responseType = OIDCResponseType.parse(Collections.singletonList("code")); + responseType = OIDCResponseType.parse(Collections.singletonList("code")); Assert.assertTrue(responseType.hasResponseType("code")); Assert.assertFalse(responseType.hasResponseType("none")); Assert.assertFalse(responseType.isImplicitOrHybridFlow()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java index f0fbe2bedc..81a69af78c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java @@ -90,7 +90,7 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest { try { OIDCClientRepresentation response = create(); reg.auth(Auth.token(response)); - response.setResponseTypes(Arrays.asList("code", "token")); + response.setResponseTypes(Arrays.asList("code", "tokenn")); reg.oidc().update(response); fail("Not expected to end with success"); } catch (ClientRegistrationException cre) { diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java index 12d443a031..232c57835b 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java @@ -171,10 +171,10 @@ public class AuthorizationCodeTest { @Test public void authorizationRequestInvalidResponseType() throws IOException { UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl()); - b.replaceQueryParam(OAuth2Constants.RESPONSE_TYPE, "token"); + b.replaceQueryParam(OAuth2Constants.RESPONSE_TYPE, "tokenn"); driver.navigate().to(b.build().toURL()); assertEquals("Invalid parameter: response_type", errorPage.getError()); - events.expectLogin().error(Errors.INVALID_REQUEST).client((String) null).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "token").assertEvent(); + events.expectLogin().error(Errors.INVALID_REQUEST).client((String) null).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "tokenn").assertEvent(); } private void assertCode(String expectedCodeId, String actualCode) { From 3bc4355bb1a96a36b091f8fc229c01cb2c0ca84b Mon Sep 17 00:00:00 2001 From: mposolda Date: Tue, 26 Jan 2016 17:12:26 +0100 Subject: [PATCH 3/3] Small note about distributable HttpSessions in clustering docs --- .../reference/en/en-US/modules/application-clustering.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/application-clustering.xml b/docbook/auth-server-docs/reference/en/en-US/modules/application-clustering.xml index c4246d2f12..5dab883901 100644 --- a/docbook/auth-server-docs/reference/en/en-US/modules/application-clustering.xml +++ b/docbook/auth-server-docs/reference/en/en-US/modules/application-clustering.xml @@ -28,6 +28,14 @@ and his browser and hence can't rely on sticky sessions. + + + To enable distributable (replicated) HTTP Sessions in your application, you may need to do some additional steps. Usually you need to put ]]> + tag into WEB-INF/web.xml file of your application and possibly do some additional steps to configure underlying cluster cache (In case of + Wildfly, the implementation of cluster cache is based on Infinispan). These steps are server specific, so consult documentation of your application server for more details. + + +
Stateless token store