Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5a3016d5d | ||
|
|
91f1a61cf5 | ||
|
|
22e6d049eb | ||
|
|
5eaf454ea5 | ||
|
|
8a09eeb8a7 | ||
|
|
4c661724f6 | ||
|
|
d05d42b706 | ||
|
|
d022b6c6e8 | ||
|
|
6fa2fef61e |
No files matched your search
@@ -45,6 +45,3 @@ catalog.xml
|
|||||||
#########
|
#########
|
||||||
target
|
target
|
||||||
|
|
||||||
# Maven shade
|
|
||||||
#############
|
|
||||||
*dependency-reduced-pom.xml
|
|
||||||
+2
-15
@@ -1,22 +1,9 @@
|
|||||||
language: java
|
language: java
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/.m2
|
|
||||||
|
|
||||||
before_cache:
|
|
||||||
- rm -rf $HOME/.m2/repository/org/keycloak
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- MAVEN_SKIP_RC=true
|
- MAVEN_SKIP_RC=true
|
||||||
- MAVEN_OPTS="-Xms512m -Xmx2048m"
|
- MAVEN_OPTS="-Xms512m -Xmx2048m"
|
||||||
matrix:
|
|
||||||
- TESTS=old
|
|
||||||
- TESTS=group1
|
|
||||||
- TESTS=group2
|
|
||||||
- TESTS=group3
|
|
||||||
- TESTS=adapter
|
|
||||||
|
|
||||||
jdk:
|
jdk:
|
||||||
- oraclejdk8
|
- oraclejdk8
|
||||||
@@ -25,9 +12,9 @@ before_script:
|
|||||||
- export MAVEN_SKIP_RC=true
|
- export MAVEN_SKIP_RC=true
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- travis_wait 60 mvn install -Pdistribution -DskipTests=true -B -V -q
|
- ( mvn install -Pdistribution -DskipTests=true -B -V -q ) & ( MYPID=$!; while [ $(ps -ef | grep $MYPID | grep -v grep | wc -l) -gt 0 ]; do sleep 10; date; done; )
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./travis-run-tests.sh $TESTS
|
- mvn test -B
|
||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
@@ -9,7 +9,7 @@ For more information about Keycloak visit [Keycloak homepage](http://keycloak.or
|
|||||||
Building
|
Building
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Ensure you have JDK 8 (or newer), Maven 3.1.1 (or newer) and Git installed
|
Ensure you have JDK 8 (or newer), Maven 3.2.1 (or newer) and Git installed
|
||||||
|
|
||||||
java -version
|
java -version
|
||||||
mvn -version
|
mvn -version
|
||||||
@@ -36,7 +36,7 @@ Once completed you will find distribution archives in `distribution`.
|
|||||||
Starting Keycloak
|
Starting Keycloak
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
To start Keycloak during development first build as specified above, then run:
|
To start Keycloak during development first build as specficied above, then run:
|
||||||
|
|
||||||
mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server
|
mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ To stop the server press `Ctrl + C`.
|
|||||||
|
|
||||||
Help and Documentation
|
Help and Documentation
|
||||||
----------------------
|
----------------------
|
||||||
* [Documentation](http://www.keycloak.org/documentation.html) - User Guide, Admin REST API and Javadocs
|
* [Documentation](http://keycloak.jboss.org/docs) - User Guide, Admin REST API and Javadocs
|
||||||
* [User Mailing List](https://lists.jboss.org/mailman/listinfo/keycloak-user) - Mailing list to ask for help and general questions about Keycloak
|
* [User Mailing List](https://lists.jboss.org/mailman/listinfo/keycloak-user) - Mailing list to ask for help and general questions about Keycloak
|
||||||
* [JIRA](https://issues.jboss.org/projects/KEYCLOAK) - Issue tracker for bugs and feature requests
|
* [JIRA](https://issues.jboss.org/projects/KEYCLOAK) - Issue tracker for bugs and feature requests
|
||||||
|
|
||||||
@@ -65,11 +65,10 @@ Contributing
|
|||||||
* [Testsuite](misc/Testsuite.md) - Details about testsuite, but also how to quickly run Keycloak during development and a few test tools (OTP generation, LDAP server, Mail server)
|
* [Testsuite](misc/Testsuite.md) - Details about testsuite, but also how to quickly run Keycloak during development and a few test tools (OTP generation, LDAP server, Mail server)
|
||||||
* [Database Testing](misc/DatabaseTesting.md) - How to do testing of Keycloak on different databases
|
* [Database Testing](misc/DatabaseTesting.md) - How to do testing of Keycloak on different databases
|
||||||
* [Updating Database](misc/UpdatingDatabaseSchema.md) - How to change the Keycloak database
|
* [Updating Database](misc/UpdatingDatabaseSchema.md) - How to change the Keycloak database
|
||||||
* [Changing the Default keycloak-subsystem Configuration](misc/UpdatingServerConfig.md) - How to update the default keycloak-subsystem config
|
|
||||||
* [Developer Mailing List](https://lists.jboss.org/mailman/listinfo/keycloak-dev) - Mailing list to discuss development of Keycloak
|
* [Developer Mailing List](https://lists.jboss.org/mailman/listinfo/keycloak-dev) - Mailing list to discuss development of Keycloak
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
* [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)
|
* [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+55
-35
@@ -17,21 +17,26 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters;
|
package org.keycloak.adapters;
|
||||||
|
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.authentication.ClientCredentialsProvider;
|
import org.keycloak.adapters.authentication.ClientCredentialsProvider;
|
||||||
import org.keycloak.adapters.authorization.PolicyEnforcer;
|
|
||||||
import org.keycloak.adapters.rotation.PublicKeyLocator;
|
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.common.enums.RelativeUrlsUsed;
|
import org.keycloak.common.enums.RelativeUrlsUsed;
|
||||||
import org.keycloak.common.enums.SslRequired;
|
import org.keycloak.common.enums.SslRequired;
|
||||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
|
||||||
import org.keycloak.enums.TokenStore;
|
import org.keycloak.enums.TokenStore;
|
||||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
|
import org.keycloak.representations.idm.PublishedRealmRepresentation;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.PublicKey;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +57,7 @@ public class AdapterDeploymentContext {
|
|||||||
* during the application deployment's life cycle.
|
* during the application deployment's life cycle.
|
||||||
*
|
*
|
||||||
* @param deployment A KeycloakConfigResolver, possibly missing the Auth
|
* @param deployment A KeycloakConfigResolver, possibly missing the Auth
|
||||||
* Server URL
|
* Server URL and/or Realm Public Key
|
||||||
*/
|
*/
|
||||||
public AdapterDeploymentContext(KeycloakDeployment deployment) {
|
public AdapterDeploymentContext(KeycloakDeployment deployment) {
|
||||||
this.deployment = deployment;
|
this.deployment = deployment;
|
||||||
@@ -74,6 +79,7 @@ public class AdapterDeploymentContext {
|
|||||||
/**
|
/**
|
||||||
* For single-tenant deployments, it complements KeycloakDeployment
|
* For single-tenant deployments, it complements KeycloakDeployment
|
||||||
* by resolving a relative Auth Server's URL based on the current request
|
* by resolving a relative Auth Server's URL based on the current request
|
||||||
|
* and, if needed, will lazily resolve the Realm's Public Key.
|
||||||
*
|
*
|
||||||
* For multi-tenant deployments, defers the resolution of KeycloakDeployment
|
* For multi-tenant deployments, defers the resolution of KeycloakDeployment
|
||||||
* to the KeycloakConfigResolver .
|
* to the KeycloakConfigResolver .
|
||||||
@@ -92,8 +98,8 @@ public class AdapterDeploymentContext {
|
|||||||
if (deployment.getAuthServerBaseUrl() == null) return deployment;
|
if (deployment.getAuthServerBaseUrl() == null) return deployment;
|
||||||
|
|
||||||
KeycloakDeployment resolvedDeployment = resolveUrls(deployment, facade);
|
KeycloakDeployment resolvedDeployment = resolveUrls(deployment, facade);
|
||||||
if (resolvedDeployment.getPublicKeyLocator() == null) {
|
if (resolvedDeployment.getRealmKey() == null) {
|
||||||
throw new RuntimeException("KeycloakDeployment was never initialized through appropriate SPIs");
|
resolveRealmKey(resolvedDeployment);
|
||||||
}
|
}
|
||||||
return resolvedDeployment;
|
return resolvedDeployment;
|
||||||
}
|
}
|
||||||
@@ -109,6 +115,45 @@ public class AdapterDeploymentContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resolveRealmKey(KeycloakDeployment deployment) {
|
||||||
|
if (deployment.getClient() == null) {
|
||||||
|
throw new RuntimeException("KeycloakDeployment was never initialized through appropriate SPIs");
|
||||||
|
}
|
||||||
|
HttpGet get = new HttpGet(deployment.getRealmInfoUrl());
|
||||||
|
try {
|
||||||
|
HttpResponse response = deployment.getClient().execute(get);
|
||||||
|
int status = response.getStatusLine().getStatusCode();
|
||||||
|
if (status != 200) {
|
||||||
|
close(response);
|
||||||
|
throw new RuntimeException("Unable to resolve realm public key remotely, status = " + status);
|
||||||
|
}
|
||||||
|
HttpEntity entity = response.getEntity();
|
||||||
|
if (entity == null) {
|
||||||
|
throw new RuntimeException("Unable to resolve realm public key remotely. There was no entity.");
|
||||||
|
}
|
||||||
|
InputStream is = entity.getContent();
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
int c;
|
||||||
|
while ((c = is.read()) != -1) {
|
||||||
|
os.write(c);
|
||||||
|
}
|
||||||
|
byte[] bytes = os.toByteArray();
|
||||||
|
String json = new String(bytes);
|
||||||
|
PublishedRealmRepresentation rep = JsonSerialization.readValue(json, PublishedRealmRepresentation.class);
|
||||||
|
deployment.setRealmKey(rep.getPublicKey());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Unable to resolve realm public key remotely", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This delegate is used to store temporary, per-request metadata like request resolved URLs.
|
* This delegate is used to store temporary, per-request metadata like request resolved URLs.
|
||||||
* Ever method is delegated except URL get methods and isConfigured()
|
* Ever method is delegated except URL get methods and isConfigured()
|
||||||
@@ -162,11 +207,6 @@ public class AdapterDeploymentContext {
|
|||||||
return (this.unregisterNodeUrl != null) ? this.unregisterNodeUrl : delegate.getUnregisterNodeUrl();
|
return (this.unregisterNodeUrl != null) ? this.unregisterNodeUrl : delegate.getUnregisterNodeUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getJwksUrl() {
|
|
||||||
return (this.jwksUrl != null) ? this.jwksUrl : delegate.getJwksUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getResourceName() {
|
public String getResourceName() {
|
||||||
return delegate.getResourceName();
|
return delegate.getResourceName();
|
||||||
@@ -183,13 +223,13 @@ public class AdapterDeploymentContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPublicKeyLocator(PublicKeyLocator publicKeyLocator) {
|
public PublicKey getRealmKey() {
|
||||||
delegate.setPublicKeyLocator(publicKeyLocator);
|
return delegate.getRealmKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PublicKeyLocator getPublicKeyLocator() {
|
public void setRealmKey(PublicKey realmKey) {
|
||||||
return delegate.getPublicKeyLocator();
|
delegate.setRealmKey(realmKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -426,26 +466,6 @@ public class AdapterDeploymentContext {
|
|||||||
public void setTokenMinimumTimeToLive(final int tokenMinimumTimeToLive) {
|
public void setTokenMinimumTimeToLive(final int tokenMinimumTimeToLive) {
|
||||||
delegate.setTokenMinimumTimeToLive(tokenMinimumTimeToLive);
|
delegate.setTokenMinimumTimeToLive(tokenMinimumTimeToLive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PolicyEnforcer getPolicyEnforcer() {
|
|
||||||
return delegate.getPolicyEnforcer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPolicyEnforcer(PolicyEnforcer policyEnforcer) {
|
|
||||||
delegate.setPolicyEnforcer(policyEnforcer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMinTimeBetweenJwksRequests(int minTimeBetweenJwksRequests) {
|
|
||||||
delegate.setMinTimeBetweenJwksRequests(minTimeBetweenJwksRequests);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMinTimeBetweenJwksRequests() {
|
|
||||||
return delegate.getMinTimeBetweenJwksRequests();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
|
protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ package org.keycloak.adapters;
|
|||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.KeycloakPrincipal;
|
import org.keycloak.KeycloakPrincipal;
|
||||||
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.common.util.UriUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|||||||
+2
-6
@@ -142,13 +142,9 @@ public class AuthenticatedActionsHandler {
|
|||||||
AuthorizationContext authorizationContext = policyEnforcer.enforce(facade);
|
AuthorizationContext authorizationContext = policyEnforcer.enforce(facade);
|
||||||
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) facade.getSecurityContext();
|
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) facade.getSecurityContext();
|
||||||
|
|
||||||
if (session != null) {
|
session.setAuthorizationContext(authorizationContext);
|
||||||
session.setAuthorizationContext(authorizationContext);
|
|
||||||
|
|
||||||
return authorizationContext.isGranted();
|
return authorizationContext.isGranted();
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to enforce policy decisions.", e);
|
throw new RuntimeException("Failed to enforce policy decisions.", e);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -31,10 +31,10 @@ import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
|||||||
import org.keycloak.adapters.spi.AuthOutcome;
|
import org.keycloak.adapters.spi.AuthOutcome;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.common.util.Base64;
|
import org.keycloak.common.util.Base64;
|
||||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
|
||||||
import org.keycloak.constants.ServiceUrlConstants;
|
import org.keycloak.constants.ServiceUrlConstants;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -18,7 +18,7 @@
|
|||||||
package org.keycloak.adapters;
|
package org.keycloak.adapters;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
import org.keycloak.RSATokenVerifier;
|
||||||
import org.keycloak.adapters.spi.AuthChallenge;
|
import org.keycloak.adapters.spi.AuthChallenge;
|
||||||
import org.keycloak.adapters.spi.AuthOutcome;
|
import org.keycloak.adapters.spi.AuthOutcome;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
@@ -84,7 +84,7 @@ public class BearerTokenRequestAuthenticator {
|
|||||||
|
|
||||||
protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) {
|
protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) {
|
||||||
try {
|
try {
|
||||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||||
} catch (VerificationException e) {
|
} catch (VerificationException e) {
|
||||||
log.error("Failed to verify token", e);
|
log.error("Failed to verify token", e);
|
||||||
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, "invalid_token", e.getMessage());
|
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, "invalid_token", e.getMessage());
|
||||||
|
|||||||
+5
-3
@@ -17,17 +17,19 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters;
|
package org.keycloak.adapters;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.KeycloakPrincipal;
|
import org.keycloak.KeycloakPrincipal;
|
||||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
import org.keycloak.RSATokenVerifier;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.common.VerificationException;
|
import org.keycloak.common.VerificationException;
|
||||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
|
||||||
import org.keycloak.constants.AdapterConstants;
|
import org.keycloak.constants.AdapterConstants;
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
import org.keycloak.jose.jws.JWSInputException;
|
import org.keycloak.jose.jws.JWSInputException;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.IDToken;
|
import org.keycloak.representations.IDToken;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
@@ -71,7 +73,7 @@ public class CookieTokenStore {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Skip check if token is active now. It's supposed to be done later by the caller
|
// Skip check if token is active now. It's supposed to be done later by the caller
|
||||||
AccessToken accessToken = AdapterRSATokenVerifier.verifyToken(accessTokenString, deployment, false, true);
|
AccessToken accessToken = RSATokenVerifier.verifyToken(accessTokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl(), false, true);
|
||||||
IDToken idToken;
|
IDToken idToken;
|
||||||
if (idTokenString != null && idTokenString.length() > 0) {
|
if (idTokenString != null && idTokenString.length() > 0) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,79 +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.client.methods.HttpRequestBase;
|
|
||||||
import org.keycloak.util.JsonSerialization;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class HttpAdapterUtils {
|
|
||||||
|
|
||||||
|
|
||||||
public static <T> T sendJsonHttpRequest(KeycloakDeployment deployment, HttpRequestBase httpRequest, Class<T> clazz) throws HttpClientAdapterException {
|
|
||||||
try {
|
|
||||||
HttpResponse response = deployment.getClient().execute(httpRequest);
|
|
||||||
int status = response.getStatusLine().getStatusCode();
|
|
||||||
if (status != 200) {
|
|
||||||
close(response);
|
|
||||||
throw new HttpClientAdapterException("Unexpected status = " + status);
|
|
||||||
}
|
|
||||||
HttpEntity entity = response.getEntity();
|
|
||||||
if (entity == null) {
|
|
||||||
throw new HttpClientAdapterException("There was no entity.");
|
|
||||||
}
|
|
||||||
InputStream is = entity.getContent();
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
|
||||||
int c;
|
|
||||||
while ((c = is.read()) != -1) {
|
|
||||||
os.write(c);
|
|
||||||
}
|
|
||||||
byte[] bytes = os.toByteArray();
|
|
||||||
String json = new String(bytes);
|
|
||||||
return JsonSerialization.readValue(json, clazz);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
is.close();
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new HttpClientAdapterException("IO error", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void close(HttpResponse response) {
|
|
||||||
if (response.getEntity() != null) {
|
|
||||||
try {
|
|
||||||
response.getEntity().getContent().close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-4
@@ -38,7 +38,7 @@ import org.apache.http.params.BasicHttpParams;
|
|||||||
import org.apache.http.params.HttpConnectionParams;
|
import org.apache.http.params.HttpConnectionParams;
|
||||||
import org.keycloak.common.util.EnvUtil;
|
import org.keycloak.common.util.EnvUtil;
|
||||||
import org.keycloak.common.util.KeystoreUtil;
|
import org.keycloak.common.util.KeystoreUtil;
|
||||||
import org.keycloak.representations.adapters.config.AdapterHttpClientConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
@@ -333,7 +333,7 @@ public class HttpClientBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpClient build(AdapterHttpClientConfig adapterConfig) {
|
public HttpClient build(AdapterConfig adapterConfig) {
|
||||||
disableCookieCache(); // disable cookie cache as we don't want sticky sessions for load balancing
|
disableCookieCache(); // disable cookie cache as we don't want sticky sessions for load balancing
|
||||||
|
|
||||||
String truststorePath = adapterConfig.getTruststore();
|
String truststorePath = adapterConfig.getTruststore();
|
||||||
@@ -379,13 +379,13 @@ public class HttpClientBuilder {
|
|||||||
/**
|
/**
|
||||||
* Configures a the proxy to use for auth-server requests if provided.
|
* Configures a the proxy to use for auth-server requests if provided.
|
||||||
* <p>
|
* <p>
|
||||||
* If the given {@link AdapterHttpClientConfig} contains the attribute {@code proxy-url} we use the
|
* If the given {@link AdapterConfig} contains the attribute {@code proxy-url} we use the
|
||||||
* given URL as a proxy server, otherwise the proxy configuration is ignored.
|
* given URL as a proxy server, otherwise the proxy configuration is ignored.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param adapterConfig
|
* @param adapterConfig
|
||||||
*/
|
*/
|
||||||
private void configureProxyForAuthServerIfProvided(AdapterHttpClientConfig adapterConfig) {
|
private void configureProxyForAuthServerIfProvided(AdapterConfig adapterConfig) {
|
||||||
|
|
||||||
if (adapterConfig == null || adapterConfig.getProxyUrl() == null || adapterConfig.getProxyUrl().trim().isEmpty()) {
|
if (adapterConfig == null || adapterConfig.getProxyUrl() == null || adapterConfig.getProxyUrl().trim().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+9
-24
@@ -21,15 +21,15 @@ import org.apache.http.client.HttpClient;
|
|||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.authentication.ClientCredentialsProvider;
|
import org.keycloak.adapters.authentication.ClientCredentialsProvider;
|
||||||
import org.keycloak.adapters.authorization.PolicyEnforcer;
|
import org.keycloak.adapters.authorization.PolicyEnforcer;
|
||||||
import org.keycloak.adapters.rotation.PublicKeyLocator;
|
import org.keycloak.constants.ServiceUrlConstants;
|
||||||
import org.keycloak.common.enums.RelativeUrlsUsed;
|
import org.keycloak.common.enums.RelativeUrlsUsed;
|
||||||
import org.keycloak.common.enums.SslRequired;
|
import org.keycloak.common.enums.SslRequired;
|
||||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
|
||||||
import org.keycloak.constants.ServiceUrlConstants;
|
|
||||||
import org.keycloak.enums.TokenStore;
|
import org.keycloak.enums.TokenStore;
|
||||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.PublicKey;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ public class KeycloakDeployment {
|
|||||||
|
|
||||||
protected RelativeUrlsUsed relativeUrls;
|
protected RelativeUrlsUsed relativeUrls;
|
||||||
protected String realm;
|
protected String realm;
|
||||||
protected PublicKeyLocator publicKeyLocator;
|
protected volatile PublicKey realmKey;
|
||||||
protected String authServerBaseUrl;
|
protected String authServerBaseUrl;
|
||||||
protected String realmInfoUrl;
|
protected String realmInfoUrl;
|
||||||
protected KeycloakUriBuilder authUrl;
|
protected KeycloakUriBuilder authUrl;
|
||||||
@@ -52,7 +52,6 @@ public class KeycloakDeployment {
|
|||||||
protected String accountUrl;
|
protected String accountUrl;
|
||||||
protected String registerNodeUrl;
|
protected String registerNodeUrl;
|
||||||
protected String unregisterNodeUrl;
|
protected String unregisterNodeUrl;
|
||||||
protected String jwksUrl;
|
|
||||||
protected String principalAttribute = "sub";
|
protected String principalAttribute = "sub";
|
||||||
|
|
||||||
protected String resourceName;
|
protected String resourceName;
|
||||||
@@ -80,14 +79,13 @@ public class KeycloakDeployment {
|
|||||||
|
|
||||||
protected volatile int notBefore;
|
protected volatile int notBefore;
|
||||||
protected int tokenMinimumTimeToLive;
|
protected int tokenMinimumTimeToLive;
|
||||||
protected int minTimeBetweenJwksRequests;
|
|
||||||
private PolicyEnforcer policyEnforcer;
|
private PolicyEnforcer policyEnforcer;
|
||||||
|
|
||||||
public KeycloakDeployment() {
|
public KeycloakDeployment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConfigured() {
|
public boolean isConfigured() {
|
||||||
return getRealm() != null && getPublicKeyLocator() != null && (isBearerOnly() || getAuthServerBaseUrl() != null);
|
return getRealm() != null && getRealmKey() != null && (isBearerOnly() || getAuthServerBaseUrl() != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getResourceName() {
|
public String getResourceName() {
|
||||||
@@ -102,12 +100,12 @@ public class KeycloakDeployment {
|
|||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PublicKeyLocator getPublicKeyLocator() {
|
public PublicKey getRealmKey() {
|
||||||
return publicKeyLocator;
|
return realmKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPublicKeyLocator(PublicKeyLocator publicKeyLocator) {
|
public void setRealmKey(PublicKey realmKey) {
|
||||||
this.publicKeyLocator = publicKeyLocator;
|
this.realmKey = realmKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAuthServerBaseUrl() {
|
public String getAuthServerBaseUrl() {
|
||||||
@@ -149,7 +147,6 @@ public class KeycloakDeployment {
|
|||||||
accountUrl = authUrlBuilder.clone().path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH).build(getRealm()).toString();
|
accountUrl = authUrlBuilder.clone().path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH).build(getRealm()).toString();
|
||||||
registerNodeUrl = authUrlBuilder.clone().path(ServiceUrlConstants.CLIENTS_MANAGEMENT_REGISTER_NODE_PATH).build(getRealm()).toString();
|
registerNodeUrl = authUrlBuilder.clone().path(ServiceUrlConstants.CLIENTS_MANAGEMENT_REGISTER_NODE_PATH).build(getRealm()).toString();
|
||||||
unregisterNodeUrl = authUrlBuilder.clone().path(ServiceUrlConstants.CLIENTS_MANAGEMENT_UNREGISTER_NODE_PATH).build(getRealm()).toString();
|
unregisterNodeUrl = authUrlBuilder.clone().path(ServiceUrlConstants.CLIENTS_MANAGEMENT_UNREGISTER_NODE_PATH).build(getRealm()).toString();
|
||||||
jwksUrl = authUrlBuilder.clone().path(ServiceUrlConstants.JWKS_URL).build(getRealm()).toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RelativeUrlsUsed getRelativeUrls() {
|
public RelativeUrlsUsed getRelativeUrls() {
|
||||||
@@ -184,10 +181,6 @@ public class KeycloakDeployment {
|
|||||||
return unregisterNodeUrl;
|
return unregisterNodeUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getJwksUrl() {
|
|
||||||
return jwksUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setResourceName(String resourceName) {
|
public void setResourceName(String resourceName) {
|
||||||
this.resourceName = resourceName;
|
this.resourceName = resourceName;
|
||||||
}
|
}
|
||||||
@@ -376,14 +369,6 @@ public class KeycloakDeployment {
|
|||||||
this.tokenMinimumTimeToLive = tokenMinimumTimeToLive;
|
this.tokenMinimumTimeToLive = tokenMinimumTimeToLive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinTimeBetweenJwksRequests() {
|
|
||||||
return minTimeBetweenJwksRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMinTimeBetweenJwksRequests(int minTimeBetweenJwksRequests) {
|
|
||||||
this.minTimeBetweenJwksRequests = minTimeBetweenJwksRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPolicyEnforcer(PolicyEnforcer policyEnforcer) {
|
public void setPolicyEnforcer(PolicyEnforcer policyEnforcer) {
|
||||||
this.policyEnforcer = policyEnforcer;
|
this.policyEnforcer = policyEnforcer;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-10
@@ -22,8 +22,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||||
import org.keycloak.adapters.authorization.PolicyEnforcer;
|
import org.keycloak.adapters.authorization.PolicyEnforcer;
|
||||||
import org.keycloak.adapters.rotation.HardcodedPublicKeyLocator;
|
|
||||||
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
|
|
||||||
import org.keycloak.common.enums.SslRequired;
|
import org.keycloak.common.enums.SslRequired;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
import org.keycloak.enums.TokenStore;
|
import org.keycloak.enums.TokenStore;
|
||||||
@@ -61,16 +59,11 @@ public class KeycloakDeploymentBuilder {
|
|||||||
PublicKey realmKey;
|
PublicKey realmKey;
|
||||||
try {
|
try {
|
||||||
realmKey = PemUtils.decodePublicKey(realmKeyPem);
|
realmKey = PemUtils.decodePublicKey(realmKeyPem);
|
||||||
HardcodedPublicKeyLocator pkLocator = new HardcodedPublicKeyLocator(realmKey);
|
|
||||||
deployment.setPublicKeyLocator(pkLocator);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
} else {
|
deployment.setRealmKey(realmKey);
|
||||||
JWKPublicKeyLocator pkLocator = new JWKPublicKeyLocator();
|
|
||||||
deployment.setPublicKeyLocator(pkLocator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adapterConfig.getSslRequired() != null) {
|
if (adapterConfig.getSslRequired() != null) {
|
||||||
deployment.setSslRequired(SslRequired.valueOf(adapterConfig.getSslRequired().toUpperCase()));
|
deployment.setSslRequired(SslRequired.valueOf(adapterConfig.getSslRequired().toUpperCase()));
|
||||||
} else {
|
} else {
|
||||||
@@ -104,7 +97,6 @@ public class KeycloakDeploymentBuilder {
|
|||||||
deployment.setRegisterNodeAtStartup(adapterConfig.isRegisterNodeAtStartup());
|
deployment.setRegisterNodeAtStartup(adapterConfig.isRegisterNodeAtStartup());
|
||||||
deployment.setRegisterNodePeriod(adapterConfig.getRegisterNodePeriod());
|
deployment.setRegisterNodePeriod(adapterConfig.getRegisterNodePeriod());
|
||||||
deployment.setTokenMinimumTimeToLive(adapterConfig.getTokenMinimumTimeToLive());
|
deployment.setTokenMinimumTimeToLive(adapterConfig.getTokenMinimumTimeToLive());
|
||||||
deployment.setMinTimeBetweenJwksRequests(adapterConfig.getMinTimeBetweenJwksRequests());
|
|
||||||
|
|
||||||
if (realmKeyPem == null && adapterConfig.isBearerOnly() && adapterConfig.getAuthServerUrl() == null) {
|
if (realmKeyPem == null && adapterConfig.isBearerOnly() && adapterConfig.getAuthServerUrl() == null) {
|
||||||
throw new IllegalArgumentException("For bearer auth, you must set the realm-public-key or auth-server-url");
|
throw new IllegalArgumentException("For bearer auth, you must set the realm-public-key or auth-server-url");
|
||||||
@@ -113,7 +105,7 @@ public class KeycloakDeploymentBuilder {
|
|||||||
deployment.setClient(new HttpClientBuilder().build(adapterConfig));
|
deployment.setClient(new HttpClientBuilder().build(adapterConfig));
|
||||||
}
|
}
|
||||||
if (adapterConfig.getAuthServerUrl() == null && (!deployment.isBearerOnly() || realmKeyPem == null)) {
|
if (adapterConfig.getAuthServerUrl() == null && (!deployment.isBearerOnly() || realmKeyPem == null)) {
|
||||||
throw new RuntimeException("You must specify auth-server-url");
|
throw new RuntimeException("You must specify auth-url");
|
||||||
}
|
}
|
||||||
deployment.setAuthServerBaseUrl(adapterConfig);
|
deployment.setAuthServerBaseUrl(adapterConfig);
|
||||||
if (adapterConfig.getTurnOffChangeSessionIdOnLogin() != null) {
|
if (adapterConfig.getTurnOffChangeSessionIdOnLogin() != null) {
|
||||||
|
|||||||
+4
-4
@@ -17,10 +17,6 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters;
|
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.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -28,6 +24,10 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.common.util.HostUtils;
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
|
|||||||
+4
-4
@@ -19,14 +19,12 @@ package org.keycloak.adapters;
|
|||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
import org.keycloak.RSATokenVerifier;
|
||||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||||
import org.keycloak.adapters.spi.AuthChallenge;
|
import org.keycloak.adapters.spi.AuthChallenge;
|
||||||
import org.keycloak.adapters.spi.AuthOutcome;
|
import org.keycloak.adapters.spi.AuthOutcome;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.common.VerificationException;
|
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.constants.AdapterConstants;
|
||||||
import org.keycloak.enums.TokenStore;
|
import org.keycloak.enums.TokenStore;
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
@@ -34,6 +32,8 @@ import org.keycloak.jose.jws.JWSInputException;
|
|||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.representations.IDToken;
|
import org.keycloak.representations.IDToken;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
|
import org.keycloak.common.util.UriUtils;
|
||||||
import org.keycloak.util.TokenUtil;
|
import org.keycloak.util.TokenUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -342,7 +342,7 @@ public class OAuthRequestAuthenticator {
|
|||||||
refreshToken = tokenResponse.getRefreshToken();
|
refreshToken = tokenResponse.getRefreshToken();
|
||||||
idTokenString = tokenResponse.getIdToken();
|
idTokenString = tokenResponse.getIdToken();
|
||||||
try {
|
try {
|
||||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||||
if (idTokenString != null) {
|
if (idTokenString != null) {
|
||||||
try {
|
try {
|
||||||
JWSInput input = new JWSInput(idTokenString);
|
JWSInput input = new JWSInput(idTokenString);
|
||||||
|
|||||||
+2
-41
@@ -17,32 +17,20 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters;
|
package org.keycloak.adapters;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.authentication.ClientCredentialsProvider;
|
|
||||||
import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
|
|
||||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.adapters.spi.UserSessionManagement;
|
import org.keycloak.adapters.spi.UserSessionManagement;
|
||||||
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.jose.jws.JWSInputException;
|
import org.keycloak.jose.jws.JWSInputException;
|
||||||
import org.keycloak.representations.VersionRepresentation;
|
import org.keycloak.representations.VersionRepresentation;
|
||||||
import org.keycloak.constants.AdapterConstants;
|
import org.keycloak.constants.AdapterConstants;
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
import org.keycloak.jose.jws.JWSInputException;
|
|
||||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||||
import org.keycloak.representations.VersionRepresentation;
|
|
||||||
import org.keycloak.representations.adapters.action.AdminAction;
|
import org.keycloak.representations.adapters.action.AdminAction;
|
||||||
import org.keycloak.representations.adapters.action.LogoutAction;
|
import org.keycloak.representations.adapters.action.LogoutAction;
|
||||||
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
|
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
|
||||||
import org.keycloak.representations.adapters.action.TestAvailabilityAction;
|
import org.keycloak.representations.adapters.action.TestAvailabilityAction;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
import org.keycloak.common.util.StreamUtil;
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
@@ -94,10 +82,6 @@ public class PreAuthActionsHandler {
|
|||||||
if (!resolveDeployment()) return true;
|
if (!resolveDeployment()) return true;
|
||||||
handleTestAvailable();
|
handleTestAvailable();
|
||||||
return true;
|
return true;
|
||||||
} else if (requestUri.endsWith(AdapterConstants.K_JWKS)) {
|
|
||||||
if (!resolveDeployment()) return true;
|
|
||||||
handleJwksRequest();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -214,8 +198,7 @@ public class PreAuthActionsHandler {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
JWSInput input = new JWSInput(token);
|
JWSInput input = new JWSInput(token);
|
||||||
PublicKey publicKey = AdapterRSATokenVerifier.getPublicKey(input.getHeader().getKeyId(), deployment);
|
if (RSAProvider.verify(input, deployment.getRealmKey())) {
|
||||||
if (RSAProvider.verify(input, publicKey)) {
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
} catch (JWSInputException ignore) {
|
} catch (JWSInputException ignore) {
|
||||||
@@ -257,26 +240,4 @@ public class PreAuthActionsHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -20,7 +20,7 @@ package org.keycloak.adapters;
|
|||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.AuthorizationContext;
|
import org.keycloak.AuthorizationContext;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
import org.keycloak.RSATokenVerifier;
|
||||||
import org.keycloak.common.VerificationException;
|
import org.keycloak.common.VerificationException;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
@@ -130,7 +130,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
|
|||||||
String tokenString = response.getToken();
|
String tokenString = response.getToken();
|
||||||
AccessToken token = null;
|
AccessToken token = null;
|
||||||
try {
|
try {
|
||||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||||
log.debug("Token Verification succeeded!");
|
log.debug("Token Verification succeeded!");
|
||||||
} catch (VerificationException e) {
|
} catch (VerificationException e) {
|
||||||
log.error("failed verification of token");
|
log.error("failed verification of token");
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ import org.apache.http.client.methods.HttpPost;
|
|||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||||
import org.keycloak.common.util.HostUtils;
|
|
||||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
|
||||||
import org.keycloak.common.util.StreamUtil;
|
|
||||||
import org.keycloak.constants.AdapterConstants;
|
import org.keycloak.constants.AdapterConstants;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
|
import org.keycloak.common.util.HostUtils;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
|
import org.keycloak.common.util.StreamUtil;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|||||||
+2
-2
@@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.authentication;
|
package org.keycloak.adapters.authentication;
|
||||||
|
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The simple SPI for authenticating clients/applications . It's used by adapter during all OIDC backchannel requests to Keycloak server
|
* The simple SPI for authenticating clients/applications . It's used by adapter during all OIDC backchannel requests to Keycloak server
|
||||||
* (codeToToken exchange, refresh token or backchannel logout) . You can also use it in your application during direct access grants or service account request
|
* (codeToToken exchange, refresh token or backchannel logout) . You can also use it in your application during direct access grants or service account request
|
||||||
|
|||||||
+6
-6
@@ -17,12 +17,6 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.authentication;
|
package org.keycloak.adapters.authentication;
|
||||||
|
|
||||||
import org.apache.http.NameValuePair;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -30,6 +24,12 @@ import java.util.Map;
|
|||||||
import java.util.ServiceConfigurationError;
|
import java.util.ServiceConfigurationError;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
import org.apache.http.NameValuePair;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-2
@@ -17,14 +17,14 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.authentication;
|
package org.keycloak.adapters.authentication;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
import org.keycloak.util.BasicAuthHelper;
|
import org.keycloak.util.BasicAuthHelper;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Traditional OAuth2 authentication of clients based on client_id and client_secret
|
* Traditional OAuth2 authentication of clients based on client_id and client_secret
|
||||||
*
|
*
|
||||||
|
|||||||
+6
-24
@@ -17,24 +17,16 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.authentication;
|
package org.keycloak.adapters.authentication;
|
||||||
|
|
||||||
import java.security.KeyPair;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.jose.jwk.JWK;
|
|
||||||
import org.keycloak.jose.jwk.JWKBuilder;
|
|
||||||
import org.keycloak.jose.jws.JWSBuilder;
|
import org.keycloak.jose.jws.JWSBuilder;
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
import org.keycloak.common.util.KeystoreUtil;
|
import org.keycloak.common.util.KeystoreUtil;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.jose.jws.JWSBuilder;
|
|
||||||
import org.keycloak.representations.JsonWebToken;
|
|
||||||
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client authentication based on JWT signed by client private key .
|
* Client authentication based on JWT signed by client private key .
|
||||||
@@ -46,9 +38,7 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
|||||||
|
|
||||||
public static final String PROVIDER_ID = "jwt";
|
public static final String PROVIDER_ID = "jwt";
|
||||||
|
|
||||||
private KeyPair keyPair;
|
private PrivateKey privateKey;
|
||||||
private JWK publicKeyJwk;
|
|
||||||
|
|
||||||
private int tokenTimeout;
|
private int tokenTimeout;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,9 +46,8 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
|||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupKeyPair(KeyPair keyPair) {
|
public void setPrivateKey(PrivateKey privateKey) {
|
||||||
this.keyPair = keyPair;
|
this.privateKey = privateKey;
|
||||||
this.publicKeyJwk = JWKBuilder.create().rs256(keyPair.getPublic());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTokenTimeout(int tokenTimeout) {
|
public void setTokenTimeout(int tokenTimeout) {
|
||||||
@@ -69,10 +58,6 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
|||||||
return tokenTimeout;
|
return tokenTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PublicKey getPublicKey() {
|
|
||||||
return keyPair.getPublic();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(KeycloakDeployment deployment, Object config) {
|
public void init(KeycloakDeployment deployment, Object config) {
|
||||||
if (config == null || !(config instanceof Map)) {
|
if (config == null || !(config instanceof Map)) {
|
||||||
@@ -103,9 +88,7 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
|||||||
if (clientKeyAlias == null) {
|
if (clientKeyAlias == null) {
|
||||||
clientKeyAlias = deployment.getResourceName();
|
clientKeyAlias = deployment.getResourceName();
|
||||||
}
|
}
|
||||||
|
this.privateKey = KeystoreUtil.loadPrivateKeyFromKeystore(clientKeystoreFile, clientKeystorePassword, clientKeyPassword, clientKeyAlias, clientKeystoreFormat);
|
||||||
KeyPair keyPair = KeystoreUtil.loadKeyPairFromKeystore(clientKeystoreFile, clientKeystorePassword, clientKeyPassword, clientKeyAlias, clientKeystoreFormat);
|
|
||||||
setupKeyPair(keyPair);
|
|
||||||
|
|
||||||
this.tokenTimeout = asInt(cfg, "token-timeout", 10);
|
this.tokenTimeout = asInt(cfg, "token-timeout", 10);
|
||||||
}
|
}
|
||||||
@@ -137,9 +120,8 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
|||||||
public String createSignedRequestToken(String clientId, String realmInfoUrl) {
|
public String createSignedRequestToken(String clientId, String realmInfoUrl) {
|
||||||
JsonWebToken jwt = createRequestToken(clientId, realmInfoUrl);
|
JsonWebToken jwt = createRequestToken(clientId, realmInfoUrl);
|
||||||
return new JWSBuilder()
|
return new JWSBuilder()
|
||||||
.kid(publicKeyJwk.getKeyId())
|
|
||||||
.jsonContent(jwt)
|
.jsonContent(jwt)
|
||||||
.rsa256(keyPair.getPrivate());
|
.rsa256(privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JsonWebToken createRequestToken(String clientId, String realmInfoUrl) {
|
protected JsonWebToken createRequestToken(String clientId, String realmInfoUrl) {
|
||||||
|
|||||||
+34
-56
@@ -19,7 +19,6 @@ package org.keycloak.adapters.authorization;
|
|||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.AuthorizationContext;
|
import org.keycloak.AuthorizationContext;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
|
||||||
import org.keycloak.adapters.OIDCHttpFacade;
|
import org.keycloak.adapters.OIDCHttpFacade;
|
||||||
import org.keycloak.adapters.spi.HttpFacade.Request;
|
import org.keycloak.adapters.spi.HttpFacade.Request;
|
||||||
import org.keycloak.adapters.spi.HttpFacade.Response;
|
import org.keycloak.adapters.spi.HttpFacade.Response;
|
||||||
@@ -33,7 +32,6 @@ import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathCon
|
|||||||
import org.keycloak.representations.idm.authorization.Permission;
|
import org.keycloak.representations.idm.authorization.Permission;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -57,7 +55,7 @@ public abstract class AbstractPolicyEnforcer {
|
|||||||
this.enforcerConfig = policyEnforcer.getEnforcerConfig();
|
this.enforcerConfig = policyEnforcer.getEnforcerConfig();
|
||||||
this.authzClient = policyEnforcer.getClient();
|
this.authzClient = policyEnforcer.getClient();
|
||||||
this.pathMatcher = new PathMatcher();
|
this.pathMatcher = new PathMatcher();
|
||||||
this.paths = new ArrayList<>(policyEnforcer.getPaths());
|
this.paths = policyEnforcer.getPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthorizationContext authorize(OIDCHttpFacade httpFacade) {
|
public AuthorizationContext authorize(OIDCHttpFacade httpFacade) {
|
||||||
@@ -67,51 +65,40 @@ public abstract class AbstractPolicyEnforcer {
|
|||||||
return createEmptyAuthorizationContext(true);
|
return createEmptyAuthorizationContext(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
|
AccessToken accessToken = httpFacade.getSecurityContext().getToken();
|
||||||
|
Request request = httpFacade.getRequest();
|
||||||
|
Response response = httpFacade.getResponse();
|
||||||
|
String pathInfo = URI.create(request.getURI()).getPath().substring(1);
|
||||||
|
String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
|
||||||
|
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
|
||||||
|
|
||||||
if (securityContext != null) {
|
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
|
||||||
AccessToken accessToken = securityContext.getToken();
|
|
||||||
|
|
||||||
if (accessToken != null) {
|
if (pathConfig == null) {
|
||||||
Request request = httpFacade.getRequest();
|
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
|
||||||
Response response = httpFacade.getResponse();
|
return createAuthorizationContext(accessToken);
|
||||||
String pathInfo = URI.create(request.getURI()).getPath().substring(1);
|
|
||||||
String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
|
|
||||||
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
|
|
||||||
|
|
||||||
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
|
|
||||||
|
|
||||||
if (pathConfig == null) {
|
|
||||||
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
|
|
||||||
return createAuthorizationContext(accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.debugf("Could not find a configuration for path [%s]", path);
|
|
||||||
response.sendError(403, "Could not find a configuration for path [" + path + "].");
|
|
||||||
|
|
||||||
return createEmptyAuthorizationContext(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
|
|
||||||
return createEmptyAuthorizationContext(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
|
|
||||||
Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
|
|
||||||
|
|
||||||
if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
|
|
||||||
try {
|
|
||||||
return createAuthorizationContext(accessToken);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
|
|
||||||
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
|
|
||||||
response.sendError(403, "Authorization failed.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGGER.debugf("Could not find a configuration for path [%s]", path);
|
||||||
|
response.sendError(403, "Could not find a configuration for path [" + path + "].");
|
||||||
|
|
||||||
|
return createEmptyAuthorizationContext(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
|
||||||
|
Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
|
||||||
|
|
||||||
|
if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
|
||||||
|
try {
|
||||||
|
return createAuthorizationContext(accessToken);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
|
||||||
|
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
|
||||||
|
response.sendError(403, "Authorization failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return createEmptyAuthorizationContext(false);
|
return createEmptyAuthorizationContext(false);
|
||||||
@@ -122,7 +109,7 @@ public abstract class AbstractPolicyEnforcer {
|
|||||||
protected boolean isAuthorized(PathConfig actualPathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
protected boolean isAuthorized(PathConfig actualPathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||||
Request request = httpFacade.getRequest();
|
Request request = httpFacade.getRequest();
|
||||||
PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
|
PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
|
||||||
String accessDeniedPath = enforcerConfig.getOnDenyRedirectTo();
|
String accessDeniedPath = enforcerConfig.getAccessDeniedPath();
|
||||||
|
|
||||||
if (accessDeniedPath != null) {
|
if (accessDeniedPath != null) {
|
||||||
if (request.getURI().contains(accessDeniedPath)) {
|
if (request.getURI().contains(accessDeniedPath)) {
|
||||||
@@ -137,17 +124,14 @@ public abstract class AbstractPolicyEnforcer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Permission> permissions = authorization.getPermissions();
|
List<Permission> permissions = authorization.getPermissions();
|
||||||
boolean hasPermission = false;
|
|
||||||
|
|
||||||
for (Permission permission : permissions) {
|
for (Permission permission : permissions) {
|
||||||
if (permission.getResourceSetId() != null) {
|
if (permission.getResourceSetId() != null) {
|
||||||
if (isResourcePermission(actualPathConfig, permission)) {
|
if (isResourcePermission(actualPathConfig, permission)) {
|
||||||
hasPermission = true;
|
|
||||||
|
|
||||||
if (actualPathConfig.isInstance() && !matchResourcePermission(actualPathConfig, permission)) {
|
if (actualPathConfig.isInstance() && !matchResourcePermission(actualPathConfig, permission)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
|
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
|
||||||
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
|
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
|
||||||
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
|
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
|
||||||
@@ -158,16 +142,11 @@ public abstract class AbstractPolicyEnforcer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
|
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
|
||||||
hasPermission = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasPermission && EnforcementMode.PERMISSIVE.equals(actualPathConfig.getEnforcementMode())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.debugf("Authorization FAILED for path [%s]. No enough permissions [%s].", actualPathConfig, permissions);
|
LOGGER.debugf("Authorization FAILED for path [%s]. No enough permissions [%s].", actualPathConfig, permissions);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -238,7 +217,6 @@ public abstract class AbstractPolicyEnforcer {
|
|||||||
config.setScopes(originalConfig.getScopes());
|
config.setScopes(originalConfig.getScopes());
|
||||||
config.setMethods(originalConfig.getMethods());
|
config.setMethods(originalConfig.getMethods());
|
||||||
config.setParentConfig(originalConfig);
|
config.setParentConfig(originalConfig);
|
||||||
config.setEnforcementMode(originalConfig.getEnforcementMode());
|
|
||||||
|
|
||||||
this.paths.add(config);
|
this.paths.add(config);
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -26,6 +26,7 @@ import org.keycloak.authorization.client.resource.PermissionResource;
|
|||||||
import org.keycloak.authorization.client.resource.ProtectionResource;
|
import org.keycloak.authorization.client.resource.ProtectionResource;
|
||||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,7 +42,7 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
||||||
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
if (getEnforcerConfig().getUmaProtocolConfig() != null) {
|
||||||
challengeUmaAuthentication(pathConfig, requiredScopes, facade);
|
challengeUmaAuthentication(pathConfig, requiredScopes, facade);
|
||||||
} else {
|
} else {
|
||||||
challengeEntitlementAuthentication(facade);
|
challengeEntitlementAuthentication(facade);
|
||||||
|
|||||||
+7
-6
@@ -18,9 +18,9 @@
|
|||||||
package org.keycloak.adapters.authorization;
|
package org.keycloak.adapters.authorization;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.RSATokenVerifier;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.OIDCHttpFacade;
|
import org.keycloak.adapters.OIDCHttpFacade;
|
||||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.authorization.client.AuthorizationDeniedException;
|
import org.keycloak.authorization.client.AuthorizationDeniedException;
|
||||||
import org.keycloak.authorization.client.AuthzClient;
|
import org.keycloak.authorization.client.AuthzClient;
|
||||||
@@ -33,6 +33,7 @@ import org.keycloak.authorization.client.representation.PermissionResponse;
|
|||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||||
import org.keycloak.representations.idm.authorization.Permission;
|
import org.keycloak.representations.idm.authorization.Permission;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -88,7 +89,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
||||||
String accessDeniedPath = getEnforcerConfig().getOnDenyRedirectTo();
|
String accessDeniedPath = getEnforcerConfig().getAccessDeniedPath();
|
||||||
HttpFacade.Response response = facade.getResponse();
|
HttpFacade.Response response = facade.getResponse();
|
||||||
|
|
||||||
if (accessDeniedPath != null) {
|
if (accessDeniedPath != null) {
|
||||||
@@ -107,7 +108,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||||||
AuthzClient authzClient = getAuthzClient();
|
AuthzClient authzClient = getAuthzClient();
|
||||||
KeycloakDeployment deployment = getPolicyEnforcer().getDeployment();
|
KeycloakDeployment deployment = getPolicyEnforcer().getDeployment();
|
||||||
|
|
||||||
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
if (getEnforcerConfig().getUmaProtocolConfig() != null) {
|
||||||
LOGGER.debug("Obtaining authorization for authenticated user.");
|
LOGGER.debug("Obtaining authorization for authenticated user.");
|
||||||
PermissionRequest permissionRequest = new PermissionRequest();
|
PermissionRequest permissionRequest = new PermissionRequest();
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||||||
AuthorizationResponse authzResponse = authzClient.authorization(accessToken).authorize(authzRequest);
|
AuthorizationResponse authzResponse = authzClient.authorization(accessToken).authorize(authzRequest);
|
||||||
|
|
||||||
if (authzResponse != null) {
|
if (authzResponse != null) {
|
||||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -129,7 +130,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||||||
|
|
||||||
if (token.getAuthorization() == null) {
|
if (token.getAuthorization() == null) {
|
||||||
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getClientId());
|
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getClientId());
|
||||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||||
} else {
|
} else {
|
||||||
EntitlementRequest request = new EntitlementRequest();
|
EntitlementRequest request = new EntitlementRequest();
|
||||||
PermissionRequest permissionRequest = new PermissionRequest();
|
PermissionRequest permissionRequest = new PermissionRequest();
|
||||||
@@ -138,7 +139,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||||||
permissionRequest.setScopes(new HashSet<>(pathConfig.getScopes()));
|
permissionRequest.setScopes(new HashSet<>(pathConfig.getScopes()));
|
||||||
request.addPermission(permissionRequest);
|
request.addPermission(permissionRequest);
|
||||||
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).get(authzClient.getConfiguration().getClientId(), request);
|
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).get(authzClient.getConfiguration().getClientId(), request);
|
||||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (AuthorizationDeniedException e) {
|
} catch (AuthorizationDeniedException e) {
|
||||||
|
|||||||
+5
-29
@@ -33,7 +33,6 @@ import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathCon
|
|||||||
import org.keycloak.representations.idm.authorization.Permission;
|
import org.keycloak.representations.idm.authorization.Permission;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -96,8 +95,8 @@ public class PolicyEnforcer {
|
|||||||
return authzClient;
|
return authzClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PathConfig> getPaths() {
|
List<PathConfig> getPaths() {
|
||||||
return Collections.unmodifiableList(paths);
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeycloakDeployment getDeployment() {
|
KeycloakDeployment getDeployment() {
|
||||||
@@ -105,16 +104,7 @@ public class PolicyEnforcer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<PathConfig> configurePaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
|
private List<PathConfig> configurePaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
|
||||||
boolean loadPathsFromServer = true;
|
if (enforcerConfig.getPaths().isEmpty()) {
|
||||||
|
|
||||||
for (PathConfig pathConfig : enforcerConfig.getPaths()) {
|
|
||||||
if (!PolicyEnforcerConfig.EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
|
|
||||||
loadPathsFromServer = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadPathsFromServer) {
|
|
||||||
LOGGER.info("No path provided in configuration.");
|
LOGGER.info("No path provided in configuration.");
|
||||||
return configureAllPathsForResourceServer(protectedResource);
|
return configureAllPathsForResourceServer(protectedResource);
|
||||||
} else {
|
} else {
|
||||||
@@ -164,27 +154,13 @@ public class PolicyEnforcer {
|
|||||||
|
|
||||||
pathConfig.setId(registrationResponse.getId());
|
pathConfig.setId(registrationResponse.getId());
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Could not find matching resource on server with uri [" + path + "] or name [" + resourceName + "]. Make sure you have created a resource on the server that matches with the path configuration.");
|
throw new RuntimeException("Could not find matching resource on server with uri [" + path + "] or name [" + resourceName + ". Make sure you have created a resource on the server that matches with the path configuration.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pathConfig.setId(search.iterator().next());
|
pathConfig.setId(search.iterator().next());
|
||||||
}
|
}
|
||||||
|
|
||||||
PathConfig existingPath = null;
|
paths.add(pathConfig);
|
||||||
|
|
||||||
for (PathConfig current : paths) {
|
|
||||||
if (current.getId().equals(pathConfig.getId()) && current.getPath().equals(pathConfig.getPath())) {
|
|
||||||
existingPath = current;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingPath == null) {
|
|
||||||
paths.add(pathConfig);
|
|
||||||
} else {
|
|
||||||
existingPath.getMethods().addAll(pathConfig.getMethods());
|
|
||||||
existingPath.getScopes().addAll(pathConfig.getScopes());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return paths;
|
return paths;
|
||||||
|
|||||||
+25
-20
@@ -17,17 +17,14 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.jaas;
|
package org.keycloak.adapters.jaas;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import java.io.InputStream;
|
||||||
import org.keycloak.KeycloakPrincipal;
|
import java.lang.reflect.Constructor;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import java.security.Principal;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import java.util.HashSet;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import java.util.Map;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import java.util.Set;
|
||||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import org.keycloak.common.VerificationException;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import org.keycloak.common.util.FindFile;
|
|
||||||
import org.keycloak.common.util.reflections.Reflections;
|
|
||||||
import org.keycloak.representations.AccessToken;
|
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
import javax.security.auth.callback.Callback;
|
import javax.security.auth.callback.Callback;
|
||||||
@@ -37,14 +34,19 @@ import javax.security.auth.callback.PasswordCallback;
|
|||||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||||
import javax.security.auth.login.LoginException;
|
import javax.security.auth.login.LoginException;
|
||||||
import javax.security.auth.spi.LoginModule;
|
import javax.security.auth.spi.LoginModule;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.lang.reflect.Constructor;
|
import org.jboss.logging.Logger;
|
||||||
import java.security.Principal;
|
import org.keycloak.KeycloakPrincipal;
|
||||||
import java.util.HashSet;
|
import org.keycloak.RSATokenVerifier;
|
||||||
import java.util.Map;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import java.util.Set;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
|
import org.keycloak.common.VerificationException;
|
||||||
|
import org.keycloak.common.util.FindFile;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.common.util.reflections.Reflections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
@@ -86,6 +88,9 @@ public abstract class AbstractKeycloakLoginModule implements LoginModule {
|
|||||||
try {
|
try {
|
||||||
InputStream is = FindFile.findFile(keycloakConfigFile);
|
InputStream is = FindFile.findFile(keycloakConfigFile);
|
||||||
KeycloakDeployment kd = KeycloakDeploymentBuilder.build(is);
|
KeycloakDeployment kd = KeycloakDeploymentBuilder.build(is);
|
||||||
|
if (kd.getRealmKey() == null) {
|
||||||
|
new AdapterDeploymentContext().resolveRealmKey(kd);
|
||||||
|
}
|
||||||
return kd;
|
return kd;
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
getLogger().debug("Unable to find or parse file " + keycloakConfigFile + " due to " + e.getMessage(), e);
|
getLogger().debug("Unable to find or parse file " + keycloakConfigFile + " due to " + e.getMessage(), e);
|
||||||
@@ -185,7 +190,7 @@ public abstract class AbstractKeycloakLoginModule implements LoginModule {
|
|||||||
|
|
||||||
|
|
||||||
protected Auth bearerAuth(String tokenString) throws VerificationException {
|
protected Auth bearerAuth(String tokenString) throws VerificationException {
|
||||||
AccessToken token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
AccessToken token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||||
|
|
||||||
boolean verifyCaller;
|
boolean verifyCaller;
|
||||||
if (deployment.isUseResourceRoleMappings()) {
|
if (deployment.isUseResourceRoleMappings()) {
|
||||||
|
|||||||
+21
-21
@@ -17,6 +17,19 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.jaas;
|
package org.keycloak.adapters.jaas;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
|
import javax.security.auth.login.LoginException;
|
||||||
|
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.NameValuePair;
|
import org.apache.http.NameValuePair;
|
||||||
@@ -26,25 +39,12 @@ import org.apache.http.client.methods.HttpPost;
|
|||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
|
||||||
import org.keycloak.common.VerificationException;
|
import org.keycloak.common.VerificationException;
|
||||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||||
import org.keycloak.constants.ServiceUrlConstants;
|
import org.keycloak.constants.ServiceUrlConstants;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
|
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
import javax.security.auth.Subject;
|
|
||||||
import javax.security.auth.callback.CallbackHandler;
|
|
||||||
import javax.security.auth.login.LoginException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login module based on Resource Owner password credentials grant from OAuth2 specs. It's supposed to be used in environments. which
|
* Login module based on Resource Owner password credentials grant from OAuth2 specs. It's supposed to be used in environments. which
|
||||||
@@ -102,9 +102,9 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
|
|||||||
StringBuilder errorBuilder = new StringBuilder("Login failed. Invalid status: " + status);
|
StringBuilder errorBuilder = new StringBuilder("Login failed. Invalid status: " + status);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
InputStream is = entity.getContent();
|
InputStream is = entity.getContent();
|
||||||
OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(is, OAuth2ErrorRepresentation.class);
|
Map<String, String> errors = (Map<String, String>) JsonSerialization.readValue(is, Map.class);
|
||||||
errorBuilder.append(", OAuth2 error. Error: " + errorRep.getError())
|
errorBuilder.append(", OAuth2 error. Error: " + errors.get(OAuth2Constants.ERROR))
|
||||||
.append(", Error description: " + errorRep.getErrorDescription());
|
.append(", Error description: " + errors.get(OAuth2Constants.ERROR_DESCRIPTION));
|
||||||
}
|
}
|
||||||
String error = errorBuilder.toString();
|
String error = errorBuilder.toString();
|
||||||
log.warn(error);
|
log.warn(error);
|
||||||
@@ -161,9 +161,9 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
|
|||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
InputStream is = entity.getContent();
|
InputStream is = entity.getContent();
|
||||||
if (status == 400) {
|
if (status == 400) {
|
||||||
OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(is, OAuth2ErrorRepresentation.class);
|
Map<String, String> errors = (Map<String, String>) JsonSerialization.readValue(is, Map.class);
|
||||||
errorBuilder.append(", OAuth2 error. Error: " + errorRep.getError())
|
errorBuilder.append(", OAuth2 error. Error: " + errors.get(OAuth2Constants.ERROR))
|
||||||
.append(", Error description: " + errorRep.getErrorDescription());
|
.append(", Error description: " + errors.get(OAuth2Constants.ERROR_DESCRIPTION));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (is != null) is.close();
|
if (is != null) is.close();
|
||||||
|
|||||||
-58
@@ -1,58 +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.rotation;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.RSATokenVerifier;
|
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
|
||||||
import org.keycloak.common.VerificationException;
|
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
|
||||||
import org.keycloak.representations.AccessToken;
|
|
||||||
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class AdapterRSATokenVerifier {
|
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(AdapterRSATokenVerifier.class);
|
|
||||||
|
|
||||||
public static AccessToken verifyToken(String tokenString, KeycloakDeployment deployment) throws VerificationException {
|
|
||||||
return verifyToken(tokenString, deployment, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static PublicKey getPublicKey(String kid, KeycloakDeployment deployment) throws VerificationException {
|
|
||||||
PublicKeyLocator pkLocator = deployment.getPublicKeyLocator();
|
|
||||||
|
|
||||||
PublicKey publicKey = pkLocator.getPublicKey(kid, deployment);
|
|
||||||
if (publicKey == null) {
|
|
||||||
log.errorf("Didn't find publicKey for kid: %s", kid);
|
|
||||||
throw new VerificationException("Didn't find publicKey for specified kid");
|
|
||||||
}
|
|
||||||
|
|
||||||
return publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AccessToken verifyToken(String tokenString, KeycloakDeployment deployment, boolean checkActive, boolean checkTokenType) throws VerificationException {
|
|
||||||
RSATokenVerifier verifier = RSATokenVerifier.create(tokenString).realmUrl(deployment.getRealmInfoUrl()).checkActive(checkActive).checkTokenType(checkTokenType);
|
|
||||||
PublicKey publicKey = getPublicKey(verifier.getHeader().getKeyId(), deployment);
|
|
||||||
return verifier.publicKey(publicKey).verify().getToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-101
@@ -1,101 +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.rotation;
|
|
||||||
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.adapters.HttpAdapterUtils;
|
|
||||||
import org.keycloak.adapters.HttpClientAdapterException;
|
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
import org.keycloak.jose.jwk.JSONWebKeySet;
|
|
||||||
import org.keycloak.jose.jwk.JWK;
|
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
|
||||||
import org.keycloak.util.JWKSUtils;
|
|
||||||
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When needed, publicKeys are downloaded by sending request to realm's jwks_url
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class JWKPublicKeyLocator implements PublicKeyLocator {
|
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(JWKPublicKeyLocator.class);
|
|
||||||
|
|
||||||
private Map<String, PublicKey> currentKeys = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private volatile int lastRequestTime = 0;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PublicKey getPublicKey(String kid, KeycloakDeployment deployment) {
|
|
||||||
int minTimeBetweenRequests = deployment.getMinTimeBetweenJwksRequests();
|
|
||||||
|
|
||||||
// Check if key is in cache.
|
|
||||||
PublicKey publicKey = currentKeys.get(kid);
|
|
||||||
if (publicKey != null) {
|
|
||||||
return publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
int currentTime = Time.currentTime();
|
|
||||||
|
|
||||||
// Check if we are allowed to send request
|
|
||||||
if (currentTime > lastRequestTime + minTimeBetweenRequests) {
|
|
||||||
synchronized (this) {
|
|
||||||
currentTime = Time.currentTime();
|
|
||||||
if (currentTime > lastRequestTime + minTimeBetweenRequests) {
|
|
||||||
sendRequest(deployment);
|
|
||||||
lastRequestTime = currentTime;
|
|
||||||
} else {
|
|
||||||
log.debugf("Won't send request to realm jwks url. Last request time was %d", lastRequestTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentKeys.get(kid);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void sendRequest(KeycloakDeployment deployment) {
|
|
||||||
if (log.isTraceEnabled()) {
|
|
||||||
log.tracef("Going to send request to retrieve new set of realm public keys for client %s", deployment.getResourceName());
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpGet getMethod = new HttpGet(deployment.getJwksUrl());
|
|
||||||
try {
|
|
||||||
JSONWebKeySet jwks = HttpAdapterUtils.sendJsonHttpRequest(deployment, getMethod, JSONWebKeySet.class);
|
|
||||||
|
|
||||||
Map<String, PublicKey> publicKeys = JWKSUtils.getKeysForUse(jwks, JWK.Use.SIG);
|
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debugf("Realm public keys successfully retrieved for client %s. New kids: %s", deployment.getResourceName(), publicKeys.keySet().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update current keys
|
|
||||||
currentKeys.clear();
|
|
||||||
currentKeys.putAll(publicKeys);
|
|
||||||
|
|
||||||
} catch (HttpClientAdapterException e) {
|
|
||||||
log.error("Error when sending request to retrieve realm keys", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-37
@@ -1,37 +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.rotation;
|
|
||||||
|
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
|
||||||
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public interface PublicKeyLocator {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param kid
|
|
||||||
* @param deployment
|
|
||||||
* @return publicKey, which should be used for verify signature on given "input"
|
|
||||||
*/
|
|
||||||
PublicKey getPublicKey(String kid, KeycloakDeployment deployment);
|
|
||||||
|
|
||||||
}
|
|
||||||
+2
-12
@@ -21,12 +21,10 @@ import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider;
|
import org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider;
|
||||||
import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
|
import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
|
||||||
import org.keycloak.adapters.rotation.HardcodedPublicKeyLocator;
|
|
||||||
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
|
|
||||||
import org.keycloak.common.enums.RelativeUrlsUsed;
|
import org.keycloak.common.enums.RelativeUrlsUsed;
|
||||||
import org.keycloak.common.enums.SslRequired;
|
import org.keycloak.common.enums.SslRequired;
|
||||||
import org.keycloak.common.util.PemUtils;
|
|
||||||
import org.keycloak.enums.TokenStore;
|
import org.keycloak.enums.TokenStore;
|
||||||
|
import org.keycloak.common.util.PemUtils;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -41,11 +39,7 @@ public class KeycloakDeploymentBuilderTest {
|
|||||||
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak.json"));
|
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak.json"));
|
||||||
assertEquals("demo", deployment.getRealm());
|
assertEquals("demo", deployment.getRealm());
|
||||||
assertEquals("customer-portal", deployment.getResourceName());
|
assertEquals("customer-portal", deployment.getResourceName());
|
||||||
|
assertEquals(PemUtils.decodePublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"), deployment.getRealmKey());
|
||||||
assertTrue(deployment.getPublicKeyLocator() instanceof HardcodedPublicKeyLocator);
|
|
||||||
assertEquals(PemUtils.decodePublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"),
|
|
||||||
deployment.getPublicKeyLocator().getPublicKey(null, deployment));
|
|
||||||
|
|
||||||
assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/auth", deployment.getAuthUrl().build().toString());
|
assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/auth", deployment.getAuthUrl().build().toString());
|
||||||
assertEquals(SslRequired.EXTERNAL, deployment.getSslRequired());
|
assertEquals(SslRequired.EXTERNAL, deployment.getSslRequired());
|
||||||
assertTrue(deployment.isUseResourceRoleMappings());
|
assertTrue(deployment.isUseResourceRoleMappings());
|
||||||
@@ -68,16 +62,12 @@ public class KeycloakDeploymentBuilderTest {
|
|||||||
assertEquals(TokenStore.COOKIE, deployment.getTokenStore());
|
assertEquals(TokenStore.COOKIE, deployment.getTokenStore());
|
||||||
assertEquals("email", deployment.getPrincipalAttribute());
|
assertEquals("email", deployment.getPrincipalAttribute());
|
||||||
assertEquals(10, deployment.getTokenMinimumTimeToLive());
|
assertEquals(10, deployment.getTokenMinimumTimeToLive());
|
||||||
assertEquals(20, deployment.getMinTimeBetweenJwksRequests());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loadNoClientCredentials() throws Exception {
|
public void loadNoClientCredentials() throws Exception {
|
||||||
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-no-credentials.json"));
|
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-no-credentials.json"));
|
||||||
assertEquals(ClientIdAndSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
|
assertEquals(ClientIdAndSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
|
||||||
|
|
||||||
assertTrue(deployment.getPublicKeyLocator() instanceof JWKPublicKeyLocator);
|
|
||||||
assertEquals(10, deployment.getMinTimeBetweenJwksRequests());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
package org.keycloak.adapters;
|
package org.keycloak.adapters;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
|
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
/**
|
/**
|
||||||
* @author github.com/tubbynl
|
* @author github.com/tubbynl
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"realm": "demo",
|
"realm": "demo",
|
||||||
"resource": "customer-portal",
|
"resource": "customer-portal",
|
||||||
|
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||||
"auth-server-url": "https://localhost:8443/auth",
|
"auth-server-url": "https://localhost:8443/auth",
|
||||||
"public-client": true,
|
"public-client": true,
|
||||||
"expose-token": true
|
"expose-token": true
|
||||||
|
|||||||
@@ -29,6 +29,5 @@
|
|||||||
"register-node-period": 1000,
|
"register-node-period": 1000,
|
||||||
"token-store": "cookie",
|
"token-store": "cookie",
|
||||||
"principal-attribute": "email",
|
"principal-attribute": "email",
|
||||||
"token-minimum-time-to-live": 10,
|
"token-minimum-time-to-live": 10
|
||||||
"min-time-between-jwks-requests": 20
|
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+4
@@ -22,11 +22,15 @@ import org.apache.catalina.connector.Request;
|
|||||||
import org.apache.catalina.connector.Response;
|
import org.apache.catalina.connector.Response;
|
||||||
import org.apache.catalina.core.StandardContext;
|
import org.apache.catalina.core.StandardContext;
|
||||||
import org.apache.catalina.deploy.LoginConfig;
|
import org.apache.catalina.deploy.LoginConfig;
|
||||||
|
import org.apache.catalina.realm.GenericPrincipal;
|
||||||
import org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve;
|
import org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve;
|
||||||
import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
|
import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keycloak authentication valve
|
* Keycloak authentication valve
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -68,9 +68,8 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
|
|||||||
|
|
||||||
boolean hasSubsystemConfig = service.isSecureDeployment(deploymentUnit);
|
boolean hasSubsystemConfig = service.isSecureDeployment(deploymentUnit);
|
||||||
boolean webRequiresKC = loginConfig != null && "KEYCLOAK".equalsIgnoreCase(loginConfig.getAuthMethod());
|
boolean webRequiresKC = loginConfig != null && "KEYCLOAK".equalsIgnoreCase(loginConfig.getAuthMethod());
|
||||||
boolean isConfigured = service.isDeploymentConfigured(deploymentUnit);
|
|
||||||
|
|
||||||
if ((hasSubsystemConfig && isConfigured) || webRequiresKC) {
|
if (hasSubsystemConfig || webRequiresKC) {
|
||||||
log.debug("Setting up KEYCLOAK auth method for WAR: " + deploymentUnit.getName());
|
log.debug("Setting up KEYCLOAK auth method for WAR: " + deploymentUnit.getName());
|
||||||
|
|
||||||
// if secure-deployment configuration exists for web app, we force KEYCLOAK auth method on it
|
// if secure-deployment configuration exists for web app, we force KEYCLOAK auth method on it
|
||||||
|
|||||||
+7
-21
@@ -17,17 +17,17 @@
|
|||||||
|
|
||||||
package org.keycloak.subsystem.as7;
|
package org.keycloak.subsystem.as7;
|
||||||
|
|
||||||
import org.jboss.as.server.deployment.DeploymentUnit;
|
|
||||||
import org.jboss.as.web.deployment.WarMetaData;
|
|
||||||
import org.jboss.dmr.ModelNode;
|
import org.jboss.dmr.ModelNode;
|
||||||
import org.jboss.dmr.Property;
|
import org.jboss.dmr.Property;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.metadata.web.jboss.JBossWebMetaData;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnit;
|
||||||
|
import org.jboss.as.web.deployment.WarMetaData;
|
||||||
|
import org.jboss.metadata.web.jboss.JBossWebMetaData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This service keeps track of the entire Keycloak management model so as to provide
|
* This service keeps track of the entire Keycloak management model so as to provide
|
||||||
@@ -158,22 +158,15 @@ public final class KeycloakAdapterConfigService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getRealmName(DeploymentUnit deploymentUnit) {
|
public String getRealmName(DeploymentUnit deploymentUnit) {
|
||||||
ModelNode deployment = getSecureDeployment(deploymentUnit);
|
String deploymentName = preferredDeploymentName(deploymentUnit);
|
||||||
|
ModelNode deployment = this.secureDeployments.get(deploymentName);
|
||||||
return deployment.get(RealmDefinition.TAG_NAME).asString();
|
return deployment.get(RealmDefinition.TAG_NAME).asString();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isDeploymentConfigured(DeploymentUnit deploymentUnit) {
|
|
||||||
ModelNode deployment = getSecureDeployment(deploymentUnit);
|
|
||||||
if (! deployment.isDefined()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ModelNode resource = deployment.get(SecureDeploymentDefinition.RESOURCE.getName());
|
|
||||||
return resource.isDefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getJSON(DeploymentUnit deploymentUnit) {
|
public String getJSON(DeploymentUnit deploymentUnit) {
|
||||||
ModelNode deployment = getSecureDeployment(deploymentUnit);
|
String deploymentName = preferredDeploymentName(deploymentUnit);
|
||||||
|
ModelNode deployment = this.secureDeployments.get(deploymentName);
|
||||||
String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
|
String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
|
||||||
ModelNode realm = this.realms.get(realmName);
|
ModelNode realm = this.realms.get(realmName);
|
||||||
|
|
||||||
@@ -202,13 +195,6 @@ public final class KeycloakAdapterConfigService {
|
|||||||
String deploymentName = preferredDeploymentName(deploymentUnit);
|
String deploymentName = preferredDeploymentName(deploymentUnit);
|
||||||
return this.secureDeployments.containsKey(deploymentName);
|
return this.secureDeployments.containsKey(deploymentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModelNode getSecureDeployment(DeploymentUnit deploymentUnit) {
|
|
||||||
String deploymentName = preferredDeploymentName(deploymentUnit);
|
|
||||||
return this.secureDeployments.containsKey(deploymentName)
|
|
||||||
? this.secureDeployments.get(deploymentName)
|
|
||||||
: new ModelNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
// KEYCLOAK-3273: prefer module name if available
|
// KEYCLOAK-3273: prefer module name if available
|
||||||
private String preferredDeploymentName(DeploymentUnit deploymentUnit) {
|
private String preferredDeploymentName(DeploymentUnit deploymentUnit) {
|
||||||
|
|||||||
+1
@@ -25,6 +25,7 @@ import org.jboss.as.server.AbstractDeploymentChainStep;
|
|||||||
import org.jboss.as.server.DeploymentProcessorTarget;
|
import org.jboss.as.server.DeploymentProcessorTarget;
|
||||||
import org.jboss.as.server.deployment.Phase;
|
import org.jboss.as.server.deployment.Phase;
|
||||||
import org.jboss.dmr.ModelNode;
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
import org.jboss.msc.service.ServiceController;
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
+3
-3
@@ -86,7 +86,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
|
|||||||
|
|
||||||
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
|
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
|
||||||
//TODO: externalize the message
|
//TODO: externalize the message
|
||||||
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
|
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
|
||||||
}
|
}
|
||||||
|
|
||||||
list.add(addRealm);
|
list.add(addRealm);
|
||||||
@@ -117,7 +117,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
|
|||||||
* TODO need to check realm-ref first.
|
* TODO need to check realm-ref first.
|
||||||
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
|
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
|
||||||
//TODO: externalize the message
|
//TODO: externalize the message
|
||||||
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
|
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
|
|||||||
credentialsToAdd.add(addCredential);
|
credentialsToAdd.add(addCredential);
|
||||||
} else {
|
} else {
|
||||||
for (Map.Entry<String, String> entry : values.entrySet()) {
|
for (Map.Entry<String, String> entry : values.entrySet()) {
|
||||||
ModelNode addCredential = getCredentialToAdd(parent, name + "." + entry.getKey(), entry.getValue());
|
ModelNode addCredential = getCredentialToAdd(parent, name + "" + entry.getKey(), entry.getValue());
|
||||||
credentialsToAdd.add(addCredential);
|
credentialsToAdd.add(addCredential);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
|
|||||||
|
|
||||||
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
|
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
|
||||||
//TODO: externalize message
|
//TODO: externalize message
|
||||||
throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
|
throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -23,6 +23,8 @@ import org.jboss.as.controller.OperationContext;
|
|||||||
import org.jboss.as.controller.OperationFailedException;
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
import org.jboss.dmr.ModelNode;
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update an attribute on a realm.
|
* Update an attribute on a realm.
|
||||||
*
|
*
|
||||||
|
|||||||
-22
@@ -23,7 +23,6 @@ import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
|
|||||||
import org.jboss.as.controller.SimpleResourceDefinition;
|
import org.jboss.as.controller.SimpleResourceDefinition;
|
||||||
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
|
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
|
||||||
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
|
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
|
||||||
import org.jboss.as.controller.operations.validation.IntRangeValidator;
|
|
||||||
import org.jboss.as.controller.operations.validation.StringLengthValidator;
|
import org.jboss.as.controller.operations.validation.StringLengthValidator;
|
||||||
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
import org.jboss.as.controller.registry.OperationEntry;
|
import org.jboss.as.controller.registry.OperationEntry;
|
||||||
@@ -80,24 +79,6 @@ class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
|||||||
.setAllowExpression(true)
|
.setAllowExpression(true)
|
||||||
.setDefaultValue(new ModelNode(false))
|
.setDefaultValue(new ModelNode(false))
|
||||||
.build();
|
.build();
|
||||||
protected static final SimpleAttributeDefinition TURN_OFF_CHANGE_SESSION =
|
|
||||||
new SimpleAttributeDefinitionBuilder("turn-off-change-session-id-on-login", ModelType.BOOLEAN, true)
|
|
||||||
.setXmlName("turn-off-change-session-id-on-login")
|
|
||||||
.setAllowExpression(true)
|
|
||||||
.setDefaultValue(new ModelNode(false))
|
|
||||||
.build();
|
|
||||||
protected static final SimpleAttributeDefinition TOKEN_MINIMUM_TIME_TO_LIVE =
|
|
||||||
new SimpleAttributeDefinitionBuilder("token-minimum-time-to-live", ModelType.INT, true)
|
|
||||||
.setXmlName("token-minimum-time-to-live")
|
|
||||||
.setValidator(new IntRangeValidator(-1, true))
|
|
||||||
.setAllowExpression(true)
|
|
||||||
.build();
|
|
||||||
protected static final SimpleAttributeDefinition MIN_TIME_BETWEEN_JWKS_REQUESTS =
|
|
||||||
new SimpleAttributeDefinitionBuilder("min-time-between-jwks-requests", ModelType.INT, true)
|
|
||||||
.setXmlName("min-time-between-jwks-requests")
|
|
||||||
.setValidator(new IntRangeValidator(-1, true))
|
|
||||||
.setAllowExpression(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
static {
|
static {
|
||||||
@@ -107,9 +88,6 @@ class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
|||||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
|
||||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
|
||||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
|
||||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(TURN_OFF_CHANGE_SESSION);
|
|
||||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(TOKEN_MINIMUM_TIME_TO_LIVE);
|
|
||||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(MIN_TIME_BETWEEN_JWKS_REQUESTS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
|||||||
-2
@@ -80,8 +80,6 @@ keycloak.secure-deployment.register-node-period=how often to re-register node
|
|||||||
keycloak.secure-deployment.token-store=cookie or session storage for auth session data
|
keycloak.secure-deployment.token-store=cookie or session storage for auth session data
|
||||||
keycloak.secure-deployment.principal-attribute=token attribute to use to set Principal name
|
keycloak.secure-deployment.principal-attribute=token attribute to use to set Principal name
|
||||||
keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
|
keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
|
||||||
keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
|
|
||||||
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
|
|
||||||
|
|
||||||
keycloak.secure-deployment.credential=Credential value
|
keycloak.secure-deployment.credential=Credential value
|
||||||
|
|
||||||
|
|||||||
@@ -105,8 +105,6 @@
|
|||||||
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
<xs:element name="enable-basic-auth" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
<xs:element name="enable-basic-auth" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
<xs:element name="turn-off-change-session-id-on-login" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
<xs:element name="turn-off-change-session-id-on-login" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
<xs:element name="token-minimum-time-to-live" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element name="min-time-between-jwks-requests" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
|
||||||
</xs:all>
|
</xs:all>
|
||||||
<xs:attribute name="name" type="xs:string" use="required">
|
<xs:attribute name="name" type="xs:string" use="required">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
|
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+3
-3
@@ -19,11 +19,11 @@ package org.keycloak.adapters.installed;
|
|||||||
|
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.OAuthErrorException;
|
import org.keycloak.OAuthErrorException;
|
||||||
|
import org.keycloak.RSATokenVerifier;
|
||||||
|
import org.keycloak.common.VerificationException;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
import org.keycloak.adapters.ServerRequest;
|
import org.keycloak.adapters.ServerRequest;
|
||||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
|
||||||
import org.keycloak.common.VerificationException;
|
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
import org.keycloak.jose.jws.JWSInputException;
|
import org.keycloak.jose.jws.JWSInputException;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
@@ -213,7 +213,7 @@ public class KeycloakInstalled {
|
|||||||
refreshToken = tokenResponse.getRefreshToken();
|
refreshToken = tokenResponse.getRefreshToken();
|
||||||
idTokenString = tokenResponse.getIdToken();
|
idTokenString = tokenResponse.getIdToken();
|
||||||
|
|
||||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||||
if (idTokenString != null) {
|
if (idTokenString != null) {
|
||||||
try {
|
try {
|
||||||
JWSInput input = new JWSInput(idTokenString);
|
JWSInput input = new JWSInput(idTokenString);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+3
-2
@@ -20,6 +20,8 @@ package org.keycloak.jaxrs;
|
|||||||
import org.keycloak.KeycloakPrincipal;
|
import org.keycloak.KeycloakPrincipal;
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
|
import org.keycloak.adapters.spi.AuthChallenge;
|
||||||
|
import org.keycloak.adapters.spi.AuthOutcome;
|
||||||
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
||||||
import org.keycloak.adapters.BasicAuthRequestAuthenticator;
|
import org.keycloak.adapters.BasicAuthRequestAuthenticator;
|
||||||
import org.keycloak.adapters.BearerTokenRequestAuthenticator;
|
import org.keycloak.adapters.BearerTokenRequestAuthenticator;
|
||||||
@@ -29,8 +31,6 @@ import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
|||||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.spi.AuthChallenge;
|
|
||||||
import org.keycloak.adapters.spi.AuthOutcome;
|
|
||||||
import org.keycloak.adapters.spi.UserSessionManagement;
|
import org.keycloak.adapters.spi.UserSessionManagement;
|
||||||
import org.keycloak.common.constants.GenericConstants;
|
import org.keycloak.common.constants.GenericConstants;
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@ import javax.ws.rs.container.ContainerRequestContext;
|
|||||||
import javax.ws.rs.container.PreMatching;
|
import javax.ws.rs.container.PreMatching;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.SecurityContext;
|
import javax.ws.rs.core.SecurityContext;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|||||||
+10
-9
@@ -17,20 +17,21 @@
|
|||||||
|
|
||||||
package org.keycloak.jaxrs;
|
package org.keycloak.jaxrs;
|
||||||
|
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import java.io.InputStream;
|
||||||
import org.keycloak.adapters.OIDCHttpFacade;
|
import java.io.OutputStream;
|
||||||
import org.keycloak.adapters.spi.AuthenticationError;
|
import java.util.List;
|
||||||
import org.keycloak.adapters.spi.LogoutError;
|
import java.util.Map;
|
||||||
import org.keycloak.common.util.HostUtils;
|
|
||||||
|
|
||||||
import javax.security.cert.X509Certificate;
|
import javax.security.cert.X509Certificate;
|
||||||
import javax.ws.rs.container.ContainerRequestContext;
|
import javax.ws.rs.container.ContainerRequestContext;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.SecurityContext;
|
import javax.ws.rs.core.SecurityContext;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import java.util.List;
|
import org.keycloak.adapters.OIDCHttpFacade;
|
||||||
import java.util.Map;
|
import org.keycloak.adapters.spi.AuthenticationError;
|
||||||
|
import org.keycloak.adapters.spi.LogoutError;
|
||||||
|
import org.keycloak.common.util.HostUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
|||||||
+8
-7
@@ -17,18 +17,19 @@
|
|||||||
|
|
||||||
package org.keycloak.jaxrs;
|
package org.keycloak.jaxrs;
|
||||||
|
|
||||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
|
||||||
import org.keycloak.common.constants.GenericConstants;
|
|
||||||
import org.osgi.framework.BundleContext;
|
|
||||||
|
|
||||||
import javax.annotation.Priority;
|
|
||||||
import javax.ws.rs.Priorities;
|
|
||||||
import javax.ws.rs.container.PreMatching;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Priority;
|
||||||
|
import javax.ws.rs.Priorities;
|
||||||
|
import javax.ws.rs.container.PreMatching;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||||
|
import org.keycloak.common.constants.GenericConstants;
|
||||||
|
import org.osgi.framework.BundleContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variant of JaxrsBearerTokenFilter, which can be used to properly use resources from current osgi bundle
|
* Variant of JaxrsBearerTokenFilter, which can be used to properly use resources from current osgi bundle
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../../pom.xml</relativePath>
|
<relativePath>../../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+8
-5
@@ -27,26 +27,28 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
|||||||
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
|
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
|
||||||
import org.eclipse.jetty.server.Authentication;
|
import org.eclipse.jetty.server.Authentication;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Response;
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
|
import org.eclipse.jetty.util.URIUtil;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.KeycloakPrincipal;
|
import org.keycloak.KeycloakPrincipal;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import org.keycloak.adapters.AdapterTokenStore;
|
import org.keycloak.adapters.AdapterTokenStore;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
|
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||||
|
import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
|
||||||
|
import org.keycloak.adapters.spi.AuthChallenge;
|
||||||
|
import org.keycloak.adapters.spi.AuthOutcome;
|
||||||
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
||||||
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
|
||||||
import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
|
|
||||||
import org.keycloak.adapters.spi.AuthChallenge;
|
|
||||||
import org.keycloak.adapters.spi.AuthOutcome;
|
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
|
||||||
import org.keycloak.constants.AdapterConstants;
|
import org.keycloak.constants.AdapterConstants;
|
||||||
import org.keycloak.enums.TokenStore;
|
import org.keycloak.enums.TokenStore;
|
||||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
@@ -59,6 +61,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|||||||
+1
-1
@@ -23,11 +23,11 @@ import org.keycloak.KeycloakPrincipal;
|
|||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.AdapterTokenStore;
|
import org.keycloak.adapters.AdapterTokenStore;
|
||||||
import org.keycloak.adapters.CookieTokenStore;
|
import org.keycloak.adapters.CookieTokenStore;
|
||||||
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.RequestAuthenticator;
|
import org.keycloak.adapters.RequestAuthenticator;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle storage of token info in cookie. Per-request object.
|
* Handle storage of token info in cookie. Per-request object.
|
||||||
|
|||||||
+1
-1
@@ -23,12 +23,12 @@ import org.keycloak.KeycloakPrincipal;
|
|||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.AdapterTokenStore;
|
import org.keycloak.adapters.AdapterTokenStore;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
||||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.RequestAuthenticator;
|
import org.keycloak.adapters.RequestAuthenticator;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
|||||||
+1
-1
@@ -21,13 +21,13 @@ import org.eclipse.jetty.server.Request;
|
|||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.KeycloakPrincipal;
|
import org.keycloak.KeycloakPrincipal;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
|
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||||
import org.keycloak.adapters.AdapterTokenStore;
|
import org.keycloak.adapters.AdapterTokenStore;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.RequestAuthenticator;
|
import org.keycloak.adapters.RequestAuthenticator;
|
||||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../../pom.xml</relativePath>
|
<relativePath>../../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+1
-1
@@ -20,8 +20,8 @@ package org.keycloak.adapters.jetty;
|
|||||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.util.MultiMap;
|
import org.eclipse.jetty.util.MultiMap;
|
||||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
|
||||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||||
|
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../../pom.xml</relativePath>
|
<relativePath>../../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+1
-1
@@ -21,8 +21,8 @@ import org.eclipse.jetty.http.HttpMethod;
|
|||||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.util.MultiMap;
|
import org.eclipse.jetty.util.MultiMap;
|
||||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
|
||||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||||
|
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../../pom.xml</relativePath>
|
<relativePath>../../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+1
-1
@@ -21,8 +21,8 @@ import org.eclipse.jetty.http.HttpMethod;
|
|||||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.util.MultiMap;
|
import org.eclipse.jetty.util.MultiMap;
|
||||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
|
||||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||||
|
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../../pom.xml</relativePath>
|
<relativePath>../../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+2
-1
@@ -17,11 +17,12 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.jetty;
|
package org.keycloak.adapters.jetty;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.util.MultiMap;
|
import org.eclipse.jetty.util.MultiMap;
|
||||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
|
||||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||||
|
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<name>Keycloak Jetty Integration</name>
|
<name>Keycloak Jetty Integration</name>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function( window, undefined ) {
|
(function( window, undefined ) {
|
||||||
|
|
||||||
var KeycloakAuthorization = function (keycloak) {
|
var KeycloakAuthorization = function (keycloak) {
|
||||||
var _instance = this;
|
var _instance = this;
|
||||||
this.rpt = null;
|
this.rpt = null;
|
||||||
@@ -112,55 +112,44 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return this;
|
/**
|
||||||
};
|
* Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
|
||||||
|
*/
|
||||||
|
this.entitlement = function (resourceSeververId) {
|
||||||
|
this.then = function (onGrant, onDeny, onError) {
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
|
||||||
/**
|
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
|
||||||
* Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
|
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
|
||||||
*/
|
|
||||||
this.entitlement = function (resourceSeververId, entitlementRequest ) {
|
|
||||||
this.then = function (onGrant, onDeny, onError) {
|
|
||||||
var request = new XMLHttpRequest();
|
|
||||||
|
|
||||||
|
request.onreadystatechange = function () {
|
||||||
|
if (request.readyState == 4) {
|
||||||
|
var status = request.status;
|
||||||
|
|
||||||
|
if (status >= 200 && status < 300) {
|
||||||
request.onreadystatechange = function () {
|
var rpt = JSON.parse(request.responseText).rpt;
|
||||||
if (request.readyState == 4) {
|
_instance.rpt = rpt;
|
||||||
var status = request.status;
|
onGrant(rpt);
|
||||||
|
} else if (status == 403) {
|
||||||
if (status >= 200 && status < 300) {
|
if (onDeny) {
|
||||||
var rpt = JSON.parse(request.responseText).rpt;
|
onDeny();
|
||||||
_instance.rpt = rpt;
|
} else {
|
||||||
onGrant(rpt);
|
console.error('Authorization request was denied by the server.');
|
||||||
} else if (status == 403) {
|
}
|
||||||
if (onDeny) {
|
|
||||||
onDeny();
|
|
||||||
} else {
|
} else {
|
||||||
console.error('Authorization request was denied by the server.');
|
if (onError) {
|
||||||
}
|
onError();
|
||||||
} else {
|
} else {
|
||||||
if (onError) {
|
console.error('Could not obtain authorization data from server.');
|
||||||
onError();
|
}
|
||||||
} else {
|
|
||||||
console.error('Could not obtain authorization data from server.');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
request.send(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
var erJson = null
|
return this;
|
||||||
|
|
||||||
if(entitlementRequest) {
|
|
||||||
request.open('POST', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
|
|
||||||
request.setRequestHeader("Content-type", "application/json");
|
|
||||||
erJson = JSON.stringify(entitlementRequest)
|
|
||||||
} else {
|
|
||||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
|
|
||||||
request.send(erJson);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
var loginIframe = {
|
var loginIframe = {
|
||||||
enable: true,
|
enable: true,
|
||||||
callbackList: [],
|
callbackMap: [],
|
||||||
interval: 5
|
interval: 5
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -154,34 +154,21 @@
|
|||||||
return;
|
return;
|
||||||
} else if (initOptions) {
|
} else if (initOptions) {
|
||||||
if (initOptions.token || initOptions.refreshToken) {
|
if (initOptions.token || initOptions.refreshToken) {
|
||||||
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
|
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken, false);
|
||||||
|
kc.timeSkew = initOptions.timeSkew || 0;
|
||||||
|
|
||||||
if (loginIframe.enable) {
|
if (loginIframe.enable) {
|
||||||
setupCheckLoginIframe().success(function() {
|
setupCheckLoginIframe().success(function() {
|
||||||
checkLoginIframe().success(function () {
|
checkLoginIframe().success(function () {
|
||||||
kc.onAuthSuccess && kc.onAuthSuccess();
|
|
||||||
initPromise.setSuccess();
|
initPromise.setSuccess();
|
||||||
}).error(function () {
|
}).error(function () {
|
||||||
kc.onAuthError && kc.onAuthError();
|
|
||||||
if (initOptions.onLoad) {
|
if (initOptions.onLoad) {
|
||||||
onLoad();
|
onLoad();
|
||||||
} else {
|
|
||||||
initPromise.setError();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
kc.updateToken(-1).success(function() {
|
initPromise.setSuccess();
|
||||||
kc.onAuthSuccess && kc.onAuthSuccess();
|
|
||||||
initPromise.setSuccess();
|
|
||||||
}).error(function() {
|
|
||||||
kc.onAuthError && kc.onAuthError();
|
|
||||||
if (initOptions.onLoad) {
|
|
||||||
onLoad();
|
|
||||||
} else {
|
|
||||||
initPromise.setError();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else if (initOptions.onLoad) {
|
} else if (initOptions.onLoad) {
|
||||||
onLoad();
|
onLoad();
|
||||||
@@ -210,18 +197,11 @@
|
|||||||
var nonce = createUUID();
|
var nonce = createUUID();
|
||||||
|
|
||||||
var redirectUri = adapter.redirectUri(options);
|
var redirectUri = adapter.redirectUri(options);
|
||||||
|
|
||||||
var callbackState = {
|
|
||||||
state: state,
|
|
||||||
nonce: nonce,
|
|
||||||
redirectUri: encodeURIComponent(redirectUri),
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options && options.prompt) {
|
if (options && options.prompt) {
|
||||||
callbackState.prompt = options.prompt;
|
redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'prompt=' + options.prompt;
|
||||||
}
|
}
|
||||||
|
|
||||||
callbackStorage.add(callbackState);
|
callbackStorage.add({ state: state, nonce: nonce, redirectUri: encodeURIComponent(redirectUri) });
|
||||||
|
|
||||||
var action = 'auth';
|
var action = 'auth';
|
||||||
if (options && options.action == 'register') {
|
if (options && options.action == 'register') {
|
||||||
@@ -369,10 +349,11 @@
|
|||||||
throw 'Not authenticated';
|
throw 'Not authenticated';
|
||||||
}
|
}
|
||||||
|
|
||||||
var expiresIn = kc.tokenParsed['exp'] - Math.ceil(new Date().getTime() / 1000) + kc.timeSkew;
|
var expiresIn = kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew;
|
||||||
if (minValidity) {
|
if (minValidity) {
|
||||||
expiresIn -= minValidity;
|
expiresIn -= minValidity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return expiresIn < 0;
|
return expiresIn < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,20 +368,7 @@
|
|||||||
minValidity = minValidity || 5;
|
minValidity = minValidity || 5;
|
||||||
|
|
||||||
var exec = function() {
|
var exec = function() {
|
||||||
var refreshToken = false;
|
if (!kc.isTokenExpired(minValidity)) {
|
||||||
if (kc.timeSkew == -1) {
|
|
||||||
console.info('Skew ' + kc.timeSkew);
|
|
||||||
refreshToken = true;
|
|
||||||
console.info('[KEYCLOAK] Refreshing token: time skew not set');
|
|
||||||
} else if (minValidity == -1) {
|
|
||||||
refreshToken = true;
|
|
||||||
console.info('[KEYCLOAK] Refreshing token: forced refresh');
|
|
||||||
} else if (kc.isTokenExpired(minValidity)) {
|
|
||||||
refreshToken = true;
|
|
||||||
console.info('[KEYCLOAK] Refreshing token: token expired');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!refreshToken) {
|
|
||||||
promise.setSuccess(false);
|
promise.setSuccess(false);
|
||||||
} else {
|
} else {
|
||||||
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
|
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
|
||||||
@@ -412,7 +380,6 @@
|
|||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
req.open('POST', url, true);
|
req.open('POST', url, true);
|
||||||
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||||
req.withCredentials = true;
|
|
||||||
|
|
||||||
if (kc.clientId && kc.clientSecret) {
|
if (kc.clientId && kc.clientSecret) {
|
||||||
req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
|
req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
|
||||||
@@ -425,21 +392,18 @@
|
|||||||
req.onreadystatechange = function () {
|
req.onreadystatechange = function () {
|
||||||
if (req.readyState == 4) {
|
if (req.readyState == 4) {
|
||||||
if (req.status == 200) {
|
if (req.status == 200) {
|
||||||
console.info('[KEYCLOAK] Token refreshed');
|
|
||||||
|
|
||||||
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
||||||
|
|
||||||
var tokenResponse = JSON.parse(req.responseText);
|
var tokenResponse = JSON.parse(req.responseText);
|
||||||
|
setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], true);
|
||||||
|
|
||||||
setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], timeLocal);
|
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
|
||||||
|
|
||||||
kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
|
kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
|
||||||
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
|
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
|
||||||
p.setSuccess(true);
|
p.setSuccess(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('[KEYCLOAK] Failed to refresh token');
|
|
||||||
|
|
||||||
kc.onAuthRefreshError && kc.onAuthRefreshError();
|
kc.onAuthRefreshError && kc.onAuthRefreshError();
|
||||||
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
|
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
|
||||||
p.setError(true);
|
p.setError(true);
|
||||||
@@ -469,7 +433,7 @@
|
|||||||
|
|
||||||
kc.clearToken = function() {
|
kc.clearToken = function() {
|
||||||
if (kc.token) {
|
if (kc.token) {
|
||||||
setToken(null, null, null);
|
setToken(null, null, null, true);
|
||||||
kc.onAuthLogout && kc.onAuthLogout();
|
kc.onAuthLogout && kc.onAuthLogout();
|
||||||
if (kc.loginRequired) {
|
if (kc.loginRequired) {
|
||||||
kc.login();
|
kc.login();
|
||||||
@@ -550,16 +514,18 @@
|
|||||||
function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
|
function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
|
||||||
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
||||||
|
|
||||||
setToken(accessToken, refreshToken, idToken, timeLocal);
|
setToken(accessToken, refreshToken, idToken, true);
|
||||||
|
|
||||||
if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
|
if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
|
||||||
(kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
|
(kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
|
||||||
(kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce)) {
|
(kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce)) {
|
||||||
|
|
||||||
console.info('[KEYCLOAK] Invalid nonce, clearing token');
|
console.log('invalid nonce!');
|
||||||
kc.clearToken();
|
kc.clearToken();
|
||||||
promise && promise.setError();
|
promise && promise.setError();
|
||||||
} else {
|
} else {
|
||||||
|
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
|
||||||
|
|
||||||
if (fulfillPromise) {
|
if (fulfillPromise) {
|
||||||
kc.onAuthSuccess && kc.onAuthSuccess();
|
kc.onAuthSuccess && kc.onAuthSuccess();
|
||||||
promise && promise.setSuccess();
|
promise && promise.setSuccess();
|
||||||
@@ -632,7 +598,7 @@
|
|||||||
return promise.promise;
|
return promise.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setToken(token, refreshToken, idToken, timeLocal) {
|
function setToken(token, refreshToken, idToken, useTokenTime) {
|
||||||
if (kc.tokenTimeoutHandle) {
|
if (kc.tokenTimeoutHandle) {
|
||||||
clearTimeout(kc.tokenTimeoutHandle);
|
clearTimeout(kc.tokenTimeoutHandle);
|
||||||
kc.tokenTimeoutHandle = null;
|
kc.tokenTimeoutHandle = null;
|
||||||
@@ -651,24 +617,10 @@
|
|||||||
kc.realmAccess = kc.tokenParsed.realm_access;
|
kc.realmAccess = kc.tokenParsed.realm_access;
|
||||||
kc.resourceAccess = kc.tokenParsed.resource_access;
|
kc.resourceAccess = kc.tokenParsed.resource_access;
|
||||||
|
|
||||||
if (timeLocal) {
|
|
||||||
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
|
|
||||||
console.info('[KEYCLOAK] Estimated time difference between browser and server is ' + kc.timeSkew + ' seconds');
|
|
||||||
} else {
|
|
||||||
kc.timeSkew = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kc.onTokenExpired) {
|
if (kc.onTokenExpired) {
|
||||||
if (kc.timeSkew == -1) {
|
var start = useTokenTime ? kc.tokenParsed.iat : (new Date().getTime() / 1000);
|
||||||
kc.onTokenExpired();
|
var expiresIn = kc.tokenParsed.exp - start;
|
||||||
} else {
|
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn * 1000);
|
||||||
var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
|
|
||||||
if (expiresIn <= 0) {
|
|
||||||
kc.onTokenExpired();
|
|
||||||
} else {
|
|
||||||
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -754,7 +706,6 @@
|
|||||||
if (oauthState && (oauth.code || oauth.error || oauth.access_token || oauth.id_token)) {
|
if (oauthState && (oauth.code || oauth.error || oauth.access_token || oauth.id_token)) {
|
||||||
oauth.redirectUri = oauthState.redirectUri;
|
oauth.redirectUri = oauthState.redirectUri;
|
||||||
oauth.storedNonce = oauthState.nonce;
|
oauth.storedNonce = oauthState.nonce;
|
||||||
oauth.prompt = oauthState.prompt;
|
|
||||||
|
|
||||||
if (oauth.fragment) {
|
if (oauth.fragment) {
|
||||||
oauth.newUrl += '#' + oauth.fragment;
|
oauth.newUrl += '#' + oauth.fragment;
|
||||||
@@ -832,7 +783,7 @@
|
|||||||
setTimeout(check, loginIframe.interval * 1000);
|
setTimeout(check, loginIframe.interval * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
|
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html?client_id=' + encodeURIComponent(kc.clientId) + '&origin=' + getOrigin();
|
||||||
iframe.setAttribute('src', src );
|
iframe.setAttribute('src', src );
|
||||||
iframe.style.display = 'none';
|
iframe.style.display = 'none';
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
@@ -842,21 +793,30 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.data != "unchanged") {
|
try {
|
||||||
kc.clearToken();
|
var data = JSON.parse(event.data);
|
||||||
|
} catch (err) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = loginIframe.callbackList.length - 1; i >= 0; --i) {
|
if (!data.callbackId) {
|
||||||
var promise = loginIframe.callbackList[i];
|
return;
|
||||||
if (event.data == "unchanged") {
|
}
|
||||||
promise.setSuccess();
|
|
||||||
} else {
|
var promise = loginIframe.callbackMap[data.callbackId];
|
||||||
promise.setError();
|
if (!promise) {
|
||||||
}
|
return;
|
||||||
loginIframe.callbackList.splice(i, 1);
|
}
|
||||||
|
|
||||||
|
delete loginIframe.callbackMap[data.callbackId];
|
||||||
|
|
||||||
|
if ((!kc.sessionId || kc.sessionId == data.session) && data.loggedIn) {
|
||||||
|
promise.setSuccess();
|
||||||
|
} else {
|
||||||
|
kc.clearToken();
|
||||||
|
promise.setError();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('message', messageCallback, false);
|
window.addEventListener('message', messageCallback, false);
|
||||||
|
|
||||||
var check = function() {
|
var check = function() {
|
||||||
@@ -872,13 +832,12 @@
|
|||||||
function checkLoginIframe() {
|
function checkLoginIframe() {
|
||||||
var promise = createPromise();
|
var promise = createPromise();
|
||||||
|
|
||||||
if (loginIframe.iframe && loginIframe.iframeOrigin ) {
|
if (loginIframe.iframe && loginIframe.iframeOrigin) {
|
||||||
var msg = kc.clientId + ' ' + kc.sessionId;
|
var msg = {};
|
||||||
loginIframe.callbackList.push(promise);
|
msg.callbackId = createCallbackId();
|
||||||
|
loginIframe.callbackMap[msg.callbackId] = promise;
|
||||||
var origin = loginIframe.iframeOrigin;
|
var origin = loginIframe.iframeOrigin;
|
||||||
if (loginIframe.callbackList.length == 1) {
|
loginIframe.iframe.contentWindow.postMessage(JSON.stringify(msg), origin);
|
||||||
loginIframe.iframe.contentWindow.postMessage(msg, origin);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
promise.setSuccess();
|
promise.setSuccess();
|
||||||
}
|
}
|
||||||
@@ -1049,7 +1008,7 @@
|
|||||||
|
|
||||||
function clearExpired() {
|
function clearExpired() {
|
||||||
var time = new Date().getTime();
|
var time = new Date().getTime();
|
||||||
for (var i = 0; i < localStorage.length; i++) {
|
for (var i = 1; i <= localStorage.length; i++) {
|
||||||
var key = localStorage.key(i);
|
var key = localStorage.key(i);
|
||||||
if (key && key.indexOf('kc-callback-') == 0) {
|
if (key && key.indexOf('kc-callback-') == 0) {
|
||||||
var value = localStorage.getItem(key);
|
var value = localStorage.getItem(key);
|
||||||
@@ -1096,7 +1055,7 @@
|
|||||||
if (!(this instanceof CookieStorage)) {
|
if (!(this instanceof CookieStorage)) {
|
||||||
return new CookieStorage();
|
return new CookieStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
var cs = this;
|
var cs = this;
|
||||||
|
|
||||||
cs.get = function(state) {
|
cs.get = function(state) {
|
||||||
@@ -1226,6 +1185,9 @@
|
|||||||
case 'redirect_fragment':
|
case 'redirect_fragment':
|
||||||
oauth.fragment = queryParams[param];
|
oauth.fragment = queryParams[param];
|
||||||
break;
|
break;
|
||||||
|
case 'prompt':
|
||||||
|
oauth.prompt = queryParams[param];
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (responseMode != 'query' || !handleQueryParam(param, queryParams[param], oauth)) {
|
if (responseMode != 'query' || !handleQueryParam(param, queryParams[param], oauth)) {
|
||||||
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + queryParams[param];
|
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + queryParams[param];
|
||||||
|
|||||||
@@ -15,58 +15,10 @@
|
|||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
<script>
|
<script>
|
||||||
var init;
|
function getCookie(cname)
|
||||||
|
|
||||||
function checkState(clientId, origin, sessionState, callback) {
|
|
||||||
var cookie = getCookie();
|
|
||||||
|
|
||||||
if (!cookie) {
|
|
||||||
callback('changed');
|
|
||||||
} else if (!init) {
|
|
||||||
var req = new XMLHttpRequest();
|
|
||||||
|
|
||||||
var url = location.href + "/init";
|
|
||||||
url += "?client_id=" + encodeURIComponent(clientId);
|
|
||||||
url += "&origin=" + encodeURIComponent(origin);
|
|
||||||
|
|
||||||
req.open('GET', url, true);
|
|
||||||
|
|
||||||
req.onreadystatechange = function () {
|
|
||||||
if (req.readyState == 4) {
|
|
||||||
if (req.status == 204) {
|
|
||||||
init = {
|
|
||||||
clientId: clientId,
|
|
||||||
origin: origin
|
|
||||||
}
|
|
||||||
callback('unchanged');
|
|
||||||
} else if (req.status = 404) {
|
|
||||||
callback('changed');
|
|
||||||
} else {
|
|
||||||
callback('error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
req.send();
|
|
||||||
} else {
|
|
||||||
if (clientId == init.clientId && origin == init.origin) {
|
|
||||||
if (sessionState == cookie) {
|
|
||||||
callback('unchanged');
|
|
||||||
} else {
|
|
||||||
callback('changed');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
callback('error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCookie()
|
|
||||||
{
|
{
|
||||||
var name = 'KEYCLOAK_SESSION=';
|
var name = cname + "=";
|
||||||
var ca = document.cookie.split(';');
|
var ca = document.cookie.split(';');
|
||||||
for(var i=0; i<ca.length; i++)
|
for(var i=0; i<ca.length; i++)
|
||||||
{
|
{
|
||||||
@@ -75,24 +27,23 @@
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function receiveMessage(event)
|
function receiveMessage(event)
|
||||||
{
|
{
|
||||||
var origin = event.origin;
|
if (event.origin !== "ORIGIN") {
|
||||||
var data = event.data.split(' ');
|
console.log(event.origin + " does not match built origin");
|
||||||
if (data.length != 2) {
|
return;
|
||||||
event.source.postMessage('error', origin);
|
|
||||||
|
}
|
||||||
|
var data = JSON.parse(event.data);
|
||||||
|
data.loggedIn = false;
|
||||||
|
var cookie = getCookie('KEYCLOAK_SESSION');
|
||||||
|
if (cookie) {
|
||||||
|
data.loggedIn = true;
|
||||||
|
data.session = cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientId = data[0];
|
event.source.postMessage(JSON.stringify(data),
|
||||||
var sessionState = data[1];
|
event.origin);
|
||||||
|
|
||||||
checkState(clientId, event.origin, sessionState, function(result) {
|
|
||||||
event.source.postMessage(result, origin);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("message", receiveMessage, false);
|
window.addEventListener("message", receiveMessage, false);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+5
-5
@@ -16,11 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.keycloak.adapters.osgi;
|
package org.keycloak.adapters.osgi;
|
||||||
|
|
||||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
|
||||||
import org.keycloak.adapters.OIDCHttpFacade;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@@ -28,6 +23,11 @@ import java.io.InputStream;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||||
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
|
import org.keycloak.adapters.OIDCHttpFacade;
|
||||||
|
|
||||||
public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
|
public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
|
||||||
|
|
||||||
private final Map<String, KeycloakDeployment> cache = new ConcurrentHashMap<String, KeycloakDeployment>();
|
private final Map<String, KeycloakDeployment> cache = new ConcurrentHashMap<String, KeycloakDeployment>();
|
||||||
|
|||||||
+5
-5
@@ -17,6 +17,11 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.osgi;
|
package org.keycloak.adapters.osgi;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.security.ConstraintMapping;
|
import org.eclipse.jetty.security.ConstraintMapping;
|
||||||
import org.eclipse.jetty.util.security.Constraint;
|
import org.eclipse.jetty.util.security.Constraint;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
@@ -27,11 +32,6 @@ import org.osgi.service.http.HttpContext;
|
|||||||
import org.osgi.util.tracker.ServiceTracker;
|
import org.osgi.util.tracker.ServiceTracker;
|
||||||
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration with pax-web, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
|
* Integration with pax-web, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
|
||||||
* and allows to inject custom security constraint for securing resources by Keycloak.
|
* and allows to inject custom security constraint for securing resources by Keycloak.
|
||||||
|
|||||||
+9
-8
@@ -17,6 +17,15 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.osgi;
|
package org.keycloak.adapters.osgi;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Dictionary;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.servlet.Servlet;
|
||||||
|
|
||||||
import org.apache.cxf.transport.http.DestinationRegistry;
|
import org.apache.cxf.transport.http.DestinationRegistry;
|
||||||
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
|
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
@@ -29,14 +38,6 @@ import org.osgi.service.http.HttpContext;
|
|||||||
import org.osgi.util.tracker.ServiceTracker;
|
import org.osgi.util.tracker.ServiceTracker;
|
||||||
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
||||||
|
|
||||||
import javax.servlet.Servlet;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Dictionary;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service, which allows to remove previously registered servlets in karaf/fuse environment. It assumes that particular servlet was previously
|
* Service, which allows to remove previously registered servlets in karaf/fuse environment. It assumes that particular servlet was previously
|
||||||
* registered as service in OSGI container under {@link javax.servlet.Servlet} interface.
|
* registered as service in OSGI container under {@link javax.servlet.Servlet} interface.
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<name>Keycloak OIDC Client Adapter Modules</name>
|
<name>Keycloak OIDC Client Adapter Modules</name>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+11
-50
@@ -18,15 +18,15 @@
|
|||||||
package org.keycloak.adapters.servlet;
|
package org.keycloak.adapters.servlet;
|
||||||
|
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
|
import org.keycloak.adapters.spi.AuthChallenge;
|
||||||
|
import org.keycloak.adapters.spi.AuthOutcome;
|
||||||
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
||||||
|
import org.keycloak.adapters.spi.InMemorySessionIdMapper;
|
||||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||||
import org.keycloak.adapters.spi.AuthChallenge;
|
|
||||||
import org.keycloak.adapters.spi.AuthOutcome;
|
|
||||||
import org.keycloak.adapters.spi.InMemorySessionIdMapper;
|
|
||||||
import org.keycloak.adapters.spi.SessionIdMapper;
|
import org.keycloak.adapters.spi.SessionIdMapper;
|
||||||
import org.keycloak.adapters.spi.UserSessionManagement;
|
import org.keycloak.adapters.spi.UserSessionManagement;
|
||||||
|
|
||||||
@@ -39,6 +39,7 @@ import javax.servlet.ServletResponse;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequestWrapper;
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -46,7 +47,6 @@ import java.io.InputStream;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
@@ -56,18 +56,10 @@ public class KeycloakOIDCFilter implements Filter {
|
|||||||
protected AdapterDeploymentContext deploymentContext;
|
protected AdapterDeploymentContext deploymentContext;
|
||||||
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
|
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
|
||||||
protected NodesRegistrationManagement nodesRegistrationManagement;
|
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||||
protected Pattern skipPattern;
|
|
||||||
|
|
||||||
private final static Logger log = Logger.getLogger(""+KeycloakOIDCFilter.class);
|
private final static Logger log = Logger.getLogger(""+KeycloakOIDCFilter.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||||
|
|
||||||
String skipPatternDefinition = filterConfig.getInitParameter("keycloak.config.skipPattern");
|
|
||||||
if (skipPatternDefinition != null) {
|
|
||||||
skipPattern = Pattern.compile(skipPatternDefinition, Pattern.DOTALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
String configResolverClass = filterConfig.getInitParameter("keycloak.config.resolver");
|
String configResolverClass = filterConfig.getInitParameter("keycloak.config.resolver");
|
||||||
if (configResolverClass != null) {
|
if (configResolverClass != null) {
|
||||||
try {
|
try {
|
||||||
@@ -93,7 +85,13 @@ public class KeycloakOIDCFilter implements Filter {
|
|||||||
if (pathParam != null) path = pathParam;
|
if (pathParam != null) path = pathParam;
|
||||||
is = filterConfig.getServletContext().getResourceAsStream(path);
|
is = filterConfig.getServletContext().getResourceAsStream(path);
|
||||||
}
|
}
|
||||||
KeycloakDeployment kd = createKeycloakDeploymentFrom(is);
|
KeycloakDeployment kd;
|
||||||
|
if (is == null) {
|
||||||
|
log.fine("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
||||||
|
kd = new KeycloakDeployment();
|
||||||
|
} else {
|
||||||
|
kd = KeycloakDeploymentBuilder.build(is);
|
||||||
|
}
|
||||||
deploymentContext = new AdapterDeploymentContext(kd);
|
deploymentContext = new AdapterDeploymentContext(kd);
|
||||||
log.fine("Keycloak is using a per-deployment configuration.");
|
log.fine("Keycloak is using a per-deployment configuration.");
|
||||||
}
|
}
|
||||||
@@ -101,30 +99,13 @@ public class KeycloakOIDCFilter implements Filter {
|
|||||||
nodesRegistrationManagement = new NodesRegistrationManagement();
|
nodesRegistrationManagement = new NodesRegistrationManagement();
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeycloakDeployment createKeycloakDeploymentFrom(InputStream is) {
|
|
||||||
|
|
||||||
if (is == null) {
|
|
||||||
log.fine("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
|
||||||
return new KeycloakDeployment();
|
|
||||||
}
|
|
||||||
|
|
||||||
return KeycloakDeploymentBuilder.build(is);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||||
|
|
||||||
log.fine("Keycloak OIDC Filter");
|
log.fine("Keycloak OIDC Filter");
|
||||||
//System.err.println("Keycloak OIDC Filter: " + ((HttpServletRequest)req).getRequestURL().toString());
|
//System.err.println("Keycloak OIDC Filter: " + ((HttpServletRequest)req).getRequestURL().toString());
|
||||||
HttpServletRequest request = (HttpServletRequest) req;
|
HttpServletRequest request = (HttpServletRequest) req;
|
||||||
HttpServletResponse response = (HttpServletResponse) res;
|
HttpServletResponse response = (HttpServletResponse) res;
|
||||||
|
|
||||||
if (shouldSkip(request)) {
|
|
||||||
chain.doFilter(req, res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OIDCServletHttpFacade facade = new OIDCServletHttpFacade(request, response);
|
OIDCServletHttpFacade facade = new OIDCServletHttpFacade(request, response);
|
||||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||||
if (deployment == null || !deployment.isConfigured()) {
|
if (deployment == null || !deployment.isConfigured()) {
|
||||||
@@ -190,26 +171,6 @@ public class KeycloakOIDCFilter implements Filter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Decides whether this {@link Filter} should skip the given {@link HttpServletRequest} based on the configured {@link KeycloakOIDCFilter#skipPattern}.
|
|
||||||
* Patterns are matched against the {@link HttpServletRequest#getRequestURI() requestURI} of a request without the context-path.
|
|
||||||
* A request for {@code /myapp/index.html} would be tested with {@code /index.html} against the skip pattern.
|
|
||||||
* Skipped requests will not be processed further by {@link KeycloakOIDCFilter} and immediately delegated to the {@link FilterChain}.
|
|
||||||
*
|
|
||||||
* @param request the request to check
|
|
||||||
* @return {@code true} if the request should not be handled,
|
|
||||||
* {@code false} otherwise.
|
|
||||||
*/
|
|
||||||
private boolean shouldSkip(HttpServletRequest request) {
|
|
||||||
|
|
||||||
if (skipPattern == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String requestPath = request.getRequestURI().substring(request.getContextPath().length());
|
|
||||||
return skipPattern.matcher(requestPath).matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+2
-2
@@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
package org.keycloak.servlet;
|
package org.keycloak.servlet;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.keycloak.AbstractOAuthClient;
|
import org.keycloak.AbstractOAuthClient;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.common.enums.RelativeUrlsUsed;
|
import org.keycloak.common.enums.RelativeUrlsUsed;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
|
|||||||
+1
-1
@@ -25,11 +25,11 @@ import org.keycloak.adapters.OIDCHttpFacade;
|
|||||||
import org.keycloak.adapters.ServerRequest;
|
import org.keycloak.adapters.ServerRequest;
|
||||||
import org.keycloak.adapters.spi.AuthenticationError;
|
import org.keycloak.adapters.spi.AuthenticationError;
|
||||||
import org.keycloak.adapters.spi.LogoutError;
|
import org.keycloak.adapters.spi.LogoutError;
|
||||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
import org.keycloak.jose.jws.JWSInputException;
|
import org.keycloak.jose.jws.JWSInputException;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.representations.IDToken;
|
import org.keycloak.representations.IDToken;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
import org.keycloak.util.TokenUtil;
|
import org.keycloak.util.TokenUtil;
|
||||||
|
|
||||||
import javax.security.cert.X509Certificate;
|
import javax.security.cert.X509Certificate;
|
||||||
|
|||||||
-1
@@ -20,7 +20,6 @@ package org.keycloak.servlet;
|
|||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+1
-1
@@ -215,7 +215,7 @@ public class KeycloakSpringBootConfiguration {
|
|||||||
securityHandler.setConstraintMappings(jettyConstraintMappings);
|
securityHandler.setConstraintMappings(jettyConstraintMappings);
|
||||||
securityHandler.setAuthenticator(keycloakJettyAuthenticator);
|
securityHandler.setAuthenticator(keycloakJettyAuthenticator);
|
||||||
|
|
||||||
webAppContext.setSecurityHandler(securityHandler);
|
webAppContext.setHandler(securityHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-12
@@ -17,27 +17,15 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.springboot;
|
package org.keycloak.adapters.springboot;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "keycloak", ignoreUnknownFields = false)
|
@ConfigurationProperties(prefix = "keycloak", ignoreUnknownFields = false)
|
||||||
public class KeycloakSpringBootProperties extends AdapterConfig {
|
public class KeycloakSpringBootProperties extends AdapterConfig {
|
||||||
|
|
||||||
/* this is a dummy property to avoid re-rebinding problem with property keycloak.config.resolver
|
|
||||||
when using spring cloud - see KEYCLOAK-2977 */
|
|
||||||
@JsonIgnore
|
|
||||||
private Map config = new HashMap();
|
|
||||||
|
|
||||||
public Map getConfig() {
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<SecurityConstraint> securityConstraints = new ArrayList<SecurityConstraint>();
|
private List<SecurityConstraint> securityConstraints = new ArrayList<SecurityConstraint>();
|
||||||
|
|
||||||
public static class SecurityConstraint {
|
public static class SecurityConstraint {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>2.4.0.CR1-SNAPSHOT</version>
|
<version>2.1.0.Final</version>
|
||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+6
-4
@@ -17,20 +17,22 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.springsecurity;
|
package org.keycloak.adapters.springsecurity;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link FactoryBean} that creates an {@link AdapterDeploymentContext} given a {@link Resource} defining the Keycloak
|
* {@link FactoryBean} that creates an {@link AdapterDeploymentContext} given a {@link Resource} defining the Keycloak
|
||||||
* client configuration or a {@link KeycloakConfigResolver} for multi-tenant environments.
|
* client configuration or a {@link KeycloakConfigResolver} for multi-tenant environments.
|
||||||
|
|||||||
+2
-2
@@ -21,13 +21,13 @@ import org.keycloak.KeycloakPrincipal;
|
|||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.AdapterTokenStore;
|
import org.keycloak.adapters.AdapterTokenStore;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
|
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
||||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.RequestAuthenticator;
|
import org.keycloak.adapters.RequestAuthenticator;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
|
||||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
|
||||||
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
|
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
+1
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.springsecurity.client;
|
package org.keycloak.adapters.springsecurity.client;
|
||||||
|
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
import org.apache.http.client.methods.HttpUriRequest;
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
|
|||||||
+4
-6
@@ -19,10 +19,10 @@ package org.keycloak.adapters.springsecurity.filter;
|
|||||||
|
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import org.keycloak.adapters.AdapterTokenStore;
|
import org.keycloak.adapters.AdapterTokenStore;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
|
||||||
import org.keycloak.adapters.RequestAuthenticator;
|
|
||||||
import org.keycloak.adapters.spi.AuthChallenge;
|
import org.keycloak.adapters.spi.AuthChallenge;
|
||||||
import org.keycloak.adapters.spi.AuthOutcome;
|
import org.keycloak.adapters.spi.AuthOutcome;
|
||||||
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
import org.keycloak.adapters.RequestAuthenticator;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.adapters.springsecurity.KeycloakAuthenticationException;
|
import org.keycloak.adapters.springsecurity.KeycloakAuthenticationException;
|
||||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint;
|
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint;
|
||||||
@@ -63,8 +63,6 @@ import java.io.IOException;
|
|||||||
public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {
|
public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {
|
||||||
public static final String DEFAULT_LOGIN_URL = "/sso/login";
|
public static final String DEFAULT_LOGIN_URL = "/sso/login";
|
||||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
public static final String AUTHORIZATION_HEADER = "Authorization";
|
||||||
public static final String SCHEME_BEARER = "bearer ";
|
|
||||||
public static final String SCHEME_BASIC = "basic ";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request matcher that matches requests to the {@link KeycloakAuthenticationEntryPoint#DEFAULT_LOGIN_URI default login URI}
|
* Request matcher that matches requests to the {@link KeycloakAuthenticationEntryPoint#DEFAULT_LOGIN_URI default login URI}
|
||||||
@@ -166,7 +164,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
|
|||||||
*/
|
*/
|
||||||
protected boolean isBearerTokenRequest(HttpServletRequest request) {
|
protected boolean isBearerTokenRequest(HttpServletRequest request) {
|
||||||
String authValue = request.getHeader(AUTHORIZATION_HEADER);
|
String authValue = request.getHeader(AUTHORIZATION_HEADER);
|
||||||
return authValue != null && authValue.toLowerCase().startsWith(SCHEME_BEARER);
|
return authValue != null && authValue.startsWith("Bearer");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,7 +176,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
|
|||||||
*/
|
*/
|
||||||
protected boolean isBasicAuthRequest(HttpServletRequest request) {
|
protected boolean isBasicAuthRequest(HttpServletRequest request) {
|
||||||
String authValue = request.getHeader(AUTHORIZATION_HEADER);
|
String authValue = request.getHeader(AUTHORIZATION_HEADER);
|
||||||
return authValue != null && authValue.toLowerCase().startsWith(SCHEME_BASIC);
|
return authValue != null && authValue.startsWith("Basic");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -18,9 +18,9 @@
|
|||||||
package org.keycloak.adapters.springsecurity.filter;
|
package org.keycloak.adapters.springsecurity.filter;
|
||||||
|
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
|
||||||
import org.keycloak.adapters.spi.UserSessionManagement;
|
import org.keycloak.adapters.spi.UserSessionManagement;
|
||||||
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
+1
@@ -69,5 +69,6 @@ public class HttpSessionManager implements HttpSessionListener, UserSessionManag
|
|||||||
session.invalidate();
|
session.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sessions.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.springsecurity.token;
|
package org.keycloak.adapters.springsecurity.token;
|
||||||
|
|
||||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
|
||||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||||
|
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
|||||||
+4
-2
@@ -17,17 +17,19 @@
|
|||||||
|
|
||||||
package org.keycloak.adapters.springsecurity;
|
package org.keycloak.adapters.springsecurity;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import org.keycloak.adapters.spi.HttpFacade;
|
import org.keycloak.adapters.spi.HttpFacade;
|
||||||
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
public class AdapterDeploymentContextFactoryBeanTest {
|
public class AdapterDeploymentContextFactoryBeanTest {
|
||||||
|
|||||||
+1
-2
@@ -23,8 +23,7 @@ import org.junit.Test;
|
|||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP header inspecting API request matcher tests.
|
* HTTP header inspecting API request matcher tests.
|
||||||
|
|||||||
+1
-2
@@ -24,8 +24,7 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keycloak authentication entry point tests.
|
* Keycloak authentication entry point tests.
|
||||||
|
|||||||
+3
-6
@@ -19,8 +19,8 @@ package org.keycloak.adapters.springsecurity.authentication;
|
|||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
|
||||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||||
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
|
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
import org.mockito.internal.util.collections.Sets;
|
import org.mockito.internal.util.collections.Sets;
|
||||||
@@ -32,11 +32,8 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
|
|||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keycloak authentication provider tests.
|
* Keycloak authentication provider tests.
|
||||||
|
|||||||
Loaded 100 of 3204 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user