From b9c04bb8bcdf9cd8485bf4c0a145b76267b5af23 Mon Sep 17 00:00:00 2001 From: Douglas Palmer Date: Wed, 22 May 2024 13:21:13 -0700 Subject: [PATCH] Refactor PolicyEnforcer tests to remove dependency on keycloak-adapter-core and remove keycloak-adapter-core Closes #29189 Closes #28791 Signed-off-by: Douglas Palmer --- adapters/oidc/adapter-core/pom.xml | 162 ------- .../keycloak/adapters/AdapterTokenStore.java | 61 --- .../BasicAuthRequestAuthenticator.java | 124 ------ .../BearerTokenRequestAuthenticator.java | 203 --------- .../keycloak/adapters/CookieTokenStore.java | 128 ------ .../adapters/NodesRegistrationManagement.java | 147 ------ .../adapters/OAuthRequestAuthenticator.java | 419 ------------------ .../adapters/OIDCAuthenticationError.java | 64 --- .../adapters/OidcKeycloakAccount.java | 29 -- .../adapters/PreAuthActionsHandler.java | 267 ----------- ...eryParameterTokenRequestAuthenticator.java | 60 --- .../adapters/RequestAuthenticator.java | 240 ---------- .../KeycloakDeploymentBuilderTest.java | 139 ------ .../adapters/KeycloakDeploymentTest.java | 86 ---- ...efreshableKeycloakSecurityContextTest.java | 114 ----- .../src/test/resources/cacerts.jks | Bin 959 -> 0 bytes .../test/resources/keycloak-http-client.json | 8 - .../src/test/resources/keycloak-jwt.json | 13 - .../resources/keycloak-no-credentials.json | 7 - .../test/resources/keycloak-secret-jwt.json | 12 - .../src/test/resources/keycloak.json | 41 -- .../src/test/resources/keystore.jks | Bin 2051 -> 0 bytes adapters/oidc/pom.xml | 1 - adapters/saml/wildfly-elytron-jakarta/pom.xml | 5 - adapters/saml/wildfly-elytron/pom.xml | 5 - boms/adapter/pom.xml | 5 - .../adapter-feature-pack/pom.xml | 10 - .../keycloak-adapter-core/main/module.xml | 42 -- pom.xml | 5 - .../test-apps/app-profile-jee/pom.xml | 6 +- .../test-apps/cors/database-service/pom.xml | 6 +- .../test-apps/servlets-jakarta/pom.xml | 5 +- .../test-apps/servlets/pom.xml | 5 +- .../servlet/DemoServletsAdapterTest.java | 5 +- .../authz/admin/PolicyEnforcerTest.java | 2 +- testsuite/integration-arquillian/util/pom.xml | 8 + .../adapters/AdapterDeploymentContext.java | 0 .../org/keycloak/adapters/AdapterUtils.java | 0 .../adapters/AuthenticatedActionsHandler.java | 4 +- .../org/keycloak/adapters/CorsHeaders.java | 0 .../keycloak/adapters/HttpAdapterUtils.java | 0 .../adapters/HttpClientAdapterException.java | 0 .../keycloak/adapters/HttpClientBuilder.java | 0 .../adapters/KeycloakConfigResolver.java | 0 .../keycloak/adapters/KeycloakDeployment.java | 2 +- .../adapters/KeycloakDeploymentBuilder.java | 0 .../org/keycloak/adapters/OIDCHttpFacade.java | 0 .../RefreshableKeycloakSecurityContext.java | 10 +- .../org/keycloak/adapters/ServerRequest.java | 0 .../adapters/SniSSLSocketFactory.java | 0 .../adapters/pep/HttpAuthzRequest.java | 2 +- .../adapters/pep/HttpAuthzResponse.java | 0 .../rotation/AdapterTokenVerifier.java | 2 +- .../rotation/HardcodedPublicKeyLocator.java | 0 .../rotation/JWKPublicKeyLocator.java | 0 .../adapters/rotation/PublicKeyLocator.java | 0 56 files changed, 30 insertions(+), 2424 deletions(-) delete mode 100755 adapters/oidc/adapter-core/pom.xml delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BasicAuthRequestAuthenticator.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCAuthenticationError.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OidcKeycloakAccount.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java delete mode 100644 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParameterTokenRequestAuthenticator.java delete mode 100755 adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java delete mode 100644 adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java delete mode 100644 adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentTest.java delete mode 100644 adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/RefreshableKeycloakSecurityContextTest.java delete mode 100644 adapters/oidc/adapter-core/src/test/resources/cacerts.jks delete mode 100644 adapters/oidc/adapter-core/src/test/resources/keycloak-http-client.json delete mode 100644 adapters/oidc/adapter-core/src/test/resources/keycloak-jwt.json delete mode 100644 adapters/oidc/adapter-core/src/test/resources/keycloak-no-credentials.json delete mode 100644 adapters/oidc/adapter-core/src/test/resources/keycloak-secret-jwt.json delete mode 100644 adapters/oidc/adapter-core/src/test/resources/keycloak.json delete mode 100644 adapters/oidc/adapter-core/src/test/resources/keystore.jks delete mode 100755 distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-adapter-core/main/module.xml rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java (100%) mode change 100755 => 100644 rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/AdapterUtils.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/CorsHeaders.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/HttpClientAdapterException.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/HttpClientBuilder.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/KeycloakConfigResolver.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/KeycloakDeployment.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/OIDCHttpFacade.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java (94%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/ServerRequest.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/pep/HttpAuthzRequest.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/pep/HttpAuthzResponse.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/rotation/HardcodedPublicKeyLocator.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java (100%) rename {adapters/oidc/adapter-core => testsuite/integration-arquillian/util}/src/main/java/org/keycloak/adapters/rotation/PublicKeyLocator.java (100%) diff --git a/adapters/oidc/adapter-core/pom.xml b/adapters/oidc/adapter-core/pom.xml deleted file mode 100755 index 3509f9fef5..0000000000 --- a/adapters/oidc/adapter-core/pom.xml +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - keycloak-parent - org.keycloak - 999.0.0-SNAPSHOT - ../../../pom.xml - - 4.0.0 - - keycloak-adapter-core - Keycloak Adapter Core - - - - - org.keycloak.adapters.* - - - org.keycloak.*;version="${project.version}", - org.apache.http.auth.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.client.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.conn.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.cookie.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.impl.auth.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.impl.client.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.impl.conn.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.impl.cookie.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.impl.execchain.*;version=${apache.httpcomponents.fuse.version}, - org.apache.http.*;version=${apache.httpcomponents.httpcore.fuse.version}, - *;resolution:=optional - - - - - - org.bouncycastle - bcprov-jdk18on - provided - - - org.jboss.logging - jboss-logging - provided - - - org.jboss.logging - commons-logging-jboss-logging - provided - - - org.keycloak - keycloak-adapter-spi - provided - - - org.keycloak - keycloak-core - provided - - - org.keycloak - ${keycloak.crypto.artifactId} - - - org.keycloak - keycloak-authz-client - provided - - - org.keycloak - keycloak-policy-enforcer - provided - - - com.fasterxml.jackson.core - jackson-core - provided - - - com.fasterxml.jackson.core - jackson-databind - provided - - - com.fasterxml.jackson.core - jackson-annotations - provided - - - junit - junit - test - - - org.apache.httpcomponents - httpclient - provided - - - - - - - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - - - - org.apache.felix - maven-bundle-plugin - true - - - bundle-manifest - process-classes - - manifest - - - - - - . - ${project.name} - ${project.groupId}.${project.artifactId} - ${keycloak.osgi.import} - ${keycloak.osgi.export} - - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)", osgi.serviceloader; filter:="(osgi.serviceloader=org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory)";cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)" - - - osgi.serviceloader; osgi.serviceloader=org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory - - - - - - - - diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java deleted file mode 100755 index daf9754685..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java +++ /dev/null @@ -1,61 +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.keycloak.adapters.spi.AdapterSessionStore; - -/** - * Abstraction for storing token info on adapter side. Intended to be per-request object - * - * @author Marek Posolda - */ -public interface AdapterTokenStore extends AdapterSessionStore { - - /** - * Impl can validate if current token exists and perform refreshing if it exists and is expired - */ - void checkCurrentToken(); - - /** - * Check if we are logged already (we have already valid and successfully refreshed accessToken). Establish security context if yes - * - * @param authenticator used for actual request authentication - * @return true if we are logged-in already - */ - boolean isCached(RequestAuthenticator authenticator); - - /** - * Finish successful OAuth2 login and store validated account - * - * @param account - */ - void saveAccountInfo(OidcKeycloakAccount account); - - /** - * Handle logout on store side and possibly propagate logout call to Keycloak - */ - void logout(); - - /** - * Callback invoked after successful token refresh - * - * @param securityContext context where refresh was performed - */ - void refreshCallback(RefreshableKeycloakSecurityContext securityContext); - -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BasicAuthRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BasicAuthRequestAuthenticator.java deleted file mode 100755 index ebdece45a7..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BasicAuthRequestAuthenticator.java +++ /dev/null @@ -1,124 +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.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.jboss.logging.Logger; -import org.keycloak.OAuth2Constants; -import org.keycloak.adapters.spi.AuthOutcome; -import org.keycloak.adapters.spi.HttpFacade; -import org.keycloak.common.util.Base64; -import org.keycloak.representations.AccessTokenResponse; -import org.keycloak.util.JsonSerialization; - -import java.util.List; - -/** - * Basic auth request authenticator. - */ -public class BasicAuthRequestAuthenticator extends BearerTokenRequestAuthenticator { - protected Logger log = Logger.getLogger(BasicAuthRequestAuthenticator.class); - - public BasicAuthRequestAuthenticator(KeycloakDeployment deployment) { - super(deployment); - } - - public AuthOutcome authenticate(HttpFacade exchange) { - List authHeaders = exchange.getRequest().getHeaders("Authorization"); - if (authHeaders == null || authHeaders.isEmpty()) { - log.debug("Authorization header not present"); - challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.NO_AUTHORIZATION_HEADER, null, null); - return AuthOutcome.NOT_ATTEMPTED; - } - - tokenString = null; - for (String authHeader : authHeaders) { - String[] split = authHeader.trim().split("\\s+"); - if (split.length != 2) continue; - if (!split[0].equalsIgnoreCase("Basic")) continue; - tokenString = split[1]; - } - - if (tokenString == null) { - log.debug("Token is not present in Authorization header"); - challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, null, null); - return AuthOutcome.NOT_ATTEMPTED; - } - - AccessTokenResponse atr=null; - try { - String userpw=new String(Base64.decode(tokenString)); - int seperatorIndex = userpw.indexOf(":"); - String user = userpw.substring(0, seperatorIndex); - String pw = userpw.substring(seperatorIndex + 1); - atr = getToken(user, pw); - tokenString = atr.getToken(); - } catch (Exception e) { - log.debug("Failed to obtain token", e); - challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, "no_token", e.getMessage()); - return AuthOutcome.FAILED; - } - - return authenticateToken(exchange, atr.getToken()); - } - - protected AccessTokenResponse getToken(String username, String password) throws Exception { - AccessTokenResponse tokenResponse=null; - HttpClient client = deployment.getClient(); - - HttpPost post = new HttpPost(deployment.getTokenUrl()); - java.util.List formparams = new java.util.ArrayList (); - formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)); - formparams.add(new BasicNameValuePair("username", username)); - formparams.add(new BasicNameValuePair("password", password)); - - AdapterUtils.setClientCredentials(deployment, post, formparams); - - UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8"); - post.setEntity(form); - - HttpResponse response = client.execute(post); - int status = response.getStatusLine().getStatusCode(); - HttpEntity entity = response.getEntity(); - if (status != 200) { - EntityUtils.consumeQuietly(entity); - throw new java.io.IOException("Bad status: " + status); - } - if (entity == null) { - throw new java.io.IOException("No Entity"); - } - java.io.InputStream is = entity.getContent(); - try { - tokenResponse = JsonSerialization.readValue(is, AccessTokenResponse.class); - } finally { - try { - is.close(); - } catch (java.io.IOException ignored) { } - } - - return (tokenResponse); - } - -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java deleted file mode 100755 index 406ee0acc8..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java +++ /dev/null @@ -1,203 +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.jboss.logging.Logger; -import org.keycloak.adapters.pep.HttpAuthzRequest; -import org.keycloak.adapters.pep.HttpAuthzResponse; -import org.keycloak.adapters.rotation.AdapterTokenVerifier; -import org.keycloak.adapters.spi.AuthChallenge; -import org.keycloak.adapters.spi.AuthOutcome; -import org.keycloak.adapters.spi.HttpFacade; -import org.keycloak.common.VerificationException; -import org.keycloak.jose.jws.JWSInput; -import org.keycloak.jose.jws.JWSInputException; -import org.keycloak.representations.AccessToken; - -import java.util.List; -import javax.security.cert.X509Certificate; -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class BearerTokenRequestAuthenticator { - protected Logger log = Logger.getLogger(BearerTokenRequestAuthenticator.class); - protected String tokenString; - protected AccessToken token; - protected String surrogate; - protected AuthChallenge challenge; - protected KeycloakDeployment deployment; - - public BearerTokenRequestAuthenticator(KeycloakDeployment deployment) { - this.deployment = deployment; - } - - public AuthChallenge getChallenge() { - return challenge; - } - - public String getTokenString() { - return tokenString; - } - - public AccessToken getToken() { - return token; - } - - public String getSurrogate() { - return surrogate; - } - - public AuthOutcome authenticate(HttpFacade exchange) { - List authHeaders = exchange.getRequest().getHeaders("Authorization"); - if (authHeaders == null || authHeaders.isEmpty()) { - log.debug("Authorization header not present"); - challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.NO_BEARER_TOKEN, null, null); - return AuthOutcome.NOT_ATTEMPTED; - } - - tokenString = null; - for (String authHeader : authHeaders) { - String[] split = authHeader.trim().split("\\s+"); - if (split.length != 2) continue; - if (split[0].equalsIgnoreCase("Bearer")) { - tokenString = split[1]; - - log.debugf("Found [%d] values in authorization header, selecting the first value for Bearer.", (Integer) authHeaders.size()); - break; - } - } - - if (tokenString == null) { - log.debug("Token is not present in Authorization header"); - challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.NO_BEARER_TOKEN, null, null); - return AuthOutcome.NOT_ATTEMPTED; - } - - return (authenticateToken(exchange, tokenString)); - } - - protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) { - log.debug("Verifying access_token"); - if (log.isTraceEnabled()) { - try { - JWSInput jwsInput = new JWSInput(tokenString); - String wireString = jwsInput.getWireString(); - log.tracef("\taccess_token: %s", wireString.substring(0, wireString.lastIndexOf(".")) + ".signature"); - } catch (JWSInputException e) { - log.errorf(e, "Failed to parse access_token: %s", tokenString); - } - } - try { - token = AdapterTokenVerifier.verifyToken(tokenString, deployment); - } catch (VerificationException e) { - log.debugf("Failed to verify token: %s", e.getMessage()); - challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, "invalid_token", e.getMessage()); - return AuthOutcome.FAILED; - } - if (token.getIat() < deployment.getNotBefore()) { - log.debug("Stale token"); - challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.STALE_TOKEN, "invalid_token", "Stale token"); - return AuthOutcome.FAILED; - } - boolean verifyCaller = false; - if (deployment.isUseResourceRoleMappings()) { - verifyCaller = token.isVerifyCaller(deployment.getResourceName()); - } else { - verifyCaller = token.isVerifyCaller(); - } - surrogate = null; - if (verifyCaller) { - if (token.getTrustedCertificates() == null || token.getTrustedCertificates().isEmpty()) { - log.warn("No trusted certificates in token"); - challenge = clientCertChallenge(); - return AuthOutcome.FAILED; - } - - // for now, we just make sure Undertow did two-way SSL - // assume JBoss Web verifies the client cert - X509Certificate[] chain = new X509Certificate[0]; - try { - chain = exchange.getCertificateChain(); - } catch (Exception ignore) { - - } - if (chain == null || chain.length == 0) { - log.warn("No certificates provided by undertow to verify the caller"); - challenge = clientCertChallenge(); - return AuthOutcome.FAILED; - } - surrogate = chain[0].getSubjectDN().getName(); - } - log.debug("successful authorized"); - return AuthOutcome.AUTHENTICATED; - } - - protected AuthChallenge clientCertChallenge() { - return new AuthChallenge() { - @Override - public int getResponseCode() { - return 0; - } - - @Override - public boolean challenge(HttpFacade exchange) { - // do the same thing as client cert auth - return false; - } - }; - } - - - protected AuthChallenge challengeResponse(HttpFacade facade, final OIDCAuthenticationError.Reason reason, final String error, final String description) { - StringBuilder header = new StringBuilder("Bearer realm=\""); - header.append(deployment.getRealm()).append("\""); - if (error != null) { - header.append(", error=\"").append(error).append("\""); - } - if (description != null) { - header.append(", error_description=\"").append(description).append("\""); - } - final String challenge = header.toString(); - return new AuthChallenge() { - @Override - public int getResponseCode() { - return 401; - } - - @Override - public boolean challenge(HttpFacade facade) { - OIDCHttpFacade oidcFacade = (OIDCHttpFacade) facade; - if (deployment.getPolicyEnforcer() != null) { - deployment.getPolicyEnforcer().enforce(new HttpAuthzRequest(oidcFacade), new HttpAuthzResponse(oidcFacade)); - return true; - } - OIDCAuthenticationError error = new OIDCAuthenticationError(reason, description); - facade.getRequest().setError(error); - facade.getResponse().addHeader("WWW-Authenticate", challenge); - if(deployment.isDelegateBearerErrorResponseSending()){ - facade.getResponse().setStatus(401); - } - else { - facade.getResponse().sendError(401); - } - return true; - } - }; - } -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java deleted file mode 100755 index de837c4a8a..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java +++ /dev/null @@ -1,128 +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.jboss.logging.Logger; -import org.keycloak.KeycloakPrincipal; -import org.keycloak.TokenVerifier; -import org.keycloak.adapters.rotation.AdapterTokenVerifier; -import org.keycloak.adapters.spi.HttpFacade; -import org.keycloak.common.VerificationException; -import org.keycloak.common.util.KeycloakUriBuilder; -import org.keycloak.constants.AdapterConstants; -import org.keycloak.jose.jws.JWSInput; -import org.keycloak.jose.jws.JWSInputException; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.IDToken; - -/** - * @author Marek Posolda - */ -public class CookieTokenStore { - - private static final Logger log = Logger.getLogger(CookieTokenStore.class); - private static final String DELIM = "___"; - - public static void setTokenCookie(KeycloakDeployment deployment, HttpFacade facade, RefreshableKeycloakSecurityContext session) { - log.debugf("Set new %s cookie now", AdapterConstants.KEYCLOAK_ADAPTER_STATE_COOKIE); - String accessToken = session.getTokenString(); - String idToken = session.getIdTokenString(); - String refreshToken = session.getRefreshToken(); - String cookie = new StringBuilder(accessToken).append(DELIM) - .append(idToken).append(DELIM) - .append(refreshToken).toString(); - - String cookiePath = getCookiePath(deployment, facade); - facade.getResponse().setCookie(AdapterConstants.KEYCLOAK_ADAPTER_STATE_COOKIE, cookie, cookiePath, null, -1, deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr()), true); - } - - public static KeycloakPrincipal getPrincipalFromCookie(KeycloakDeployment deployment, HttpFacade facade, AdapterTokenStore tokenStore) { - OIDCHttpFacade.Cookie cookie = facade.getRequest().getCookie(AdapterConstants.KEYCLOAK_ADAPTER_STATE_COOKIE); - if (cookie == null) { - log.debug("Not found adapter state cookie in current request"); - return null; - } - - String cookieVal = cookie.getValue(); - - String[] tokens = cookieVal.split(DELIM); - if (tokens.length != 3) { - log.warnf("Invalid format of %s cookie. Count of tokens: %s, expected 3", AdapterConstants.KEYCLOAK_ADAPTER_STATE_COOKIE, tokens.length); - return null; - } - - String accessTokenString = tokens[0]; - String idTokenString = tokens[1]; - String refreshTokenString = tokens[2]; - - try { - // Skip check if token is active now. It's supposed to be done later by the caller - TokenVerifier tokenVerifier = AdapterTokenVerifier.createVerifier(accessTokenString, deployment, true, AccessToken.class) - .checkActive(false) - .verify(); - AccessToken accessToken = tokenVerifier.getToken(); - - IDToken idToken; - if (idTokenString != null && idTokenString.length() > 0) { - try { - JWSInput input = new JWSInput(idTokenString); - idToken = input.readJsonContent(IDToken.class); - } catch (JWSInputException e) { - throw new VerificationException(e); - } - } else { - idToken = null; - } - - log.debug("Token Verification succeeded!"); - RefreshableKeycloakSecurityContext secContext = new RefreshableKeycloakSecurityContext(deployment, tokenStore, accessTokenString, accessToken, idTokenString, idToken, refreshTokenString); - return new KeycloakPrincipal<>(AdapterUtils.getPrincipalName(deployment, accessToken), secContext); - } catch (VerificationException ve) { - log.warn("Failed verify token", ve); - return null; - } - } - - public static void removeCookie(KeycloakDeployment deployment, HttpFacade facade) { - String cookiePath = getCookiePath(deployment, facade); - facade.getResponse().resetCookie(AdapterConstants.KEYCLOAK_ADAPTER_STATE_COOKIE, cookiePath); - } - - static String getCookiePath(KeycloakDeployment deployment, HttpFacade facade) { - String path = deployment.getAdapterStateCookiePath() == null ? "" : deployment.getAdapterStateCookiePath().trim(); - if (path.startsWith("/")) { - return path; - } - String contextPath = getContextPath(facade); - StringBuilder cookiePath = new StringBuilder(contextPath); - if (!contextPath.endsWith("/") && !path.isEmpty()) { - cookiePath.append("/"); - } - return cookiePath.append(path).toString(); - } - - static String getContextPath(HttpFacade facade) { - String uri = facade.getRequest().getURI(); - String path = KeycloakUriBuilder.fromUri(uri).getPath(); - if (path == null || path.isEmpty()) { - return "/"; - } - int index = path.indexOf("/", 1); - return index == -1 ? path : path.substring(0, index); - } -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java deleted file mode 100755 index f32fa0dce1..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java +++ /dev/null @@ -1,147 +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.jboss.logging.Logger; -import org.keycloak.common.util.HostUtils; -import org.keycloak.common.util.Time; - -import java.io.IOException; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * @author Marek Posolda - */ -public class NodesRegistrationManagement { - - private static final Logger log = Logger.getLogger(NodesRegistrationManagement.class); - - private final Map nodeRegistrations = new ConcurrentHashMap(); - private final ExecutorService executor = Executors.newSingleThreadExecutor(); - - // Sending registration event during first request to application or if re-registration is needed - public void tryRegister(final KeycloakDeployment resolvedDeployment) { - if (resolvedDeployment.isRegisterNodeAtStartup()) { - final String registrationUri = resolvedDeployment.getRegisterNodeUrl(); - if (needRefreshRegistration(registrationUri, resolvedDeployment)) { - Runnable runnable = new Runnable() { - - @Override - public void run() { - // Need to check it again in case that executor triggered by other thread already finished computation in the meantime - if (needRefreshRegistration(registrationUri, resolvedDeployment)) { - sendRegistrationEvent(resolvedDeployment); - } - } - }; - executor.execute(runnable); - } - } - } - - private boolean needRefreshRegistration(String registrationUri, KeycloakDeployment resolvedDeployment) { - NodeRegistrationContext currentRegistration = nodeRegistrations.get(registrationUri); - /// We don't yet have any registration for this node - if (currentRegistration == null) { - return true; - } - - return currentRegistration.lastRegistrationTime + resolvedDeployment.getRegisterNodePeriod() < Time.currentTime(); - } - - /** - * Called during undeployment or server stop. De-register from all previously registered deployments - */ - public void stop() { - executor.shutdownNow(); - - Collection allRegistrations = nodeRegistrations.values(); - for (NodeRegistrationContext registration : allRegistrations) { - sendUnregistrationEvent(registration.resolvedDeployment); - } - } - - protected void sendRegistrationEvent(KeycloakDeployment deployment) { - // This method is invoked from single-thread executor, so no synchronization is needed - // However, it could happen that the same deployment was submitted more than once to that executor - // Hence we need to recheck that the registration is really needed - final String registrationUri = deployment.getRegisterNodeUrl(); - if (! needRefreshRegistration(registrationUri, deployment)) { - return; - } - if (Thread.currentThread().isInterrupted()) { - return; - } - - log.debug("Sending registration event right now"); - - String host = HostUtils.getHostName(); - try { - ServerRequest.invokeRegisterNode(deployment, host); - NodeRegistrationContext regContext = new NodeRegistrationContext(Time.currentTime(), deployment); - nodeRegistrations.put(deployment.getRegisterNodeUrl(), regContext); - log.debugf("Node '%s' successfully registered in Keycloak", host); - } catch (ServerRequest.HttpFailure failure) { - log.error("failed to register node to keycloak"); - log.error("status from server: " + failure.getStatus()); - if (failure.getError() != null) { - log.error(" " + failure.getError()); - } - } catch (IOException e) { - log.error("failed to register node to keycloak", e); - } - } - - protected boolean sendUnregistrationEvent(KeycloakDeployment deployment) { - log.debug("Sending Unregistration event right now"); - - String host = HostUtils.getHostName(); - try { - ServerRequest.invokeUnregisterNode(deployment, host); - log.debugf("Node '%s' successfully unregistered from Keycloak", host); - return true; - } catch (ServerRequest.HttpFailure failure) { - log.error("failed to unregister node from keycloak"); - log.error("status from server: " + failure.getStatus()); - if (failure.getError() != null) { - log.error(" " + failure.getError()); - } - return false; - } catch (IOException e) { - log.error("failed to unregister node from keycloak", e); - return false; - } - } - - public static class NodeRegistrationContext { - - private final Integer lastRegistrationTime; - // deployment instance used for registration request - private final KeycloakDeployment resolvedDeployment; - - public NodeRegistrationContext(Integer lastRegTime, KeycloakDeployment deployment) { - this.lastRegistrationTime = lastRegTime; - this.resolvedDeployment = deployment; - } - } - -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java deleted file mode 100755 index d0735ebc32..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java +++ /dev/null @@ -1,419 +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.jboss.logging.Logger; -import org.keycloak.OAuth2Constants; -import org.keycloak.adapters.rotation.AdapterTokenVerifier; -import org.keycloak.adapters.spi.AdapterSessionStore; -import org.keycloak.adapters.spi.AuthChallenge; -import org.keycloak.adapters.spi.AuthOutcome; -import org.keycloak.adapters.spi.HttpFacade; -import org.keycloak.common.VerificationException; -import org.keycloak.common.util.KeycloakUriBuilder; -import org.keycloak.common.util.UriUtils; -import org.keycloak.constants.AdapterConstants; -import org.keycloak.enums.TokenStore; -import org.keycloak.jose.jws.JWSInput; -import org.keycloak.jose.jws.JWSInputException; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.AccessTokenResponse; -import org.keycloak.representations.IDToken; -import org.keycloak.util.TokenUtil; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Map; - - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class OAuthRequestAuthenticator { - private static final Logger log = Logger.getLogger(OAuthRequestAuthenticator.class); - protected KeycloakDeployment deployment; - protected RequestAuthenticator reqAuthenticator; - protected int sslRedirectPort; - protected AdapterSessionStore tokenStore; - protected String tokenString; - protected String idTokenString; - protected IDToken idToken; - protected AccessToken token; - protected HttpFacade facade; - protected AuthChallenge challenge; - protected String refreshToken; - protected String strippedOauthParametersRequestUri; - - public OAuthRequestAuthenticator(RequestAuthenticator requestAuthenticator, HttpFacade facade, KeycloakDeployment deployment, int sslRedirectPort, AdapterSessionStore tokenStore) { - this.reqAuthenticator = requestAuthenticator; - this.facade = facade; - this.deployment = deployment; - this.sslRedirectPort = deployment.getConfidentialPort() != -1 ? deployment.getConfidentialPort() : sslRedirectPort; - this.tokenStore = tokenStore; - } - - public AuthChallenge getChallenge() { - return challenge; - } - - public String getTokenString() { - return tokenString; - } - - public AccessToken getToken() { - return token; - } - - public String getRefreshToken() { - return refreshToken; - } - - public String getIdTokenString() { - return idTokenString; - } - - public void setIdTokenString(String idTokenString) { - this.idTokenString = idTokenString; - } - - public IDToken getIdToken() { - return idToken; - } - - public void setIdToken(IDToken idToken) { - this.idToken = idToken; - } - - public String getStrippedOauthParametersRequestUri() { - return strippedOauthParametersRequestUri; - } - - public void setStrippedOauthParametersRequestUri(String strippedOauthParametersRequestUri) { - this.strippedOauthParametersRequestUri = strippedOauthParametersRequestUri; - } - - protected String getRequestUrl() { - return facade.getRequest().getURI(); - } - - protected boolean isRequestSecure() { - return facade.getRequest().isSecure(); - } - - protected OIDCHttpFacade.Cookie getCookie(String cookieName) { - return facade.getRequest().getCookie(cookieName); - } - - protected String getCookieValue(String cookieName) { - OIDCHttpFacade.Cookie cookie = getCookie(cookieName); - if (cookie == null) return null; - return cookie.getValue(); - } - - protected String getQueryParamValue(String paramName) { - return facade.getRequest().getQueryParamValue(paramName); - } - - protected String getError() { - return getQueryParamValue(OAuth2Constants.ERROR); - } - - protected String getCode() { - return getQueryParamValue(OAuth2Constants.CODE); - } - - protected String getRedirectUri(String state) { - String url = getRequestUrl(); - log.debugf("callback uri: %s", url); - - if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) { - int port = sslRedirectPort(); - if (port < 0) { - // disabled? - return null; - } - KeycloakUriBuilder secureUrl = KeycloakUriBuilder.fromUri(url).scheme("https").port(-1); - if (port != 443) secureUrl.port(port); - url = secureUrl.buildAsString(); - } - - String loginHint = getQueryParamValue("login_hint"); - url = UriUtils.stripQueryParam(url,"login_hint"); - - String idpHint = getQueryParamValue(AdapterConstants.KC_IDP_HINT); - url = UriUtils.stripQueryParam(url, AdapterConstants.KC_IDP_HINT); - - String scope = getQueryParamValue(OAuth2Constants.SCOPE); - url = UriUtils.stripQueryParam(url, OAuth2Constants.SCOPE); - - String prompt = getQueryParamValue(OAuth2Constants.PROMPT); - url = UriUtils.stripQueryParam(url, OAuth2Constants.PROMPT); - - String maxAge = getQueryParamValue(OAuth2Constants.MAX_AGE); - url = UriUtils.stripQueryParam(url, OAuth2Constants.MAX_AGE); - - String uiLocales = getQueryParamValue(OAuth2Constants.UI_LOCALES_PARAM); - url = UriUtils.stripQueryParam(url, OAuth2Constants.UI_LOCALES_PARAM); - - KeycloakUriBuilder redirectUriBuilder = deployment.getAuthUrl().clone() - .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE) - .queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName()) - .queryParam(OAuth2Constants.REDIRECT_URI, rewrittenRedirectUri(url)) - .queryParam(OAuth2Constants.STATE, state) - .queryParam("login", "true"); - if(loginHint != null && loginHint.length() > 0){ - redirectUriBuilder.queryParam("login_hint",loginHint); - } - if (idpHint != null && idpHint.length() > 0) { - redirectUriBuilder.queryParam(AdapterConstants.KC_IDP_HINT,idpHint); - } - if (prompt != null && prompt.length() > 0) { - redirectUriBuilder.queryParam(OAuth2Constants.PROMPT, prompt); - } - if (maxAge != null && maxAge.length() > 0) { - redirectUriBuilder.queryParam(OAuth2Constants.MAX_AGE, maxAge); - } - if (uiLocales != null && uiLocales.length() > 0) { - redirectUriBuilder.queryParam(OAuth2Constants.UI_LOCALES_PARAM, uiLocales); - } - - scope = TokenUtil.attachOIDCScope(scope); - redirectUriBuilder.queryParam(OAuth2Constants.SCOPE, scope); - - return redirectUriBuilder.buildAsString(); - } - - protected int sslRedirectPort() { - return sslRedirectPort; - } - - protected String getStateCode() { - return AdapterUtils.generateId(); - } - - protected AuthChallenge loginRedirect() { - final String state = getStateCode(); - final String redirect = getRedirectUri(state); - if (redirect == null) { - return challenge(403, OIDCAuthenticationError.Reason.NO_REDIRECT_URI, null); - } - return new AuthChallenge() { - - @Override - public int getResponseCode() { - return 0; - } - - @Override - public boolean challenge(HttpFacade exchange) { - tokenStore.saveRequest(); - log.debug("Sending redirect to login page: " + redirect); - exchange.getResponse().setStatus(302); - exchange.getResponse().setCookie(deployment.getStateCookieName(), state, "/", null, -1, deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr()), true); - exchange.getResponse().setHeader("Location", redirect); - return true; - } - }; - } - - protected AuthChallenge checkStateCookie() { - OIDCHttpFacade.Cookie stateCookie = getCookie(deployment.getStateCookieName()); - - if (stateCookie == null) { - log.warn("No state cookie"); - return challenge(400, OIDCAuthenticationError.Reason.INVALID_STATE_COOKIE, null); - } - // reset the cookie - log.debug("** reseting application state cookie"); - facade.getResponse().resetCookie(deployment.getStateCookieName(), stateCookie.getPath()); - String stateCookieValue = getCookieValue(deployment.getStateCookieName()); - - String state = getQueryParamValue(OAuth2Constants.STATE); - if (state == null) { - log.warn("state parameter was null"); - return challenge(400, OIDCAuthenticationError.Reason.INVALID_STATE_COOKIE, null); - } - if (!state.equals(stateCookieValue)) { - log.warn("state parameter invalid"); - log.warn("cookie: " + stateCookieValue); - log.warn("queryParam: " + state); - return challenge(400, OIDCAuthenticationError.Reason.INVALID_STATE_COOKIE, null); - } - return null; - - } - - public AuthOutcome authenticate() { - String code = getCode(); - if (code == null) { - log.debug("there was no code"); - String error = getError(); - if (error != null) { - // todo how do we send a response? - log.warn("There was an error: " + error); - challenge = challenge(400, OIDCAuthenticationError.Reason.OAUTH_ERROR, error); - return AuthOutcome.FAILED; - } else { - log.debug("redirecting to auth server"); - challenge = loginRedirect(); - return AuthOutcome.NOT_ATTEMPTED; - } - } else { - log.debug("there was a code, resolving"); - challenge = resolveCode(code); - if (challenge != null) { - return AuthOutcome.FAILED; - } - return AuthOutcome.AUTHENTICATED; - } - - } - - protected AuthChallenge challenge(final int code, final OIDCAuthenticationError.Reason reason, final String description) { - return new AuthChallenge() { - @Override - public int getResponseCode() { - return code; - } - - @Override - public boolean challenge(HttpFacade exchange) { - OIDCAuthenticationError error = new OIDCAuthenticationError(reason, description); - exchange.getRequest().setError(error); - exchange.getResponse().sendError(code); - return true; - } - }; - } - - /** - * Start or continue the oauth login process. - *

- * if code query parameter is not present, then browser is redirected to authUrl. The redirect URL will be - * the URL of the current request. - *

- * If code query parameter is present, then an access token is obtained by invoking a secure request to the codeUrl. - * If the access token is obtained, the browser is again redirected to the current request URL, but any OAuth - * protocol specific query parameters are removed. - * - * @return null if an access token was obtained, otherwise a challenge is returned - */ - protected AuthChallenge resolveCode(String code) { - // abort if not HTTPS - if (!isRequestSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) { - log.error("Adapter requires SSL. Request: " + facade.getRequest().getURI()); - return challenge(403, OIDCAuthenticationError.Reason.SSL_REQUIRED, null); - } - - log.debug("checking state cookie for after code"); - AuthChallenge challenge = checkStateCookie(); - if (challenge != null) return challenge; - - AccessTokenResponse tokenResponse = null; - strippedOauthParametersRequestUri = rewrittenRedirectUri(stripOauthParametersFromRedirect()); - - try { - // For COOKIE store we don't have httpSessionId and single sign-out won't be available - String httpSessionId = deployment.getTokenStore() == TokenStore.SESSION ? reqAuthenticator.changeHttpSessionId(true) : null; - tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, strippedOauthParametersRequestUri, httpSessionId); - } catch (ServerRequest.HttpFailure failure) { - log.error("failed to turn code into token"); - log.error("status from server: " + failure.getStatus()); - if (failure.getError() != null && !failure.getError().trim().isEmpty()) { - log.error(" " + failure.getError()); - } - return challenge(403, OIDCAuthenticationError.Reason.CODE_TO_TOKEN_FAILURE, null); - - } catch (IOException e) { - log.error("failed to turn code into token", e); - return challenge(403, OIDCAuthenticationError.Reason.CODE_TO_TOKEN_FAILURE, null); - } - - tokenString = tokenResponse.getToken(); - refreshToken = tokenResponse.getRefreshToken(); - idTokenString = tokenResponse.getIdToken(); - - log.debug("Verifying tokens"); - if (log.isTraceEnabled()) { - logToken("\taccess_token", tokenString); - logToken("\tid_token", idTokenString); - logToken("\trefresh_token", refreshToken); - } - - try { - AdapterTokenVerifier.VerifiedTokens tokens = AdapterTokenVerifier.verifyTokens(tokenString, idTokenString, deployment); - token = tokens.getAccessToken(); - idToken = tokens.getIdToken(); - log.debug("Token Verification succeeded!"); - } catch (VerificationException e) { - log.error("failed verification of token: " + e.getMessage()); - return challenge(403, OIDCAuthenticationError.Reason.INVALID_TOKEN, null); - } - if (tokenResponse.getNotBeforePolicy() > deployment.getNotBefore()) { - deployment.updateNotBefore(tokenResponse.getNotBeforePolicy()); - } - if (token.getIat() < deployment.getNotBefore()) { - log.error("Stale token"); - return challenge(403, OIDCAuthenticationError.Reason.STALE_TOKEN, null); - } - log.debug("successful authenticated"); - return null; - } - - /** - * strip out unwanted query parameters and redirect so bookmarks don't retain oauth protocol bits - */ - protected String stripOauthParametersFromRedirect() { - KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(facade.getRequest().getURI()) - .replaceQueryParam(OAuth2Constants.CODE, null) - .replaceQueryParam(OAuth2Constants.STATE, null) - .replaceQueryParam(OAuth2Constants.SESSION_STATE, null) - .replaceQueryParam(OAuth2Constants.ISSUER, null); - return builder.buildAsString(); - } - - private String rewrittenRedirectUri(String originalUri) { - Map rewriteRules = deployment.getRedirectRewriteRules(); - if(rewriteRules != null && !rewriteRules.isEmpty()) { - try { - URL url = new URL(originalUri); - Map.Entry rule = rewriteRules.entrySet().iterator().next(); - StringBuilder redirectUriBuilder = new StringBuilder(url.getProtocol()); - redirectUriBuilder.append("://"+ url.getAuthority()); - redirectUriBuilder.append(url.getPath().replaceFirst(rule.getKey(), rule.getValue())); - return redirectUriBuilder.toString(); - } catch (MalformedURLException ex) { - log.error("Not a valid request url"); - throw new RuntimeException(ex); - } - } - return originalUri; - } - - private void logToken(String name, String token) { - try { - JWSInput jwsInput = new JWSInput(token); - String wireString = jwsInput.getWireString(); - log.tracef("\t%s: %s", name, wireString.substring(0, wireString.lastIndexOf(".")) + ".signature"); - } catch (JWSInputException e) { - log.errorf(e, "Failed to parse %s: %s", name, token); - } - } -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCAuthenticationError.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCAuthenticationError.java deleted file mode 100755 index a58a05a87b..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCAuthenticationError.java +++ /dev/null @@ -1,64 +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.keycloak.adapters.spi.AuthenticationError; - -/** - * Object that describes the OIDC error that happened. - * - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class OIDCAuthenticationError implements AuthenticationError { - public static enum Reason { - NO_BEARER_TOKEN, - NO_REDIRECT_URI, - INVALID_STATE_COOKIE, - OAUTH_ERROR, - SSL_REQUIRED, - CODE_TO_TOKEN_FAILURE, - INVALID_TOKEN, - STALE_TOKEN, - NO_AUTHORIZATION_HEADER, - NO_QUERY_PARAMETER_ACCESS_TOKEN - } - - private Reason reason; - private String description; - - public OIDCAuthenticationError(Reason reason, String description) { - this.reason = reason; - this.description = description; - } - - public Reason getReason() { - return reason; - } - - public String getDescription() { - return description; - } - - @Override - public String toString() { - return "OIDCAuthenticationError [reason=" + reason + ", description=" + description + "]"; - } - - -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OidcKeycloakAccount.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OidcKeycloakAccount.java deleted file mode 100755 index 24dcae2af5..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OidcKeycloakAccount.java +++ /dev/null @@ -1,29 +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.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.spi.KeycloakAccount; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public interface OidcKeycloakAccount extends KeycloakAccount { - KeycloakSecurityContext getKeycloakSecurityContext(); -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java deleted file mode 100755 index a4dc295dd0..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java +++ /dev/null @@ -1,267 +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 java.security.PublicKey; - -import org.jboss.logging.Logger; -import org.keycloak.TokenVerifier; -import org.keycloak.adapters.rotation.AdapterTokenVerifier; -import org.keycloak.adapters.spi.HttpFacade; -import org.keycloak.adapters.spi.UserSessionManagement; -import org.keycloak.common.VerificationException; -import org.keycloak.common.util.StreamUtil; -import org.keycloak.jose.jwk.JSONWebKeySet; -import org.keycloak.jose.jwk.JWK; -import org.keycloak.jose.jwk.JWKBuilder; -import org.keycloak.protocol.oidc.client.authentication.ClientCredentialsProvider; -import org.keycloak.protocol.oidc.client.authentication.JWTClientCredentialsProvider; -import org.keycloak.representations.JsonWebToken; -import org.keycloak.constants.AdapterConstants; -import org.keycloak.jose.jws.JWSInput; -import org.keycloak.representations.adapters.action.AdminAction; -import org.keycloak.representations.adapters.action.LogoutAction; -import org.keycloak.representations.adapters.action.PushNotBeforeAction; -import org.keycloak.representations.adapters.action.TestAvailabilityAction; -import org.keycloak.util.JsonSerialization; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class PreAuthActionsHandler { - - private static final Logger log = Logger.getLogger(PreAuthActionsHandler.class); - - protected UserSessionManagement userSessionManagement; - protected AdapterDeploymentContext deploymentContext; - protected KeycloakDeployment deployment; - protected HttpFacade facade; - - public PreAuthActionsHandler(UserSessionManagement userSessionManagement, AdapterDeploymentContext deploymentContext, HttpFacade facade) { - this.userSessionManagement = userSessionManagement; - this.deploymentContext = deploymentContext; - this.facade = facade; - } - - protected boolean resolveDeployment() { - deployment = deploymentContext.resolveDeployment(facade); - if (!deployment.isConfigured()) { - log.warn("can't take request, adapter not configured"); - facade.getResponse().sendError(403, "adapter not configured"); - return false; - } - return true; - } - - public boolean handleRequest() { - String requestUri = facade.getRequest().getURI(); - log.debugv("adminRequest {0}", requestUri); - if (preflightCors()) { - return true; - } - if (requestUri.endsWith(AdapterConstants.K_LOGOUT)) { - if (!resolveDeployment()) return true; - handleLogout(); - return true; - } else if (requestUri.endsWith(AdapterConstants.K_PUSH_NOT_BEFORE)) { - if (!resolveDeployment()) return true; - handlePushNotBefore(); - return true; - } else if (requestUri.endsWith(AdapterConstants.K_TEST_AVAILABLE)) { - if (!resolveDeployment()) return true; - handleTestAvailable(); - return true; - } else if (requestUri.endsWith(AdapterConstants.K_JWKS)) { - if (!resolveDeployment()) return true; - handleJwksRequest(); - return true; - } - return false; - } - - public boolean preflightCors() { - // don't need to resolve deployment on cors requests. Just need to know local cors config. - KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade); - if (!deployment.isCors()) return false; - log.debugv("checkCorsPreflight {0}", facade.getRequest().getURI()); - if (!facade.getRequest().getMethod().equalsIgnoreCase("OPTIONS")) { - return false; - } - String origin = facade.getRequest().getHeader(CorsHeaders.ORIGIN); - if (origin == null) { - log.debug("checkCorsPreflight: no origin header"); - return false; - } - log.debug("Preflight request returning"); - facade.getResponse().setStatus(200); - facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin); - facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); - String requestMethods = facade.getRequest().getHeader(CorsHeaders.ACCESS_CONTROL_REQUEST_METHOD); - if (requestMethods != null) { - if (deployment.getCorsAllowedMethods() != null) { - requestMethods = deployment.getCorsAllowedMethods(); - } - facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethods); - } - String allowHeaders = facade.getRequest().getHeader(CorsHeaders.ACCESS_CONTROL_REQUEST_HEADERS); - if (allowHeaders != null) { - if (deployment.getCorsAllowedHeaders() != null) { - allowHeaders = deployment.getCorsAllowedHeaders(); - } - facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_HEADERS, allowHeaders); - } - if (deployment.getCorsMaxAge() > -1) { - facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_MAX_AGE, Integer.toString(deployment.getCorsMaxAge())); - } - return true; - } - - protected void handleLogout() { - if (log.isTraceEnabled()) { - log.trace("K_LOGOUT sent"); - } - try { - JWSInput token = verifyAdminRequest(); - if (token == null) { - return; - } - LogoutAction action = JsonSerialization.readValue(token.getContent(), LogoutAction.class); - if (!validateAction(action)) return; - if (action.getAdapterSessionIds() != null) { - userSessionManagement.logoutHttpSessions(action.getAdapterSessionIds()); - } else { - log.debugf("logout of all sessions for application '%s'", action.getResource()); - if (action.getNotBefore() > deployment.getNotBefore()) { - deployment.updateNotBefore(action.getNotBefore()); - } - userSessionManagement.logoutAll(); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - - - protected void handlePushNotBefore() { - if (log.isTraceEnabled()) { - log.trace("K_PUSH_NOT_BEFORE sent"); - } - try { - JWSInput token = verifyAdminRequest(); - if (token == null) { - return; - } - PushNotBeforeAction action = JsonSerialization.readValue(token.getContent(), PushNotBeforeAction.class); - if (!validateAction(action)) return; - deployment.updateNotBefore(action.getNotBefore()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected void handleTestAvailable() { - if (log.isTraceEnabled()) { - log.trace("K_TEST_AVAILABLE sent"); - } - try { - JWSInput token = verifyAdminRequest(); - if (token == null) { - return; - } - TestAvailabilityAction action = JsonSerialization.readValue(token.getContent(), TestAvailabilityAction.class); - validateAction(action); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected JWSInput verifyAdminRequest() throws Exception { - if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) { - log.warn("SSL is required for adapter admin action"); - facade.getResponse().sendError(403, "ssl required"); - return null; - } - String token = StreamUtil.readString(facade.getRequest().getInputStream()); - if (token == null) { - log.warn("admin request failed, no token"); - facade.getResponse().sendError(403, "no token"); - return null; - } - - try { - // Check just signature. Other things checked in validateAction - TokenVerifier tokenVerifier = AdapterTokenVerifier.createVerifier(token, deployment, false, JsonWebToken.class); - tokenVerifier.verify(); - return new JWSInput(token); - } catch (VerificationException ignore) { - log.warn("admin request failed, unable to verify token: " + ignore.getMessage()); - if (log.isDebugEnabled()) { - log.debug(ignore.getMessage(), ignore); - } - - facade.getResponse().sendError(403, "token failed verification"); - return null; - } - } - - - protected boolean validateAction(AdminAction action) { - if (!action.validate()) { - log.warn("admin request failed, not validated" + action.getAction()); - facade.getResponse().sendError(400, "Not validated"); - return false; - } - if (action.isExpired()) { - log.warn("admin request failed, expired token"); - facade.getResponse().sendError(400, "Expired token"); - return false; - } - if (!deployment.getResourceName().equals(action.getResource())) { - log.warn("Resource name does not match"); - facade.getResponse().sendError(400, "Resource name does not match"); - return false; - - } - return true; - } - - protected void handleJwksRequest() { - try { - JSONWebKeySet jwks = new JSONWebKeySet(); - ClientCredentialsProvider clientCredentialsProvider = deployment.getClientAuthenticator(); - - // For now, just get signature key from JWT provider. We can add more if we support encryption etc. - if (clientCredentialsProvider instanceof JWTClientCredentialsProvider) { - PublicKey publicKey = ((JWTClientCredentialsProvider) clientCredentialsProvider).getPublicKey(); - JWK jwk = JWKBuilder.create().rs256(publicKey); - jwks.setKeys(new JWK[] { jwk }); - } else { - jwks.setKeys(new JWK[] {}); - } - - facade.getResponse().setStatus(200); - facade.getResponse().setHeader("Content-Type", "application/json"); - JsonSerialization.writeValueToStream(facade.getResponse().getOutputStream(), jwks); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParameterTokenRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParameterTokenRequestAuthenticator.java deleted file mode 100644 index c7446c6f9c..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParameterTokenRequestAuthenticator.java +++ /dev/null @@ -1,60 +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.jboss.logging.Logger; -import org.keycloak.adapters.spi.AuthOutcome; -import org.keycloak.adapters.spi.HttpFacade; - -/** - * @author Christian Froehlich - * @author Brad Culley - * @author John D. Ament - * @version $Revision: 1 $ - */ -public class QueryParameterTokenRequestAuthenticator extends BearerTokenRequestAuthenticator { - public static final String ACCESS_TOKEN = "access_token"; - protected Logger log = Logger.getLogger(QueryParameterTokenRequestAuthenticator.class); - - public QueryParameterTokenRequestAuthenticator(KeycloakDeployment deployment) { - super(deployment); - } - - public AuthOutcome authenticate(HttpFacade exchange) { - if(!deployment.isOAuthQueryParameterEnabled()) { - return AuthOutcome.NOT_ATTEMPTED; - } - tokenString = null; - tokenString = getAccessTokenFromQueryParameter(exchange); - if (tokenString == null || tokenString.trim().isEmpty()) { - log.debug("Token is not present in query"); - challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.NO_QUERY_PARAMETER_ACCESS_TOKEN, null, null); - return AuthOutcome.NOT_ATTEMPTED; - } - return (authenticateToken(exchange, tokenString)); - } - - String getAccessTokenFromQueryParameter(HttpFacade exchange) { - try { - if (exchange != null && exchange.getRequest() != null) { - return exchange.getRequest().getQueryParamValue(ACCESS_TOKEN); - } - } catch (Exception ignore) { - } - return null; - } -} diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java deleted file mode 100755 index ae71fae438..0000000000 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java +++ /dev/null @@ -1,240 +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 java.util.Collections; -import java.util.List; -import org.jboss.logging.Logger; -import org.keycloak.KeycloakPrincipal; -import org.keycloak.adapters.spi.AuthChallenge; -import org.keycloak.adapters.spi.AuthOutcome; -import org.keycloak.adapters.spi.HttpFacade; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public abstract class RequestAuthenticator { - protected static Logger log = Logger.getLogger(RequestAuthenticator.class); - protected HttpFacade facade; - protected AuthChallenge challenge; - - protected KeycloakDeployment deployment; - protected AdapterTokenStore tokenStore; - protected int sslRedirectPort; - - public RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort) { - this.facade = facade; - this.deployment = deployment; - this.tokenStore = tokenStore; - this.sslRedirectPort = sslRedirectPort; - } - - public RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment) { - this.facade = facade; - this.deployment = deployment; - } - - public AuthChallenge getChallenge() { - return challenge; - } - - public AuthOutcome authenticate() { - if (log.isTraceEnabled()) { - log.trace("--> authenticate()"); - } - - BearerTokenRequestAuthenticator bearer = createBearerTokenAuthenticator(); - if (log.isTraceEnabled()) { - log.trace("try bearer"); - } - - AuthOutcome outcome = bearer.authenticate(facade); - if (outcome == AuthOutcome.FAILED) { - challenge = bearer.getChallenge(); - log.debug("Bearer FAILED"); - return AuthOutcome.FAILED; - } else if (outcome == AuthOutcome.AUTHENTICATED) { - if (verifySSL()) return AuthOutcome.FAILED; - completeAuthentication(bearer, "KEYCLOAK"); - log.debug("Bearer AUTHENTICATED"); - return AuthOutcome.AUTHENTICATED; - } - - QueryParameterTokenRequestAuthenticator queryParamAuth = createQueryParameterTokenRequestAuthenticator(); - if (log.isTraceEnabled()) { - log.trace("try query parameter auth"); - } - - outcome = queryParamAuth.authenticate(facade); - if (outcome == AuthOutcome.FAILED) { - challenge = queryParamAuth.getChallenge(); - log.debug("QueryParamAuth auth FAILED"); - return AuthOutcome.FAILED; - } else if (outcome == AuthOutcome.AUTHENTICATED) { - if (verifySSL()) return AuthOutcome.FAILED; - log.debug("QueryParamAuth AUTHENTICATED"); - completeAuthentication(queryParamAuth, "KEYCLOAK"); - return AuthOutcome.AUTHENTICATED; - } - - if (deployment.isEnableBasicAuth()) { - BasicAuthRequestAuthenticator basicAuth = createBasicAuthAuthenticator(); - if (log.isTraceEnabled()) { - log.trace("try basic auth"); - } - - outcome = basicAuth.authenticate(facade); - if (outcome == AuthOutcome.FAILED) { - challenge = basicAuth.getChallenge(); - log.debug("BasicAuth FAILED"); - return AuthOutcome.FAILED; - } else if (outcome == AuthOutcome.AUTHENTICATED) { - if (verifySSL()) return AuthOutcome.FAILED; - log.debug("BasicAuth AUTHENTICATED"); - completeAuthentication(basicAuth, "BASIC"); - return AuthOutcome.AUTHENTICATED; - } - } - - if (deployment.isBearerOnly()) { - challenge = bearer.getChallenge(); - log.debug("NOT_ATTEMPTED: bearer only"); - return AuthOutcome.NOT_ATTEMPTED; - } - - if (isAutodetectedBearerOnly(facade.getRequest())) { - challenge = bearer.getChallenge(); - log.debug("NOT_ATTEMPTED: Treating as bearer only"); - return AuthOutcome.NOT_ATTEMPTED; - } - - if (log.isTraceEnabled()) { - log.trace("try oauth"); - } - - if (tokenStore.isCached(this)) { - if (verifySSL()) return AuthOutcome.FAILED; - log.debug("AUTHENTICATED: was cached"); - return AuthOutcome.AUTHENTICATED; - } - - OAuthRequestAuthenticator oauth = createOAuthAuthenticator(); - outcome = oauth.authenticate(); - if (outcome == AuthOutcome.FAILED) { - challenge = oauth.getChallenge(); - return AuthOutcome.FAILED; - } else if (outcome == AuthOutcome.NOT_ATTEMPTED) { - challenge = oauth.getChallenge(); - return AuthOutcome.NOT_ATTEMPTED; - - } - - if (verifySSL()) return AuthOutcome.FAILED; - - completeAuthentication(oauth); - - // redirect to strip out access code and state query parameters - facade.getResponse().setHeader("Location", oauth.getStrippedOauthParametersRequestUri()); - facade.getResponse().setStatus(302); - facade.getResponse().end(); - - log.debug("AUTHENTICATED"); - return AuthOutcome.AUTHENTICATED; - } - - protected boolean verifySSL() { - if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) { - log.warnf("SSL is required to authenticate. Remote address %s is secure: %s, SSL required for: %s .", - facade.getRequest().getRemoteAddr(), facade.getRequest().isSecure(), deployment.getSslRequired().name()); - return true; - } - return false; - } - - protected boolean isAutodetectedBearerOnly(HttpFacade.Request request) { - if (!deployment.isAutodetectBearerOnly()) return false; - - String headerValue = facade.getRequest().getHeader("X-Requested-With"); - if (headerValue != null && headerValue.equalsIgnoreCase("XMLHttpRequest")) { - return true; - } - - headerValue = facade.getRequest().getHeader("Faces-Request"); - if (headerValue != null && headerValue.startsWith("partial/")) { - return true; - } - - headerValue = facade.getRequest().getHeader("SOAPAction"); - if (headerValue != null) { - return true; - } - - List accepts = facade.getRequest().getHeaders("Accept"); - if (accepts == null) accepts = Collections.emptyList(); - - for (String accept : accepts) { - if (accept.contains("text/html") || accept.contains("text/*") || accept.contains("*/*")) { - return false; - } - } - - return true; - } - - protected abstract OAuthRequestAuthenticator createOAuthAuthenticator(); - - protected BearerTokenRequestAuthenticator createBearerTokenAuthenticator() { - return new BearerTokenRequestAuthenticator(deployment); - } - - protected BasicAuthRequestAuthenticator createBasicAuthAuthenticator() { - return new BasicAuthRequestAuthenticator(deployment); - } - - protected QueryParameterTokenRequestAuthenticator createQueryParameterTokenRequestAuthenticator() { - return new QueryParameterTokenRequestAuthenticator(deployment); - } - - protected void completeAuthentication(OAuthRequestAuthenticator oauth) { - RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, tokenStore, oauth.getTokenString(), oauth.getToken(), oauth.getIdTokenString(), oauth.getIdToken(), oauth.getRefreshToken()); - final KeycloakPrincipal principal = new KeycloakPrincipal<>(AdapterUtils.getPrincipalName(deployment, oauth.getToken()), session); - completeOAuthAuthentication(principal); - log.debugv("User ''{0}'' invoking ''{1}'' on client ''{2}''", principal.getName(), facade.getRequest().getURI(), deployment.getResourceName()); - } - - protected abstract void completeOAuthAuthentication(KeycloakPrincipal principal); - - protected abstract void completeBearerAuthentication(KeycloakPrincipal principal, String method); - - /** - * After code is received, we change the session id if possible to guard against https://www.owasp.org/index.php/Session_Fixation - * - * @param create - * @return - */ - protected abstract String changeHttpSessionId(boolean create); - - protected void completeAuthentication(BearerTokenRequestAuthenticator bearer, String method) { - RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, null, bearer.getTokenString(), bearer.getToken(), null, null, null); - final KeycloakPrincipal principal = new KeycloakPrincipal<>(AdapterUtils.getPrincipalName(deployment, bearer.getToken()), session); - completeBearerAuthentication(principal, method); - log.debugv("User ''{0}'' invoking ''{1}'' on client ''{2}''", principal.getName(), facade.getRequest().getURI(), deployment.getResourceName()); - } - -} 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 deleted file mode 100644 index c607e7bfe4..0000000000 --- a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java +++ /dev/null @@ -1,139 +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.apache.http.client.HttpClient; -import org.apache.http.client.methods.Configurable; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.hamcrest.CoreMatchers; -import org.junit.Test; -import org.keycloak.adapters.rotation.HardcodedPublicKeyLocator; -import org.keycloak.adapters.rotation.JWKPublicKeyLocator; -import org.keycloak.common.enums.RelativeUrlsUsed; -import org.keycloak.common.enums.SslRequired; -import org.keycloak.common.util.PemUtils; -import org.keycloak.enums.TokenStore; -import org.keycloak.protocol.oidc.client.authentication.ClientIdAndSecretCredentialsProvider; -import org.keycloak.protocol.oidc.client.authentication.JWTClientCredentialsProvider; -import org.keycloak.protocol.oidc.client.authentication.JWTClientSecretCredentialsProvider; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.lang.reflect.Field; - -/** - * @author Stian Thorgersen - * @author Brad Culley - * @author John D. Ament - */ -public class KeycloakDeploymentBuilderTest { - - @Test - public void load() { - KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak.json")); - assertEquals("demo", deployment.getRealm()); - assertEquals("customer-portal", deployment.getResourceName()); - - assertTrue(deployment.getPublicKeyLocator() instanceof HardcodedPublicKeyLocator); - assertEquals(PemUtils.decodePublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"), - deployment.getPublicKeyLocator().getPublicKey(null, deployment)); - - assertEquals("https://localhost:8443/auth", deployment.getAuthServerBaseUrl()); - assertEquals(SslRequired.EXTERNAL, deployment.getSslRequired()); - assertTrue(deployment.isUseResourceRoleMappings()); - assertTrue(deployment.isCors()); - assertEquals(1000, deployment.getCorsMaxAge()); - assertEquals("POST, PUT, DELETE, GET", deployment.getCorsAllowedMethods()); - assertEquals("X-Custom, X-Custom2", deployment.getCorsAllowedHeaders()); - assertEquals("X-Custom3, X-Custom4", deployment.getCorsExposedHeaders()); - assertTrue(deployment.isBearerOnly()); - 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()); - HttpClient client = deployment.getClient(); - int maxPoolConnections = -1; - Field connManager = null; - - try { - connManager = client.getClass().getDeclaredField("connManager"); - connManager.setAccessible(true); - maxPoolConnections = ((PoolingHttpClientConnectionManager) connManager.get(client)).getMaxTotal(); - } catch (Exception cause) { - throw new RuntimeException("Failed to get max pool connections", cause); - } finally { - connManager.setAccessible(false); - } - - - assertEquals(20, maxPoolConnections); - assertEquals(RelativeUrlsUsed.NEVER, deployment.getRelativeUrls()); - assertTrue(deployment.isAlwaysRefreshToken()); - assertTrue(deployment.isRegisterNodeAtStartup()); - assertEquals(1000, deployment.getRegisterNodePeriod()); - assertEquals(TokenStore.COOKIE, deployment.getTokenStore()); - assertEquals("email", deployment.getPrincipalAttribute()); - assertEquals(10, deployment.getTokenMinimumTimeToLive()); - assertEquals(20, deployment.getMinTimeBetweenJwksRequests()); - assertEquals(120, deployment.getPublicKeyCacheTtl()); - assertEquals("/api/$1", deployment.getRedirectRewriteRules().get("^/wsmaster/api/(.*)$")); - assertTrue(deployment.isVerifyTokenAudience()); - } - - @Test - public void loadNoClientCredentials() { - KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-no-credentials.json")); - assertEquals(ClientIdAndSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId()); - - assertTrue(deployment.getPublicKeyLocator() instanceof JWKPublicKeyLocator); - assertEquals(10, deployment.getMinTimeBetweenJwksRequests()); - assertEquals(86400, deployment.getPublicKeyCacheTtl()); - } - - @Test - public void loadJwtCredentials() { - KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-jwt.json")); - assertEquals(JWTClientCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId()); - } - - @Test - public void loadSecretJwtCredentials() { - KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-secret-jwt.json")); - assertEquals(JWTClientSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId()); - } - - @Test - public void loadHttpClientTimeoutConfiguration() { - KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-http-client.json")); - assertThat(deployment, CoreMatchers.notNullValue()); - - HttpClient client = deployment.getClient(); - assertThat(client, CoreMatchers.notNullValue()); - - long socketTimeout = ((Configurable) client).getConfig().getSocketTimeout(); - long connectionTimeout = ((Configurable) client).getConfig().getConnectTimeout(); - - assertThat(socketTimeout, CoreMatchers.is(2000L)); - assertThat(connectionTimeout, CoreMatchers.is(6000L)); - } -} 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 deleted file mode 100644 index 2d2c32e46b..0000000000 --- a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentTest.java +++ /dev/null @@ -1,86 +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.Test; -import org.keycloak.common.util.KeycloakUriBuilder; -import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation; -import org.keycloak.representations.adapters.config.AdapterConfig; - -import static org.junit.Assert.assertEquals; -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 KeycloakDeploymentMock(); - keycloakDeployment.setIgnoreOAuthQueryParameter(true); - assertFalse(keycloakDeployment.isOAuthQueryParameterEnabled()); - } - - @Test - public void shouldEnableOAuthQueryParamWhenIgnoreIsFalse() { - KeycloakDeployment keycloakDeployment = new KeycloakDeploymentMock(); - keycloakDeployment.setIgnoreOAuthQueryParameter(false); - assertTrue(keycloakDeployment.isOAuthQueryParameterEnabled()); - } - - @Test - public void shouldEnableOAuthQueryParamWhenIgnoreNotSet() { - KeycloakDeployment keycloakDeployment = new KeycloakDeploymentMock(); - - assertTrue(keycloakDeployment.isOAuthQueryParameterEnabled()); - } - - @Test - public void stripDefaultPorts() { - KeycloakDeployment keycloakDeployment = new KeycloakDeploymentMock(); - keycloakDeployment.setRealm("test"); - AdapterConfig config = new AdapterConfig(); - config.setAuthServerUrl("http://localhost:80/auth"); - - keycloakDeployment.setAuthServerBaseUrl(config); - - assertEquals("http://localhost/auth", keycloakDeployment.getAuthServerBaseUrl()); - - config.setAuthServerUrl("https://localhost:443/auth"); - keycloakDeployment.setAuthServerBaseUrl(config); - - assertEquals("https://localhost/auth", keycloakDeployment.getAuthServerBaseUrl()); - } - - class KeycloakDeploymentMock extends KeycloakDeployment { - - @Override - protected OIDCConfigurationRepresentation getOidcConfiguration(String discoveryUrl) throws Exception { - String base = KeycloakUriBuilder.fromUri(discoveryUrl).replacePath("/auth").build().toString(); - - OIDCConfigurationRepresentation rep = new OIDCConfigurationRepresentation(); - rep.setAuthorizationEndpoint(base + "/realms/test/authz"); - rep.setTokenEndpoint(base + "/realms/test/tokens"); - rep.setIssuer(base + "/realms/test"); - rep.setJwksUri(base + "/realms/test/jwks"); - rep.setLogoutEndpoint(base + "/realms/test/logout"); - return rep; - } - } -} \ No newline at end of file diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/RefreshableKeycloakSecurityContextTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/RefreshableKeycloakSecurityContextTest.java deleted file mode 100644 index af3508522d..0000000000 --- a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/RefreshableKeycloakSecurityContextTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.keycloak.adapters; - -import org.junit.Assert; -import org.junit.Test; -import org.keycloak.KeycloakPrincipal; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.jose.jws.JWSBuilder; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.IDToken; -import org.keycloak.representations.oidc.TokenMetadataRepresentation; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.security.KeyPair; -import java.security.KeyPairGenerator; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * @author github.com/tubbynl - * - */ -public class RefreshableKeycloakSecurityContextTest { - - @Test - public void isActive() { - TokenMetadataRepresentation token = new TokenMetadataRepresentation(); - token.setActive(true); - token.issuedNow(); - RefreshableKeycloakSecurityContext sut = new RefreshableKeycloakSecurityContext(null,null,null,token,null, null, null); - - // verify false if null deployment (KEYCLOAK-3050; yielded a npe) - assertFalse(sut.isActive()); - } - - @Test - public void sameIssuedAtAsNotBeforeIsActiveKEYCLOAK10013() { - KeycloakDeployment keycloakDeployment = new KeycloakDeployment(); - keycloakDeployment.setNotBefore(5000); - - TokenMetadataRepresentation token = new TokenMetadataRepresentation(); - token.setActive(true); - token.iat(4999L); - - RefreshableKeycloakSecurityContext sut = new RefreshableKeycloakSecurityContext(keycloakDeployment,null,null,token,null, null, null); - - assertFalse(sut.isActive()); - - token.iat(5000L); - assertTrue(sut.isActive()); - } - - private AccessToken createSimpleToken() { - AccessToken token = new AccessToken(); - token.id("111"); - token.issuer("http://localhost:8080/auth/acme"); - token.addAccess("foo").addRole("admin"); - token.addAccess("bar").addRole("user"); - return token; - } - - @Test - public void testSerialization() throws Exception { - AccessToken token = createSimpleToken(); - IDToken idToken = new IDToken(); - - idToken.setEmail("joe@email.cz"); - - KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); - - String encoded = new JWSBuilder() - .jsonContent(token) - .rsa256(keyPair.getPrivate()); - String encodedIdToken = new JWSBuilder() - .jsonContent(idToken) - .rsa256(keyPair.getPrivate()); - - KeycloakDeployment keycloakDeployment = new KeycloakDeployment(); - keycloakDeployment.setNotBefore(5000); - - KeycloakSecurityContext ctx = new RefreshableKeycloakSecurityContext(keycloakDeployment,null, encoded, token,encodedIdToken, null, null); - KeycloakPrincipal principal = new KeycloakPrincipal("joe", ctx); - - // Serialize - ByteArrayOutputStream bso = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(bso); - oos.writeObject(principal); - oos.close(); - - // Deserialize - byte[] bytes = bso.toByteArray(); - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(bis); - principal = (KeycloakPrincipal)ois.readObject(); - ctx = principal.getKeycloakSecurityContext(); - token = ctx.getToken(); - idToken = ctx.getIdToken(); - - System.out.println("Size of serialized principal: " + bytes.length); - - Assert.assertEquals(encoded, ctx.getTokenString()); - Assert.assertEquals(encodedIdToken, ctx.getIdTokenString()); - Assert.assertEquals("111", token.getId()); - Assert.assertEquals("111", token.getId()); - Assert.assertTrue(token.getResourceAccess("foo").isUserInRole("admin")); - Assert.assertTrue(token.getResourceAccess("bar").isUserInRole("user")); - Assert.assertEquals("joe@email.cz", idToken.getEmail()); - Assert.assertEquals("acme", ctx.getRealm()); - ois.close(); - } -} diff --git a/adapters/oidc/adapter-core/src/test/resources/cacerts.jks b/adapters/oidc/adapter-core/src/test/resources/cacerts.jks deleted file mode 100644 index f8ae5a39a090cf399cb053666d89844a8aa52cc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 959 zcmezO_TO6u1_mY|W(3nb#i>PQsYSYpIhl#YKtZn~y!#6oSR?dI4J;WLn5zt$n9B^B znBo>NGchtTF+1lN81S-jYPET^edlFlJh%m!N4CKUl4NVOU4a^M<4Gav7qrhAfIG4_@X<}4D4h}|E2IeM4eg=ak zMlPl%Mn;D18yojKX4^Oa`&O|yE`P_8>B>ys%h&LlN!{HPE+2Mv@2gUm-P&{Shxv+C z7xKmT<@$YJ^X}rgjJoTOy$fF_cu(^>a`%0qA=kkSRZZ!=Q%@e`*caxs=2C-==7e*1 zHZ!@(WCd?I9^4o6#K-&N-Lsv{+b*4&Uc~jRW6|t|HQKVdb9#3REJ*a|zp&_;=I+fu zZq2{eGKX>Pn``2$L`5x@h`!J}xtrsm*+irEe|@n^1=Fx$uXhF8HKQcn zNrLT9o_BHf&X19L|7*U2T=bp4mMZ<19H*79o|zT+V2MG2*iTP2QKkPARvZlL`Txma z$MorwO8$TDkXR#l)jj>BYB&=!BLm}NMFV*QSzrp0d`@Q88*t zJ2r06Sic`R5P@k57>JAvi`Hxv?09nS`e6>Z@Csntwcpf zNy%B2)7A_3aJ)Qly2>~ljOJemi=?)+N-a@|IL&XYjQWbOV>HC z%-;O-Lp*|FW*K_jRB7 zZjsRy|Cb9h1yZBG8~6Q`vgirUx_>07sDDS|vk-;1(+zF@ADus+DSe0HkEmyFyZ00727j A8vp*u5ZA$ERNWjUI4=AqLve|#8zxnh zNtk7&3dT|qI9;y2Z?)E$9pvO=%+XZtQj;#%<9ymSX4&BO3OYIq&I&aqExYymWS`>LSRK79XluR*CV50dTIlU+yZxvA zy@=V!u6Hz!IWTX zuK;Uod6SK9Q_e#ZN!8&D>*umrcVGEPMZQwl@rrHhg+$0G?J-SQ4;D0tU7k>v!>NNI zZ9xiO`0w}#@h!_iSDNMLqBRwjs%Hm%?N1N0vr;a0nNjkDw1~+mj=XWne)TJPPjMZEl1hB^W{yS2-I3Gi zprp);{wf8a5{5D-f2;gYhT~57{uej8)+n$MXKl)PGJ2^y6*ZT$Q1)2OTpH|Tt={A5 z^|zb3DU3BZ;IsasrFfw}AWgrStkAdb<0Gx8KyTlX$#Go^?RDk&PY@>2SM%*R-$%a1 zWyEi-6dyT#bBJ8&NrMU&gCm~R_iT(=5BgTu4!+m@pcXUK#q*%s21YMLs+&>oJJ}eO zV~L4XOowpd%&Qck%$2yjwg%+f6O&6&yEYZX>y3wc&)$dyryY5SuPu!!3+*qv8ackK ztAJYLQzR=m?4j9(#I?8i;v2l+w%@yOKB-NW`DP)`GBv``mlfqWb0@f8E_Z0+@Uq># zgUHK8QNyOZM5+5PrTiF+9}~5Tstk7L#Vs9lw8$0KnAOXcZ=%1|X-(K9qXj(W^i=Yp zKYsHN?BTxwU27c0=-I!nRO@|=KnC=+c^8Pi)QWEQy3%(cTgU&)A2iCy=9;ZA;BIG< zrkl3hK&8vy`zgt!%9PwoWdkkD_f<8t09 za~`YR2|orJSDmOcXqC@#Nk+pd&B+)e1IBr?*MZM*LWi(gYsbgj)sVBbxr_N$uIyRa z8SZ-Id$<{K#E-2w+5m8~mYxAk`dKE&5{De?{Iq^37JFh1A9dORxP2j=S{wNt?8TWL z3lkfH!1rlD#bO$UiY26!?-gN-X}p&@KSh|7_7feyyI3eq$HWLSXV~qyy9sNqS~)+n z4n>P3*2RT#fxaE`KWfgA#1ojwHPtM&w!?gNmb|J_KU^;%`qoCJhC}1PWXf(E7XvFD zyLd)G4y4D*|U?mWKm7Fc~gs5Gn>{zDx3`q!f?hq ztJ13OaCZ1QZBWPHQKT-B+x)OZmY_XORmZi~r64%Lnk49#S`flqtU2{ZdSn;*4fdeELA{ISkCjz78crNTj8ush_=H@d>MDgmdY{^QaXYs63>2tV2 zaeV%x&$h6flIK@#;{xb14}=>2YE3O$D_Sty^T!r8Y&J3Ky~)`OGJYm|ZUi%s ze|$C8<*@d!>#;oB?^hmg2@af0v=2&u1)@I+)M6Ng(;#@phoftZ#}&h%4%_L}<0YN$ Til985qpom - adapter-core js diff --git a/adapters/saml/wildfly-elytron-jakarta/pom.xml b/adapters/saml/wildfly-elytron-jakarta/pom.xml index b3a496978e..d8d785b220 100755 --- a/adapters/saml/wildfly-elytron-jakarta/pom.xml +++ b/adapters/saml/wildfly-elytron-jakarta/pom.xml @@ -41,11 +41,6 @@ - - org.keycloak - keycloak-adapter-core - provided - org.keycloak keycloak-saml-core diff --git a/adapters/saml/wildfly-elytron/pom.xml b/adapters/saml/wildfly-elytron/pom.xml index 5dfaf1bb6e..f9c8910614 100755 --- a/adapters/saml/wildfly-elytron/pom.xml +++ b/adapters/saml/wildfly-elytron/pom.xml @@ -31,11 +31,6 @@ - - org.keycloak - keycloak-adapter-core - provided - org.keycloak keycloak-saml-core diff --git a/boms/adapter/pom.xml b/boms/adapter/pom.xml index f0aba284cc..d4953f21a6 100644 --- a/boms/adapter/pom.xml +++ b/boms/adapter/pom.xml @@ -39,11 +39,6 @@ keycloak-core ${project.version} - - org.keycloak - keycloak-adapter-core - ${project.version} - org.keycloak keycloak-crypto-default diff --git a/distribution/feature-packs/adapter-feature-pack/pom.xml b/distribution/feature-packs/adapter-feature-pack/pom.xml index 6562edc7ed..e36605f059 100755 --- a/distribution/feature-packs/adapter-feature-pack/pom.xml +++ b/distribution/feature-packs/adapter-feature-pack/pom.xml @@ -72,16 +72,6 @@ - - org.keycloak - keycloak-adapter-core - - - * - * - - - org.keycloak keycloak-jboss-adapter-core diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-adapter-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-adapter-core/main/module.xml deleted file mode 100755 index 4e2e48ac34..0000000000 --- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-adapter-core/main/module.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pom.xml b/pom.xml index 835e49d708..77808fc7c3 100644 --- a/pom.xml +++ b/pom.xml @@ -970,11 +970,6 @@ keycloak-adapter-spi ${project.version} - - org.keycloak - keycloak-adapter-core - ${project.version} - org.keycloak keycloak-admin-client-jee diff --git a/testsuite/integration-arquillian/test-apps/app-profile-jee/pom.xml b/testsuite/integration-arquillian/test-apps/app-profile-jee/pom.xml index d25c47c91c..1bd6c5a6ed 100644 --- a/testsuite/integration-arquillian/test-apps/app-profile-jee/pom.xml +++ b/testsuite/integration-arquillian/test-apps/app-profile-jee/pom.xml @@ -30,9 +30,9 @@ provided - org.keycloak - keycloak-adapter-core - provided + org.keycloak.testsuite + integration-arquillian-util + ${project.version} org.keycloak diff --git a/testsuite/integration-arquillian/test-apps/cors/database-service/pom.xml b/testsuite/integration-arquillian/test-apps/cors/database-service/pom.xml index e6bb20846a..439cb94d02 100755 --- a/testsuite/integration-arquillian/test-apps/cors/database-service/pom.xml +++ b/testsuite/integration-arquillian/test-apps/cors/database-service/pom.xml @@ -58,9 +58,9 @@ provided - org.keycloak - keycloak-adapter-core - provided + org.keycloak.testsuite + integration-arquillian-util + ${project.version} org.apache.httpcomponents diff --git a/testsuite/integration-arquillian/test-apps/servlets-jakarta/pom.xml b/testsuite/integration-arquillian/test-apps/servlets-jakarta/pom.xml index ff0e3f1d8c..92cff95593 100644 --- a/testsuite/integration-arquillian/test-apps/servlets-jakarta/pom.xml +++ b/testsuite/integration-arquillian/test-apps/servlets-jakarta/pom.xml @@ -31,8 +31,9 @@ compile - org.keycloak - keycloak-adapter-core + org.keycloak.testsuite + integration-arquillian-util + ${project.version} org.keycloak diff --git a/testsuite/integration-arquillian/test-apps/servlets/pom.xml b/testsuite/integration-arquillian/test-apps/servlets/pom.xml index 88e482771d..a809558d73 100644 --- a/testsuite/integration-arquillian/test-apps/servlets/pom.xml +++ b/testsuite/integration-arquillian/test-apps/servlets/pom.xml @@ -26,8 +26,9 @@ compile - org.keycloak - keycloak-adapter-core + org.keycloak.testsuite + integration-arquillian-util + ${project.version} org.keycloak diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/DemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/DemoServletsAdapterTest.java index a99f92a4f9..1dc3e2850a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/DemoServletsAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/DemoServletsAdapterTest.java @@ -35,7 +35,6 @@ import org.junit.Before; import org.junit.After; import org.junit.Test; import org.keycloak.OAuth2Constants; -import org.keycloak.adapters.OIDCAuthenticationError; import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.common.util.Time; @@ -661,14 +660,14 @@ public class DemoServletsAdapterTest extends AbstractServletsAdapterTest { assertEquals(401, response.getStatus()); String errorPageResponse = response.readEntity(String.class); assertThat(errorPageResponse, containsString("Error Page")); - assertThat(errorPageResponse, containsString(OIDCAuthenticationError.Reason.NO_BEARER_TOKEN.toString())); + assertThat(errorPageResponse, containsString("NO_BEARER_TOKEN")); } try (Response response = target.request().header(HttpHeaders.AUTHORIZATION, "Bearer null").get()) { assertEquals(401, response.getStatus()); String errorPageResponse = response.readEntity(String.class); assertThat(errorPageResponse, containsString("Error Page")); - assertThat(errorPageResponse, containsString(OIDCAuthenticationError.Reason.INVALID_TOKEN.toString())); + assertThat(errorPageResponse, containsString("INVALID_TOKEN")); } client.close(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/admin/PolicyEnforcerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/admin/PolicyEnforcerTest.java index e09def8e14..1ed681e376 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/admin/PolicyEnforcerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/admin/PolicyEnforcerTest.java @@ -865,7 +865,7 @@ public class PolicyEnforcerTest extends AbstractKeycloakTest { } catch (JWSInputException cause) { throw new RuntimeException(cause); } - return new RefreshableKeycloakSecurityContext(deployment, null, token, accessToken, null, null, null); + return new RefreshableKeycloakSecurityContext(deployment, token, accessToken, null, null, null); } return null; } diff --git a/testsuite/integration-arquillian/util/pom.xml b/testsuite/integration-arquillian/util/pom.xml index 0ff73d861d..2264a5f07d 100644 --- a/testsuite/integration-arquillian/util/pom.xml +++ b/testsuite/integration-arquillian/util/pom.xml @@ -91,5 +91,13 @@ jakarta.servlet jakarta.servlet-api + + org.keycloak + keycloak-adapter-spi + + + org.keycloak + keycloak-policy-enforcer + diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java old mode 100755 new mode 100644 similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/AdapterUtils.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/AdapterUtils.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java index c0d19c1651..77249e8510 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java +++ b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java @@ -17,11 +17,11 @@ package org.keycloak.adapters; +import org.keycloak.adapters.pep.HttpAuthzRequest; +import org.keycloak.adapters.pep.HttpAuthzResponse; import org.jboss.logging.Logger; import org.keycloak.AuthorizationContext; import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.pep.HttpAuthzRequest; -import org.keycloak.adapters.pep.HttpAuthzResponse; import org.keycloak.adapters.authorization.PolicyEnforcer; import org.keycloak.common.util.UriUtils; import org.keycloak.constants.AdapterConstants; diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CorsHeaders.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/CorsHeaders.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CorsHeaders.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/CorsHeaders.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientAdapterException.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/HttpClientAdapterException.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientAdapterException.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/HttpClientAdapterException.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/HttpClientBuilder.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/HttpClientBuilder.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakConfigResolver.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/KeycloakConfigResolver.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakConfigResolver.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/KeycloakConfigResolver.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/KeycloakDeployment.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/KeycloakDeployment.java index 590ac4b392..eebe9bedee 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java +++ b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/KeycloakDeployment.java @@ -17,13 +17,13 @@ package org.keycloak.adapters; +import org.keycloak.adapters.rotation.PublicKeyLocator; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.util.EntityUtils; import org.jboss.logging.Logger; import org.keycloak.adapters.authorization.PolicyEnforcer; -import org.keycloak.adapters.rotation.PublicKeyLocator; import org.keycloak.common.enums.RelativeUrlsUsed; import org.keycloak.common.enums.SslRequired; import org.keycloak.common.util.KeycloakUriBuilder; diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCHttpFacade.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/OIDCHttpFacade.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCHttpFacade.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/OIDCHttpFacade.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java similarity index 94% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java index 03bdf68d26..9a91f1225e 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java +++ b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java @@ -38,16 +38,14 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext protected static Logger log = Logger.getLogger(RefreshableKeycloakSecurityContext.class); protected transient KeycloakDeployment deployment; - protected transient AdapterTokenStore tokenStore; protected String refreshToken; public RefreshableKeycloakSecurityContext() { } - public RefreshableKeycloakSecurityContext(KeycloakDeployment deployment, AdapterTokenStore tokenStore, String tokenString, AccessToken token, String idTokenString, IDToken idToken, String refreshToken) { + public RefreshableKeycloakSecurityContext(KeycloakDeployment deployment, String tokenString, AccessToken token, String idTokenString, IDToken idToken, String refreshToken) { super(tokenString, token, idTokenString, idToken); this.deployment = deployment; - this.tokenStore = tokenStore; this.refreshToken = refreshToken; } @@ -99,9 +97,8 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext return deployment; } - public void setCurrentRequestInfo(KeycloakDeployment deployment, AdapterTokenStore tokenStore) { + public void setCurrentRequestInfo(KeycloakDeployment deployment) { this.deployment = deployment; - this.tokenStore = tokenStore; } /** @@ -182,9 +179,6 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext this.refreshToken = response.getRefreshToken(); } this.tokenString = tokenString; - if (tokenStore != null) { - tokenStore.refreshCallback(this); - } } return true; diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/ServerRequest.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/ServerRequest.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/SniSSLSocketFactory.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/pep/HttpAuthzRequest.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/pep/HttpAuthzRequest.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/pep/HttpAuthzRequest.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/pep/HttpAuthzRequest.java index 54c9d119df..bcc216485c 100644 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/pep/HttpAuthzRequest.java +++ b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/pep/HttpAuthzRequest.java @@ -20,8 +20,8 @@ package org.keycloak.adapters.pep; import java.io.InputStream; import java.util.List; -import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.OIDCHttpFacade; +import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.authorization.TokenPrincipal; import org.keycloak.adapters.authorization.spi.HttpRequest; import org.keycloak.adapters.spi.HttpFacade.Cookie; diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/pep/HttpAuthzResponse.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/pep/HttpAuthzResponse.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/pep/HttpAuthzResponse.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/pep/HttpAuthzResponse.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java index d989492f81..80c20a0e96 100644 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java +++ b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java @@ -17,9 +17,9 @@ package org.keycloak.adapters.rotation; +import org.keycloak.adapters.KeycloakDeployment; import org.jboss.logging.Logger; import org.keycloak.TokenVerifier; -import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.common.VerificationException; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/HardcodedPublicKeyLocator.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/HardcodedPublicKeyLocator.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/HardcodedPublicKeyLocator.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/HardcodedPublicKeyLocator.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/PublicKeyLocator.java b/testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/PublicKeyLocator.java similarity index 100% rename from adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/PublicKeyLocator.java rename to testsuite/integration-arquillian/util/src/main/java/org/keycloak/adapters/rotation/PublicKeyLocator.java