From cb7cef88583f840144e5a6b35acd614014772f17 Mon Sep 17 00:00:00 2001 From: John Ament Date: Fri, 14 Apr 2017 11:04:29 -0400 Subject: [PATCH 1/4] KEYCLOAK-4765 - Add ability to disable Query Parameter parsing. --- adapters/oidc/adapter-core/pom.xml | 6 ++ .../keycloak/adapters/KeycloakDeployment.java | 10 ++ .../adapters/KeycloakDeploymentBuilder.java | 3 + ...ueryParamterTokenRequestAuthenticator.java | 5 + .../KeycloakDeploymentBuilderTest.java | 4 + .../adapters/KeycloakDeploymentTest.java | 49 +++++++++ ...ParamterTokenRequestAuthenticatorTest.java | 99 +++++++++++++++++++ .../src/test/resources/keycloak.json | 3 +- .../adapters/config/AdapterConfig.java | 13 ++- 9 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentTest.java create mode 100644 adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticatorTest.java diff --git a/adapters/oidc/adapter-core/pom.xml b/adapters/oidc/adapter-core/pom.xml index a92ff5fd58..19c7794446 100755 --- a/adapters/oidc/adapter-core/pom.xml +++ b/adapters/oidc/adapter-core/pom.xml @@ -95,6 +95,12 @@ httpclient provided + + org.mockito + mockito-core + 2.7.16 + test + diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java index ba7bc5d759..1ea1d5bc47 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java @@ -35,6 +35,8 @@ import java.util.Map; /** * @author Bill Burke + * @author Brad Culley + * @author John D. Ament * @version $Revision: 1 $ */ public class KeycloakDeployment { @@ -87,6 +89,7 @@ public class KeycloakDeployment { // https://tools.ietf.org/html/rfc7636 protected boolean pkce = false; + protected boolean ignoreOAuthQueryParameter; public KeycloakDeployment() { } @@ -427,4 +430,11 @@ public class KeycloakDeployment { this.pkce = pkce; } + public void setIgnoreOAuthQueryParameter(boolean ignoreOAuthQueryParameter) { + this.ignoreOAuthQueryParameter = ignoreOAuthQueryParameter; + } + + public boolean isOAuthQueryParameterEnabled() { + return !this.ignoreOAuthQueryParameter; + } } diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java index 2fd92760c6..6791edd955 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java @@ -37,6 +37,8 @@ import java.security.PublicKey; /** * @author Bill Burke + * @author Brad Culley + * @author John D. Ament * @version $Revision: 1 $ */ public class KeycloakDeploymentBuilder { @@ -112,6 +114,7 @@ public class KeycloakDeploymentBuilder { deployment.setTokenMinimumTimeToLive(adapterConfig.getTokenMinimumTimeToLive()); deployment.setMinTimeBetweenJwksRequests(adapterConfig.getMinTimeBetweenJwksRequests()); deployment.setPublicKeyCacheTtl(adapterConfig.getPublicKeyCacheTtl()); + deployment.setIgnoreOAuthQueryParameter(adapterConfig.isIgnoreOAuthQueryParameter()); if (realmKeyPem == null && adapterConfig.isBearerOnly() && adapterConfig.getAuthServerUrl() == null) { throw new IllegalArgumentException("For bearer auth, you must set the realm-public-key or auth-server-url"); diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticator.java index 5ee6662c1f..d2cabb3d75 100644 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticator.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticator.java @@ -22,6 +22,8 @@ import org.keycloak.adapters.spi.HttpFacade; /** * @author Christian Froehlich + * @author Brad Culley + * @author John D. Ament * @version $Revision: 1 $ */ public class QueryParamterTokenRequestAuthenticator extends BearerTokenRequestAuthenticator { @@ -33,6 +35,9 @@ public class QueryParamterTokenRequestAuthenticator extends BearerTokenRequestAu } public AuthOutcome authenticate(HttpFacade exchange) { + if(!deployment.isOAuthQueryParameterEnabled()) { + return AuthOutcome.NOT_ATTEMPTED; + } tokenString = null; tokenString = getAccessTokenFromQueryParamter(exchange); if (tokenString == null || tokenString.trim().isEmpty()) { diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java index 233c1ed2f0..0d723a3c4b 100644 --- a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java +++ b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java @@ -29,10 +29,13 @@ import org.keycloak.common.util.PemUtils; import org.keycloak.enums.TokenStore; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * @author Stian Thorgersen + * @author Brad Culley + * @author John D. Ament */ public class KeycloakDeploymentBuilderTest { @@ -57,6 +60,7 @@ public class KeycloakDeploymentBuilderTest { assertTrue(deployment.isPublicClient()); assertTrue(deployment.isEnableBasicAuth()); assertTrue(deployment.isExposeToken()); + assertFalse(deployment.isOAuthQueryParameterEnabled()); assertEquals("234234-234234-234234", deployment.getResourceCredentials().get("secret")); assertEquals(ClientIdAndSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId()); assertEquals(20, ((ThreadSafeClientConnManager) deployment.getClient().getConnectionManager()).getMaxTotal()); diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentTest.java new file mode 100644 index 0000000000..3bb5bce2a3 --- /dev/null +++ b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.keycloak.adapters; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author Brad Culley + * @author John D. Ament + */ +public class KeycloakDeploymentTest { + @Test + public void shouldNotEnableOAuthQueryParamWhenIgnoreIsTrue() { + KeycloakDeployment keycloakDeployment = new KeycloakDeployment(); + keycloakDeployment.setIgnoreOAuthQueryParameter(true); + assertFalse(keycloakDeployment.isOAuthQueryParameterEnabled()); + } + + @Test + public void shouldEnableOAuthQueryParamWhenIgnoreIsFalse() { + KeycloakDeployment keycloakDeployment = new KeycloakDeployment(); + keycloakDeployment.setIgnoreOAuthQueryParameter(false); + assertTrue(keycloakDeployment.isOAuthQueryParameterEnabled()); + } + + @Test + public void shouldEnableOAuthQueryParamWhenIgnoreNotSet() { + KeycloakDeployment keycloakDeployment = new KeycloakDeployment(); + + assertTrue(keycloakDeployment.isOAuthQueryParameterEnabled()); + } +} \ No newline at end of file diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticatorTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticatorTest.java new file mode 100644 index 0000000000..0193a56766 --- /dev/null +++ b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticatorTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.keycloak.adapters; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.keycloak.adapters.spi.AuthOutcome; +import org.keycloak.adapters.spi.HttpFacade; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * @author Brad Culley + * @author John D. Ament + */ +@RunWith(MockitoJUnitRunner.class) +public class QueryParamterTokenRequestAuthenticatorTest { + @Mock + private KeycloakDeployment keycloakDeployment; + @Mock + private HttpFacade httpFacade; + + private QueryParamterTokenRequestAuthenticator queryParamterTokenRequestAuthenticator; + + @Before + public void setup() { + when(keycloakDeployment.getRealm()).thenReturn("realm"); + when(keycloakDeployment.isOAuthQueryParameterEnabled()).thenReturn(true); + this.queryParamterTokenRequestAuthenticator = spy(new QueryParamterTokenRequestAuthenticator(keycloakDeployment)); + } + + @Test + public void shouldReturnNotAttemptedWhenQueryParameterNotSet() { + doReturn(null).when(queryParamterTokenRequestAuthenticator).getAccessTokenFromQueryParamter(httpFacade); + + AuthOutcome authOutcome = queryParamterTokenRequestAuthenticator.authenticate(httpFacade); + + assertEquals(authOutcome, AuthOutcome.NOT_ATTEMPTED); + } + + @Test + public void shouldReturnNotAttemptedWhenQueryParameterIsEmptyString() { + doReturn("").when(queryParamterTokenRequestAuthenticator).getAccessTokenFromQueryParamter(httpFacade); + + AuthOutcome authOutcome = queryParamterTokenRequestAuthenticator.authenticate(httpFacade); + + assertEquals(authOutcome, AuthOutcome.NOT_ATTEMPTED); + verify(queryParamterTokenRequestAuthenticator).getAccessTokenFromQueryParamter(httpFacade); + } + + @Test + public void shouldDelegateToAuthenticateTokenWhenAccessTokenSet() { + final String accessToken = "test"; + final AuthOutcome expectedAuthOutcome = AuthOutcome.FAILED; + doReturn(accessToken).when(queryParamterTokenRequestAuthenticator).getAccessTokenFromQueryParamter(httpFacade); + doReturn(expectedAuthOutcome).when(queryParamterTokenRequestAuthenticator).authenticateToken(httpFacade, accessToken); + + AuthOutcome authOutcome = queryParamterTokenRequestAuthenticator.authenticate(httpFacade); + + assertEquals(authOutcome, expectedAuthOutcome); + verify(queryParamterTokenRequestAuthenticator).authenticateToken(httpFacade, accessToken); + } + + @Test + public void shouldNotAttemptQueryParamterLogicWhenQueryParameterIsDisabled() { + given(keycloakDeployment.isOAuthQueryParameterEnabled()).willReturn(false); + + AuthOutcome authOutcome = queryParamterTokenRequestAuthenticator.authenticate(httpFacade); + + verify(queryParamterTokenRequestAuthenticator, never()).getAccessTokenFromQueryParamter(any(HttpFacade.class)); + verify(queryParamterTokenRequestAuthenticator, never()).authenticateToken(any(HttpFacade.class), anyString()); + assertEquals(authOutcome, AuthOutcome.NOT_ATTEMPTED); + } +} \ No newline at end of file diff --git a/adapters/oidc/adapter-core/src/test/resources/keycloak.json b/adapters/oidc/adapter-core/src/test/resources/keycloak.json index 9f0a204826..400128b6e4 100644 --- a/adapters/oidc/adapter-core/src/test/resources/keycloak.json +++ b/adapters/oidc/adapter-core/src/test/resources/keycloak.json @@ -31,5 +31,6 @@ "principal-attribute": "email", "token-minimum-time-to-live": 10, "min-time-between-jwks-requests": 20, - "public-key-cache-ttl": 120 + "public-key-cache-ttl": 120, + "ignore-oauth-query-parameter": true } \ No newline at end of file diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java index f063962a55..265ba40772 100755 --- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java +++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java @@ -24,6 +24,8 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; * Configuration for Java based adapters * * @author Bill Burke + * @author Brad Culley + * @author John D. Ament * @version $Revision: 1 $ */ @JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required", @@ -38,7 +40,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; "register-node-at-startup", "register-node-period", "token-store", "principal-attribute", "proxy-url", "turn-off-change-session-id-on-login", "token-minimum-time-to-live", "min-time-between-jwks-requests", "public-key-cache-ttl", - "policy-enforcer" + "policy-enforcer", "ignore-oauth-query-parameter" }) public class AdapterConfig extends BaseAdapterConfig implements AdapterHttpClientConfig { @@ -81,6 +83,8 @@ public class AdapterConfig extends BaseAdapterConfig implements AdapterHttpClien // https://tools.ietf.org/html/rfc7636 @JsonProperty("enable-pkce") protected boolean pkce = false; + @JsonProperty("ignore-oauth-query-parameter") + protected boolean ignoreOAuthQueryParameter = false; /** * The Proxy url to use for requests to the auth-server, configurable via the adapter config property {@code proxy-url}. @@ -257,4 +261,11 @@ public class AdapterConfig extends BaseAdapterConfig implements AdapterHttpClien this.pkce = pkce; } + public boolean isIgnoreOAuthQueryParameter() { + return ignoreOAuthQueryParameter; + } + + public void setIgnoreOAuthQueryParameter(boolean ignoreOAuthQueryParameter) { + this.ignoreOAuthQueryParameter = ignoreOAuthQueryParameter; + } } From 754b0fd123262a63dc738fdf369fb2d6dca164e7 Mon Sep 17 00:00:00 2001 From: John Ament Date: Tue, 25 Apr 2017 20:29:35 -0400 Subject: [PATCH 2/4] KEYCLOAK-4765 - Adding integration tests for adapter module. --- .../keycloak/testsuite/adapter/AdapterTest.java | 15 ++++++++++++--- .../testsuite/adapter/AdapterTestStrategy.java | 10 ++++++++++ .../resources/adapter-test/no-access-token.json | 11 +++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 testsuite/integration/src/test/resources/adapter-test/no-access-token.json diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java index 4a2ce9693d..a2ec8bb430 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java @@ -19,20 +19,18 @@ package org.keycloak.testsuite.adapter; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.keycloak.common.util.Encode; -import org.keycloak.common.util.KeycloakUriBuilder; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.services.managers.RealmManager; import org.keycloak.testsuite.rule.AbstractKeycloakRule; import java.net.URL; -import java.security.PublicKey; /** * Tests Undertow Adapter * * @author Bill Burke + * @author John Ament */ public class AdapterTest { @@ -93,6 +91,12 @@ public class AdapterTest { .name("input-portal").contextPath("/input-portal") .servletClass(InputServlet.class).adapterConfigPath(url.getPath()) .role("user").constraintUrl("/secured/*").deployApplication(); + + url = getClass().getResource("/adapter-test/no-access-token.json"); + createApplicationDeployment() + .name("no-access-token").contextPath("/no-access-token") + .servletClass(InputServlet.class).adapterConfigPath(url.getPath()) + .role("user").constraintUrl("/secured/*").deployApplication(); } }; @@ -237,4 +241,9 @@ public class AdapterTest { testStrategy.testRestCallWithAccessTokenAsQueryParameter(); } + + @Test + public void testCallURLWithAccessToken() throws Exception { + testStrategy.checkThatAccessTokenCanBeSentPublicly(); + } } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java index bd0a144607..e006820549 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java @@ -67,6 +67,7 @@ import java.util.concurrent.atomic.AtomicInteger; * Tests Undertow Adapter * * @author Bill Burke + * @author John Ament */ public class AdapterTestStrategy extends ExternalResource { @@ -814,4 +815,13 @@ public class AdapterTestStrategy extends ExternalResource { } + void checkThatAccessTokenCanBeSentPublicly() { + // test login to customer-portal which does a bearer request to customer-db + final String applicationURL = APP_SERVER_BASE_URL + "/no-access-token?access_token=invalid_token"; + driver.navigate().to(applicationURL); + System.out.println("Current url: " + driver.getCurrentUrl()); + Assert.assertEquals(applicationURL, driver.getCurrentUrl()); + inputPage.execute("hello"); + } + } diff --git a/testsuite/integration/src/test/resources/adapter-test/no-access-token.json b/testsuite/integration/src/test/resources/adapter-test/no-access-token.json new file mode 100644 index 0000000000..9c8cb7ea43 --- /dev/null +++ b/testsuite/integration/src/test/resources/adapter-test/no-access-token.json @@ -0,0 +1,11 @@ +{ + "realm" : "demo", + "resource" : "no-access-token", + "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", + "auth-server-url" : "http://${my.host.name}:8081/auth", + "ssl-required" : "external", + "credentials" : { + "secret": "password" + }, + "ignore-oauth-query-parameter": true +} \ No newline at end of file From 1f98dc5527a9ffa10669e1349d6fda742345d016 Mon Sep 17 00:00:00 2001 From: John Ament Date: Tue, 25 Apr 2017 20:36:07 -0400 Subject: [PATCH 3/4] KEYCLOAK-4765 - Simplified unit tests. --- adapters/oidc/adapter-core/pom.xml | 6 -- ...ParamterTokenRequestAuthenticatorTest.java | 99 ------------------- 2 files changed, 105 deletions(-) delete mode 100644 adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticatorTest.java diff --git a/adapters/oidc/adapter-core/pom.xml b/adapters/oidc/adapter-core/pom.xml index 19c7794446..a92ff5fd58 100755 --- a/adapters/oidc/adapter-core/pom.xml +++ b/adapters/oidc/adapter-core/pom.xml @@ -95,12 +95,6 @@ httpclient provided - - org.mockito - mockito-core - 2.7.16 - test - diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticatorTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticatorTest.java deleted file mode 100644 index 0193a56766..0000000000 --- a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticatorTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.adapters; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.keycloak.adapters.spi.AuthOutcome; -import org.keycloak.adapters.spi.HttpFacade; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** - * @author Brad Culley - * @author John D. Ament - */ -@RunWith(MockitoJUnitRunner.class) -public class QueryParamterTokenRequestAuthenticatorTest { - @Mock - private KeycloakDeployment keycloakDeployment; - @Mock - private HttpFacade httpFacade; - - private QueryParamterTokenRequestAuthenticator queryParamterTokenRequestAuthenticator; - - @Before - public void setup() { - when(keycloakDeployment.getRealm()).thenReturn("realm"); - when(keycloakDeployment.isOAuthQueryParameterEnabled()).thenReturn(true); - this.queryParamterTokenRequestAuthenticator = spy(new QueryParamterTokenRequestAuthenticator(keycloakDeployment)); - } - - @Test - public void shouldReturnNotAttemptedWhenQueryParameterNotSet() { - doReturn(null).when(queryParamterTokenRequestAuthenticator).getAccessTokenFromQueryParamter(httpFacade); - - AuthOutcome authOutcome = queryParamterTokenRequestAuthenticator.authenticate(httpFacade); - - assertEquals(authOutcome, AuthOutcome.NOT_ATTEMPTED); - } - - @Test - public void shouldReturnNotAttemptedWhenQueryParameterIsEmptyString() { - doReturn("").when(queryParamterTokenRequestAuthenticator).getAccessTokenFromQueryParamter(httpFacade); - - AuthOutcome authOutcome = queryParamterTokenRequestAuthenticator.authenticate(httpFacade); - - assertEquals(authOutcome, AuthOutcome.NOT_ATTEMPTED); - verify(queryParamterTokenRequestAuthenticator).getAccessTokenFromQueryParamter(httpFacade); - } - - @Test - public void shouldDelegateToAuthenticateTokenWhenAccessTokenSet() { - final String accessToken = "test"; - final AuthOutcome expectedAuthOutcome = AuthOutcome.FAILED; - doReturn(accessToken).when(queryParamterTokenRequestAuthenticator).getAccessTokenFromQueryParamter(httpFacade); - doReturn(expectedAuthOutcome).when(queryParamterTokenRequestAuthenticator).authenticateToken(httpFacade, accessToken); - - AuthOutcome authOutcome = queryParamterTokenRequestAuthenticator.authenticate(httpFacade); - - assertEquals(authOutcome, expectedAuthOutcome); - verify(queryParamterTokenRequestAuthenticator).authenticateToken(httpFacade, accessToken); - } - - @Test - public void shouldNotAttemptQueryParamterLogicWhenQueryParameterIsDisabled() { - given(keycloakDeployment.isOAuthQueryParameterEnabled()).willReturn(false); - - AuthOutcome authOutcome = queryParamterTokenRequestAuthenticator.authenticate(httpFacade); - - verify(queryParamterTokenRequestAuthenticator, never()).getAccessTokenFromQueryParamter(any(HttpFacade.class)); - verify(queryParamterTokenRequestAuthenticator, never()).authenticateToken(any(HttpFacade.class), anyString()); - assertEquals(authOutcome, AuthOutcome.NOT_ATTEMPTED); - } -} \ No newline at end of file From b37ed7145c0ffc4cfa45a1938d5b35ba59cdef75 Mon Sep 17 00:00:00 2001 From: John Ament Date: Wed, 26 Apr 2017 09:42:00 -0400 Subject: [PATCH 4/4] KEYCLOAK-4765 - Adding support for wildfly subsystem disable query parameter parsing. --- .../wf8/extension/SharedAttributeDefinitons.java | 10 +++++++++- .../wf8/extension/LocalDescriptions.properties | 2 ++ .../src/main/resources/schema/wildfly-keycloak_1_1.xsd | 2 ++ .../adapter/extension/SharedAttributeDefinitons.java | 7 +++++++ .../adapter/extension/LocalDescriptions.properties | 2 ++ .../src/main/resources/schema/wildfly-keycloak_1_1.xsd | 2 ++ 6 files changed, 24 insertions(+), 1 deletion(-) diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java index e4ff98816a..741b2c15b9 100755 --- a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java +++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java @@ -172,7 +172,14 @@ public class SharedAttributeDefinitons { .setXmlName("autodetect-bearer-only") .setAllowExpression(true) .setDefaultValue(new ModelNode(false)) - .build(); + .build(); + + protected static final SimpleAttributeDefinition IGNORE_OAUTH_QUERY_PARAMETER = + new SimpleAttributeDefinitionBuilder("ignore-oauth-query-parameter", ModelType.BOOLEAN, true) + .setXmlName("ignore-oauth-query-parameter") + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); protected static final List ATTRIBUTES = new ArrayList(); static { @@ -199,6 +206,7 @@ public class SharedAttributeDefinitons { ATTRIBUTES.add(TOKEN_STORE); ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE); ATTRIBUTES.add(AUTODETECT_BEARER_ONLY); + ATTRIBUTES.add(IGNORE_OAUTH_QUERY_PARAMETER); } /** diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties index 6244b0c797..271ba7fd65 100755 --- a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties +++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties @@ -47,6 +47,7 @@ keycloak.realm.register-node-period=how often to re-register node keycloak.realm.token-store=cookie or session storage for auth session data keycloak.realm.principal-attribute=token attribute to use to set Principal name keycloak.realm.autodetect-bearer-only=autodetect bearer-only requests +keycloak.realm.ignore-oauth-query-parameter=disable query parameter parsing for access_token keycloak.secure-deployment=A deployment secured by Keycloak keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak @@ -84,6 +85,7 @@ keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds keycloak.secure-deployment.autodetect-bearer-only=autodetect bearer-only requests +keycloak.secure-deployment.ignore-oauth-query-parameter=disable query parameter parsing for access_token keycloak.secure-deployment.credential=Credential value diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd index e9839bc069..40259d4fc3 100755 --- a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd +++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd @@ -66,6 +66,7 @@ + @@ -109,6 +110,7 @@ + diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java index 02d14e5b81..8b712048d9 100755 --- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java +++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java @@ -173,6 +173,12 @@ public class SharedAttributeDefinitons { .setDefaultValue(new ModelNode(false)) .build(); + protected static final SimpleAttributeDefinition IGNORE_OAUTH_QUERY_PARAMETER = + new SimpleAttributeDefinitionBuilder("ignore-oauth-query-parameter", ModelType.BOOLEAN, true) + .setXmlName("ignore-oauth-query-parameter") + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); protected static final List ATTRIBUTES = new ArrayList(); @@ -200,6 +206,7 @@ public class SharedAttributeDefinitons { ATTRIBUTES.add(TOKEN_STORE); ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE); ATTRIBUTES.add(AUTODETECT_BEARER_ONLY); + ATTRIBUTES.add(IGNORE_OAUTH_QUERY_PARAMETER); } private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) { diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties index c0ca52e0dc..b1134ed1b7 100755 --- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties +++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties @@ -47,6 +47,7 @@ keycloak.realm.register-node-period=how often to re-register node keycloak.realm.token-store=cookie or session storage for auth session data keycloak.realm.principal-attribute=token attribute to use to set Principal name keycloak.realm.autodetect-bearer-only=autodetect bearer-only requests +keycloak.realm.ignore-oauth-query-parameter=disable query parameter parsing for access_token keycloak.secure-deployment=A deployment secured by Keycloak keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak @@ -84,6 +85,7 @@ keycloak.secure-deployment.principal-attribute=token attribute to use to set Pri keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds +keycloak.secure-deployment.ignore-oauth-query-parameter=disable query parameter parsing for access_token keycloak.secure-deployment.credential=Credential value diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd index 84399a361a..1bc4950853 100755 --- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd +++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd @@ -66,6 +66,7 @@ + @@ -109,6 +110,7 @@ +