Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e418390a2a | ||
|
|
1570d222a1 | ||
|
|
f0a1cb4f26 |
No files matched your search
@@ -14,7 +14,6 @@
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
catalog.xml
|
||||
nbproject
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
|
||||
+1
-2
@@ -12,12 +12,11 @@ env:
|
||||
- MAVEN_SKIP_RC=true
|
||||
- MAVEN_OPTS="-Xms512m -Xmx2048m"
|
||||
matrix:
|
||||
- TESTS=old
|
||||
- TESTS=group1
|
||||
- TESTS=group2
|
||||
- TESTS=group3
|
||||
- TESTS=group4
|
||||
- TESTS=adapter
|
||||
- TESTS=old
|
||||
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
-16
@@ -342,12 +342,6 @@ public class AdapterDeploymentContext {
|
||||
return delegate.getNotBefore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotBefore(int notBefore) {
|
||||
delegate.setNotBefore(notBefore);
|
||||
getPublicKeyLocator().reset(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExposeToken(boolean exposeToken) {
|
||||
delegate.setExposeToken(exposeToken);
|
||||
@@ -452,16 +446,6 @@ public class AdapterDeploymentContext {
|
||||
public int getMinTimeBetweenJwksRequests() {
|
||||
return delegate.getMinTimeBetweenJwksRequests();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPublicKeyCacheTtl() {
|
||||
return delegate.getPublicKeyCacheTtl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPublicKeyCacheTtl(int publicKeyCacheTtl) {
|
||||
delegate.setPublicKeyCacheTtl(publicKeyCacheTtl);
|
||||
}
|
||||
}
|
||||
|
||||
protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
|
||||
|
||||
+8
-1
@@ -46,7 +46,14 @@ public class HttpAdapterUtils {
|
||||
}
|
||||
InputStream is = entity.getContent();
|
||||
try {
|
||||
return JsonSerialization.readValue(is, clazz);
|
||||
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();
|
||||
|
||||
-23
@@ -57,7 +57,6 @@ public class KeycloakDeployment {
|
||||
|
||||
protected String resourceName;
|
||||
protected boolean bearerOnly;
|
||||
protected boolean autodetectBearerOnly;
|
||||
protected boolean enableBasicAuth;
|
||||
protected boolean publicClient;
|
||||
protected Map<String, Object> resourceCredentials = new HashMap<>();
|
||||
@@ -82,7 +81,6 @@ public class KeycloakDeployment {
|
||||
protected volatile int notBefore;
|
||||
protected int tokenMinimumTimeToLive;
|
||||
protected int minTimeBetweenJwksRequests;
|
||||
protected int publicKeyCacheTtl;
|
||||
private PolicyEnforcer policyEnforcer;
|
||||
|
||||
public KeycloakDeployment() {
|
||||
@@ -202,14 +200,6 @@ public class KeycloakDeployment {
|
||||
this.bearerOnly = bearerOnly;
|
||||
}
|
||||
|
||||
public boolean isAutodetectBearerOnly() {
|
||||
return autodetectBearerOnly;
|
||||
}
|
||||
|
||||
public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
|
||||
this.autodetectBearerOnly = autodetectBearerOnly;
|
||||
}
|
||||
|
||||
public boolean isEnableBasicAuth() {
|
||||
return enableBasicAuth;
|
||||
}
|
||||
@@ -338,11 +328,6 @@ public class KeycloakDeployment {
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
|
||||
public void updateNotBefore(int notBefore) {
|
||||
this.notBefore = notBefore;
|
||||
getPublicKeyLocator().reset(this);
|
||||
}
|
||||
|
||||
public boolean isAlwaysRefreshToken() {
|
||||
return alwaysRefreshToken;
|
||||
}
|
||||
@@ -399,14 +384,6 @@ public class KeycloakDeployment {
|
||||
this.minTimeBetweenJwksRequests = minTimeBetweenJwksRequests;
|
||||
}
|
||||
|
||||
public int getPublicKeyCacheTtl() {
|
||||
return publicKeyCacheTtl;
|
||||
}
|
||||
|
||||
public void setPublicKeyCacheTtl(int publicKeyCacheTtl) {
|
||||
this.publicKeyCacheTtl = publicKeyCacheTtl;
|
||||
}
|
||||
|
||||
public void setPolicyEnforcer(PolicyEnforcer policyEnforcer) {
|
||||
this.policyEnforcer = policyEnforcer;
|
||||
}
|
||||
|
||||
-2
@@ -99,14 +99,12 @@ public class KeycloakDeploymentBuilder {
|
||||
}
|
||||
|
||||
deployment.setBearerOnly(adapterConfig.isBearerOnly());
|
||||
deployment.setAutodetectBearerOnly(adapterConfig.isAutodetectBearerOnly());
|
||||
deployment.setEnableBasicAuth(adapterConfig.isEnableBasicAuth());
|
||||
deployment.setAlwaysRefreshToken(adapterConfig.isAlwaysRefreshToken());
|
||||
deployment.setRegisterNodeAtStartup(adapterConfig.isRegisterNodeAtStartup());
|
||||
deployment.setRegisterNodePeriod(adapterConfig.getRegisterNodePeriod());
|
||||
deployment.setTokenMinimumTimeToLive(adapterConfig.getTokenMinimumTimeToLive());
|
||||
deployment.setMinTimeBetweenJwksRequests(adapterConfig.getMinTimeBetweenJwksRequests());
|
||||
deployment.setPublicKeyCacheTtl(adapterConfig.getPublicKeyCacheTtl());
|
||||
|
||||
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");
|
||||
|
||||
+6
-5
@@ -25,7 +25,6 @@ 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.Encode;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.common.util.UriUtils;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
@@ -170,7 +169,7 @@ public class OAuthRequestAuthenticator {
|
||||
KeycloakUriBuilder redirectUriBuilder = deployment.getAuthUrl().clone()
|
||||
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
|
||||
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
|
||||
.queryParam(OAuth2Constants.REDIRECT_URI, Encode.encodeQueryParamAsIs(url)) // Need to encode uri ourselves as queryParam() will not encode % characters.
|
||||
.queryParam(OAuth2Constants.REDIRECT_URI, url)
|
||||
.queryParam(OAuth2Constants.STATE, state)
|
||||
.queryParam("login", "true");
|
||||
if(loginHint != null && loginHint.length() > 0){
|
||||
@@ -196,13 +195,15 @@ public class OAuthRequestAuthenticator {
|
||||
return sslRedirectPort;
|
||||
}
|
||||
|
||||
protected static final AtomicLong counter = new AtomicLong();
|
||||
|
||||
protected String getStateCode() {
|
||||
return AdapterUtils.generateId();
|
||||
return counter.getAndIncrement() + "/" + AdapterUtils.generateId();
|
||||
}
|
||||
|
||||
protected AuthChallenge loginRedirect() {
|
||||
final String state = getStateCode();
|
||||
final String redirect = getRedirectUri(state);
|
||||
final String redirect = getRedirectUri(state);
|
||||
if (redirect == null) {
|
||||
return challenge(403, OIDCAuthenticationError.Reason.NO_REDIRECT_URI, null);
|
||||
}
|
||||
@@ -356,7 +357,7 @@ public class OAuthRequestAuthenticator {
|
||||
return challenge(403, OIDCAuthenticationError.Reason.INVALID_TOKEN, null);
|
||||
}
|
||||
if (tokenResponse.getNotBeforePolicy() > deployment.getNotBefore()) {
|
||||
deployment.updateNotBefore(tokenResponse.getNotBeforePolicy());
|
||||
deployment.setNotBefore(tokenResponse.getNotBeforePolicy());
|
||||
}
|
||||
if (token.getIssuedAt() < deployment.getNotBefore()) {
|
||||
log.error("Stale token");
|
||||
|
||||
+2
-2
@@ -155,7 +155,7 @@ public class PreAuthActionsHandler {
|
||||
} else {
|
||||
log.debugf("logout of all sessions for application '%s'", action.getResource());
|
||||
if (action.getNotBefore() > deployment.getNotBefore()) {
|
||||
deployment.updateNotBefore(action.getNotBefore());
|
||||
deployment.setNotBefore(action.getNotBefore());
|
||||
}
|
||||
userSessionManagement.logoutAll();
|
||||
}
|
||||
@@ -177,7 +177,7 @@ public class PreAuthActionsHandler {
|
||||
}
|
||||
PushNotBeforeAction action = JsonSerialization.readValue(token.getContent(), PushNotBeforeAction.class);
|
||||
if (!validateAction(action)) return;
|
||||
deployment.updateNotBefore(action.getNotBefore());
|
||||
deployment.setNotBefore(action.getNotBefore());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
|
||||
}
|
||||
|
||||
if (response.getNotBeforePolicy() > deployment.getNotBefore()) {
|
||||
deployment.updateNotBefore(response.getNotBeforePolicy());
|
||||
deployment.setNotBefore(response.getNotBeforePolicy());
|
||||
}
|
||||
|
||||
this.token = token;
|
||||
|
||||
-38
@@ -17,8 +17,6 @@
|
||||
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
@@ -118,12 +116,6 @@ public abstract class RequestAuthenticator {
|
||||
return AuthOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
|
||||
if (isAutodetectedBearerOnly(facade.getRequest())) {
|
||||
challenge = bearer.getChallenge();
|
||||
log.debug("NOT_ATTEMPTED: Treating as bearer only");
|
||||
return AuthOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("try oauth");
|
||||
}
|
||||
@@ -166,36 +158,6 @@ public abstract class RequestAuthenticator {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isAutodetectedBearerOnly(HttpFacade.Request request) {
|
||||
if (!deployment.isAutodetectBearerOnly()) return false;
|
||||
|
||||
String headerValue = facade.getRequest().getHeader("X-Requested-With");
|
||||
if (headerValue != null && headerValue.equalsIgnoreCase("XMLHttpRequest")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
headerValue = facade.getRequest().getHeader("Faces-Request");
|
||||
if (headerValue != null && headerValue.startsWith("partial/")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
headerValue = facade.getRequest().getHeader("SOAPAction");
|
||||
if (headerValue != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<String> accepts = facade.getRequest().getHeaders("Accept");
|
||||
if (accepts == null) accepts = Collections.emptyList();
|
||||
|
||||
for (String accept : accepts) {
|
||||
if (accept.contains("text/html") || accept.contains("text/*") || accept.contains("*/*")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract OAuthRequestAuthenticator createOAuthAuthenticator();
|
||||
|
||||
protected BearerTokenRequestAuthenticator createBearerTokenAuthenticator() {
|
||||
|
||||
+24
-31
@@ -17,13 +17,6 @@
|
||||
*/
|
||||
package org.keycloak.adapters.authorization;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.AuthorizationContext;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
@@ -39,6 +32,13 @@ import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.Enforce
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
import org.keycloak.representations.idm.authorization.Permission;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@@ -48,7 +48,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||
private final PolicyEnforcerConfig enforcerConfig;
|
||||
private final PolicyEnforcer policyEnforcer;
|
||||
|
||||
private Map<String, PathConfig> paths;
|
||||
private List<PathConfig> paths;
|
||||
private AuthzClient authzClient;
|
||||
private PathMatcher pathMatcher;
|
||||
|
||||
@@ -57,7 +57,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||
this.enforcerConfig = policyEnforcer.getEnforcerConfig();
|
||||
this.authzClient = policyEnforcer.getClient();
|
||||
this.pathMatcher = new PathMatcher();
|
||||
this.paths = policyEnforcer.getPaths();
|
||||
this.paths = new ArrayList<>(policyEnforcer.getPaths());
|
||||
}
|
||||
|
||||
public AuthorizationContext authorize(OIDCHttpFacade httpFacade) {
|
||||
@@ -75,7 +75,8 @@ public abstract class AbstractPolicyEnforcer {
|
||||
if (accessToken != null) {
|
||||
Request request = httpFacade.getRequest();
|
||||
Response response = httpFacade.getResponse();
|
||||
String path = getPath(request);
|
||||
String pathInfo = URI.create(request.getURI()).getPath().substring(1);
|
||||
String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
|
||||
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
|
||||
|
||||
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
|
||||
@@ -121,9 +122,12 @@ public abstract class AbstractPolicyEnforcer {
|
||||
protected boolean isAuthorized(PathConfig actualPathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||
Request request = httpFacade.getRequest();
|
||||
PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
|
||||
String accessDeniedPath = enforcerConfig.getOnDenyRedirectTo();
|
||||
|
||||
if (isDefaultAccessDeniedUri(request, enforcerConfig)) {
|
||||
return true;
|
||||
if (accessDeniedPath != null) {
|
||||
if (request.getURI().contains(accessDeniedPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
AccessToken.Authorization authorization = accessToken.getAuthorization();
|
||||
@@ -169,17 +173,6 @@ public abstract class AbstractPolicyEnforcer {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isDefaultAccessDeniedUri(Request request, PolicyEnforcerConfig enforcerConfig) {
|
||||
String accessDeniedPath = enforcerConfig.getOnDenyRedirectTo();
|
||||
|
||||
if (accessDeniedPath != null) {
|
||||
if (request.getURI().contains(accessDeniedPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasResourceScopePermission(Set<String> requiredScopes, Permission permission, PathConfig actualPathConfig) {
|
||||
Set<String> allowedScopes = permission.getScopes();
|
||||
return (allowedScopes.containsAll(requiredScopes) || allowedScopes.isEmpty());
|
||||
@@ -227,23 +220,27 @@ public abstract class AbstractPolicyEnforcer {
|
||||
}
|
||||
|
||||
private PathConfig resolvePathConfig(PathConfig originalConfig, Request request) {
|
||||
String path = getPath(request);
|
||||
|
||||
if (originalConfig.hasPattern()) {
|
||||
String pathInfo = URI.create(request.getURI()).getPath().substring(1);
|
||||
String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
|
||||
ProtectedResource resource = this.authzClient.protection().resource();
|
||||
Set<String> search = resource.findByFilter("uri=" + path);
|
||||
|
||||
if (!search.isEmpty()) {
|
||||
// resource does exist on the server, cache it
|
||||
ResourceRepresentation targetResource = resource.findById(search.iterator().next()).getResourceDescription();
|
||||
PathConfig config = PolicyEnforcer.createPathConfig(targetResource);
|
||||
PathConfig config = new PathConfig();
|
||||
|
||||
config.setId(targetResource.getId());
|
||||
config.setName(targetResource.getName());
|
||||
config.setType(targetResource.getType());
|
||||
config.setPath(targetResource.getUri());
|
||||
config.setScopes(originalConfig.getScopes());
|
||||
config.setMethods(originalConfig.getMethods());
|
||||
config.setParentConfig(originalConfig);
|
||||
config.setEnforcementMode(originalConfig.getEnforcementMode());
|
||||
|
||||
this.policyEnforcer.addPath(config);
|
||||
this.paths.add(config);
|
||||
|
||||
return config;
|
||||
}
|
||||
@@ -252,10 +249,6 @@ public abstract class AbstractPolicyEnforcer {
|
||||
return originalConfig;
|
||||
}
|
||||
|
||||
private String getPath(Request request) {
|
||||
return request.getRelativePath();
|
||||
}
|
||||
|
||||
private Set<String> getRequiredScopes(PathConfig pathConfig, Request request) {
|
||||
Set<String> requiredScopes = new HashSet<>();
|
||||
|
||||
|
||||
+34
-31
@@ -17,10 +17,6 @@
|
||||
*/
|
||||
package org.keycloak.adapters.authorization;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
@@ -38,6 +34,10 @@ import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
import org.keycloak.representations.idm.authorization.Permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@@ -51,34 +51,39 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
|
||||
@Override
|
||||
protected boolean isAuthorized(PathConfig pathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||
int retry = 2;
|
||||
AccessToken original = accessToken;
|
||||
|
||||
if (super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
|
||||
return true;
|
||||
while (retry > 0) {
|
||||
if (super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
accessToken = requestAuthorizationToken(pathConfig, requiredScopes, httpFacade);
|
||||
|
||||
if (accessToken == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AccessToken.Authorization authorization = original.getAuthorization();
|
||||
|
||||
if (authorization == null) {
|
||||
authorization = new AccessToken.Authorization();
|
||||
authorization.setPermissions(new ArrayList<Permission>());
|
||||
}
|
||||
|
||||
AccessToken.Authorization newAuthorization = accessToken.getAuthorization();
|
||||
|
||||
if (newAuthorization != null) {
|
||||
authorization.getPermissions().addAll(newAuthorization.getPermissions());
|
||||
}
|
||||
|
||||
original.setAuthorization(authorization);
|
||||
|
||||
retry--;
|
||||
}
|
||||
|
||||
accessToken = requestAuthorizationToken(pathConfig, requiredScopes, httpFacade);
|
||||
|
||||
if (accessToken == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AccessToken.Authorization authorization = original.getAuthorization();
|
||||
|
||||
if (authorization == null) {
|
||||
authorization = new AccessToken.Authorization();
|
||||
authorization.setPermissions(new ArrayList<Permission>());
|
||||
}
|
||||
|
||||
AccessToken.Authorization newAuthorization = accessToken.getAuthorization();
|
||||
|
||||
if (newAuthorization != null) {
|
||||
authorization.getPermissions().addAll(newAuthorization.getPermissions());
|
||||
}
|
||||
|
||||
original.setAuthorization(authorization);
|
||||
|
||||
return super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,7 +108,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
KeycloakDeployment deployment = getPolicyEnforcer().getDeployment();
|
||||
|
||||
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
||||
LOGGER.debug("Obtaining authorization for authenticated user.");
|
||||
LOGGER.debug("Obtaining authorization for authenticated user.");
|
||||
PermissionRequest permissionRequest = new PermissionRequest();
|
||||
|
||||
permissionRequest.setResourceSetId(pathConfig.getId());
|
||||
@@ -131,14 +136,12 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
permissionRequest.setResourceSetId(pathConfig.getId());
|
||||
permissionRequest.setResourceSetName(pathConfig.getName());
|
||||
permissionRequest.setScopes(new HashSet<>(pathConfig.getScopes()));
|
||||
LOGGER.debugf("Sending entitlements request: resource_set_id [%s], resource_set_name [%s], scopes [%s].", permissionRequest.getResourceSetId(), permissionRequest.getResourceSetName(), permissionRequest.getScopes());
|
||||
request.addPermission(permissionRequest);
|
||||
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).get(authzClient.getConfiguration().getClientId(), request);
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
||||
}
|
||||
}
|
||||
} catch (AuthorizationDeniedException e) {
|
||||
LOGGER.debug("Authorization denied", e);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unexpected error during authorization request.", e);
|
||||
|
||||
+3
-9
@@ -19,7 +19,7 @@ package org.keycloak.adapters.authorization;
|
||||
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
@@ -28,16 +28,10 @@ class PathMatcher {
|
||||
|
||||
private static final String ANY_RESOURCE_PATTERN = "/*";
|
||||
|
||||
PathConfig matches(final String requestedUri, Map<String, PathConfig> paths) {
|
||||
PathConfig pathConfig = paths.get(requestedUri);
|
||||
|
||||
if (pathConfig != null) {
|
||||
return pathConfig;
|
||||
}
|
||||
|
||||
PathConfig matches(final String requestedUri, List<PathConfig> paths) {
|
||||
PathConfig actualConfig = null;
|
||||
|
||||
for (PathConfig entry : paths.values()) {
|
||||
for (PathConfig entry : paths) {
|
||||
String protectedUri = entry.getPath();
|
||||
String selectedUri = null;
|
||||
|
||||
|
||||
+13
-20
@@ -34,10 +34,8 @@ import org.keycloak.representations.idm.authorization.Permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -50,7 +48,7 @@ public class PolicyEnforcer {
|
||||
private final KeycloakDeployment deployment;
|
||||
private final AuthzClient authzClient;
|
||||
private final PolicyEnforcerConfig enforcerConfig;
|
||||
private final Map<String, PathConfig> paths;
|
||||
private final List<PathConfig> paths;
|
||||
|
||||
public PolicyEnforcer(KeycloakDeployment deployment, AdapterConfig adapterConfig) {
|
||||
this.deployment = deployment;
|
||||
@@ -60,7 +58,7 @@ public class PolicyEnforcer {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Initialization complete. Path configurations:");
|
||||
for (PathConfig pathConfig : this.paths.values()) {
|
||||
for (PathConfig pathConfig : this.paths) {
|
||||
LOGGER.debug(pathConfig);
|
||||
}
|
||||
}
|
||||
@@ -98,19 +96,15 @@ public class PolicyEnforcer {
|
||||
return authzClient;
|
||||
}
|
||||
|
||||
public Map<String, PathConfig> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
void addPath(PathConfig pathConfig) {
|
||||
paths.put(pathConfig.getPath(), pathConfig);
|
||||
public List<PathConfig> getPaths() {
|
||||
return Collections.unmodifiableList(paths);
|
||||
}
|
||||
|
||||
KeycloakDeployment getDeployment() {
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private Map<String, PathConfig> configurePaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
|
||||
private List<PathConfig> configurePaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
|
||||
boolean loadPathsFromServer = true;
|
||||
|
||||
for (PathConfig pathConfig : enforcerConfig.getPaths()) {
|
||||
@@ -129,8 +123,8 @@ public class PolicyEnforcer {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, PathConfig> configureDefinedPaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
|
||||
Map<String, PathConfig> paths = Collections.synchronizedMap(new HashMap<String, PathConfig>());
|
||||
private List<PathConfig> configureDefinedPaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
|
||||
List<PathConfig> paths = new ArrayList<>();
|
||||
|
||||
for (PathConfig pathConfig : enforcerConfig.getPaths()) {
|
||||
Set<String> search;
|
||||
@@ -178,7 +172,7 @@ public class PolicyEnforcer {
|
||||
|
||||
PathConfig existingPath = null;
|
||||
|
||||
for (PathConfig current : paths.values()) {
|
||||
for (PathConfig current : paths) {
|
||||
if (current.getId().equals(pathConfig.getId()) && current.getPath().equals(pathConfig.getPath())) {
|
||||
existingPath = current;
|
||||
break;
|
||||
@@ -186,7 +180,7 @@ public class PolicyEnforcer {
|
||||
}
|
||||
|
||||
if (existingPath == null) {
|
||||
paths.put(pathConfig.getPath(), pathConfig);
|
||||
paths.add(pathConfig);
|
||||
} else {
|
||||
existingPath.getMethods().addAll(pathConfig.getMethods());
|
||||
existingPath.getScopes().addAll(pathConfig.getScopes());
|
||||
@@ -196,24 +190,23 @@ public class PolicyEnforcer {
|
||||
return paths;
|
||||
}
|
||||
|
||||
private Map<String, PathConfig> configureAllPathsForResourceServer(ProtectedResource protectedResource) {
|
||||
private List<PathConfig> configureAllPathsForResourceServer(ProtectedResource protectedResource) {
|
||||
LOGGER.info("Querying the server for all resources associated with this application.");
|
||||
Map<String, PathConfig> paths = Collections.synchronizedMap(new HashMap<String, PathConfig>());
|
||||
List<PathConfig> paths = new ArrayList<>();
|
||||
|
||||
for (String id : protectedResource.findAll()) {
|
||||
RegistrationResponse response = protectedResource.findById(id);
|
||||
ResourceRepresentation resourceDescription = response.getResourceDescription();
|
||||
|
||||
if (resourceDescription.getUri() != null) {
|
||||
PathConfig pathConfig = createPathConfig(resourceDescription);
|
||||
paths.put(pathConfig.getPath(), pathConfig);
|
||||
paths.add(createPathConfig(resourceDescription));
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
static PathConfig createPathConfig(ResourceRepresentation resourceDescription) {
|
||||
private PathConfig createPathConfig(ResourceRepresentation resourceDescription) {
|
||||
PathConfig pathConfig = new PathConfig();
|
||||
|
||||
pathConfig.setId(resourceDescription.getId());
|
||||
|
||||
-5
@@ -37,9 +37,4 @@ public class HardcodedPublicKeyLocator implements PublicKeyLocator {
|
||||
public PublicKey getPublicKey(String kid, KeycloakDeployment deployment) {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(KeycloakDeployment deployment) {
|
||||
|
||||
}
|
||||
}
|
||||
+16
-30
@@ -25,6 +25,7 @@ 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;
|
||||
@@ -47,51 +48,36 @@ public class JWKPublicKeyLocator implements PublicKeyLocator {
|
||||
@Override
|
||||
public PublicKey getPublicKey(String kid, KeycloakDeployment deployment) {
|
||||
int minTimeBetweenRequests = deployment.getMinTimeBetweenJwksRequests();
|
||||
int publicKeyCacheTtl = deployment.getPublicKeyCacheTtl();
|
||||
int currentTime = Time.currentTime();
|
||||
|
||||
// Check if key is in cache.
|
||||
PublicKey publicKey = lookupCachedKey(publicKeyCacheTtl, currentTime, kid);
|
||||
PublicKey publicKey = currentKeys.get(kid);
|
||||
if (publicKey != null) {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
int currentTime = Time.currentTime();
|
||||
|
||||
// Check if we are allowed to send request
|
||||
synchronized (this) {
|
||||
currentTime = Time.currentTime();
|
||||
if (currentTime > lastRequestTime + minTimeBetweenRequests) {
|
||||
sendRequest(deployment);
|
||||
lastRequestTime = currentTime;
|
||||
} else {
|
||||
log.debug("Won't send request to realm jwks url. Last request time was " + lastRequestTime);
|
||||
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 lookupCachedKey(publicKeyCacheTtl, currentTime, kid);
|
||||
}
|
||||
}
|
||||
|
||||
return currentKeys.get(kid);
|
||||
|
||||
@Override
|
||||
public void reset(KeycloakDeployment deployment) {
|
||||
synchronized (this) {
|
||||
sendRequest(deployment);
|
||||
lastRequestTime = Time.currentTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private PublicKey lookupCachedKey(int publicKeyCacheTtl, int currentTime, String kid) {
|
||||
if (lastRequestTime + publicKeyCacheTtl > currentTime) {
|
||||
return currentKeys.get(kid);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void sendRequest(KeycloakDeployment deployment) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Going to send request to retrieve new set of realm public keys for client " + deployment.getResourceName());
|
||||
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());
|
||||
@@ -101,7 +87,7 @@ public class JWKPublicKeyLocator implements PublicKeyLocator {
|
||||
Map<String, PublicKey> publicKeys = JWKSUtils.getKeysForUse(jwks, JWK.Use.SIG);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Realm public keys successfully retrieved for client " + deployment.getResourceName() + ". New kids: " + publicKeys.keySet().toString());
|
||||
log.debugf("Realm public keys successfully retrieved for client %s. New kids: %s", deployment.getResourceName(), publicKeys.keySet().toString());
|
||||
}
|
||||
|
||||
// Update current keys
|
||||
|
||||
-7
@@ -34,11 +34,4 @@ public interface PublicKeyLocator {
|
||||
*/
|
||||
PublicKey getPublicKey(String kid, KeycloakDeployment deployment);
|
||||
|
||||
/**
|
||||
* Reset the state of locator (eg. clear the cached keys)
|
||||
*
|
||||
* @param deployment
|
||||
*/
|
||||
void reset(KeycloakDeployment deployment);
|
||||
|
||||
}
|
||||
-2
@@ -69,7 +69,6 @@ public class KeycloakDeploymentBuilderTest {
|
||||
assertEquals("email", deployment.getPrincipalAttribute());
|
||||
assertEquals(10, deployment.getTokenMinimumTimeToLive());
|
||||
assertEquals(20, deployment.getMinTimeBetweenJwksRequests());
|
||||
assertEquals(120, deployment.getPublicKeyCacheTtl());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,7 +78,6 @@ public class KeycloakDeploymentBuilderTest {
|
||||
|
||||
assertTrue(deployment.getPublicKeyLocator() instanceof JWKPublicKeyLocator);
|
||||
assertEquals(10, deployment.getMinTimeBetweenJwksRequests());
|
||||
assertEquals(86400, deployment.getPublicKeyCacheTtl());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -30,6 +30,5 @@
|
||||
"token-store": "cookie",
|
||||
"principal-attribute": "email",
|
||||
"token-minimum-time-to-live": 10,
|
||||
"min-time-between-jwks-requests": 20,
|
||||
"public-key-cache-ttl": 120
|
||||
"min-time-between-jwks-requests": 20
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</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.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -66,11 +66,6 @@ public class JaxrsHttpFacade implements OIDCHttpFacade {
|
||||
return requestContext.getUriInfo().getRequestUri().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRelativePath() {
|
||||
return requestContext.getUriInfo().getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return securityContext.isSecure();
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -87,10 +87,6 @@
|
||||
}
|
||||
kc.flow = initOptions.flow;
|
||||
}
|
||||
|
||||
if (initOptions.timeSkew != null) {
|
||||
kc.timeSkew = initOptions.timeSkew;
|
||||
}
|
||||
}
|
||||
|
||||
if (!kc.responseMode) {
|
||||
@@ -157,7 +153,7 @@
|
||||
processCallback(callback, initPromise);
|
||||
return;
|
||||
} else if (initOptions) {
|
||||
if (initOptions.refreshToken) {
|
||||
if (initOptions.token || initOptions.refreshToken) {
|
||||
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
|
||||
|
||||
if (loginIframe.enable) {
|
||||
@@ -166,8 +162,12 @@
|
||||
kc.onAuthSuccess && kc.onAuthSuccess();
|
||||
initPromise.setSuccess();
|
||||
}).error(function () {
|
||||
setToken(null, null, null);
|
||||
initPromise.setSuccess();
|
||||
kc.onAuthError && kc.onAuthError();
|
||||
if (initOptions.onLoad) {
|
||||
onLoad();
|
||||
} else {
|
||||
initPromise.setError();
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -369,11 +369,6 @@
|
||||
throw 'Not authenticated';
|
||||
}
|
||||
|
||||
if (kc.timeSkew == null) {
|
||||
console.info('[KEYCLOAK] Unable to determine if token is expired as timeskew is not set');
|
||||
return true;
|
||||
}
|
||||
|
||||
var expiresIn = kc.tokenParsed['exp'] - Math.ceil(new Date().getTime() / 1000) + kc.timeSkew;
|
||||
if (minValidity) {
|
||||
expiresIn -= minValidity;
|
||||
@@ -384,7 +379,7 @@
|
||||
kc.updateToken = function(minValidity) {
|
||||
var promise = createPromise();
|
||||
|
||||
if (!kc.refreshToken) {
|
||||
if (!kc.tokenParsed || !kc.refreshToken) {
|
||||
promise.setError();
|
||||
return promise.promise;
|
||||
}
|
||||
@@ -393,10 +388,14 @@
|
||||
|
||||
var exec = function() {
|
||||
var refreshToken = false;
|
||||
if (minValidity == -1) {
|
||||
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.tokenParsed || kc.isTokenExpired(minValidity)) {
|
||||
} else if (kc.isTokenExpired(minValidity)) {
|
||||
refreshToken = true;
|
||||
console.info('[KEYCLOAK] Refreshing token: token expired');
|
||||
}
|
||||
@@ -639,6 +638,49 @@
|
||||
kc.tokenTimeoutHandle = null;
|
||||
}
|
||||
|
||||
if (token) {
|
||||
kc.token = token;
|
||||
kc.tokenParsed = decodeToken(token);
|
||||
var sessionId = kc.realm + '/' + kc.tokenParsed.sub;
|
||||
if (kc.tokenParsed.session_state) {
|
||||
sessionId = sessionId + '/' + kc.tokenParsed.session_state;
|
||||
}
|
||||
kc.sessionId = sessionId;
|
||||
kc.authenticated = true;
|
||||
kc.subject = kc.tokenParsed.sub;
|
||||
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) {
|
||||
if (kc.timeSkew == -1) {
|
||||
kc.onTokenExpired();
|
||||
} else {
|
||||
var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
|
||||
if (expiresIn <= 0) {
|
||||
kc.onTokenExpired();
|
||||
} else {
|
||||
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
delete kc.token;
|
||||
delete kc.tokenParsed;
|
||||
delete kc.subject;
|
||||
delete kc.realmAccess;
|
||||
delete kc.resourceAccess;
|
||||
|
||||
kc.authenticated = false;
|
||||
}
|
||||
|
||||
if (refreshToken) {
|
||||
kc.refreshToken = refreshToken;
|
||||
kc.refreshTokenParsed = decodeToken(refreshToken);
|
||||
@@ -654,42 +696,6 @@
|
||||
delete kc.idToken;
|
||||
delete kc.idTokenParsed;
|
||||
}
|
||||
|
||||
if (token) {
|
||||
kc.token = token;
|
||||
kc.tokenParsed = decodeToken(token);
|
||||
kc.sessionId = kc.tokenParsed.session_state;
|
||||
kc.authenticated = true;
|
||||
kc.subject = kc.tokenParsed.sub;
|
||||
kc.realmAccess = kc.tokenParsed.realm_access;
|
||||
kc.resourceAccess = kc.tokenParsed.resource_access;
|
||||
|
||||
if (timeLocal) {
|
||||
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
|
||||
}
|
||||
|
||||
if (kc.timeSkew != null) {
|
||||
console.info('[KEYCLOAK] Estimated time difference between browser and server is ' + kc.timeSkew + ' seconds');
|
||||
|
||||
if (kc.onTokenExpired) {
|
||||
var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
|
||||
console.info('[KEYCLOAK] Token expires in ' + Math.round(expiresIn / 1000) + ' s');
|
||||
if (expiresIn <= 0) {
|
||||
kc.onTokenExpired();
|
||||
} else {
|
||||
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
delete kc.token;
|
||||
delete kc.tokenParsed;
|
||||
delete kc.subject;
|
||||
delete kc.realmAccess;
|
||||
delete kc.resourceAccess;
|
||||
|
||||
kc.authenticated = false;
|
||||
}
|
||||
}
|
||||
|
||||
function decodeToken(str) {
|
||||
@@ -840,15 +846,14 @@
|
||||
kc.clearToken();
|
||||
}
|
||||
|
||||
var callbacks = loginIframe.callbackList.splice(0, loginIframe.callbackList.length);
|
||||
|
||||
for (var i = callbacks.length - 1; i >= 0; --i) {
|
||||
var promise = callbacks[i];
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,49 +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.
|
||||
-->
|
||||
|
||||
<script>
|
||||
function getCookie(cname)
|
||||
{
|
||||
var name = cname + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0; i<ca.length; i++)
|
||||
{
|
||||
var c = ca[i].trim();
|
||||
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
event.source.postMessage(JSON.stringify(data),
|
||||
event.origin);
|
||||
}
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
</script>
|
||||
@@ -35,14 +35,14 @@
|
||||
req.open('GET', url, true);
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState === 4) {
|
||||
if (req.status === 204) {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 204) {
|
||||
init = {
|
||||
clientId: clientId,
|
||||
origin: origin
|
||||
}
|
||||
callback('unchanged');
|
||||
} else if (req.status === 404) {
|
||||
} else if (req.status = 404) {
|
||||
callback('changed');
|
||||
} else {
|
||||
callback('error');
|
||||
@@ -52,9 +52,8 @@
|
||||
|
||||
req.send();
|
||||
} else {
|
||||
if (clientId === init.clientId && origin === init.origin) {
|
||||
var c = cookie.split('/');
|
||||
if (sessionState === c[2]) {
|
||||
if (clientId == init.clientId && origin == init.origin) {
|
||||
if (sessionState == cookie) {
|
||||
callback('unchanged');
|
||||
} else {
|
||||
callback('changed');
|
||||
@@ -72,7 +71,7 @@
|
||||
for(var i=0; i<ca.length; i++)
|
||||
{
|
||||
var c = ca[i].trim();
|
||||
if (c.indexOf(name)===0) return c.substring(name.length,c.length);
|
||||
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -82,7 +81,7 @@
|
||||
var origin = event.origin;
|
||||
var data = event.data.split(' ');
|
||||
if (data.length != 2) {
|
||||
return;
|
||||
event.source.postMessage('error', origin);
|
||||
}
|
||||
|
||||
var clientId = data[0];
|
||||
@@ -96,4 +95,4 @@
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
-83
@@ -1,83 +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.osgi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class BundleBasedKeycloakConfigResolver implements KeycloakConfigResolver {
|
||||
|
||||
private volatile KeycloakDeployment cachedDeployment;
|
||||
|
||||
private BundleContext bundleContext;
|
||||
private String configLocation = "WEB-INF/keycloak.json";
|
||||
|
||||
public BundleContext getBundleContext() {
|
||||
return bundleContext;
|
||||
}
|
||||
|
||||
public void setBundleContext(BundleContext bundleContext) {
|
||||
this.bundleContext = bundleContext;
|
||||
}
|
||||
|
||||
public String getConfigLocation() {
|
||||
return configLocation;
|
||||
}
|
||||
|
||||
public void setConfigLocation(String configLocation) {
|
||||
this.configLocation = configLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakDeployment resolve(HttpFacade.Request request) {
|
||||
if (cachedDeployment != null) {
|
||||
return cachedDeployment;
|
||||
} else {
|
||||
cachedDeployment = findDeployment(request);
|
||||
return cachedDeployment;
|
||||
}
|
||||
}
|
||||
|
||||
protected KeycloakDeployment findDeployment(HttpFacade.Request request) {
|
||||
if (bundleContext == null) {
|
||||
throw new IllegalStateException("bundleContext must be set for BundleBasedKeycloakConfigResolver!");
|
||||
}
|
||||
|
||||
URL url = bundleContext.getBundle().getResource(configLocation);
|
||||
if (url == null) {
|
||||
throw new IllegalStateException("Failed to find the file " + configLocation + " on classpath.");
|
||||
}
|
||||
|
||||
try {
|
||||
InputStream is = url.openStream();
|
||||
return KeycloakDeploymentBuilder.build(is);
|
||||
} catch (IOException ioe) {
|
||||
throw new IllegalStateException("Error reading file' " + configLocation + "' from bundle classpath.", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
-5
@@ -218,11 +218,6 @@ public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
|
||||
return servletRequest.getRequestURL().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRelativePath() {
|
||||
return servletRequest.getServletPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return servletRequest.isSecure();
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+2
-12
@@ -30,12 +30,6 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
|
||||
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
/**
|
||||
* Provides a Keycloak {@link AuthenticationEntryPoint authentication entry point}. Uses a
|
||||
@@ -62,15 +56,12 @@ public class KeycloakAuthenticationEntryPoint implements AuthenticationEntryPoin
|
||||
private final RequestMatcher apiRequestMatcher;
|
||||
private String loginUri = DEFAULT_LOGIN_URI;
|
||||
private String realm = DEFAULT_REALM;
|
||||
|
||||
private AdapterDeploymentContext adapterDeploymentContext;
|
||||
|
||||
/**
|
||||
* Creates a new Keycloak authentication entry point.
|
||||
*/
|
||||
public KeycloakAuthenticationEntryPoint(AdapterDeploymentContext adapterDeploymentContext) {
|
||||
public KeycloakAuthenticationEntryPoint() {
|
||||
this(DEFAULT_API_REQUEST_MATCHER);
|
||||
this.adapterDeploymentContext = adapterDeploymentContext;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,8 +79,7 @@ public class KeycloakAuthenticationEntryPoint implements AuthenticationEntryPoin
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException
|
||||
{
|
||||
HttpFacade facade = new SimpleHttpFacade(request, response);
|
||||
if (apiRequestMatcher.matches(request) || adapterDeploymentContext.resolveDeployment(facade).isBearerOnly()) {
|
||||
if (apiRequestMatcher.matches(request)) {
|
||||
commenceUnauthorizedResponse(request, response);
|
||||
} else {
|
||||
commenceLoginRedirect(request, response);
|
||||
|
||||
+2
-2
@@ -71,8 +71,8 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
|
||||
return factoryBean.getObject();
|
||||
}
|
||||
|
||||
protected AuthenticationEntryPoint authenticationEntryPoint() throws Exception {
|
||||
return new KeycloakAuthenticationEntryPoint(adapterDeploymentContext());
|
||||
protected AuthenticationEntryPoint authenticationEntryPoint() {
|
||||
return new KeycloakAuthenticationEntryPoint();
|
||||
}
|
||||
|
||||
protected KeycloakAuthenticationProvider keycloakAuthenticationProvider() {
|
||||
|
||||
-5
@@ -70,11 +70,6 @@ class WrappedHttpServletRequest implements Request {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRelativePath() {
|
||||
return request.getServletPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return request.isSecure();
|
||||
|
||||
-90
@@ -1,90 +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.springsecurity.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
/**
|
||||
* Exposes a Keycloak adapter {@link AuthenticatedActionsHandler} as a Spring Security filter.
|
||||
*
|
||||
* @author <a href="mailto:srossillo@smartling.com">Scott Rossillo</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeycloakAuthenticatedActionsFilter extends GenericFilterBean implements ApplicationContextAware {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(KeycloakAuthenticatedActionsFilter.class);
|
||||
|
||||
private final NodesRegistrationManagement management = new NodesRegistrationManagement();
|
||||
private ApplicationContext applicationContext;
|
||||
private AdapterDeploymentContext deploymentContext;
|
||||
|
||||
|
||||
public KeycloakAuthenticatedActionsFilter() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFilterBean() throws ServletException {
|
||||
deploymentContext = applicationContext.getBean(AdapterDeploymentContext.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
log.debug("Unregistering deployment");
|
||||
management.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
HttpFacade facade = new SimpleHttpFacade((HttpServletRequest)request, (HttpServletResponse)response);
|
||||
AuthenticatedActionsHandler handler = new AuthenticatedActionsHandler(deploymentContext.resolveDeployment(facade), (OIDCHttpFacade)facade);
|
||||
boolean handled = handler.handledRequest();
|
||||
if (handled) {
|
||||
log.debug("Authenticated filter handled request: {}", ((HttpServletRequest) request).getRequestURI());
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
-1
@@ -142,7 +142,6 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
|
||||
if (AuthOutcome.FAILED.equals(result)) {
|
||||
throw new KeycloakAuthenticationException("Auth outcome: " + result);
|
||||
}
|
||||
|
||||
else if (AuthOutcome.AUTHENTICATED.equals(result)) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
Assert.notNull(authentication, "Authentication SecurityContextHolder was null");
|
||||
|
||||
+1
-22
@@ -26,15 +26,6 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Keycloak authentication entry point tests.
|
||||
@@ -44,24 +35,12 @@ public class KeycloakAuthenticationEntryPointTest {
|
||||
private KeycloakAuthenticationEntryPoint authenticationEntryPoint;
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
@Mock
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Mock
|
||||
private AdapterDeploymentContext adapterDeploymentContext;
|
||||
|
||||
@Mock
|
||||
private KeycloakDeployment keycloakDeployment;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
authenticationEntryPoint = new KeycloakAuthenticationEntryPoint(adapterDeploymentContext);
|
||||
authenticationEntryPoint = new KeycloakAuthenticationEntryPoint();
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
when(applicationContext.getBean(eq(AdapterDeploymentContext.class))).thenReturn(adapterDeploymentContext);
|
||||
when(adapterDeploymentContext.resolveDeployment(any(HttpFacade.class))).thenReturn(keycloakDeployment);
|
||||
when(keycloakDeployment.isBearerOnly()).thenReturn(Boolean.FALSE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
-1
@@ -154,7 +154,6 @@ public class KeycloakAuthenticationProcessingFilterTest {
|
||||
when(keycloakDeployment.getResourceName()).thenReturn("resource-name");
|
||||
when(keycloakDeployment.getStateCookieName()).thenReturn("kc-cookie");
|
||||
when(keycloakDeployment.getSslRequired()).thenReturn(SslRequired.NONE);
|
||||
when(keycloakDeployment.isBearerOnly()).thenReturn(Boolean.FALSE);
|
||||
filter.attemptAuthentication(request, response);
|
||||
|
||||
verify(response).setStatus(302);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+11
-9
@@ -25,7 +25,6 @@ import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.authenticator.FormAuthenticator;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
@@ -49,6 +48,8 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Keycloak authentication valve
|
||||
@@ -61,7 +62,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
|
||||
|
||||
public static final String TOKEN_STORE_NOTE = "TOKEN_STORE_NOTE";
|
||||
|
||||
private final static Logger log = Logger.getLogger(AbstractKeycloakAuthenticatorValve.class);
|
||||
private final static Logger log = Logger.getLogger(""+AbstractKeycloakAuthenticatorValve.class);
|
||||
protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement();
|
||||
protected AdapterDeploymentContext deploymentContext;
|
||||
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||
@@ -117,22 +118,22 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
|
||||
try {
|
||||
KeycloakConfigResolver configResolver = (KeycloakConfigResolver) context.getLoader().getClassLoader().loadClass(configResolverClass).newInstance();
|
||||
deploymentContext = new AdapterDeploymentContext(configResolver);
|
||||
log.debugv("Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
|
||||
log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
|
||||
} catch (Exception ex) {
|
||||
log.errorv("The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", configResolverClass, ex.getMessage());
|
||||
log.log(Level.FINE, "The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()});
|
||||
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
|
||||
}
|
||||
} else {
|
||||
InputStream configInputStream = getConfigInputStream(context);
|
||||
KeycloakDeployment kd;
|
||||
if (configInputStream == null) {
|
||||
log.warn("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
||||
log.warning("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
||||
kd = new KeycloakDeployment();
|
||||
} else {
|
||||
kd = KeycloakDeploymentBuilder.build(configInputStream);
|
||||
}
|
||||
deploymentContext = new AdapterDeploymentContext(kd);
|
||||
log.debug("Keycloak is using a per-deployment configuration.");
|
||||
log.fine("Keycloak is using a per-deployment configuration.");
|
||||
}
|
||||
|
||||
context.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
|
||||
@@ -148,7 +149,8 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
log.trace("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
|
||||
log.finest("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
|
||||
log.finest(json);
|
||||
return new ByteArrayInputStream(json.getBytes());
|
||||
}
|
||||
|
||||
@@ -157,13 +159,13 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
|
||||
if (is == null) {
|
||||
String path = context.getServletContext().getInitParameter("keycloak.config.file");
|
||||
if (path == null) {
|
||||
log.trace("**** using /WEB-INF/keycloak.json");
|
||||
log.finest("**** using /WEB-INF/keycloak.json");
|
||||
is = context.getServletContext().getResourceAsStream("/WEB-INF/keycloak.json");
|
||||
} else {
|
||||
try {
|
||||
is = new FileInputStream(path);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.errorv("NOT FOUND {0}", path);
|
||||
log.log(Level.SEVERE, "NOT FOUND {0}", path);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+4
-9
@@ -173,15 +173,10 @@ public class KeycloakServletExtension implements ServletExtension {
|
||||
}
|
||||
});
|
||||
|
||||
ServletSessionConfig cookieConfig = deploymentInfo.getServletSessionConfig();
|
||||
if (cookieConfig == null) {
|
||||
cookieConfig = new ServletSessionConfig();
|
||||
}
|
||||
if (cookieConfig.getPath() == null) {
|
||||
log.debug("Setting jsession cookie path to: " + deploymentInfo.getContextPath());
|
||||
cookieConfig.setPath(deploymentInfo.getContextPath());
|
||||
deploymentInfo.setServletSessionConfig(cookieConfig);
|
||||
}
|
||||
log.debug("Setting jsession cookie path to: " + deploymentInfo.getContextPath());
|
||||
ServletSessionConfig cookieConfig = new ServletSessionConfig();
|
||||
cookieConfig.setPath(deploymentInfo.getContextPath());
|
||||
deploymentInfo.setServletSessionConfig(cookieConfig);
|
||||
ChangeSessionId.turnOffChangeSessionIdOnLogin(deploymentInfo);
|
||||
deploymentInfo.addListener(new ListenerInfo(UndertowNodesRegistrationManagementWrapper.class, new InstanceFactory<UndertowNodesRegistrationManagementWrapper>() {
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
+2
-2
@@ -20,10 +20,10 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Adapters</name>
|
||||
<name>Keycloak Integration</name>
|
||||
<description/>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SamlUtil {
|
||||
httpFacade.getResponse().setHeader("Content-Type", "text/html");
|
||||
httpFacade.getResponse().setHeader("Pragma", "no-cache");
|
||||
httpFacade.getResponse().setHeader("Cache-Control", "no-cache, no-store");
|
||||
httpFacade.getResponse().getOutputStream().write(html.getBytes(GeneralConstants.SAML_CHARSET));
|
||||
httpFacade.getResponse().getOutputStream().write(html.getBytes());
|
||||
httpFacade.getResponse().end();
|
||||
} else {
|
||||
String uri = asRequest ? binding.redirectBinding(document).requestURI(actionUrl).toString() : binding.redirectBinding(document).responseURI(actionUrl).toString();
|
||||
|
||||
+12
-32
@@ -60,7 +60,6 @@ import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||
import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil;
|
||||
import org.keycloak.saml.processing.web.util.PostBindingUtil;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -71,11 +70,14 @@ import java.security.KeyManagementException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Signature;
|
||||
import java.security.SignatureException;
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.keycloak.dom.saml.v2.SAML2Object;
|
||||
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
|
||||
import org.keycloak.rotation.KeyLocator;
|
||||
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -194,7 +196,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||
challenge = new AuthChallenge() {
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.INVALID_SIGNATURE, statusResponse);
|
||||
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.INVALID_SIGNATURE);
|
||||
exchange.getRequest().setError(error);
|
||||
exchange.getResponse().sendError(403);
|
||||
return true;
|
||||
@@ -310,25 +312,8 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||
return false;
|
||||
}
|
||||
|
||||
protected AuthOutcome handleLoginResponse(final ResponseType responseType, boolean postBinding, OnSessionCreated onCreateSession) {
|
||||
protected AuthOutcome handleLoginResponse(ResponseType responseType, boolean postBinding, OnSessionCreated onCreateSession) {
|
||||
AssertionType assertion = null;
|
||||
if (! isSuccessfulSamlResponse(responseType) || responseType.getAssertions() == null || responseType.getAssertions().isEmpty()) {
|
||||
challenge = new AuthChallenge() {
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.ERROR_STATUS, responseType);
|
||||
exchange.getRequest().setError(error);
|
||||
exchange.getResponse().sendError(403);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode() {
|
||||
return 403;
|
||||
}
|
||||
};
|
||||
return AuthOutcome.FAILED;
|
||||
}
|
||||
try {
|
||||
assertion = AssertionUtil.getAssertion(responseType, deployment.getDecryptionKey());
|
||||
if (AssertionUtil.hasExpired(assertion)) {
|
||||
@@ -350,7 +335,6 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||
return 403;
|
||||
}
|
||||
};
|
||||
return AuthOutcome.FAILED;
|
||||
}
|
||||
|
||||
if (deployment.getIDP().getSingleSignOnService().validateAssertionSignature()) {
|
||||
@@ -362,7 +346,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||
challenge = new AuthChallenge() {
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.INVALID_SIGNATURE, responseType);
|
||||
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.INVALID_SIGNATURE);
|
||||
exchange.getRequest().setError(error);
|
||||
exchange.getResponse().sendError(403);
|
||||
return true;
|
||||
@@ -465,14 +449,6 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||
return AuthOutcome.AUTHENTICATED;
|
||||
}
|
||||
|
||||
private boolean isSuccessfulSamlResponse(ResponseType responseType) {
|
||||
return responseType != null
|
||||
&& responseType.getStatus() != null
|
||||
&& responseType.getStatus().getStatusCode() != null
|
||||
&& responseType.getStatus().getStatusCode().getValue() != null
|
||||
&& Objects.equals(responseType.getStatus().getStatusCode().getValue().toString(), JBossSAMLURIConstants.STATUS_SUCCESS.get());
|
||||
}
|
||||
|
||||
private String getAttributeValue(Object attrValue) {
|
||||
String value = null;
|
||||
if (attrValue instanceof String) {
|
||||
@@ -595,8 +571,12 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||
key = locator.getKey(keyId);
|
||||
boolean keyLocated = key != null;
|
||||
|
||||
if (validateRedirectBindingSignatureForKey(sigAlg, rawQueryBytes, decodedSignature, key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyLocated) {
|
||||
return validateRedirectBindingSignatureForKey(sigAlg, rawQueryBytes, decodedSignature, key);
|
||||
return false;
|
||||
}
|
||||
} catch (KeyManagementException ex) {
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+16
-14
@@ -24,7 +24,6 @@ import org.apache.catalina.LifecycleListener;
|
||||
import org.apache.catalina.authenticator.FormAuthenticator;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder;
|
||||
import org.keycloak.adapters.saml.config.parsers.ResourceLoader;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
@@ -46,6 +45,8 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Keycloak authentication valve
|
||||
@@ -58,7 +59,7 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
|
||||
public static final String TOKEN_STORE_NOTE = "TOKEN_STORE_NOTE";
|
||||
|
||||
private final static Logger log = Logger.getLogger(AbstractSamlAuthenticatorValve.class);
|
||||
private final static Logger log = Logger.getLogger(""+AbstractSamlAuthenticatorValve.class);
|
||||
protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement();
|
||||
protected SamlDeploymentContext deploymentContext;
|
||||
protected SessionIdMapper mapper = new InMemorySessionIdMapper();
|
||||
@@ -102,14 +103,14 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
//deploymentContext = new SamlDeploymentContext(configResolver);
|
||||
//log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
|
||||
} catch (Exception ex) {
|
||||
log.errorv("The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", configResolverClass, ex.getMessage());
|
||||
log.log(Level.FINE, "The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()});
|
||||
//deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
|
||||
}
|
||||
} else {
|
||||
InputStream is = getConfigInputStream(context);
|
||||
final SamlDeployment deployment;
|
||||
if (is == null) {
|
||||
log.error("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
||||
log.info("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
||||
deployment = new DefaultSamlDeployment();
|
||||
} else {
|
||||
try {
|
||||
@@ -125,7 +126,7 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
}
|
||||
}
|
||||
deploymentContext = new SamlDeploymentContext(deployment);
|
||||
log.debug("Keycloak is using a per-deployment configuration.");
|
||||
log.fine("Keycloak is using a per-deployment configuration.");
|
||||
}
|
||||
|
||||
context.getServletContext().setAttribute(SamlDeploymentContext.class.getName(), deploymentContext);
|
||||
@@ -139,7 +140,8 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
if (xml == null) {
|
||||
return null;
|
||||
}
|
||||
log.trace("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
|
||||
log.finest("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
|
||||
log.finest(xml);
|
||||
return new ByteArrayInputStream(xml.getBytes());
|
||||
}
|
||||
|
||||
@@ -148,13 +150,13 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
if (is == null) {
|
||||
String path = context.getServletContext().getInitParameter("keycloak.config.file");
|
||||
if (path == null) {
|
||||
log.trace("**** using /WEB-INF/keycloak-saml.xml");
|
||||
log.fine("**** using /WEB-INF/keycloak-saml.xml");
|
||||
is = context.getServletContext().getResourceAsStream("/WEB-INF/keycloak-saml.xml");
|
||||
} else {
|
||||
try {
|
||||
is = new FileInputStream(path);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.errorv("NOT FOUND {0}", path);
|
||||
log.log(Level.SEVERE, "NOT FOUND {0}", path);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@@ -164,7 +166,7 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
|
||||
@Override
|
||||
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||
log.trace("*********************** SAML ************");
|
||||
log.fine("*********************** SAML ************");
|
||||
CatalinaHttpFacade facade = new CatalinaHttpFacade(response, request);
|
||||
SamlDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (request.getRequestURI().substring(request.getContextPath().length()).endsWith("/saml")) {
|
||||
@@ -206,11 +208,11 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
}
|
||||
|
||||
protected boolean authenticateInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
|
||||
log.trace("authenticateInternal");
|
||||
log.fine("authenticateInternal");
|
||||
CatalinaHttpFacade facade = new CatalinaHttpFacade(response, request);
|
||||
SamlDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (deployment == null || !deployment.isConfigured()) {
|
||||
log.trace("deployment not configured");
|
||||
log.fine("deployment not configured");
|
||||
return false;
|
||||
}
|
||||
SamlSessionStore tokenStore = getSessionStore(request, facade, deployment);
|
||||
@@ -223,7 +225,7 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
protected boolean executeAuthenticator(Request request, HttpServletResponse response, CatalinaHttpFacade facade, SamlDeployment deployment, SamlAuthenticator authenticator) {
|
||||
AuthOutcome outcome = authenticator.authenticate();
|
||||
if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||
log.trace("AUTHENTICATED");
|
||||
log.fine("AUTHENTICATED");
|
||||
if (facade.isEnded()) {
|
||||
return false;
|
||||
}
|
||||
@@ -235,13 +237,13 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
|
||||
forwardToLogoutPage(request, response, deployment);
|
||||
|
||||
}
|
||||
log.trace("Logging OUT");
|
||||
log.fine("Logging OUT");
|
||||
return false;
|
||||
}
|
||||
|
||||
AuthChallenge challenge = authenticator.getChallenge();
|
||||
if (challenge != null) {
|
||||
log.trace("challenge");
|
||||
log.fine("challenge");
|
||||
challenge.challenge(facade);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+4
-9
@@ -182,15 +182,10 @@ public class SamlServletExtension implements ServletExtension {
|
||||
}
|
||||
});
|
||||
|
||||
ServletSessionConfig cookieConfig = deploymentInfo.getServletSessionConfig();
|
||||
if (cookieConfig == null) {
|
||||
cookieConfig = new ServletSessionConfig();
|
||||
}
|
||||
if (cookieConfig.getPath() == null) {
|
||||
log.debug("Setting jsession cookie path to: " + deploymentInfo.getContextPath());
|
||||
cookieConfig.setPath(deploymentInfo.getContextPath());
|
||||
deploymentInfo.setServletSessionConfig(cookieConfig);
|
||||
}
|
||||
log.debug("Setting jsession cookie path to: " + deploymentInfo.getContextPath());
|
||||
ServletSessionConfig cookieConfig = new ServletSessionConfig();
|
||||
cookieConfig.setPath(deploymentInfo.getContextPath());
|
||||
deploymentInfo.setServletSessionConfig(cookieConfig);
|
||||
addEndpointConstraint(deploymentInfo);
|
||||
|
||||
ChangeSessionId.turnOffChangeSessionIdOnLogin(deploymentInfo);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak SAML Wildfly Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -43,13 +43,6 @@ public interface HttpFacade {
|
||||
*/
|
||||
String getURI();
|
||||
|
||||
/**
|
||||
* Get the request relative path.
|
||||
*
|
||||
* @return the request relative path
|
||||
*/
|
||||
String getRelativePath();
|
||||
|
||||
/**
|
||||
* HTTPS?
|
||||
*
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.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>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
-5
@@ -78,11 +78,6 @@ public class JettyHttpFacade implements HttpFacade {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRelativePath() {
|
||||
return request.getServletPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstParam(String param) {
|
||||
return request.getParameter(param);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Client Adapter SPI Modules</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
-13
@@ -65,19 +65,6 @@ public class ServletHttpFacade implements HttpFacade {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRelativePath() {
|
||||
String uri = request.getRequestURI();
|
||||
String contextPath = request.getContextPath();
|
||||
String servletPath = uri.substring(uri.indexOf(contextPath) + contextPath.length());
|
||||
|
||||
if ("".equals(servletPath)) {
|
||||
servletPath = "/";
|
||||
}
|
||||
|
||||
return servletPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return request.isSecure();
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>2.5.5.Final</version>
|
||||
<version>2.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
Loaded 100 of 1478 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user