Compare commits
44
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6eb89b656c | ||
|
|
43f5983613 | ||
|
|
723ba42264 | ||
|
|
081e9883e6 | ||
|
|
df311b60b4 | ||
|
|
0ff0dcecec | ||
|
|
eda09d2b32 | ||
|
|
340c8e8426 | ||
|
|
3777dc45d0 | ||
|
|
adf0a19f9d | ||
|
|
b748e269ec | ||
|
|
25b390b2ae | ||
|
|
52b7fd8c45 | ||
|
|
4268dd1777 | ||
|
|
24b7d080af | ||
|
|
39f0e4528a | ||
|
|
6b0bc0b3be | ||
|
|
2bf6d75e57 | ||
|
|
3dd6f9cb85 | ||
|
|
044d153c37 | ||
|
|
609c521c17 | ||
|
|
0b893d5634 | ||
|
|
aaf78297c9 | ||
|
|
64f8fe4987 | ||
|
|
e85a396572 | ||
|
|
99a16dcc1f | ||
|
|
8b6db21e56 | ||
|
|
01051016f5 | ||
|
|
c4a651bcac | ||
|
|
62c1ffcb52 | ||
|
|
00da3e3669 | ||
|
|
d4a5c81034 | ||
|
|
26f257a6ac | ||
|
|
12f3d2115d | ||
|
|
24e60747b6 | ||
|
|
5b6036525c | ||
|
|
bd4098191b | ||
|
|
df22c4d613 | ||
|
|
0561d73ae2 | ||
|
|
bf758809ba | ||
|
|
1fb4ca4525 | ||
|
|
e59646aafb | ||
|
|
bd8510f4da | ||
|
|
c56e171f3a |
No files matched your search
@@ -44,6 +44,7 @@ To start Keycloak during development first build as specified above, then run:
|
||||
|
||||
mvn -f testsuite/utils/pom.xml exec:java -Pkeycloak-server
|
||||
|
||||
When running testsuite, by default an account with username `admin` and password `admin` will be created within the master realm at start.
|
||||
|
||||
To start Keycloak from the server distribution first build the distribution it as specified above, then run:
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+10
@@ -482,6 +482,16 @@ public class AdapterDeploymentContext {
|
||||
public void setPublicKeyCacheTtl(int publicKeyCacheTtl) {
|
||||
delegate.setPublicKeyCacheTtl(publicKeyCacheTtl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVerifyTokenAudience() {
|
||||
return delegate.isVerifyTokenAudience();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVerifyTokenAudience(boolean verifyTokenAudience) {
|
||||
delegate.setVerifyTokenAudience(verifyTokenAudience);
|
||||
}
|
||||
}
|
||||
|
||||
protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
|
||||
|
||||
+3
@@ -106,7 +106,10 @@ public class AuthenticatedActionsHandler {
|
||||
if (deployment.getPolicyEnforcer() != null) {
|
||||
if (exposeHeaders != null) {
|
||||
exposeHeaders += ",";
|
||||
} else {
|
||||
exposeHeaders = "";
|
||||
}
|
||||
|
||||
exposeHeaders += "WWW-Authenticate";
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
@@ -96,7 +96,7 @@ public class BearerTokenRequestAuthenticator {
|
||||
}
|
||||
}
|
||||
try {
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
token = AdapterTokenVerifier.verifyToken(tokenString, deployment);
|
||||
} catch (VerificationException e) {
|
||||
log.error("Failed to verify token", e);
|
||||
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, "invalid_token", e.getMessage());
|
||||
|
||||
+7
-2
@@ -19,7 +19,8 @@ package org.keycloak.adapters;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.TokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
@@ -71,7 +72,11 @@ public class CookieTokenStore {
|
||||
|
||||
try {
|
||||
// Skip check if token is active now. It's supposed to be done later by the caller
|
||||
AccessToken accessToken = AdapterRSATokenVerifier.verifyToken(accessTokenString, deployment, false, true);
|
||||
TokenVerifier<AccessToken> tokenVerifier = AdapterTokenVerifier.createVerifier(accessTokenString, deployment, true, AccessToken.class)
|
||||
.checkActive(false)
|
||||
.verify();
|
||||
AccessToken accessToken = tokenVerifier.getToken();
|
||||
|
||||
IDToken idToken;
|
||||
if (idTokenString != null && idTokenString.length() > 0) {
|
||||
try {
|
||||
|
||||
+10
-1
@@ -92,10 +92,11 @@ public class KeycloakDeployment {
|
||||
// https://tools.ietf.org/html/rfc7636
|
||||
protected boolean pkce = false;
|
||||
protected boolean ignoreOAuthQueryParameter;
|
||||
|
||||
|
||||
protected Map<String, String> redirectRewriteRules;
|
||||
|
||||
protected boolean delegateBearerErrorResponseSending = false;
|
||||
protected boolean verifyTokenAudience = false;
|
||||
|
||||
public KeycloakDeployment() {
|
||||
}
|
||||
@@ -477,4 +478,12 @@ public class KeycloakDeployment {
|
||||
public void setDelegateBearerErrorResponseSending(boolean delegateBearerErrorResponseSending) {
|
||||
this.delegateBearerErrorResponseSending = delegateBearerErrorResponseSending;
|
||||
}
|
||||
|
||||
public boolean isVerifyTokenAudience() {
|
||||
return verifyTokenAudience;
|
||||
}
|
||||
|
||||
public void setVerifyTokenAudience(boolean verifyTokenAudience) {
|
||||
this.verifyTokenAudience = verifyTokenAudience;
|
||||
}
|
||||
}
|
||||
+1
@@ -122,6 +122,7 @@ public class KeycloakDeploymentBuilder {
|
||||
deployment.setPublicKeyCacheTtl(adapterConfig.getPublicKeyCacheTtl());
|
||||
deployment.setIgnoreOAuthQueryParameter(adapterConfig.isIgnoreOAuthQueryParameter());
|
||||
deployment.setRewriteRedirectRules(adapterConfig.getRedirectRewriteRules());
|
||||
deployment.setVerifyTokenAudience(adapterConfig.isVerifyTokenAudience());
|
||||
|
||||
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");
|
||||
|
||||
+4
-11
@@ -19,7 +19,7 @@ package org.keycloak.adapters;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
@@ -40,7 +40,6 @@ import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
||||
/**
|
||||
@@ -359,15 +358,9 @@ public class OAuthRequestAuthenticator {
|
||||
}
|
||||
|
||||
try {
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
if (idTokenString != null) {
|
||||
try {
|
||||
JWSInput input = new JWSInput(idTokenString);
|
||||
idToken = input.readJsonContent(IDToken.class);
|
||||
} catch (JWSInputException e) {
|
||||
throw new VerificationException();
|
||||
}
|
||||
}
|
||||
AdapterTokenVerifier.VerifiedTokens tokens = AdapterTokenVerifier.verifyTokens(tokenString, idTokenString, deployment);
|
||||
token = tokens.getAccessToken();
|
||||
idToken = tokens.getIdToken();
|
||||
log.debug("Token Verification succeeded!");
|
||||
} catch (VerificationException e) {
|
||||
log.error("failed verification of token: " + e.getMessage());
|
||||
|
||||
+24
-16
@@ -20,30 +20,27 @@ package org.keycloak.adapters;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.TokenVerifier;
|
||||
import org.keycloak.adapters.authentication.ClientCredentialsProvider;
|
||||
import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.spi.UserSessionManagement;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.StreamUtil;
|
||||
import org.keycloak.jose.jwk.JSONWebKeySet;
|
||||
import org.keycloak.jose.jwk.JWK;
|
||||
import org.keycloak.jose.jwk.JWKBuilder;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.representations.JsonWebToken;
|
||||
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 java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
@@ -213,17 +210,19 @@ public class PreAuthActionsHandler {
|
||||
}
|
||||
|
||||
try {
|
||||
JWSInput input = new JWSInput(token);
|
||||
PublicKey publicKey = AdapterRSATokenVerifier.getPublicKey(input.getHeader().getKeyId(), deployment);
|
||||
if (RSAProvider.verify(input, publicKey)) {
|
||||
return input;
|
||||
// Check just signature. Other things checked in validateAction
|
||||
TokenVerifier tokenVerifier = AdapterTokenVerifier.createVerifier(token, deployment, false, JsonWebToken.class);
|
||||
tokenVerifier.verify();
|
||||
return new JWSInput(token);
|
||||
} catch (VerificationException ignore) {
|
||||
log.warn("admin request failed, unable to verify token: " + ignore.getMessage());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(ignore.getMessage(), ignore);
|
||||
}
|
||||
} catch (JWSInputException ignore) {
|
||||
}
|
||||
|
||||
log.warn("admin request failed, unable to verify token");
|
||||
facade.getResponse().sendError(403, "no token");
|
||||
return null;
|
||||
facade.getResponse().sendError(403, "token failed verification");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,6 +249,15 @@ public class PreAuthActionsHandler {
|
||||
protected void handleVersion() {
|
||||
try {
|
||||
facade.getResponse().setStatus(200);
|
||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (deployment.isCors()) {
|
||||
String origin = facade.getRequest().getHeader(CorsHeaders.ORIGIN);
|
||||
if (origin == null) {
|
||||
log.debug("no origin header set in request");
|
||||
} else {
|
||||
facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);
|
||||
}
|
||||
}
|
||||
facade.getResponse().setHeader("Content-Type", "application/json");
|
||||
JsonSerialization.writeValueToStream(facade.getResponse().getOutputStream(), VersionRepresentation.SINGLETON);
|
||||
} catch (Exception e) {
|
||||
|
||||
+3
-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.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
@@ -130,7 +130,8 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
|
||||
String tokenString = response.getToken();
|
||||
AccessToken token = null;
|
||||
try {
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
AdapterTokenVerifier.VerifiedTokens tokens = AdapterTokenVerifier.verifyTokens(tokenString, response.getIdToken(), deployment);
|
||||
token = tokens.getAccessToken();
|
||||
log.debug("Token Verification succeeded!");
|
||||
} catch (VerificationException e) {
|
||||
log.error("failed verification of token");
|
||||
|
||||
+7
-10
@@ -112,8 +112,9 @@ public abstract class AbstractPolicyEnforcer {
|
||||
}
|
||||
|
||||
MethodConfig methodConfig = getRequiredScopes(pathConfig, request);
|
||||
Map<String, List<String>> claims = resolveClaims(pathConfig, httpFacade);
|
||||
|
||||
if (isAuthorized(pathConfig, methodConfig, accessToken, httpFacade)) {
|
||||
if (isAuthorized(pathConfig, methodConfig, accessToken, httpFacade, claims)) {
|
||||
try {
|
||||
return createAuthorizationContext(accessToken, pathConfig);
|
||||
} catch (Exception e) {
|
||||
@@ -142,7 +143,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||
|
||||
protected abstract boolean challenge(PathConfig pathConfig, MethodConfig methodConfig, OIDCHttpFacade facade);
|
||||
|
||||
protected boolean isAuthorized(PathConfig actualPathConfig, MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||
protected boolean isAuthorized(PathConfig actualPathConfig, MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
|
||||
Request request = httpFacade.getRequest();
|
||||
|
||||
if (isDefaultAccessDeniedUri(request)) {
|
||||
@@ -175,7 +176,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||
policyEnforcer.getPathMatcher().removeFromCache(getPath(request));
|
||||
}
|
||||
|
||||
return hasValidClaims(actualPathConfig, permission, httpFacade, authorization);
|
||||
return hasValidClaims(permission, claims);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -197,12 +198,10 @@ public abstract class AbstractPolicyEnforcer {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasValidClaims(PathConfig actualPathConfig, Permission permission, OIDCHttpFacade httpFacade, Authorization authorization) {
|
||||
private boolean hasValidClaims(Permission permission, Map<String, List<String>> claims) {
|
||||
Map<String, Set<String>> grantedClaims = permission.getClaims();
|
||||
|
||||
if (grantedClaims != null) {
|
||||
Map<String, List<String>> claims = resolveClaims(actualPathConfig, httpFacade);
|
||||
|
||||
if (claims.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -349,18 +348,16 @@ public abstract class AbstractPolicyEnforcer {
|
||||
}
|
||||
|
||||
private Map<String, List<String>> getClaims(Map<String, Map<String, Object>>claimInformationPointConfig, HttpFacade httpFacade) {
|
||||
Map<String, List<String>> claims = new HashMap<>();
|
||||
|
||||
if (claimInformationPointConfig != null) {
|
||||
for (Entry<String, Map<String, Object>> claimDef : claimInformationPointConfig.entrySet()) {
|
||||
ClaimInformationPointProviderFactory factory = getPolicyEnforcer().getClaimInformationPointProviderFactories().get(claimDef.getKey());
|
||||
|
||||
if (factory != null) {
|
||||
claims.putAll(factory.create(claimDef.getValue()).resolve(httpFacade));
|
||||
return factory.create(claimDef.getValue()).resolve(httpFacade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return claims;
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
+7
-9
@@ -27,7 +27,7 @@ import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.authorization.client.AuthorizationDeniedException;
|
||||
import org.keycloak.authorization.client.AuthzClient;
|
||||
@@ -55,14 +55,14 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAuthorized(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||
protected boolean isAuthorized(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
|
||||
AccessToken original = accessToken;
|
||||
|
||||
if (super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade)) {
|
||||
if (super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade, claims)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
accessToken = requestAuthorizationToken(pathConfig, methodConfig, httpFacade);
|
||||
accessToken = requestAuthorizationToken(pathConfig, methodConfig, httpFacade, claims);
|
||||
|
||||
if (accessToken == null) {
|
||||
return false;
|
||||
@@ -90,7 +90,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
|
||||
original.setAuthorization(authorization);
|
||||
|
||||
return super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade);
|
||||
return super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade, claims);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,7 +133,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
}
|
||||
}
|
||||
|
||||
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade) {
|
||||
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
|
||||
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
||||
return null;
|
||||
}
|
||||
@@ -149,8 +149,6 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
authzRequest.addPermission(pathConfig.getId(), methodConfig.getScopes());
|
||||
}
|
||||
|
||||
Map<String, List<String>> claims = resolveClaims(pathConfig, httpFacade);
|
||||
|
||||
if (!claims.isEmpty()) {
|
||||
authzRequest.setClaimTokenFormat("urn:ietf:params:oauth:token-type:jwt");
|
||||
authzRequest.setClaimToken(Base64.encodeBytes(JsonSerialization.writeValueAsBytes(claims)));
|
||||
@@ -171,7 +169,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
}
|
||||
|
||||
if (authzResponse != null) {
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getToken(), deployment);
|
||||
return AdapterTokenVerifier.verifyToken(authzResponse.getToken(), deployment);
|
||||
}
|
||||
} catch (AuthorizationDeniedException ignore) {
|
||||
LOGGER.debug("Authorization denied", ignore);
|
||||
|
||||
+10
-2
@@ -23,7 +23,7 @@ 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.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.FindFile;
|
||||
import org.keycloak.common.util.reflections.Reflections;
|
||||
@@ -202,8 +202,16 @@ public abstract class AbstractKeycloakLoginModule implements LoginModule {
|
||||
|
||||
|
||||
protected Auth bearerAuth(String tokenString) throws VerificationException {
|
||||
AccessToken token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
AccessToken token = AdapterTokenVerifier.verifyToken(tokenString, deployment);
|
||||
return postTokenVerification(tokenString, token);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called after accessToken was verified (including signature, expiration etc)
|
||||
*
|
||||
*/
|
||||
protected Auth postTokenVerification(String tokenString, AccessToken token) {
|
||||
boolean verifyCaller;
|
||||
if (deployment.isUseResourceRoleMappings()) {
|
||||
verifyCaller = token.isVerifyCaller(deployment.getResourceName());
|
||||
|
||||
+11
-1
@@ -27,6 +27,7 @@ import org.apache.http.message.BasicNameValuePair;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.constants.ServiceUrlConstants;
|
||||
@@ -56,11 +57,15 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
|
||||
|
||||
private static final Logger log = Logger.getLogger(DirectAccessGrantsLoginModule.class);
|
||||
|
||||
public static final String SCOPE_OPTION = "scope";
|
||||
|
||||
private String refreshToken;
|
||||
private String scope;
|
||||
|
||||
@Override
|
||||
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
|
||||
super.initialize(subject, callbackHandler, sharedState, options);
|
||||
this.scope = (String)options.get(SCOPE_OPTION);
|
||||
|
||||
// This is used just for logout
|
||||
Iterator<RefreshTokenHolder> iterator = subject.getPrivateCredentials(RefreshTokenHolder.class).iterator();
|
||||
@@ -89,6 +94,10 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
|
||||
formparams.add(new BasicNameValuePair("username", username));
|
||||
formparams.add(new BasicNameValuePair("password", password));
|
||||
|
||||
if (scope != null) {
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.SCOPE, scope));
|
||||
}
|
||||
|
||||
ClientCredentialsProviderUtils.setClientCredentials(deployment, post, formparams);
|
||||
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
@@ -121,7 +130,8 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
|
||||
// refreshToken will be saved to privateCreds of Subject for now
|
||||
refreshToken = tokenResponse.getRefreshToken();
|
||||
|
||||
return bearerAuth(tokenResponse.getToken());
|
||||
AdapterTokenVerifier.VerifiedTokens tokens = AdapterTokenVerifier.verifyTokens(tokenResponse.getToken(), tokenResponse.getIdToken(), deployment);
|
||||
return postTokenVerification(tokenResponse.getToken(), tokens.getAccessToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.rotation;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AdapterRSATokenVerifier {
|
||||
|
||||
private static final Logger log = Logger.getLogger(AdapterRSATokenVerifier.class);
|
||||
|
||||
public static AccessToken verifyToken(String tokenString, KeycloakDeployment deployment) throws VerificationException {
|
||||
return verifyToken(tokenString, deployment, true, true);
|
||||
}
|
||||
|
||||
|
||||
public static PublicKey getPublicKey(String kid, KeycloakDeployment deployment) throws VerificationException {
|
||||
PublicKeyLocator pkLocator = deployment.getPublicKeyLocator();
|
||||
|
||||
PublicKey publicKey = pkLocator.getPublicKey(kid, deployment);
|
||||
if (publicKey == null) {
|
||||
log.errorf("Didn't find publicKey for kid: %s", kid);
|
||||
throw new VerificationException("Didn't find publicKey for specified kid");
|
||||
}
|
||||
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public static AccessToken verifyToken(String tokenString, KeycloakDeployment deployment, boolean checkActive, boolean checkTokenType) throws VerificationException {
|
||||
RSATokenVerifier verifier = RSATokenVerifier.create(tokenString).realmUrl(deployment.getRealmInfoUrl()).checkActive(checkActive).checkTokenType(checkTokenType);
|
||||
PublicKey publicKey = getPublicKey(verifier.getHeader().getKeyId(), deployment);
|
||||
return verifier.publicKey(publicKey).verify().getToken();
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.TokenVerifier;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.representations.JsonWebToken;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AdapterTokenVerifier {
|
||||
|
||||
private static final Logger log = Logger.getLogger(AdapterTokenVerifier.class);
|
||||
|
||||
|
||||
/**
|
||||
* Verifies bearer token. Typically called when bearer token (access token) is sent to the service, which wants to verify it. Hence it also checks the audience in the token.
|
||||
*
|
||||
* @param tokenString
|
||||
* @param deployment
|
||||
* @return
|
||||
* @throws VerificationException
|
||||
*/
|
||||
public static AccessToken verifyToken(String tokenString, KeycloakDeployment deployment) throws VerificationException {
|
||||
TokenVerifier<AccessToken> tokenVerifier = createVerifier(tokenString, deployment, true, AccessToken.class);
|
||||
|
||||
// Verify audience of bearer-token
|
||||
if (deployment.isVerifyTokenAudience()) {
|
||||
tokenVerifier.audience(deployment.getResourceName());
|
||||
}
|
||||
|
||||
return tokenVerifier.verify().getToken();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify access token and ID token. Typically called after successful tokenResponse is received from Keycloak
|
||||
*
|
||||
* @param accessTokenString
|
||||
* @param idTokenString
|
||||
* @param deployment
|
||||
* @return verified and parsed accessToken and idToken
|
||||
* @throws VerificationException
|
||||
*/
|
||||
public static VerifiedTokens verifyTokens(String accessTokenString, String idTokenString, KeycloakDeployment deployment) throws VerificationException {
|
||||
// Adapters currently do most of the checks including signature etc on the access token
|
||||
TokenVerifier<AccessToken> tokenVerifier = createVerifier(accessTokenString, deployment, true, AccessToken.class);
|
||||
AccessToken accessToken = tokenVerifier.verify().getToken();
|
||||
|
||||
if (idTokenString != null) {
|
||||
// Don't verify signature again on IDToken
|
||||
IDToken idToken = TokenVerifier.create(idTokenString, IDToken.class).getToken();
|
||||
TokenVerifier<IDToken> idTokenVerifier = TokenVerifier.createWithoutSignature(idToken);
|
||||
|
||||
// Always verify audience on IDToken
|
||||
idTokenVerifier.audience(deployment.getResourceName());
|
||||
|
||||
idTokenVerifier.verify();
|
||||
return new VerifiedTokens(accessToken, idToken);
|
||||
} else {
|
||||
return new VerifiedTokens(accessToken, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates verifier, initializes it from the KeycloakDeployment and adds the publicKey and some default basic checks (activeness and tokenType). Useful if caller wants to add/remove/update
|
||||
* some checks
|
||||
*
|
||||
* @param tokenString
|
||||
* @param deployment
|
||||
* @param withDefaultChecks
|
||||
* @param tokenClass
|
||||
* @param <T>
|
||||
* @return tokenVerifier
|
||||
* @throws VerificationException
|
||||
*/
|
||||
public static <T extends JsonWebToken> TokenVerifier<T> createVerifier(String tokenString, KeycloakDeployment deployment, boolean withDefaultChecks, Class<T> tokenClass) throws VerificationException {
|
||||
TokenVerifier<T> tokenVerifier = TokenVerifier.create(tokenString, tokenClass);
|
||||
|
||||
if (withDefaultChecks) {
|
||||
tokenVerifier
|
||||
.withDefaultChecks()
|
||||
.realmUrl(deployment.getRealmInfoUrl());
|
||||
}
|
||||
|
||||
String kid = tokenVerifier.getHeader().getKeyId();
|
||||
PublicKey publicKey = getPublicKey(kid, deployment);
|
||||
tokenVerifier.publicKey(publicKey);
|
||||
|
||||
return tokenVerifier;
|
||||
}
|
||||
|
||||
|
||||
private 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 class VerifiedTokens {
|
||||
|
||||
private final AccessToken accessToken;
|
||||
private final IDToken idToken;
|
||||
|
||||
public VerifiedTokens(AccessToken accessToken, IDToken idToken) {
|
||||
this.accessToken = accessToken;
|
||||
this.idToken = idToken;
|
||||
}
|
||||
|
||||
|
||||
public AccessToken getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public IDToken getIdToken() {
|
||||
return idToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -77,6 +77,7 @@ public class KeycloakDeploymentBuilderTest {
|
||||
assertEquals(20, deployment.getMinTimeBetweenJwksRequests());
|
||||
assertEquals(120, deployment.getPublicKeyCacheTtl());
|
||||
assertEquals("/api/$1", deployment.getRedirectRewriteRules().get("^/wsmaster/api/(.*)$"));
|
||||
assertTrue(deployment.isVerifyTokenAudience());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"min-time-between-jwks-requests": 20,
|
||||
"public-key-cache-ttl": 120,
|
||||
"ignore-oauth-query-parameter": true,
|
||||
"verify-token-audience": true,
|
||||
"redirect-rewrite-rules" : {
|
||||
"^/wsmaster/api/(.*)$" : "/api/$1"
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</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>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
+7
@@ -98,6 +98,12 @@ class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
||||
.setValidator(new IntRangeValidator(-1, true))
|
||||
.setAllowExpression(true)
|
||||
.build();
|
||||
protected static final SimpleAttributeDefinition PUBLIC_KEY_CACHE_TTL =
|
||||
new SimpleAttributeDefinitionBuilder("public-key-cache-ttl", ModelType.INT, true)
|
||||
.setXmlName("public-key-cache-ttl")
|
||||
.setAllowExpression(true)
|
||||
.setValidator(new IntRangeValidator(-1, true))
|
||||
.build();
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
static {
|
||||
@@ -110,6 +116,7 @@ class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
||||
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);
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_KEY_CACHE_TTL);
|
||||
}
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
|
||||
+8
@@ -173,6 +173,13 @@ class SharedAttributeDefinitons {
|
||||
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||
.build();
|
||||
|
||||
protected static final SimpleAttributeDefinition VERIFY_TOKEN_AUDIENCE =
|
||||
new SimpleAttributeDefinitionBuilder("verify-token-audience", ModelType.BOOLEAN, true)
|
||||
.setXmlName("verify-token-audience")
|
||||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
@@ -200,6 +207,7 @@ class SharedAttributeDefinitons {
|
||||
ATTRIBUTES.add(TOKEN_STORE);
|
||||
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
|
||||
ATTRIBUTES.add(PROXY_URL);
|
||||
ATTRIBUTES.add(VERIFY_TOKEN_AUDIENCE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
@@ -47,6 +47,7 @@ keycloak.realm.register-node-period=how often to re-register node
|
||||
keycloak.realm.token-store=cookie or session storage for auth session data
|
||||
keycloak.realm.principal-attribute=token attribute to use to set Principal name
|
||||
keycloak.realm.proxy-url=The URL for the HTTP proxy if one is used.
|
||||
keycloak.realm.verify-token-audience=If true, then during bearer-only authentication, the adapter will verify if token contains this client name (resource) as an audience
|
||||
|
||||
keycloak.secure-deployment=A deployment secured by Keycloak
|
||||
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
|
||||
@@ -83,7 +84,9 @@ keycloak.secure-deployment.principal-attribute=token attribute to use to set Pri
|
||||
keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
|
||||
keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
|
||||
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
|
||||
keycloak.secure-deployment.public-key-cache-ttl=Maximum time the downloaded public keys are considered valid. When this time reach, the adapter is forced to download public keys from keycloak server
|
||||
keycloak.secure-deployment.proxy-url=The URL for the HTTP proxy if one is used.
|
||||
keycloak.secure-deployment.verify-token-audience=If true, then during bearer-only authentication, the adapter will verify if token contains this client name (resource) as an audience
|
||||
keycloak.secure-deployment.credential=Credential value
|
||||
|
||||
keycloak.credential=Credential
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
<xs:element name="token-store" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="proxy-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="verify-token-audience" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
@@ -108,7 +109,9 @@
|
||||
<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:element name="public-key-cache-ttl" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="proxy-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="verify-token-audience" type="xs:boolean" 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>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-fuse7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -38,7 +38,7 @@
|
||||
org.keycloak.*;version="${project.version}",
|
||||
org.apache.camel.*,
|
||||
org.apache.camel.component.undertow,
|
||||
io.undertow.*,
|
||||
io.undertow.*;version="[1.4,3)",
|
||||
*;resolution:=optional
|
||||
</keycloak.osgi.import>
|
||||
</properties>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-fuse7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-fuse7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-fuse7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -43,7 +43,7 @@
|
||||
org.apache.cxf.transport.http;resolution:=optional;version="[3,4)",
|
||||
org.apache.cxf.transport.http_undertow;resolution:=optional;version="[3,4)",
|
||||
org.apache.cxf.transport.servlet;resolution:=optional;version="[3,4)",
|
||||
io.undertow.*,
|
||||
io.undertow.*;version="[1.4,3)",
|
||||
*;resolution:=optional
|
||||
</keycloak.osgi.import>
|
||||
<keycloak.osgi.fragment>org.ops4j.pax.web.pax-web-undertow</keycloak.osgi.fragment>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+4
-13
@@ -24,16 +24,13 @@ import org.keycloak.OAuthErrorException;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.ServerRequest;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.rotation.AdapterTokenVerifier;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.core.Form;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
@@ -537,15 +534,9 @@ public class KeycloakInstalled {
|
||||
refreshToken = tokenResponse.getRefreshToken();
|
||||
idTokenString = tokenResponse.getIdToken();
|
||||
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
if (idTokenString != null) {
|
||||
try {
|
||||
JWSInput input = new JWSInput(idTokenString);
|
||||
idToken = input.readJsonContent(IDToken.class);
|
||||
} catch (JWSInputException e) {
|
||||
throw new VerificationException();
|
||||
}
|
||||
}
|
||||
AdapterTokenVerifier.VerifiedTokens tokens = AdapterTokenVerifier.verifyTokens(tokenString, idTokenString, deployment);
|
||||
token = tokens.getAccessToken();
|
||||
idToken = tokens.getIdToken();
|
||||
}
|
||||
|
||||
public AccessToken getToken() {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</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>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</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>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+5
@@ -32,6 +32,7 @@ import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator;
|
||||
import org.keycloak.adapters.undertow.KeycloakServletExtension;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -54,6 +55,10 @@ public class KeycloakBaseSpringBootConfiguration {
|
||||
KeycloakSpringBootConfigResolver.setAdapterConfig(keycloakProperties);
|
||||
}
|
||||
|
||||
@Autowired (required = false)
|
||||
public void setKeycloakConfigResolvers(KeycloakConfigResolver configResolver) {
|
||||
KeycloakSpringBootConfigResolver.setDelegateConfigResolver(configResolver);
|
||||
}
|
||||
|
||||
static class KeycloakBaseUndertowDeploymentInfoCustomizer {
|
||||
|
||||
|
||||
+16
-6
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.keycloak.adapters.springboot;
|
||||
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
@@ -24,22 +25,31 @@ import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||
|
||||
public class KeycloakSpringBootConfigResolver implements org.keycloak.adapters.KeycloakConfigResolver {
|
||||
|
||||
private KeycloakDeployment keycloakDeployment;
|
||||
|
||||
private static AdapterConfig adapterConfig;
|
||||
private static KeycloakConfigResolver delegateConfigResolver;
|
||||
|
||||
private KeycloakDeployment keycloakDeployment;
|
||||
|
||||
@Override
|
||||
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
|
||||
if (keycloakDeployment != null) {
|
||||
if (delegateConfigResolver == null) {
|
||||
if (keycloakDeployment != null) {
|
||||
return keycloakDeployment;
|
||||
}
|
||||
|
||||
keycloakDeployment = KeycloakDeploymentBuilder.build(KeycloakSpringBootConfigResolver.adapterConfig);
|
||||
|
||||
return keycloakDeployment;
|
||||
}
|
||||
|
||||
keycloakDeployment = KeycloakDeploymentBuilder.build(KeycloakSpringBootConfigResolver.adapterConfig);
|
||||
|
||||
return keycloakDeployment;
|
||||
return delegateConfigResolver.resolve(request);
|
||||
}
|
||||
|
||||
static void setAdapterConfig(AdapterConfig adapterConfig) {
|
||||
KeycloakSpringBootConfigResolver.adapterConfig = adapterConfig;
|
||||
}
|
||||
|
||||
static void setDelegateConfigResolver(KeycloakConfigResolver configResolver) {
|
||||
KeycloakSpringBootConfigResolver.delegateConfigResolver = configResolver;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-boot-container-bundle</artifactId>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Tomcat Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -35,6 +35,7 @@
|
||||
org.keycloak.adapters.undertow.*
|
||||
</keycloak.osgi.export>
|
||||
<keycloak.osgi.import>
|
||||
io.undertow.*;version="[1.4,3)",
|
||||
*;resolution:=optional
|
||||
</keycloak.osgi.import>
|
||||
</properties>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak WildFly Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
+7
@@ -96,6 +96,12 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
||||
.setValidator(new IntRangeValidator(-1, true))
|
||||
.setAllowExpression(true)
|
||||
.build();
|
||||
protected static final SimpleAttributeDefinition PUBLIC_KEY_CACHE_TTL =
|
||||
new SimpleAttributeDefinitionBuilder("public-key-cache-ttl", ModelType.INT, true)
|
||||
.setXmlName("public-key-cache-ttl")
|
||||
.setAllowExpression(true)
|
||||
.setValidator(new IntRangeValidator(-1, true))
|
||||
.build();
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
static {
|
||||
@@ -108,6 +114,7 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
||||
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);
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_KEY_CACHE_TTL);
|
||||
}
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
|
||||
+8
@@ -194,6 +194,13 @@ public class SharedAttributeDefinitons {
|
||||
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||
.build();
|
||||
|
||||
protected static final SimpleAttributeDefinition VERIFY_TOKEN_AUDIENCE =
|
||||
new SimpleAttributeDefinitionBuilder("verify-token-audience", ModelType.BOOLEAN, true)
|
||||
.setXmlName("verify-token-audience")
|
||||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.build();
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
static {
|
||||
ATTRIBUTES.add(REALM_PUBLIC_KEY);
|
||||
@@ -222,6 +229,7 @@ public class SharedAttributeDefinitons {
|
||||
ATTRIBUTES.add(AUTODETECT_BEARER_ONLY);
|
||||
ATTRIBUTES.add(IGNORE_OAUTH_QUERY_PARAMETER);
|
||||
ATTRIBUTES.add(PROXY_URL);
|
||||
ATTRIBUTES.add(VERIFY_TOKEN_AUDIENCE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
@@ -50,6 +50,7 @@ keycloak.realm.principal-attribute=token attribute to use to set Principal name
|
||||
keycloak.realm.autodetect-bearer-only=autodetect bearer-only requests
|
||||
keycloak.realm.ignore-oauth-query-parameter=disable query parameter parsing for access_token
|
||||
keycloak.realm.proxy-url=The URL for the HTTP proxy if one is used.
|
||||
keycloak.realm.verify-token-audience=If true, then during bearer-only authentication, the adapter will verify if token contains this client name (resource) as an audience
|
||||
|
||||
keycloak.secure-deployment=A deployment secured by Keycloak
|
||||
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
|
||||
@@ -87,9 +88,11 @@ keycloak.secure-deployment.principal-attribute=token attribute to use to set Pri
|
||||
keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
|
||||
keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
|
||||
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
|
||||
keycloak.secure-deployment.public-key-cache-ttl=Maximum time the downloaded public keys are considered valid. When this time reach, the adapter is forced to download public keys from keycloak server
|
||||
keycloak.secure-deployment.autodetect-bearer-only=autodetect bearer-only requests
|
||||
keycloak.secure-deployment.ignore-oauth-query-parameter=disable query parameter parsing for access_token
|
||||
keycloak.secure-deployment.proxy-url=The URL for the HTTP proxy if one is used.
|
||||
keycloak.secure-deployment.verify-token-audience=If true, then during bearer-only authentication, the adapter will verify if token contains this client name (resource) as an audience
|
||||
keycloak.secure-deployment.credential=Credential value
|
||||
|
||||
keycloak.credential=Credential
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="ignore-oauth-query-parameter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="proxy-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="verify-token-audience" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
@@ -112,9 +113,11 @@
|
||||
<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:element name="public-key-cache-ttl" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="ignore-oauth-query-parameter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="proxy-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="verify-token-audience" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
|
||||
+2
@@ -23,12 +23,14 @@
|
||||
<turn-off-change-session-id-on-login>false</turn-off-change-session-id-on-login>
|
||||
<token-minimum-time-to-live>10</token-minimum-time-to-live>
|
||||
<min-time-between-jwks-requests>20</min-time-between-jwks-requests>
|
||||
<public-key-cache-ttl>3600</public-key-cache-ttl>
|
||||
<realm-public-key>
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4siLKUew0WYxdtq6/rwk4Uj/4amGFFnE/yzIxQVU0PUqz3QBRVkUWpDj0K6ZnS5nzJV/y6DHLEy7hjZTdRDphyF1sq09aDOYnVpzu8o2sIlMM8q5RnUyEfIyUZqwo8pSZDJ90fS0s+IDUJNCSIrAKO3w1lqZDHL6E/YFHXyzkvQIDAQAB
|
||||
</realm-public-key>
|
||||
<auth-server-url>http://localhost:8080/auth</auth-server-url>
|
||||
<ssl-required>EXTERNAL</ssl-required>
|
||||
<proxy-url>http://localhost:9000</proxy-url>
|
||||
<verify-token-audience>true</verify-token-audience>
|
||||
<credential name="secret">0aa31d98-e0aa-404c-b6e0-e771dba1e798</credential>
|
||||
</secure-deployment>
|
||||
<secure-deployment name="http-endpoint">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
+7
@@ -95,6 +95,12 @@ abstract class AbstractAdapterConfigurationDefinition extends SimpleResourceDefi
|
||||
.setValidator(new IntRangeValidator(-1, true))
|
||||
.setAllowExpression(true)
|
||||
.build();
|
||||
protected static final SimpleAttributeDefinition PUBLIC_KEY_CACHE_TTL =
|
||||
new SimpleAttributeDefinitionBuilder("public-key-cache-ttl", ModelType.INT, true)
|
||||
.setXmlName("public-key-cache-ttl")
|
||||
.setAllowExpression(true)
|
||||
.setValidator(new IntRangeValidator(-1, true))
|
||||
.build();
|
||||
|
||||
static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
|
||||
@@ -108,6 +114,7 @@ abstract class AbstractAdapterConfigurationDefinition extends SimpleResourceDefi
|
||||
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);
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_KEY_CACHE_TTL);
|
||||
}
|
||||
|
||||
static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList();
|
||||
|
||||
+8
@@ -200,6 +200,13 @@ public class SharedAttributeDefinitons {
|
||||
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||
.build();
|
||||
|
||||
protected static final SimpleAttributeDefinition VERIFY_TOKEN_AUDIENCE =
|
||||
new SimpleAttributeDefinitionBuilder("verify-token-audience", ModelType.BOOLEAN, true)
|
||||
.setXmlName("verify-token-audience")
|
||||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.build();
|
||||
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
static {
|
||||
@@ -230,6 +237,7 @@ public class SharedAttributeDefinitons {
|
||||
ATTRIBUTES.add(AUTODETECT_BEARER_ONLY);
|
||||
ATTRIBUTES.add(IGNORE_OAUTH_QUERY_PARAMETER);
|
||||
ATTRIBUTES.add(PROXY_URL);
|
||||
ATTRIBUTES.add(VERIFY_TOKEN_AUDIENCE);
|
||||
}
|
||||
|
||||
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
|
||||
|
||||
+5
@@ -53,6 +53,7 @@ keycloak.realm.principal-attribute=token attribute to use to set Principal name
|
||||
keycloak.realm.autodetect-bearer-only=autodetect bearer-only requests
|
||||
keycloak.realm.ignore-oauth-query-parameter=disable query parameter parsing for access_token
|
||||
keycloak.realm.proxy-url=The URL for the HTTP proxy if one is used.
|
||||
keycloak.realm.verify-token-audience=If true, then during bearer-only authentication, the adapter will verify if token contains this client name (resource) as an audience
|
||||
|
||||
keycloak.secure-deployment=A deployment secured by Keycloak
|
||||
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
|
||||
@@ -93,8 +94,10 @@ keycloak.secure-deployment.principal-attribute=token attribute to use to set Pri
|
||||
keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
|
||||
keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
|
||||
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
|
||||
keycloak.secure-deployment.public-key-cache-ttl=Maximum time the downloaded public keys are considered valid. When this time reach, the adapter is forced to download public keys from keycloak server
|
||||
keycloak.secure-deployment.ignore-oauth-query-parameter=disable query parameter parsing for access_token
|
||||
keycloak.secure-deployment.proxy-url=The URL for the HTTP proxy if one is used.
|
||||
keycloak.secure-deployment.verify-token-audience=If true, then during bearer-only authentication, the adapter will verify if token contains this client name (resource) as an audience
|
||||
|
||||
keycloak.secure-server=A deployment secured by Keycloak
|
||||
keycloak.secure-server.add=Add a deployment to be secured by Keycloak
|
||||
@@ -135,8 +138,10 @@ keycloak.secure-server.principal-attribute=token attribute to use to set Princip
|
||||
keycloak.secure-server.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-server.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-server.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-server.public-key-cache-ttl=Maximum time the downloaded public keys are considered valid. When this time reach, the adapter is forced to download public keys from keycloak server
|
||||
keycloak.secure-server.ignore-oauth-query-parameter=disable query parameter parsing for access_token
|
||||
keycloak.secure-server.proxy-url=The URL for the HTTP proxy if one is used.
|
||||
keycloak.secure-server.verify-token-audience=If true, then during bearer-only authentication, the adapter will verify if token contains this client name (resource) as an audience
|
||||
|
||||
keycloak.secure-deployment.credential=Credential value
|
||||
keycloak.secure-server.credential=Credential value
|
||||
|
||||
+3
@@ -71,6 +71,7 @@
|
||||
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="ignore-oauth-query-parameter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="proxy-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="verify-token-audience" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
@@ -116,9 +117,11 @@
|
||||
<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:element name="public-key-cache-ttl" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="ignore-oauth-query-parameter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="proxy-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="verify-token-audience" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
|
||||
+2
@@ -53,6 +53,7 @@
|
||||
<turn-off-change-session-id-on-login>false</turn-off-change-session-id-on-login>
|
||||
<token-minimum-time-to-live>10</token-minimum-time-to-live>
|
||||
<min-time-between-jwks-requests>20</min-time-between-jwks-requests>
|
||||
<public-key-cache-ttl>3600</public-key-cache-ttl>
|
||||
<realm-public-key>
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4siLKUew0WYxdtq6/rwk4Uj/4amGFFnE/yzIxQVU0PUqz3QBRVkUWpDj0K6ZnS5nzJV/y6DHLEy7hjZTdRDphyF1sq09aDOYnVpzu8o2sIlMM8q5RnUyEfIyUZqwo8pSZDJ90fS0s+IDUJNCSIrAKO3w1lqZDHL6E/YFHXyzkvQIDAQAB
|
||||
</realm-public-key>
|
||||
@@ -60,6 +61,7 @@
|
||||
<ssl-required>EXTERNAL</ssl-required>
|
||||
<confidential-port>443</confidential-port>
|
||||
<proxy-url>http://localhost:9000</proxy-url>
|
||||
<verify-token-audience>true</verify-token-audience>
|
||||
<credential name="secret">0aa31d98-e0aa-404c-b6e0-e771dba1e798</credential>
|
||||
<redirect-rewrite-rule name="^/wsmaster/api/(.*)$">api/$1/</redirect-rewrite-rule>
|
||||
</secure-deployment>
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Adapters</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak SAML EAP Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+5
@@ -68,6 +68,11 @@ public class DeploymentBuilder {
|
||||
SP sp = adapter.getSps().get(0);
|
||||
deployment.setConfigured(true);
|
||||
deployment.setEntityID(sp.getEntityID());
|
||||
try {
|
||||
URI.create(sp.getEntityID());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
log.warnf("Entity ID is not an URI, assertion that restricts audience will fail. Update Entity ID to be URI.", sp.getEntityID());
|
||||
}
|
||||
deployment.setForceAuthentication(sp.isForceAuthentication());
|
||||
deployment.setIsPassive(sp.isIsPassive());
|
||||
deployment.setNameIDPolicyFormat(sp.getNameIDPolicyFormat());
|
||||
|
||||
+10
-1
@@ -84,6 +84,7 @@ import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
|
||||
import org.keycloak.rotation.KeyLocator;
|
||||
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
|
||||
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
|
||||
import org.keycloak.saml.validators.ConditionsValidator;
|
||||
import org.keycloak.saml.validators.DestinationValidator;
|
||||
|
||||
/**
|
||||
@@ -342,7 +343,15 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||
}
|
||||
try {
|
||||
assertion = AssertionUtil.getAssertion(responseHolder, responseType, deployment.getDecryptionKey());
|
||||
if (AssertionUtil.hasExpired(assertion)) {
|
||||
ConditionsValidator.Builder cvb = new ConditionsValidator.Builder(assertion.getID(), assertion.getConditions(), destinationValidator);
|
||||
try {
|
||||
cvb.addAllowedAudience(URI.create(deployment.getEntityID()));
|
||||
// getDestination has been validated to match request URL already so it matches SAML endpoint
|
||||
cvb.addAllowedAudience(URI.create(responseType.getDestination()));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// warning has been already emitted in DeploymentBuilder
|
||||
}
|
||||
if (! cvb.build().isValid()) {
|
||||
return initiateLogin();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak SAML Jetty Integration</name>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak SAML Client Adapter Modules</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak SAML Tomcat Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.4.0.Final</version>
|
||||
<version>4.5.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
Loaded 100 of 867 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user