Compare commits
326
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72d38779ab | ||
|
|
839c4e8ede | ||
|
|
9c7e9da9fa | ||
|
|
3abb44c1da | ||
|
|
584d2e700d | ||
|
|
acbb17a331 | ||
|
|
9f5acccc4f | ||
|
|
e39d28517c | ||
|
|
8b5d171cb5 | ||
|
|
cddacab297 | ||
|
|
dfc09b69a8 | ||
|
|
d2e0432afb | ||
|
|
34d80c9083 | ||
|
|
06c08a9cff | ||
|
|
9f00f693c6 | ||
|
|
1f00625930 | ||
|
|
58d4d0596e | ||
|
|
ad59cd618e | ||
|
|
ac80f99e8c | ||
|
|
cdf7dd3a6c | ||
|
|
97dd10883c | ||
|
|
e6de2e7792 | ||
|
|
7f825eb415 | ||
|
|
a7f2130eae | ||
|
|
85db8ea44f | ||
|
|
2acea2b2ee | ||
|
|
2391a00aa5 | ||
|
|
934ea1c33c | ||
|
|
84bf546911 | ||
|
|
473bd5fc78 | ||
|
|
9d098e9068 | ||
|
|
8c1e5c5aae | ||
|
|
af5e8f7b09 | ||
|
|
681cb39862 | ||
|
|
7dee39bbaa | ||
|
|
e8ce9704c1 | ||
|
|
ffce2023c0 | ||
|
|
320110abaa | ||
|
|
f9a8f805c8 | ||
|
|
3779bfb6b4 | ||
|
|
4136d76b7e | ||
|
|
964cd50f1d | ||
|
|
61fa152e62 | ||
|
|
7f04dd20b3 | ||
|
|
9b5277d83d | ||
|
|
b2ea49212c | ||
|
|
bd8e435164 | ||
|
|
f8f9ebf588 | ||
|
|
79f53c5513 | ||
|
|
c2692cc0ac | ||
|
|
fdb8c04ac9 | ||
|
|
46e32b36d2 | ||
|
|
36c367a3bc | ||
|
|
1b24d2edd8 | ||
|
|
32df5225cf | ||
|
|
116f5f5795 | ||
|
|
bbc1d26b72 | ||
|
|
6f43c1f09f | ||
|
|
3c8aaaa61f | ||
|
|
e2b42b24d0 | ||
|
|
4efe12cb93 | ||
|
|
49d3d3f6e3 | ||
|
|
53fcc1bec2 | ||
|
|
490b7f6ba4 | ||
|
|
218065a349 | ||
|
|
98aa516d74 | ||
|
|
24715eabec | ||
|
|
f2f508ac2e | ||
|
|
13220e1d38 | ||
|
|
116027bd7b | ||
|
|
14a51e589d | ||
|
|
36433bb8ff | ||
|
|
edb66d6fd3 | ||
|
|
a0bbb1e7a2 | ||
|
|
a33997976f | ||
|
|
3250562d28 | ||
|
|
0a8d1e28f1 | ||
|
|
29538332d9 | ||
|
|
d941e07169 | ||
|
|
ba1fa34c56 | ||
|
|
5cef34d61a | ||
|
|
a87c08416d | ||
|
|
4f695cfe76 | ||
|
|
e41d11877f | ||
|
|
3c08153e33 | ||
|
|
c9507aa5c7 | ||
|
|
b62e6e2751 | ||
|
|
74dad004e3 | ||
|
|
2199df71bf | ||
|
|
4182e4d92a | ||
|
|
1583937295 | ||
|
|
940237ee78 | ||
|
|
3986ce2ce0 | ||
|
|
4b56743788 | ||
|
|
658988ccd0 | ||
|
|
a7287aad36 | ||
|
|
c3b577de11 | ||
|
|
c912f941e7 | ||
|
|
041413d8de | ||
|
|
386bf8d39e | ||
|
|
2ea93b8a8b | ||
|
|
dfcd598912 | ||
|
|
e157a60a23 | ||
|
|
2fd680092a | ||
|
|
37affb1e9c | ||
|
|
9df3091b22 | ||
|
|
728e68ede5 | ||
|
|
4cbc665592 | ||
|
|
d295ec709b | ||
|
|
90097e9aea | ||
|
|
07dcfeb330 | ||
|
|
3feec3ee68 | ||
|
|
f66eb8b1ef | ||
|
|
00879b39b7 | ||
|
|
77499be8d2 | ||
|
|
4ce5f9e087 | ||
|
|
f62e66681e | ||
|
|
06ad1537c8 | ||
|
|
64339aaca7 | ||
|
|
9193142bb9 | ||
|
|
2ed6067de0 | ||
|
|
98a9c50d53 | ||
|
|
144898c0d2 | ||
|
|
3b2f7630bb | ||
|
|
7c09b0c7b4 | ||
|
|
af508232dc | ||
|
|
d22f45f0d2 | ||
|
|
cefb1742a1 | ||
|
|
b320eb8fc7 | ||
|
|
5d836fefc5 | ||
|
|
dc13c701f5 | ||
|
|
e61191edb5 | ||
|
|
95f62c6aeb | ||
|
|
160e26b699 | ||
|
|
4593d89a05 | ||
|
|
8ffb1ecc7d | ||
|
|
a9ce6b9f81 | ||
|
|
c62c60c723 | ||
|
|
5d57c29fae | ||
|
|
c2684a2b36 | ||
|
|
5732b2c58f | ||
|
|
b0448d1b6f | ||
|
|
4a19d4cdc1 | ||
|
|
acdc33b2fa | ||
|
|
8a7983bf5a | ||
|
|
18e0c0277f | ||
|
|
8bdd8f4274 | ||
|
|
1c0abbd722 | ||
|
|
7a6324e02c | ||
|
|
f256e2b102 | ||
|
|
3d47ab3665 | ||
|
|
e08725e730 | ||
|
|
422805b511 | ||
|
|
1f3d29964f | ||
|
|
8c8a39c833 | ||
|
|
0938390654 | ||
|
|
635e20a510 | ||
|
|
4e245d428c | ||
|
|
cec13dae1f | ||
|
|
2d0866118e | ||
|
|
3bbbf30e64 | ||
|
|
e344dddf4b | ||
|
|
6578ce73a1 | ||
|
|
a006e1fad1 | ||
|
|
d2cae0f8c3 | ||
|
|
1e51952006 | ||
|
|
f868aa7fbe | ||
|
|
fb99f673fc | ||
|
|
9dbd1149cf | ||
|
|
455db1add4 | ||
|
|
b6e0cb374d | ||
|
|
bc2eb2b9ea | ||
|
|
fbaa731dfa | ||
|
|
03cf9bad2e | ||
|
|
f5a5fc3458 | ||
|
|
0e33e4035f | ||
|
|
c4f0053dd9 | ||
|
|
2b589186ed | ||
|
|
4bd38bb9c1 | ||
|
|
ac245d3c4b | ||
|
|
a1fd85c52a | ||
|
|
06dcf99b42 | ||
|
|
6acd9cdf1d | ||
|
|
68ca1849bf | ||
|
|
7413f46e1b | ||
|
|
db05dc6ee4 | ||
|
|
fbb65fa072 | ||
|
|
0b5bcad5f6 | ||
|
|
74325fe133 | ||
|
|
42e93742fa | ||
|
|
cfbc9cf14b | ||
|
|
67d3730c6d | ||
|
|
36aa3da3d0 | ||
|
|
c5600e888d | ||
|
|
38d1dea65e | ||
|
|
d653437830 | ||
|
|
b5a1b0bc50 | ||
|
|
a89dbabc92 | ||
|
|
4af0976194 | ||
|
|
46038b457c | ||
|
|
7af125247c | ||
|
|
442e337668 | ||
|
|
e31c2b92a9 | ||
|
|
d27a23cbe3 | ||
|
|
b1e5bc8a30 | ||
|
|
bc916a1909 | ||
|
|
f8c236afa8 | ||
|
|
c32cf51808 | ||
|
|
a60dd48300 | ||
|
|
90b5ad5bb3 | ||
|
|
cab9740221 | ||
|
|
5b1b63e364 | ||
|
|
e2094065b2 | ||
|
|
abb0bbd815 | ||
|
|
9b10110dcb | ||
|
|
ab8803a5d6 | ||
|
|
c15a425317 | ||
|
|
81e773688f | ||
|
|
d71fadabeb | ||
|
|
7447ca7b58 | ||
|
|
0f9798a10d | ||
|
|
d12f157299 | ||
|
|
f1156a49cf | ||
|
|
c852d6d817 | ||
|
|
7d038e72c9 | ||
|
|
654601c92c | ||
|
|
a743600b34 | ||
|
|
d4c3fae546 | ||
|
|
6a4e413bf4 | ||
|
|
b0da7dc72f | ||
|
|
110f6ad549 | ||
|
|
f9a0abcfc4 | ||
|
|
6e00587468 | ||
|
|
5093dd94e2 | ||
|
|
550ec2ff51 | ||
|
|
ab0c075242 | ||
|
|
bcf5ac56cd | ||
|
|
aa1ad029bb | ||
|
|
e27cbac0b5 | ||
|
|
5d34b7e682 | ||
|
|
69f66edb5f | ||
|
|
eed71a4b84 | ||
|
|
8967ca4066 | ||
|
|
a5b5e78eba | ||
|
|
a58c985934 | ||
|
|
34f62eb31d | ||
|
|
afee7d7403 | ||
|
|
d0eb26b8bb | ||
|
|
d65cc830eb | ||
|
|
6c3479665c | ||
|
|
ee2daeb364 | ||
|
|
fc6d6ff7f7 | ||
|
|
98d2fe15e8 | ||
|
|
af49d184a2 | ||
|
|
ecc104719d | ||
|
|
e8fe9bce11 | ||
|
|
3b455d1735 | ||
|
|
103fa975a1 | ||
|
|
9ee58909ab | ||
|
|
6f5dadedd5 | ||
|
|
033d1f564a | ||
|
|
bb7080584d | ||
|
|
370a6c1631 | ||
|
|
27e86e36c4 | ||
|
|
ff1326fe35 | ||
|
|
5fc7149aac | ||
|
|
a1bcd0651d | ||
|
|
22aaa4cb52 | ||
|
|
04f05c0cd1 | ||
|
|
8e65356891 | ||
|
|
f91c517a9c | ||
|
|
7209a95dce | ||
|
|
98bf095471 | ||
|
|
33963f8aa7 | ||
|
|
a9a759c4dc | ||
|
|
06c48a2830 | ||
|
|
affc62460c | ||
|
|
cd3cd4f506 | ||
|
|
8e113384aa | ||
|
|
59eec8d5b4 | ||
|
|
0ab53c5d88 | ||
|
|
4977527f60 | ||
|
|
0addfeaa75 | ||
|
|
c6a6848483 | ||
|
|
9d0c9046ad | ||
|
|
992268a8e6 | ||
|
|
5514a0c968 | ||
|
|
df1995636a | ||
|
|
ba0d71704d | ||
|
|
f69eb5503b | ||
|
|
9bc80cc323 | ||
|
|
39fa49f765 | ||
|
|
80cc9b0585 | ||
|
|
9f4cf07489 | ||
|
|
47b742a16e | ||
|
|
c26471faa8 | ||
|
|
4b1b3a0dda | ||
|
|
6bdc9dc133 | ||
|
|
12919223cf | ||
|
|
b32b222b02 | ||
|
|
44c47431a1 | ||
|
|
b2fd429749 | ||
|
|
bd2f220736 | ||
|
|
0348e427de | ||
|
|
b97908fb02 | ||
|
|
1aeec2a83c | ||
|
|
05792516f6 | ||
|
|
5afe93552a | ||
|
|
036b24378f | ||
|
|
bde45eaa07 | ||
|
|
f9b1cd191d | ||
|
|
8c518a8d38 | ||
|
|
6d5dc673d4 | ||
|
|
55e07bcde2 | ||
|
|
868f8b166f | ||
|
|
4b3d3bf55b | ||
|
|
cb1b34eee5 | ||
|
|
eb80d59cd8 | ||
|
|
04d03452bd | ||
|
|
a88e975a3a | ||
|
|
bf6246f5c1 | ||
|
|
d31d2859ae | ||
|
|
44f57b8273 | ||
|
|
5eb36f4e0f | ||
|
|
fa02277e6e | ||
|
|
4780a3453a |
No files matched your search
@@ -45,3 +45,6 @@ catalog.xml
|
||||
#########
|
||||
target
|
||||
|
||||
# Maven shade
|
||||
#############
|
||||
*dependency-reduced-pom.xml
|
||||
+1
-1
@@ -19,7 +19,7 @@ before_script:
|
||||
- export MAVEN_SKIP_RC=true
|
||||
|
||||
install:
|
||||
- travis_wait 30 mvn install -Pdistribution -DskipTests=true -B -V -q
|
||||
- travis_wait 60 mvn install -Pdistribution -DskipTests=true -B -V -q
|
||||
|
||||
script:
|
||||
- mvn test -B
|
||||
|
||||
@@ -36,7 +36,7 @@ Once completed you will find distribution archives in `distribution`.
|
||||
Starting Keycloak
|
||||
-----------------
|
||||
|
||||
To start Keycloak during development first build as specficied above, then run:
|
||||
To start Keycloak during development first build as specified above, then run:
|
||||
|
||||
mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server
|
||||
|
||||
@@ -52,7 +52,7 @@ To stop the server press `Ctrl + C`.
|
||||
|
||||
Help and Documentation
|
||||
----------------------
|
||||
* [Documentation](http://keycloak.jboss.org/docs) - User Guide, Admin REST API and Javadocs
|
||||
* [Documentation](http://www.keycloak.org/documentation.html) - 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
|
||||
* [JIRA](https://issues.jboss.org/projects/KEYCLOAK) - Issue tracker for bugs and feature requests
|
||||
|
||||
@@ -72,4 +72,4 @@ Contributing
|
||||
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>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+35
-55
@@ -17,26 +17,21 @@
|
||||
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.jboss.logging.Logger;
|
||||
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.common.enums.RelativeUrlsUsed;
|
||||
import org.keycloak.common.enums.SslRequired;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
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.InputStream;
|
||||
import java.net.URI;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -57,7 +52,7 @@ public class AdapterDeploymentContext {
|
||||
* during the application deployment's life cycle.
|
||||
*
|
||||
* @param deployment A KeycloakConfigResolver, possibly missing the Auth
|
||||
* Server URL and/or Realm Public Key
|
||||
* Server URL
|
||||
*/
|
||||
public AdapterDeploymentContext(KeycloakDeployment deployment) {
|
||||
this.deployment = deployment;
|
||||
@@ -79,7 +74,6 @@ public class AdapterDeploymentContext {
|
||||
/**
|
||||
* For single-tenant deployments, it complements KeycloakDeployment
|
||||
* 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
|
||||
* to the KeycloakConfigResolver .
|
||||
@@ -98,8 +92,8 @@ public class AdapterDeploymentContext {
|
||||
if (deployment.getAuthServerBaseUrl() == null) return deployment;
|
||||
|
||||
KeycloakDeployment resolvedDeployment = resolveUrls(deployment, facade);
|
||||
if (resolvedDeployment.getRealmKey() == null) {
|
||||
resolveRealmKey(resolvedDeployment);
|
||||
if (resolvedDeployment.getPublicKeyLocator() == null) {
|
||||
throw new RuntimeException("KeycloakDeployment was never initialized through appropriate SPIs");
|
||||
}
|
||||
return resolvedDeployment;
|
||||
}
|
||||
@@ -115,45 +109,6 @@ 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.
|
||||
* Ever method is delegated except URL get methods and isConfigured()
|
||||
@@ -207,6 +162,11 @@ public class AdapterDeploymentContext {
|
||||
return (this.unregisterNodeUrl != null) ? this.unregisterNodeUrl : delegate.getUnregisterNodeUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJwksUrl() {
|
||||
return (this.jwksUrl != null) ? this.jwksUrl : delegate.getJwksUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceName() {
|
||||
return delegate.getResourceName();
|
||||
@@ -223,13 +183,13 @@ public class AdapterDeploymentContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicKey getRealmKey() {
|
||||
return delegate.getRealmKey();
|
||||
public void setPublicKeyLocator(PublicKeyLocator publicKeyLocator) {
|
||||
delegate.setPublicKeyLocator(publicKeyLocator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRealmKey(PublicKey realmKey) {
|
||||
delegate.setRealmKey(realmKey);
|
||||
public PublicKeyLocator getPublicKeyLocator() {
|
||||
return delegate.getPublicKeyLocator();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -466,6 +426,26 @@ public class AdapterDeploymentContext {
|
||||
public void setTokenMinimumTimeToLive(final int 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) {
|
||||
|
||||
@@ -19,9 +19,7 @@ package org.keycloak.adapters;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.common.util.UriUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
+1
-1
@@ -31,10 +31,10 @@ import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.constants.ServiceUrlConstants;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
@@ -84,7 +84,7 @@ public class BearerTokenRequestAuthenticator {
|
||||
|
||||
protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) {
|
||||
try {
|
||||
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
} catch (VerificationException e) {
|
||||
log.error("Failed to verify token", e);
|
||||
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, "invalid_token", e.getMessage());
|
||||
|
||||
+3
-5
@@ -17,19 +17,17 @@
|
||||
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
@@ -73,7 +71,7 @@ public class CookieTokenStore {
|
||||
|
||||
try {
|
||||
// Skip check if token is active now. It's supposed to be done later by the caller
|
||||
AccessToken accessToken = RSATokenVerifier.verifyToken(accessTokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl(), false, true);
|
||||
AccessToken accessToken = AdapterRSATokenVerifier.verifyToken(accessTokenString, deployment, false, true);
|
||||
IDToken idToken;
|
||||
if (idTokenString != null && idTokenString.length() > 0) {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-10
@@ -15,22 +15,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.example;
|
||||
package org.keycloak.adapters;
|
||||
|
||||
/**
|
||||
* Client authentication with traditional OAuth2 client_id + client_secret
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ProductSAClientSecretServlet extends ProductServiceAccountServlet {
|
||||
public class HttpClientAdapterException extends Exception {
|
||||
|
||||
@Override
|
||||
protected String getAdapterConfigLocation() {
|
||||
return "/WEB-INF/keycloak-client-secret.json";
|
||||
public HttpClientAdapterException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getClientAuthenticationMethod() {
|
||||
return "secret";
|
||||
public HttpClientAdapterException(String message, Throwable t) {
|
||||
super(message, t);
|
||||
}
|
||||
}
|
||||
+24
-9
@@ -21,15 +21,15 @@ import org.apache.http.client.HttpClient;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.authentication.ClientCredentialsProvider;
|
||||
import org.keycloak.adapters.authorization.PolicyEnforcer;
|
||||
import org.keycloak.constants.ServiceUrlConstants;
|
||||
import org.keycloak.adapters.rotation.PublicKeyLocator;
|
||||
import org.keycloak.common.enums.RelativeUrlsUsed;
|
||||
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.representations.adapters.config.AdapterConfig;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.PublicKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -43,7 +43,7 @@ public class KeycloakDeployment {
|
||||
|
||||
protected RelativeUrlsUsed relativeUrls;
|
||||
protected String realm;
|
||||
protected volatile PublicKey realmKey;
|
||||
protected PublicKeyLocator publicKeyLocator;
|
||||
protected String authServerBaseUrl;
|
||||
protected String realmInfoUrl;
|
||||
protected KeycloakUriBuilder authUrl;
|
||||
@@ -52,6 +52,7 @@ public class KeycloakDeployment {
|
||||
protected String accountUrl;
|
||||
protected String registerNodeUrl;
|
||||
protected String unregisterNodeUrl;
|
||||
protected String jwksUrl;
|
||||
protected String principalAttribute = "sub";
|
||||
|
||||
protected String resourceName;
|
||||
@@ -79,13 +80,14 @@ public class KeycloakDeployment {
|
||||
|
||||
protected volatile int notBefore;
|
||||
protected int tokenMinimumTimeToLive;
|
||||
protected int minTimeBetweenJwksRequests;
|
||||
private PolicyEnforcer policyEnforcer;
|
||||
|
||||
public KeycloakDeployment() {
|
||||
}
|
||||
|
||||
public boolean isConfigured() {
|
||||
return getRealm() != null && getRealmKey() != null && (isBearerOnly() || getAuthServerBaseUrl() != null);
|
||||
return getRealm() != null && getPublicKeyLocator() != null && (isBearerOnly() || getAuthServerBaseUrl() != null);
|
||||
}
|
||||
|
||||
public String getResourceName() {
|
||||
@@ -100,12 +102,12 @@ public class KeycloakDeployment {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public PublicKey getRealmKey() {
|
||||
return realmKey;
|
||||
public PublicKeyLocator getPublicKeyLocator() {
|
||||
return publicKeyLocator;
|
||||
}
|
||||
|
||||
public void setRealmKey(PublicKey realmKey) {
|
||||
this.realmKey = realmKey;
|
||||
public void setPublicKeyLocator(PublicKeyLocator publicKeyLocator) {
|
||||
this.publicKeyLocator = publicKeyLocator;
|
||||
}
|
||||
|
||||
public String getAuthServerBaseUrl() {
|
||||
@@ -147,6 +149,7 @@ public class KeycloakDeployment {
|
||||
accountUrl = authUrlBuilder.clone().path(ServiceUrlConstants.ACCOUNT_SERVICE_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();
|
||||
jwksUrl = authUrlBuilder.clone().path(ServiceUrlConstants.JWKS_URL).build(getRealm()).toString();
|
||||
}
|
||||
|
||||
public RelativeUrlsUsed getRelativeUrls() {
|
||||
@@ -181,6 +184,10 @@ public class KeycloakDeployment {
|
||||
return unregisterNodeUrl;
|
||||
}
|
||||
|
||||
public String getJwksUrl() {
|
||||
return jwksUrl;
|
||||
}
|
||||
|
||||
public void setResourceName(String resourceName) {
|
||||
this.resourceName = resourceName;
|
||||
}
|
||||
@@ -369,6 +376,14 @@ public class KeycloakDeployment {
|
||||
this.tokenMinimumTimeToLive = tokenMinimumTimeToLive;
|
||||
}
|
||||
|
||||
public int getMinTimeBetweenJwksRequests() {
|
||||
return minTimeBetweenJwksRequests;
|
||||
}
|
||||
|
||||
public void setMinTimeBetweenJwksRequests(int minTimeBetweenJwksRequests) {
|
||||
this.minTimeBetweenJwksRequests = minTimeBetweenJwksRequests;
|
||||
}
|
||||
|
||||
public void setPolicyEnforcer(PolicyEnforcer policyEnforcer) {
|
||||
this.policyEnforcer = policyEnforcer;
|
||||
}
|
||||
|
||||
+10
-2
@@ -22,6 +22,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||
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.util.PemUtils;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
@@ -59,11 +61,16 @@ public class KeycloakDeploymentBuilder {
|
||||
PublicKey realmKey;
|
||||
try {
|
||||
realmKey = PemUtils.decodePublicKey(realmKeyPem);
|
||||
HardcodedPublicKeyLocator pkLocator = new HardcodedPublicKeyLocator(realmKey);
|
||||
deployment.setPublicKeyLocator(pkLocator);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
deployment.setRealmKey(realmKey);
|
||||
} else {
|
||||
JWKPublicKeyLocator pkLocator = new JWKPublicKeyLocator();
|
||||
deployment.setPublicKeyLocator(pkLocator);
|
||||
}
|
||||
|
||||
if (adapterConfig.getSslRequired() != null) {
|
||||
deployment.setSslRequired(SslRequired.valueOf(adapterConfig.getSslRequired().toUpperCase()));
|
||||
} else {
|
||||
@@ -97,6 +104,7 @@ public class KeycloakDeploymentBuilder {
|
||||
deployment.setRegisterNodeAtStartup(adapterConfig.isRegisterNodeAtStartup());
|
||||
deployment.setRegisterNodePeriod(adapterConfig.getRegisterNodePeriod());
|
||||
deployment.setTokenMinimumTimeToLive(adapterConfig.getTokenMinimumTimeToLive());
|
||||
deployment.setMinTimeBetweenJwksRequests(adapterConfig.getMinTimeBetweenJwksRequests());
|
||||
|
||||
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");
|
||||
@@ -105,7 +113,7 @@ public class KeycloakDeploymentBuilder {
|
||||
deployment.setClient(new HttpClientBuilder().build(adapterConfig));
|
||||
}
|
||||
if (adapterConfig.getAuthServerUrl() == null && (!deployment.isBearerOnly() || realmKeyPem == null)) {
|
||||
throw new RuntimeException("You must specify auth-url");
|
||||
throw new RuntimeException("You must specify auth-server-url");
|
||||
}
|
||||
deployment.setAuthServerBaseUrl(adapterConfig);
|
||||
if (adapterConfig.getTurnOffChangeSessionIdOnLogin() != null) {
|
||||
|
||||
+4
-4
@@ -17,6 +17,10 @@
|
||||
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.common.util.HostUtils;
|
||||
import org.keycloak.common.util.Time;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@@ -24,10 +28,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
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>
|
||||
*/
|
||||
|
||||
+4
-4
@@ -19,12 +19,14 @@ package org.keycloak.adapters;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.common.util.UriUtils;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
@@ -32,8 +34,6 @@ import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.common.util.UriUtils;
|
||||
import org.keycloak.util.TokenUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -342,7 +342,7 @@ public class OAuthRequestAuthenticator {
|
||||
refreshToken = tokenResponse.getRefreshToken();
|
||||
idTokenString = tokenResponse.getIdToken();
|
||||
try {
|
||||
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
if (idTokenString != null) {
|
||||
try {
|
||||
JWSInput input = new JWSInput(idTokenString);
|
||||
|
||||
+41
-2
@@ -17,20 +17,32 @@
|
||||
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
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.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.representations.VersionRepresentation;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
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.LogoutAction;
|
||||
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
|
||||
import org.keycloak.representations.adapters.action.TestAvailabilityAction;
|
||||
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>
|
||||
@@ -82,6 +94,10 @@ public class PreAuthActionsHandler {
|
||||
if (!resolveDeployment()) return true;
|
||||
handleTestAvailable();
|
||||
return true;
|
||||
} else if (requestUri.endsWith(AdapterConstants.K_JWKS)) {
|
||||
if (!resolveDeployment()) return true;
|
||||
handleJwksRequest();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -198,7 +214,8 @@ public class PreAuthActionsHandler {
|
||||
|
||||
try {
|
||||
JWSInput input = new JWSInput(token);
|
||||
if (RSAProvider.verify(input, deployment.getRealmKey())) {
|
||||
PublicKey publicKey = AdapterRSATokenVerifier.getPublicKey(input.getHeader().getKeyId(), deployment);
|
||||
if (RSAProvider.verify(input, publicKey)) {
|
||||
return input;
|
||||
}
|
||||
} catch (JWSInputException ignore) {
|
||||
@@ -240,4 +257,26 @@ 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.keycloak.AuthorizationContext;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
@@ -130,7 +130,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
|
||||
String tokenString = response.getToken();
|
||||
AccessToken token = null;
|
||||
try {
|
||||
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
log.debug("Token Verification succeeded!");
|
||||
} catch (VerificationException e) {
|
||||
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.keycloak.OAuth2Constants;
|
||||
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.common.util.HostUtils;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.common.util.StreamUtil;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
+2
-2
@@ -17,10 +17,10 @@
|
||||
|
||||
package org.keycloak.adapters.authentication;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
+6
-6
@@ -17,6 +17,12 @@
|
||||
|
||||
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.Iterator;
|
||||
import java.util.List;
|
||||
@@ -24,12 +30,6 @@ import java.util.Map;
|
||||
import java.util.ServiceConfigurationError;
|
||||
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>
|
||||
*/
|
||||
|
||||
+2
-2
@@ -17,14 +17,14 @@
|
||||
|
||||
package org.keycloak.adapters.authentication;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.util.BasicAuthHelper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Traditional OAuth2 authentication of clients based on client_id and client_secret
|
||||
*
|
||||
|
||||
+24
-6
@@ -17,16 +17,24 @@
|
||||
|
||||
package org.keycloak.adapters.authentication;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
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.representations.JsonWebToken;
|
||||
import org.keycloak.common.util.KeystoreUtil;
|
||||
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 .
|
||||
@@ -38,7 +46,9 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
||||
|
||||
public static final String PROVIDER_ID = "jwt";
|
||||
|
||||
private PrivateKey privateKey;
|
||||
private KeyPair keyPair;
|
||||
private JWK publicKeyJwk;
|
||||
|
||||
private int tokenTimeout;
|
||||
|
||||
@Override
|
||||
@@ -46,8 +56,9 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
public void setPrivateKey(PrivateKey privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
public void setupKeyPair(KeyPair keyPair) {
|
||||
this.keyPair = keyPair;
|
||||
this.publicKeyJwk = JWKBuilder.create().rs256(keyPair.getPublic());
|
||||
}
|
||||
|
||||
public void setTokenTimeout(int tokenTimeout) {
|
||||
@@ -58,6 +69,10 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
||||
return tokenTimeout;
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey() {
|
||||
return keyPair.getPublic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(KeycloakDeployment deployment, Object config) {
|
||||
if (config == null || !(config instanceof Map)) {
|
||||
@@ -88,7 +103,9 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
||||
if (clientKeyAlias == null) {
|
||||
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);
|
||||
}
|
||||
@@ -120,8 +137,9 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
|
||||
public String createSignedRequestToken(String clientId, String realmInfoUrl) {
|
||||
JsonWebToken jwt = createRequestToken(clientId, realmInfoUrl);
|
||||
return new JWSBuilder()
|
||||
.kid(publicKeyJwk.getKeyId())
|
||||
.jsonContent(jwt)
|
||||
.rsa256(privateKey);
|
||||
.rsa256(keyPair.getPrivate());
|
||||
}
|
||||
|
||||
protected JsonWebToken createRequestToken(String clientId, String realmInfoUrl) {
|
||||
|
||||
-1
@@ -26,7 +26,6 @@ import org.keycloak.authorization.client.resource.PermissionResource;
|
||||
import org.keycloak.authorization.client.resource.ProtectionResource;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
||||
+4
-5
@@ -18,9 +18,9 @@
|
||||
package org.keycloak.adapters.authorization;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.authorization.client.AuthorizationDeniedException;
|
||||
import org.keycloak.authorization.client.AuthzClient;
|
||||
@@ -33,7 +33,6 @@ import org.keycloak.authorization.client.representation.PermissionResponse;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
import org.keycloak.representations.idm.authorization.Permission;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
@@ -120,7 +119,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
AuthorizationResponse authzResponse = authzClient.authorization(accessToken).authorize(authzRequest);
|
||||
|
||||
if (authzResponse != null) {
|
||||
return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -130,7 +129,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
|
||||
if (token.getAuthorization() == null) {
|
||||
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getClientId());
|
||||
return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
||||
} else {
|
||||
EntitlementRequest request = new EntitlementRequest();
|
||||
PermissionRequest permissionRequest = new PermissionRequest();
|
||||
@@ -139,7 +138,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
permissionRequest.setScopes(new HashSet<>(pathConfig.getScopes()));
|
||||
request.addPermission(permissionRequest);
|
||||
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).get(authzClient.getConfiguration().getClientId(), request);
|
||||
return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
||||
}
|
||||
}
|
||||
} catch (AuthorizationDeniedException e) {
|
||||
|
||||
-3
@@ -33,12 +33,9 @@ import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathCon
|
||||
import org.keycloak.representations.idm.authorization.Permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
||||
+20
-25
@@ -17,14 +17,17 @@
|
||||
|
||||
package org.keycloak.adapters.jaas;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.security.Principal;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.common.VerificationException;
|
||||
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.callback.Callback;
|
||||
@@ -34,19 +37,14 @@ import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
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;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.security.Principal;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
@@ -88,9 +86,6 @@ public abstract class AbstractKeycloakLoginModule implements LoginModule {
|
||||
try {
|
||||
InputStream is = FindFile.findFile(keycloakConfigFile);
|
||||
KeycloakDeployment kd = KeycloakDeploymentBuilder.build(is);
|
||||
if (kd.getRealmKey() == null) {
|
||||
new AdapterDeploymentContext().resolveRealmKey(kd);
|
||||
}
|
||||
return kd;
|
||||
} catch (RuntimeException e) {
|
||||
getLogger().debug("Unable to find or parse file " + keycloakConfigFile + " due to " + e.getMessage(), e);
|
||||
@@ -190,7 +185,7 @@ public abstract class AbstractKeycloakLoginModule implements LoginModule {
|
||||
|
||||
|
||||
protected Auth bearerAuth(String tokenString) throws VerificationException {
|
||||
AccessToken token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||
AccessToken token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
|
||||
boolean verifyCaller;
|
||||
if (deployment.isUseResourceRoleMappings()) {
|
||||
|
||||
+14
-15
@@ -17,19 +17,6 @@
|
||||
|
||||
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.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
@@ -39,13 +26,25 @@ import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.constants.ServiceUrlConstants;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
|
||||
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
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
+13
-10
@@ -15,23 +15,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.example;
|
||||
package org.keycloak.adapters.rotation;
|
||||
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* Client authentication based on JWT signed by client private key .
|
||||
* See Keycloak documentation and <a href="https://tools.ietf.org/html/rfc7519">specs</a> for more details.
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ProductSAClientSignedJWTServlet extends ProductServiceAccountServlet {
|
||||
public class HardcodedPublicKeyLocator implements PublicKeyLocator {
|
||||
|
||||
@Override
|
||||
protected String getAdapterConfigLocation() {
|
||||
return "/WEB-INF/keycloak-client-signed-jwt.json";
|
||||
private PublicKey publicKey;
|
||||
|
||||
public HardcodedPublicKeyLocator(PublicKey publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getClientAuthenticationMethod() {
|
||||
return "jwt";
|
||||
public PublicKey getPublicKey(String kid, KeycloakDeployment deployment) {
|
||||
return publicKey;
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
}
|
||||
+12
-2
@@ -21,10 +21,12 @@ import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider;
|
||||
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.SslRequired;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -39,7 +41,11 @@ public class KeycloakDeploymentBuilderTest {
|
||||
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak.json"));
|
||||
assertEquals("demo", deployment.getRealm());
|
||||
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(SslRequired.EXTERNAL, deployment.getSslRequired());
|
||||
assertTrue(deployment.isUseResourceRoleMappings());
|
||||
@@ -62,12 +68,16 @@ public class KeycloakDeploymentBuilderTest {
|
||||
assertEquals(TokenStore.COOKIE, deployment.getTokenStore());
|
||||
assertEquals("email", deployment.getPrincipalAttribute());
|
||||
assertEquals(10, deployment.getTokenMinimumTimeToLive());
|
||||
assertEquals(20, deployment.getMinTimeBetweenJwksRequests());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadNoClientCredentials() throws Exception {
|
||||
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-no-credentials.json"));
|
||||
assertEquals(ClientIdAndSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
|
||||
|
||||
assertTrue(deployment.getPublicKeyLocator() instanceof JWKPublicKeyLocator);
|
||||
assertEquals(10, deployment.getMinTimeBetweenJwksRequests());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
/**
|
||||
* @author github.com/tubbynl
|
||||
*
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"realm": "demo",
|
||||
"resource": "customer-portal",
|
||||
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url": "https://localhost:8443/auth",
|
||||
"public-client": true,
|
||||
"expose-token": true
|
||||
|
||||
@@ -29,5 +29,6 @@
|
||||
"register-node-period": 1000,
|
||||
"token-store": "cookie",
|
||||
"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>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
-4
@@ -22,15 +22,11 @@ import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.deploy.LoginConfig;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
import org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve;
|
||||
import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Keycloak authentication valve
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
+2
-1
@@ -68,8 +68,9 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
|
||||
|
||||
boolean hasSubsystemConfig = service.isSecureDeployment(deploymentUnit);
|
||||
boolean webRequiresKC = loginConfig != null && "KEYCLOAK".equalsIgnoreCase(loginConfig.getAuthMethod());
|
||||
boolean isConfigured = service.isDeploymentConfigured(deploymentUnit);
|
||||
|
||||
if (hasSubsystemConfig || webRequiresKC) {
|
||||
if ((hasSubsystemConfig && isConfigured) || webRequiresKC) {
|
||||
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
|
||||
|
||||
+21
-7
@@ -17,17 +17,17 @@
|
||||
|
||||
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.Property;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.metadata.web.jboss.JBossWebMetaData;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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
|
||||
@@ -158,15 +158,22 @@ public final class KeycloakAdapterConfigService {
|
||||
}
|
||||
|
||||
public String getRealmName(DeploymentUnit deploymentUnit) {
|
||||
String deploymentName = preferredDeploymentName(deploymentUnit);
|
||||
ModelNode deployment = this.secureDeployments.get(deploymentName);
|
||||
ModelNode deployment = getSecureDeployment(deploymentUnit);
|
||||
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) {
|
||||
String deploymentName = preferredDeploymentName(deploymentUnit);
|
||||
ModelNode deployment = this.secureDeployments.get(deploymentName);
|
||||
ModelNode deployment = getSecureDeployment(deploymentUnit);
|
||||
String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
|
||||
ModelNode realm = this.realms.get(realmName);
|
||||
|
||||
@@ -195,6 +202,13 @@ public final class KeycloakAdapterConfigService {
|
||||
String deploymentName = preferredDeploymentName(deploymentUnit);
|
||||
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
|
||||
private String preferredDeploymentName(DeploymentUnit deploymentUnit) {
|
||||
|
||||
-1
@@ -25,7 +25,6 @@ import org.jboss.as.server.AbstractDeploymentChainStep;
|
||||
import org.jboss.as.server.DeploymentProcessorTarget;
|
||||
import org.jboss.as.server.deployment.Phase;
|
||||
import org.jboss.dmr.ModelNode;
|
||||
|
||||
import org.jboss.msc.service.ServiceController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
+1
-1
@@ -157,7 +157,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
|
||||
credentialsToAdd.add(addCredential);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
-2
@@ -23,8 +23,6 @@ import org.jboss.as.controller.OperationContext;
|
||||
import org.jboss.as.controller.OperationFailedException;
|
||||
import org.jboss.dmr.ModelNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Update an attribute on a realm.
|
||||
*
|
||||
|
||||
+22
@@ -23,6 +23,7 @@ import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
|
||||
import org.jboss.as.controller.SimpleResourceDefinition;
|
||||
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
|
||||
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.registry.ManagementResourceRegistration;
|
||||
import org.jboss.as.controller.registry.OperationEntry;
|
||||
@@ -79,6 +80,24 @@ class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
||||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.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>();
|
||||
static {
|
||||
@@ -88,6 +107,9 @@ class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
|
||||
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>();
|
||||
|
||||
+2
@@ -80,6 +80,8 @@ 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.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.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
|
||||
|
||||
|
||||
@@ -105,6 +105,8 @@
|
||||
<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="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:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+3
-3
@@ -19,11 +19,11 @@ package org.keycloak.adapters.installed;
|
||||
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.OAuthErrorException;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
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.JWSInputException;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
@@ -213,7 +213,7 @@ public class KeycloakInstalled {
|
||||
refreshToken = tokenResponse.getRefreshToken();
|
||||
idTokenString = tokenResponse.getIdToken();
|
||||
|
||||
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
if (idTokenString != null) {
|
||||
try {
|
||||
JWSInput input = new JWSInput(idTokenString);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+2
-3
@@ -20,8 +20,6 @@ package org.keycloak.jaxrs;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
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.BasicAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.BearerTokenRequestAuthenticator;
|
||||
@@ -31,6 +29,8 @@ import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||
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.common.constants.GenericConstants;
|
||||
|
||||
@@ -40,7 +40,6 @@ import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.container.PreMatching;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.SecurityContext;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
+9
-10
@@ -17,22 +17,21 @@
|
||||
|
||||
package org.keycloak.jaxrs;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.security.cert.X509Certificate;
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.SecurityContext;
|
||||
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
import org.keycloak.adapters.spi.AuthenticationError;
|
||||
import org.keycloak.adapters.spi.LogoutError;
|
||||
import org.keycloak.common.util.HostUtils;
|
||||
|
||||
import javax.security.cert.X509Certificate;
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.SecurityContext;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
|
||||
+7
-8
@@ -17,18 +17,17 @@
|
||||
|
||||
package org.keycloak.jaxrs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Logger;
|
||||
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 org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.common.constants.GenericConstants;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Variant of JaxrsBearerTokenFilter, which can be used to properly use resources from current osgi bundle
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+5
-8
@@ -27,28 +27,26 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
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.spi.HttpFacade;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||
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.enums.TokenStore;
|
||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||
@@ -61,7 +59,6 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
+1
-1
@@ -23,11 +23,11 @@ import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.CookieTokenStore;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
|
||||
/**
|
||||
* 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.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.security.Principal;
|
||||
|
||||
+1
-1
@@ -21,13 +21,13 @@ import org.eclipse.jetty.server.Request;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<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.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<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.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<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.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+1
-2
@@ -17,12 +17,11 @@
|
||||
|
||||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Jetty Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
(function( window, undefined ) {
|
||||
|
||||
|
||||
var KeycloakAuthorization = function (keycloak) {
|
||||
var _instance = this;
|
||||
this.rpt = null;
|
||||
@@ -112,44 +112,44 @@
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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();
|
||||
return this;
|
||||
};
|
||||
|
||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
|
||||
/**
|
||||
* 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.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).rpt;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
if (onDeny) {
|
||||
onDeny();
|
||||
} else {
|
||||
console.error('Authorization request was denied by the server.');
|
||||
}
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).rpt;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
if (onDeny) {
|
||||
onDeny();
|
||||
} else {
|
||||
if (onError) {
|
||||
onError();
|
||||
} else {
|
||||
console.error('Could not obtain authorization data from server.');
|
||||
}
|
||||
console.error('Authorization request was denied by the server.');
|
||||
}
|
||||
} else {
|
||||
if (onError) {
|
||||
onError();
|
||||
} else {
|
||||
console.error('Could not obtain authorization data from server.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
request.send(null);
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
request.send(null);
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
var loginIframe = {
|
||||
enable: true,
|
||||
callbackMap: [],
|
||||
callbackList: [],
|
||||
interval: 5
|
||||
};
|
||||
|
||||
@@ -155,7 +155,6 @@
|
||||
} else if (initOptions) {
|
||||
if (initOptions.token || initOptions.refreshToken) {
|
||||
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
|
||||
kc.timeSkew = initOptions.timeSkew || 0;
|
||||
|
||||
if (loginIframe.enable) {
|
||||
setupCheckLoginIframe().success(function() {
|
||||
@@ -166,6 +165,8 @@
|
||||
kc.onAuthError && kc.onAuthError();
|
||||
if (initOptions.onLoad) {
|
||||
onLoad();
|
||||
} else {
|
||||
initPromise.setError();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -177,6 +178,8 @@
|
||||
kc.onAuthError && kc.onAuthError();
|
||||
if (initOptions.onLoad) {
|
||||
onLoad();
|
||||
} else {
|
||||
initPromise.setError();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -359,11 +362,10 @@
|
||||
throw 'Not authenticated';
|
||||
}
|
||||
|
||||
var expiresIn = kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew;
|
||||
var expiresIn = kc.tokenParsed['exp'] - Math.ceil(new Date().getTime() / 1000) + kc.timeSkew;
|
||||
if (minValidity) {
|
||||
expiresIn -= minValidity;
|
||||
}
|
||||
|
||||
return expiresIn < 0;
|
||||
}
|
||||
|
||||
@@ -378,7 +380,20 @@
|
||||
minValidity = minValidity || 5;
|
||||
|
||||
var exec = function() {
|
||||
if (minValidity >= 0 && !kc.isTokenExpired(minValidity)) {
|
||||
var refreshToken = false;
|
||||
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);
|
||||
} else {
|
||||
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
|
||||
@@ -403,18 +418,21 @@
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
console.info('[KEYCLOAK] Token refreshed');
|
||||
|
||||
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
||||
|
||||
var tokenResponse = JSON.parse(req.responseText);
|
||||
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
|
||||
|
||||
setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token']);
|
||||
setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], timeLocal);
|
||||
|
||||
kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
|
||||
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
|
||||
p.setSuccess(true);
|
||||
}
|
||||
} else {
|
||||
console.warn('[KEYCLOAK] Failed to refresh token');
|
||||
|
||||
kc.onAuthRefreshError && kc.onAuthRefreshError();
|
||||
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
|
||||
p.setError(true);
|
||||
@@ -525,18 +543,16 @@
|
||||
function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
|
||||
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
||||
|
||||
setToken(accessToken, refreshToken, idToken);
|
||||
setToken(accessToken, refreshToken, idToken, timeLocal);
|
||||
|
||||
if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
|
||||
(kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
|
||||
(kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce)) {
|
||||
|
||||
console.log('invalid nonce!');
|
||||
console.info('[KEYCLOAK] Invalid nonce, clearing token');
|
||||
kc.clearToken();
|
||||
promise && promise.setError();
|
||||
} else {
|
||||
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
|
||||
|
||||
if (fulfillPromise) {
|
||||
kc.onAuthSuccess && kc.onAuthSuccess();
|
||||
promise && promise.setSuccess();
|
||||
@@ -609,7 +625,7 @@
|
||||
return promise.promise;
|
||||
}
|
||||
|
||||
function setToken(token, refreshToken, idToken) {
|
||||
function setToken(token, refreshToken, idToken, timeLocal) {
|
||||
if (kc.tokenTimeoutHandle) {
|
||||
clearTimeout(kc.tokenTimeoutHandle);
|
||||
kc.tokenTimeoutHandle = null;
|
||||
@@ -628,12 +644,23 @@
|
||||
kc.realmAccess = kc.tokenParsed.realm_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) {
|
||||
var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
|
||||
if (expiresIn <= 0) {
|
||||
if (kc.timeSkew == -1) {
|
||||
kc.onTokenExpired();
|
||||
} else {
|
||||
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
|
||||
var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
|
||||
if (expiresIn <= 0) {
|
||||
kc.onTokenExpired();
|
||||
} else {
|
||||
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +824,7 @@
|
||||
setTimeout(check, loginIframe.interval * 1000);
|
||||
}
|
||||
|
||||
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html?client_id=' + encodeURIComponent(kc.clientId) + '&origin=' + getOrigin();
|
||||
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
|
||||
iframe.setAttribute('src', src );
|
||||
iframe.style.display = 'none';
|
||||
document.body.appendChild(iframe);
|
||||
@@ -807,30 +834,21 @@
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var data = JSON.parse(event.data);
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.callbackId) {
|
||||
return;
|
||||
}
|
||||
|
||||
var promise = loginIframe.callbackMap[data.callbackId];
|
||||
if (!promise) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete loginIframe.callbackMap[data.callbackId];
|
||||
|
||||
if ((!kc.sessionId || kc.sessionId == data.session) && data.loggedIn) {
|
||||
promise.setSuccess();
|
||||
} else {
|
||||
if (event.data != "unchanged") {
|
||||
kc.clearToken();
|
||||
promise.setError();
|
||||
}
|
||||
|
||||
for (var i = loginIframe.callbackList.length - 1; i >= 0; --i) {
|
||||
var promise = loginIframe.callbackList[i];
|
||||
if (event.data == "unchanged") {
|
||||
promise.setSuccess();
|
||||
} else {
|
||||
promise.setError();
|
||||
}
|
||||
loginIframe.callbackList.splice(i, 1);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', messageCallback, false);
|
||||
|
||||
var check = function() {
|
||||
@@ -846,12 +864,13 @@
|
||||
function checkLoginIframe() {
|
||||
var promise = createPromise();
|
||||
|
||||
if (loginIframe.iframe && loginIframe.iframeOrigin) {
|
||||
var msg = {};
|
||||
msg.callbackId = createCallbackId();
|
||||
loginIframe.callbackMap[msg.callbackId] = promise;
|
||||
if (loginIframe.iframe && loginIframe.iframeOrigin ) {
|
||||
var msg = kc.clientId + ' ' + kc.sessionId;
|
||||
loginIframe.callbackList.push(promise);
|
||||
var origin = loginIframe.iframeOrigin;
|
||||
loginIframe.iframe.contentWindow.postMessage(JSON.stringify(msg), origin);
|
||||
if (loginIframe.callbackList.length == 1) {
|
||||
loginIframe.iframe.contentWindow.postMessage(msg, origin);
|
||||
}
|
||||
} else {
|
||||
promise.setSuccess();
|
||||
}
|
||||
|
||||
@@ -15,10 +15,56 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
function getCookie(cname)
|
||||
var init;
|
||||
|
||||
function checkState(clientId, origin, sessionState, callback) {
|
||||
if (!init) {
|
||||
var req = new XMLHttpRequest();
|
||||
|
||||
var url = location.href + "/init";
|
||||
url += "?client_id=" + encodeURIComponent(clientId);
|
||||
url += "&origin=" + encodeURIComponent(origin);
|
||||
url += "&session_state=" + encodeURIComponent(sessionState);
|
||||
|
||||
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) {
|
||||
var cookie = getCookie();
|
||||
if (sessionState == cookie) {
|
||||
callback('unchanged');
|
||||
} else {
|
||||
callback('changed');
|
||||
}
|
||||
} else {
|
||||
callback('error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCookie()
|
||||
{
|
||||
var name = cname + "=";
|
||||
var name = 'KEYCLOAK_SESSION=';
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0; i<ca.length; i++)
|
||||
{
|
||||
@@ -27,23 +73,24 @@
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function receiveMessage(event)
|
||||
{
|
||||
if (event.origin !== "ORIGIN") {
|
||||
console.log(event.origin + " does not match built origin");
|
||||
return;
|
||||
|
||||
}
|
||||
var data = JSON.parse(event.data);
|
||||
data.loggedIn = false;
|
||||
var cookie = getCookie('KEYCLOAK_SESSION');
|
||||
if (cookie) {
|
||||
data.loggedIn = true;
|
||||
data.session = cookie;
|
||||
var origin = event.origin;
|
||||
var data = event.data.split(' ');
|
||||
if (data.length != 2) {
|
||||
event.source.postMessage('error', origin);
|
||||
}
|
||||
|
||||
event.source.postMessage(JSON.stringify(data),
|
||||
event.origin);
|
||||
var clientId = data[0];
|
||||
var sessionState = data[1];
|
||||
|
||||
checkState(clientId, event.origin, sessionState, function(result) {
|
||||
event.source.postMessage(result, origin);
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+5
-5
@@ -16,6 +16,11 @@
|
||||
*/
|
||||
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.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -23,11 +28,6 @@ import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
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 {
|
||||
|
||||
private final Map<String, KeycloakDeployment> cache = new ConcurrentHashMap<String, KeycloakDeployment>();
|
||||
|
||||
+5
-5
@@ -17,11 +17,6 @@
|
||||
|
||||
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.util.security.Constraint;
|
||||
import org.jboss.logging.Logger;
|
||||
@@ -32,6 +27,11 @@ import org.osgi.service.http.HttpContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
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}
|
||||
* and allows to inject custom security constraint for securing resources by Keycloak.
|
||||
|
||||
+8
-9
@@ -17,15 +17,6 @@
|
||||
|
||||
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.servlet.CXFNonSpringServlet;
|
||||
import org.jboss.logging.Logger;
|
||||
@@ -38,6 +29,14 @@ import org.osgi.service.http.HttpContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
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
|
||||
* registered as service in OSGI container under {@link javax.servlet.Servlet} interface.
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak OIDC Client Adapter Modules</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+3
-4
@@ -18,15 +18,15 @@
|
||||
package org.keycloak.adapters.servlet;
|
||||
|
||||
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.spi.InMemorySessionIdMapper;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
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.UserSessionManagement;
|
||||
|
||||
@@ -39,7 +39,6 @@ import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+2
-2
@@ -17,12 +17,12 @@
|
||||
|
||||
package org.keycloak.servlet;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.AbstractOAuthClient;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.common.enums.RelativeUrlsUsed;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @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.spi.AuthenticationError;
|
||||
import org.keycloak.adapters.spi.LogoutError;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.util.TokenUtil;
|
||||
|
||||
import javax.security.cert.X509Certificate;
|
||||
|
||||
+1
@@ -20,6 +20,7 @@ package org.keycloak.servlet;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+12
@@ -17,15 +17,27 @@
|
||||
|
||||
package org.keycloak.adapters.springboot;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ConfigurationProperties(prefix = "keycloak", ignoreUnknownFields = false)
|
||||
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>();
|
||||
|
||||
public static class SecurityConstraint {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.2.0.Final</version>
|
||||
<version>2.3.0.CR1</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+4
-6
@@ -17,22 +17,20 @@
|
||||
|
||||
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.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
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
|
||||
* 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.adapters.AdapterTokenStore;
|
||||
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.OAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
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.token.KeycloakAuthenticationToken;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
-1
@@ -17,7 +17,6 @@
|
||||
|
||||
package org.keycloak.adapters.springsecurity.client;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
|
||||
+6
-4
@@ -19,10 +19,10 @@ package org.keycloak.adapters.springsecurity.filter;
|
||||
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.springsecurity.KeycloakAuthenticationException;
|
||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint;
|
||||
@@ -63,6 +63,8 @@ import java.io.IOException;
|
||||
public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {
|
||||
public static final String DEFAULT_LOGIN_URL = "/sso/login";
|
||||
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}
|
||||
@@ -164,7 +166,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
|
||||
*/
|
||||
protected boolean isBearerTokenRequest(HttpServletRequest request) {
|
||||
String authValue = request.getHeader(AUTHORIZATION_HEADER);
|
||||
return authValue != null && authValue.startsWith("Bearer");
|
||||
return authValue != null && authValue.toLowerCase().startsWith(SCHEME_BEARER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,7 +178,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
|
||||
*/
|
||||
protected boolean isBasicAuthRequest(HttpServletRequest request) {
|
||||
String authValue = request.getHeader(AUTHORIZATION_HEADER);
|
||||
return authValue != null && authValue.startsWith("Basic");
|
||||
return authValue != null && authValue.toLowerCase().startsWith(SCHEME_BASIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -18,9 +18,9 @@
|
||||
package org.keycloak.adapters.springsecurity.filter;
|
||||
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.spi.UserSessionManagement;
|
||||
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+1
-1
@@ -17,8 +17,8 @@
|
||||
|
||||
package org.keycloak.adapters.springsecurity.token;
|
||||
|
||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
+2
-4
@@ -17,19 +17,17 @@
|
||||
|
||||
package org.keycloak.adapters.springsecurity;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public class AdapterDeploymentContextFactoryBeanTest {
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@ import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* HTTP header inspecting API request matcher tests.
|
||||
|
||||
+2
-1
@@ -24,7 +24,8 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* Keycloak authentication entry point tests.
|
||||
|
||||
+6
-3
@@ -19,8 +19,8 @@ package org.keycloak.adapters.springsecurity.authentication;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
|
||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
import org.mockito.internal.util.collections.Sets;
|
||||
@@ -32,8 +32,11 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Keycloak authentication provider tests.
|
||||
|
||||
+6
-1
@@ -39,7 +39,12 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Keycloak logout handler tests.
|
||||
|
||||
+9
-3
@@ -22,11 +22,11 @@ import org.junit.Test;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
@@ -37,8 +37,14 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Spring Security request authenticator tests.
|
||||
|
||||
+5
-2
@@ -33,8 +33,11 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Keycloak client request factory tests.
|
||||
|
||||
+3
-1
@@ -25,7 +25,9 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import javax.servlet.http.Cookie;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Wrapped HTTP servlet request tests.
|
||||
|
||||
Loaded 100 of 2240 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user