Compare commits

..
Author SHA1 Message Date
keycloak-bot 58140c3560 Set version to 4.0.0.Beta2 2018-05-02 07:37:13 +00:00
1141 changed files with 15440 additions and 30381 deletions

No files matched your search

+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -28,7 +28,6 @@ import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.HttpFacade.Request;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.ClientAuthorizationContext;
@@ -166,7 +165,7 @@ public abstract class AbstractPolicyEnforcer {
policyEnforcer.getPathMatcher().removeFromCache(getPath(request));
}
return hasValidClaims(actualPathConfig, permission, httpFacade, authorization);
return hasValidClaims(actualPathConfig, httpFacade, authorization);
}
}
} else {
@@ -188,22 +187,35 @@ public abstract class AbstractPolicyEnforcer {
return false;
}
private boolean hasValidClaims(PathConfig actualPathConfig, Permission permission, OIDCHttpFacade httpFacade, Authorization authorization) {
Map<String, Set<String>> grantedClaims = permission.getClaims();
private boolean hasValidClaims(PathConfig actualPathConfig, OIDCHttpFacade httpFacade, Authorization authorization) {
Map<String, Map<String, Object>> claimInformationPointConfig = actualPathConfig.getClaimInformationPointConfig();
if (grantedClaims != null) {
Map<String, List<String>> claims = resolveClaims(actualPathConfig, httpFacade);
if (claimInformationPointConfig != null) {
Map<String, List<String>> claims = new HashMap<>();
if (claims.isEmpty()) {
return false;
for (Entry<String, Map<String, Object>> entry : claimInformationPointConfig.entrySet()) {
ClaimInformationPointProviderFactory factory = policyEnforcer.getClaimInformationPointProviderFactories().get(entry.getKey());
if (factory == null) {
throw new RuntimeException("Could not find claim information provider with name [" + entry.getKey() + "]");
}
claims.putAll(factory.create(entry.getValue()).resolve(httpFacade));
}
for (Entry<String, Set<String>> entry : grantedClaims.entrySet()) {
List<String> requestClaims = claims.get(entry.getKey());
Map<String, List<String>> grantedClaims = authorization.getClaims();
if (requestClaims == null || requestClaims.isEmpty() || !entry.getValue().containsAll(requestClaims)) {
if (grantedClaims != null) {
if (claims.isEmpty()) {
return false;
}
for (Entry<String, List<String>> entry : grantedClaims.entrySet()) {
List<String> requestClaims = claims.get(entry.getKey());
if (requestClaims == null || requestClaims.isEmpty() || !entry.getValue().containsAll(requestClaims)) {
return false;
}
}
}
}
@@ -330,28 +342,4 @@ public abstract class AbstractPolicyEnforcer {
private PathConfig getPathConfig(Request request) {
return isDefaultAccessDeniedUri(request) ? null : policyEnforcer.getPathMatcher().matches(getPath(request));
}
protected Map<String, List<String>> resolveClaims(PathConfig pathConfig, OIDCHttpFacade httpFacade) {
Map<String, List<String>> claims = getClaims(getEnforcerConfig().getClaimInformationPointConfig(), httpFacade);
claims.putAll(getClaims(pathConfig.getClaimInformationPointConfig(), httpFacade));
return claims;
}
private Map<String, List<String>> getClaims(Map<String, Map<String, Object>>claimInformationPointConfig, HttpFacade httpFacade) {
Map<String, List<String>> claims = new HashMap<>();
if (claimInformationPointConfig != null) {
for (Entry<String, Map<String, Object>> claimDef : claimInformationPointConfig.entrySet()) {
ClaimInformationPointProviderFactory factory = getPolicyEnforcer().getClaimInformationPointProviderFactories().get(claimDef.getKey());
if (factory != null) {
claims.putAll(factory.create(claimDef.getValue()).resolve(httpFacade));
}
}
}
return claims;
}
}
@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
@@ -86,6 +87,19 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
grantedPermissions.add(newPermission);
}
}
Map<String, List<String>> newClaims = newAuthorization.getClaims();
if (newClaims != null) {
Map<String, List<String>> claims = authorization.getClaims();
if (claims == null) {
claims = new HashMap<>();
authorization.setClaims(claims);
}
claims.putAll(newClaims);
}
}
original.setAuthorization(authorization);
@@ -140,7 +154,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
}
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
if (getPolicyEnforcer().getDeployment().isBearerOnly() || (isBearerAuthorization(httpFacade) && getEnforcerConfig().getUserManagedAccess() != null)) {
return null;
}
@@ -151,15 +165,20 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
AccessToken accessToken = securityContext.getToken();
AuthorizationRequest authzRequest = new AuthorizationRequest();
if (isBearerAuthorization(httpFacade) || accessToken.getAuthorization() != null) {
authzRequest.addPermission(pathConfig.getId(), methodConfig.getScopes());
}
if (getEnforcerConfig().getUserManagedAccess() != null) {
String ticket = getPermissionTicket(pathConfig, methodConfig, getAuthzClient(), httpFacade);
authzRequest.setTicket(ticket);
} else {
if (accessToken.getAuthorization() != null) {
authzRequest.addPermission(pathConfig.getId(), methodConfig.getScopes());
}
Map<String, List<String>> claims = resolveClaims(pathConfig, httpFacade);
Map<String, List<String>> claims = getClaims(pathConfig, httpFacade);
if (!claims.isEmpty()) {
authzRequest.setClaimTokenFormat("urn:ietf:params:oauth:token-type:jwt");
authzRequest.setClaimToken(Base64.encodeBytes(JsonSerialization.writeValueAsBytes(claims)));
if (!claims.isEmpty()) {
authzRequest.setClaimTokenFormat("urn:ietf:params:oauth:token-type:jwt");
authzRequest.setClaimToken(Base64.encodeBytes(JsonSerialization.writeValueAsBytes(claims)));
}
}
if (accessToken.getAuthorization() != null) {
@@ -167,14 +186,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
}
LOGGER.debug("Obtaining authorization for authenticated user.");
AuthorizationResponse authzResponse;
if (isBearerAuthorization(httpFacade)) {
authzRequest.setSubjectToken(accessTokenString);
authzResponse = getAuthzClient().authorization().authorize(authzRequest);
} else {
authzResponse = getAuthzClient().authorization(accessTokenString).authorize(authzRequest);
}
AuthorizationResponse authzResponse = getAuthzClient().authorization(accessTokenString).authorize(authzRequest);
if (authzResponse != null) {
return AdapterRSATokenVerifier.verifyToken(authzResponse.getToken(), deployment);
@@ -188,7 +200,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
return null;
}
private String getPermissionTicket(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AuthzClient authzClient, OIDCHttpFacade httpFacade) {
private String getPermissionTicket(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AuthzClient authzClient, HttpFacade httpFacade) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
ProtectionResource protection = authzClient.protection();
PermissionResource permission = protection.permission();
@@ -197,7 +209,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
permissionRequest.setResourceId(pathConfig.getId());
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
Map<String, List<String>> claims = resolveClaims(pathConfig, httpFacade);
Map<String, List<String>> claims = getClaims(pathConfig, httpFacade);
if (!claims.isEmpty()) {
permissionRequest.setClaims(claims);
@@ -209,6 +221,22 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
return null;
}
private Map<String, List<String>> getClaims(PathConfig pathConfig, HttpFacade httpFacade) {
Map<String, List<String>> claims = new HashMap<>();
Map<String, Map<String, Object>> claimInformationPointConfig = pathConfig.getClaimInformationPointConfig();
if (claimInformationPointConfig != null) {
for (Entry<String, Map<String, Object>> claimDef : claimInformationPointConfig.entrySet()) {
ClaimInformationPointProviderFactory factory = getPolicyEnforcer().getClaimInformationPointProviderFactories().get(claimDef.getKey());
if (factory != null) {
claims.putAll(factory.create(claimDef.getValue()).resolve(httpFacade));
}
}
}
return claims;
}
private boolean isBearerAuthorization(OIDCHttpFacade httpFacade) {
List<String> authHeaders = httpFacade.getRequest().getHeaders("Authorization");
if (authHeaders == null || authHeaders.size() == 0) {
@@ -271,17 +271,7 @@ public class PolicyEnforcer {
List<ResourceRepresentation> matchingResources = authzClient.protection().resource().findByMatchingUri(targetUri);
if (!matchingResources.isEmpty()) {
Map<String, Map<String, Object>> cipConfig = null;
if (pathConfig != null) {
cipConfig = pathConfig.getClaimInformationPointConfig();
}
pathConfig = PathConfig.createPathConfig(matchingResources.get(0));
if (cipConfig != null) {
pathConfig.setClaimInformationPointConfig(cipConfig);
}
}
} catch (Exception cause) {
LOGGER.errorf(cause, "Could not lazy load resource with path [" + targetUri + "] from server");
@@ -309,18 +299,8 @@ public class PolicyEnforcer {
protected PathConfig resolvePathConfig(PathConfig originalConfig, String path) {
if (originalConfig.hasPattern()) {
ProtectedResource resource = authzClient.protection().resource();
// search by an exact match
List<ResourceRepresentation> search = resource.findByUri(path);
// if exact match not found, try to obtain from current path the parent path.
// if path is /resource/1/test and pattern from pathConfig is /resource/{id}/*, parent path is /resource/1
// this logic allows to match sub resources of a resource instance (/resource/1) to the parent resource,
// so any permission granted to parent also applies to sub resources
if (search.isEmpty()) {
search = resource.findByUri(buildUriFromTemplate(originalConfig.getPath(), path, true));
}
if (!search.isEmpty()) {
ResourceRepresentation targetResource = search.get(0);
PathConfig config = PathConfig.createPathConfig(targetResource);
@@ -329,7 +309,6 @@ public class PolicyEnforcer {
config.setMethods(originalConfig.getMethods());
config.setParentConfig(originalConfig);
config.setEnforcementMode(originalConfig.getEnforcementMode());
config.setClaimInformationPointConfig(originalConfig.getClaimInformationPointConfig());
return config;
}
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-integration-pom</artifactId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
-144
View File
@@ -1,144 +0,0 @@
<?xml version="1.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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-camel-undertow</artifactId>
<name>Keycloak Fuse 7.0 Adapter - Camel + Undertow</name>
<packaging>bundle</packaging>
<properties>
<keycloak.osgi.export>
org.keycloak.adapters.camel.undertow;version="${project.version}"
</keycloak.osgi.export>
<keycloak.osgi.import>
org.keycloak.*;version="${project.version}",
org.apache.camel.*,
org.apache.camel.component.undertow,
io.undertow.*,
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.enterprise</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-runtime</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-undertow</artifactId>
<version>2.21.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.21.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
<Export-Service>org.apache.camel.spi.ComponentResolver;component=undertow-keycloak</Export-Service>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,187 +0,0 @@
/*
* Copyright 2018 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.camel.undertow;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.camel.CamelContext;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.component.undertow.RestUndertowHttpBinding;
import org.apache.camel.component.undertow.UndertowComponent;
import org.apache.camel.component.undertow.UndertowEndpoint;
import org.apache.camel.spi.RestConfiguration;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.HostUtils;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.URISupport;
/**
*
* @author hmlnarik
*/
public class UndertowKeycloakComponent extends UndertowComponent {
public UndertowKeycloakComponent() {
}
public UndertowKeycloakComponent(CamelContext context) {
super(context);
}
@Override
protected UndertowEndpoint createEndpointInstance(URI endpointUri, UndertowComponent component) throws URISyntaxException {
return new UndertowKeycloakEndpoint(endpointUri.toString(), component);
}
// TODO: uncomment line below after backport of https://issues.apache.org/jira/browse/CAMEL-12514 into fuse
// @Override
protected String getComponentName() {
return "undertow-keycloak";
}
// TODO: remove all below this line after backport of https://issues.apache.org/jira/browse/CAMEL-12514 into fuse
@Override
public Consumer createConsumer(CamelContext camelContext, Processor processor, String verb, String basePath, String uriTemplate,
String consumes, String produces, RestConfiguration configuration, Map<String, Object> parameters) throws Exception {
return doCreateConsumer(camelContext, processor, verb, basePath, uriTemplate, consumes, produces, configuration, parameters, false);
}
@Override
public Consumer createApiConsumer(CamelContext camelContext, Processor processor, String contextPath,
RestConfiguration configuration, Map<String, Object> parameters) throws Exception {
// reuse the createConsumer method we already have. The api need to use GET and match on uri prefix
return doCreateConsumer(camelContext, processor, "GET", contextPath, null, null, null, configuration, parameters, true);
}
Consumer doCreateConsumer(CamelContext camelContext, Processor processor, String verb, String basePath, String uriTemplate,
String consumes, String produces, RestConfiguration configuration, Map<String, Object> parameters, boolean api) throws Exception {
String path = basePath;
if (uriTemplate != null) {
// make sure to avoid double slashes
if (uriTemplate.startsWith("/")) {
path = path + uriTemplate;
} else {
path = path + "/" + uriTemplate;
}
}
path = FileUtil.stripLeadingSeparator(path);
String scheme = "http";
String host = "";
int port = 0;
RestConfiguration config = configuration;
if (config == null) {
config = camelContext.getRestConfiguration(getComponentName(), true);
}
if (config.getScheme() != null) {
scheme = config.getScheme();
}
if (config.getHost() != null) {
host = config.getHost();
}
int num = config.getPort();
if (num > 0) {
port = num;
}
// prefix path with context-path if configured in rest-dsl configuration
String contextPath = config.getContextPath();
if (ObjectHelper.isNotEmpty(contextPath)) {
contextPath = FileUtil.stripTrailingSeparator(contextPath);
contextPath = FileUtil.stripLeadingSeparator(contextPath);
if (ObjectHelper.isNotEmpty(contextPath)) {
path = contextPath + "/" + path;
}
}
// if no explicit hostname set then resolve the hostname
if (ObjectHelper.isEmpty(host)) {
if (config.getRestHostNameResolver() == RestConfiguration.RestHostNameResolver.allLocalIp) {
host = "0.0.0.0";
} else if (config.getRestHostNameResolver() == RestConfiguration.RestHostNameResolver.localHostName) {
host = HostUtils.getLocalHostName();
} else if (config.getRestHostNameResolver() == RestConfiguration.RestHostNameResolver.localIp) {
host = HostUtils.getLocalIp();
}
}
Map<String, Object> map = new HashMap<String, Object>();
// build query string, and append any endpoint configuration properties
if (config.getComponent() == null || config.getComponent().equals(getComponentName())) {
// setup endpoint options
if (config.getEndpointProperties() != null && !config.getEndpointProperties().isEmpty()) {
map.putAll(config.getEndpointProperties());
}
}
boolean explicitOptions = true;
// must use upper case for restrict
String restrict = verb.toUpperCase(Locale.US);
// allow OPTIONS in rest-dsl to allow clients to call the API and have responses with ALLOW headers
if (!restrict.contains("OPTIONS")) {
restrict += ",OPTIONS";
// this is not an explicit OPTIONS path in the rest-dsl
explicitOptions = false;
}
boolean cors = config.isEnableCORS();
if (cors) {
// allow HTTP Options as we want to handle CORS in rest-dsl
map.put("optionsEnabled", "true");
} else if (explicitOptions) {
// the rest-dsl is using OPTIONS
map.put("optionsEnabled", "true");
}
String query = URISupport.createQueryString(map);
String url;
if (api) {
url = getComponentName() + ":%s://%s:%s/%s?matchOnUriPrefix=true&httpMethodRestrict=%s";
} else {
url = getComponentName() + ":%s://%s:%s/%s?matchOnUriPrefix=false&httpMethodRestrict=%s";
}
// get the endpoint
url = String.format(url, scheme, host, port, path, restrict);
if (!query.isEmpty()) {
url = url + "&" + query;
}
UndertowEndpoint endpoint = camelContext.getEndpoint(url, UndertowEndpoint.class);
setProperties(camelContext, endpoint, parameters);
if (!map.containsKey("undertowHttpBinding")) {
// use the rest binding, if not using a custom http binding
endpoint.setUndertowHttpBinding(new RestUndertowHttpBinding());
}
// configure consumer properties
Consumer consumer = endpoint.createConsumer(processor);
if (config.getConsumerProperties() != null && !config.getConsumerProperties().isEmpty()) {
setProperties(camelContext, consumer, config.getConsumerProperties());
}
return consumer;
}
}
@@ -1,219 +0,0 @@
/*
* Copyright 2018 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.camel.undertow;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.AuthenticatedActionsHandler;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.NodesRegistrationManagement;
import org.keycloak.adapters.PreAuthActionsHandler;
import org.keycloak.adapters.RequestAuthenticator;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.InMemorySessionIdMapper;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.undertow.KeycloakUndertowAccount;
import org.keycloak.adapters.undertow.OIDCUndertowHttpFacade;
import org.keycloak.adapters.undertow.SessionManagementBridge;
import org.keycloak.adapters.undertow.UndertowCookieTokenStore;
import org.keycloak.adapters.undertow.UndertowRequestAuthenticator;
import org.keycloak.adapters.undertow.UndertowSessionTokenStore;
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
import org.keycloak.enums.TokenStore;
import io.undertow.security.api.SecurityContext;
import io.undertow.security.idm.Account;
import io.undertow.security.idm.Credential;
import io.undertow.security.idm.IdentityManager;
import io.undertow.security.impl.SecurityContextImpl;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.session.InMemorySessionManager;
import io.undertow.server.session.SessionManager;
import io.undertow.util.AttachmentKey;
import io.undertow.util.StatusCodes;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.apache.camel.Processor;
import org.apache.camel.component.undertow.UndertowConsumer;
/**
*
* @author hmlnarik
*/
public class UndertowKeycloakConsumer extends UndertowConsumer {
private static final Logger LOG = Logger.getLogger(UndertowKeycloakConsumer.class.getName());
public static final AttachmentKey<KeycloakPrincipal> KEYCLOAK_PRINCIPAL_KEY = AttachmentKey.create(KeycloakPrincipal.class);
private static final IdentityManager IDENTITY_MANAGER = new IdentityManager() {
@Override
public Account verify(Account account) {
return account;
}
@Override
public Account verify(String id, Credential credential) {
throw new IllegalStateException("Should never be called in Keycloak flow");
}
@Override
public Account verify(Credential credential) {
throw new IllegalStateException("Should never be called in Keycloak flow");
}
};
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
protected final NodesRegistrationManagement nodesRegistrationManagement = new NodesRegistrationManagement();
private final UndertowUserSessionManagement userSessionManagement = new UndertowUserSessionManagement();
protected final AdapterDeploymentContext deploymentContext;
protected final SessionManager sessionManager;
protected final List<String> allowedRoles;
private final int confidentialPort;
private final Pattern skipPattern;
public UndertowKeycloakConsumer(UndertowKeycloakEndpoint endpoint, Processor processor,
AdapterDeploymentContext deploymentContext, Pattern skipPattern, List<String> allowedRoles, int confidentialPort) {
super(endpoint, processor);
this.sessionManager = new InMemorySessionManager(endpoint.getEndpointUri());
this.deploymentContext = deploymentContext;
this.skipPattern = skipPattern;
this.confidentialPort = confidentialPort;
this.allowedRoles = allowedRoles == null ? Collections.<String>emptyList() : allowedRoles;
}
public int getConfidentialPort() {
return confidentialPort;
}
@Override
public void handleRequest(HttpServerExchange httpExchange) throws Exception {
if (shouldSkip(httpExchange.getRequestPath())) {
super.handleRequest(httpExchange);
return;
}
//perform only non-blocking operation on exchange
if (httpExchange.isInIoThread()) {
httpExchange.dispatch(this);
return;
}
OIDCUndertowHttpFacade facade = new OIDCUndertowHttpFacade(httpExchange);
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
if (deployment == null || !deployment.isConfigured()) {
httpExchange.setStatusCode(StatusCodes.FORBIDDEN);
LOG.fine("deployment not configured");
return;
}
LOG.fine("executing PreAuthActionsHandler");
SessionManagementBridge bridge = new SessionManagementBridge(userSessionManagement, sessionManager);
PreAuthActionsHandler preAuth = new PreAuthActionsHandler(bridge, deploymentContext, facade);
if (preAuth.handleRequest()) return;
SecurityContext securityContext = httpExchange.getSecurityContext();
if (securityContext == null) {
securityContext = new SecurityContextImpl(httpExchange, IDENTITY_MANAGER);
}
AdapterTokenStore tokenStore = getTokenStore(httpExchange, facade, deployment, securityContext);
tokenStore.checkCurrentToken();
LOG.fine("executing AuthenticatedActionsHandler");
RequestAuthenticator authenticator = new UndertowRequestAuthenticator(facade, deployment, confidentialPort, securityContext, httpExchange, tokenStore);
AuthOutcome outcome = authenticator.authenticate();
if (outcome == AuthOutcome.AUTHENTICATED) {
LOG.fine("AUTHENTICATED");
if (httpExchange.isResponseComplete()) {
return;
}
AuthenticatedActionsHandler actions = new AuthenticatedActionsHandler(deployment, facade);
if (actions.handledRequest()) {
return;
} else {
final Account authenticatedAccount = securityContext.getAuthenticatedAccount();
if (authenticatedAccount instanceof KeycloakUndertowAccount) {
final KeycloakUndertowAccount kua = (KeycloakUndertowAccount) authenticatedAccount;
httpExchange.putAttachment(KEYCLOAK_PRINCIPAL_KEY, (KeycloakPrincipal) kua.getPrincipal());
}
Set<String> roles = Optional
.ofNullable(authenticatedAccount.getRoles())
.orElse((Set<String>) Collections.EMPTY_SET);
LOG.log(Level.FINE, "Allowed roles: {0}, current roles: {1}", new Object[] {allowedRoles, roles});
if (isRoleAllowed(roles, httpExchange)) {
super.handleRequest(httpExchange);
} else {
httpExchange.setStatusCode(StatusCodes.FORBIDDEN);
}
return;
}
}
AuthChallenge challenge = authenticator.getChallenge();
if (challenge != null) {
LOG.fine("challenge");
challenge.challenge(facade);
return;
}
httpExchange.setStatusCode(StatusCodes.FORBIDDEN);
}
public boolean isRoleAllowed(Set<String> roles, HttpServerExchange httpExchange) throws Exception {
for (String role : allowedRoles) {
if (roles.contains(role)) {
return true;
}
}
return false;
}
protected AdapterTokenStore getTokenStore(HttpServerExchange exchange, HttpFacade facade, KeycloakDeployment deployment, SecurityContext securityContext) {
if (deployment.getTokenStore() == TokenStore.SESSION) {
return new UndertowSessionTokenStore(exchange, deployment, userSessionManagement, securityContext);
} else {
return new UndertowCookieTokenStore(facade, deployment, securityContext);
}
}
private boolean shouldSkip(String requestPath) {
return skipPattern != null && skipPattern.matcher(requestPath).matches();
}
}
@@ -1,152 +0,0 @@
/*
* Copyright 2018 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.camel.undertow;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.representations.adapters.config.AdapterConfig;
import io.undertow.server.HttpServerExchange;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.apache.camel.Consumer;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.component.undertow.UndertowComponent;
import org.apache.camel.component.undertow.UndertowEndpoint;
import static org.keycloak.adapters.camel.undertow.UndertowKeycloakConsumer.KEYCLOAK_PRINCIPAL_KEY;
/**
*
* @author hmlnarik
*/
public class UndertowKeycloakEndpoint extends UndertowEndpoint {
private static final Logger LOG = Logger.getLogger(UndertowKeycloakEndpoint.class.getName());
private KeycloakConfigResolver configResolver;
private AdapterConfig adapterConfig;
private String skipPattern;
private List<String> allowedRoles = Collections.emptyList();
private int confidentialPort = 8443;
public UndertowKeycloakEndpoint(String uri, UndertowComponent component) {
super(uri, component);
}
public AdapterConfig getAdapterConfig() {
return adapterConfig;
}
public void setAdapterConfig(AdapterConfig adapterConfig) {
LOG.info("adapterConfig");
this.adapterConfig = adapterConfig;
}
public String getSkipPattern() {
return skipPattern;
}
public void setSkipPattern(String skipPattern) {
this.skipPattern = skipPattern;
}
public List<String> getAllowedRoles() {
return allowedRoles;
}
public void setAllowedRoles(List<String> allowedRoles) {
this.allowedRoles = allowedRoles;
}
public void setAllowedRoles(String allowedRoles) {
this.allowedRoles = allowedRoles == null ? null : Arrays.asList(allowedRoles.split("\\s*,\\s*"));
}
public int getConfidentialPort() {
return confidentialPort;
}
public void setConfidentialPort(int confidentialPort) {
this.confidentialPort = confidentialPort;
}
public KeycloakConfigResolver getConfigResolver() {
return configResolver;
}
public void setConfigResolver(KeycloakConfigResolver configResolver) {
this.configResolver = configResolver;
}
@Override
public Consumer createConsumer(Processor processor) throws Exception {
return new UndertowKeycloakConsumer(this, processor, getDeploymentContext(), getSkipPatternAsPattern(), computeAllowedRoles(), this.confidentialPort);
}
public List<String> computeAllowedRoles() {
List<String> res = this.allowedRoles == null ? Collections.<String>emptyList() : this.allowedRoles;
if (res.isEmpty()) {
LOG.warning("No roles were configured, Keycloak will deny every request");
}
LOG.log(Level.FINE, "Allowed roles: {0}", res);
return res;
}
@Override
public Exchange createExchange(HttpServerExchange httpExchange) throws Exception {
final Exchange res = super.createExchange(httpExchange);
KeycloakPrincipal principal = httpExchange.getAttachment(KEYCLOAK_PRINCIPAL_KEY);
LOG.log(Level.FINE, "principal: {0}", principal);
if (principal != null) {
res.setProperty(KeycloakPrincipal.class.getName(), principal);
}
return res;
}
private AdapterDeploymentContext getDeploymentContext() {
if (configResolver != null) {
LOG.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolver.getClass());
return new AdapterDeploymentContext(configResolver);
} else if (adapterConfig != null) {
KeycloakDeployment kd = KeycloakDeploymentBuilder.build(adapterConfig);
return new AdapterDeploymentContext(kd);
}
LOG.warning("Adapter is unconfigured, Keycloak will deny every request");
return new AdapterDeploymentContext();
}
private Pattern getSkipPatternAsPattern() {
return skipPattern == null
? null
: Pattern.compile(skipPattern, Pattern.DOTALL);
}
}
@@ -1 +0,0 @@
class=org.keycloak.adapters.camel.undertow.UndertowKeycloakComponent
-130
View File
@@ -1,130 +0,0 @@
<?xml version="1.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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-pax-web-jetty94</artifactId>
<name>Keycloak Fuse 7.0 Adapter - Jetty 9.4</name>
<packaging>bundle</packaging>
<properties>
<keycloak.osgi.export>
org.keycloak.adapters.osgi.jetty94.*;version="${project.version}"
</keycloak.osgi.export>
<keycloak.osgi.import>
!org.keycloak.adapters.osgi.jetty94,
org.keycloak.*;version="${project.version}",
*;resolution:=optional
</keycloak.osgi.import>
<keycloak.osgi.fragment>org.ops4j.pax.web.pax-web-jetty</keycloak.osgi.fragment>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.enterprise</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty94-adapter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
<Fragment-Host>${keycloak.osgi.fragment}</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,41 +0,0 @@
/*
* Copyright 2018 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.jetty94;
import org.ops4j.pax.web.service.AuthenticatorService;
/**
*
* @author hmlnarik
*/
public class KeycloakAuthenticatorService implements AuthenticatorService {
@Override
public <T> T getAuthenticatorService(String method, Class<T> iface) {
if (method == null || iface != org.eclipse.jetty.security.Authenticator.class) {
return null;
}
if ("KEYCLOAK".equalsIgnoreCase(method)) {
return iface.cast(new org.keycloak.adapters.jetty.KeycloakJettyAuthenticator());
}
return null;
}
}
@@ -1,280 +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.jetty94;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.util.security.Constraint;
import org.jboss.logging.Logger;
import org.ops4j.pax.web.service.WebContainer;
import org.ops4j.pax.web.service.spi.model.SecurityConstraintMappingModel;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import java.net.URL;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Integration with pax-web, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
* and allows to inject custom security constraint for securing resources by Keycloak.
*
* <p>It assumes that pax-web {@link WebContainer} is used as implementation of OSGI {@link org.osgi.service.http.HttpService}, which
* is true in karaf/fuse environment</p>
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PaxWebIntegrationService {
protected static final Logger log = Logger.getLogger(PaxWebIntegrationService.class);
private BundleContext bundleContext;
private String jettyWebXmlLocation;
private List<Object> constraintMappings;
private ServiceTracker webContainerTracker;
private HttpContext httpContext;
public BundleContext getBundleContext() {
return bundleContext;
}
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public String getJettyWebXmlLocation() {
return jettyWebXmlLocation;
}
public void setJettyWebXmlLocation(String jettyWebXmlLocation) {
this.jettyWebXmlLocation = jettyWebXmlLocation;
}
public List<Object> getConstraintMappings() {
return constraintMappings;
}
public void setConstraintMappings(List<Object> constraintMappings) {
this.constraintMappings = constraintMappings;
}
protected ServiceTracker getWebContainerTracker() {
return webContainerTracker;
}
protected HttpContext getHttpContext() {
return httpContext;
}
public void setHttpContext(HttpContext httpContext) {
this.httpContext = httpContext;
}
public void start() {
ServiceTrackerCustomizer trackerCustomizer = new ServiceTrackerCustomizer() {
@Override
public Object addingService(ServiceReference reference) {
return addingWebContainerCallback(reference);
}
@Override
public void modifiedService(ServiceReference reference, Object service) {
}
@Override
public void removedService(ServiceReference reference, Object service) {
removingWebContainerCallback(reference);
}
};
webContainerTracker = new ServiceTracker(bundleContext, WebContainer.class.getName(), trackerCustomizer);
webContainerTracker.open();
}
public void stop() {
webContainerTracker.remove(webContainerTracker.getServiceReference());
}
protected WebContainer addingWebContainerCallback(ServiceReference webContainerServiceReference) {
WebContainer service = (WebContainer) bundleContext.getService(webContainerServiceReference);
if (httpContext == null) {
httpContext = service.createDefaultHttpContext();
}
addJettyWebXml(service);
if (constraintMappings == null) {
throw new IllegalStateException("constraintMappings was null!");
}
List<ConstraintHandler> handlers = new ArrayList<>();
try {
handlers.add(new JettyConstraintHandler());
} catch (Throwable t) {
// Ignore
}
try {
handlers.add(new PaxWebConstraintHandler());
} catch (Throwable t) {
// Ignore
}
for (Object constraintMapping : constraintMappings) {
boolean handled = false;
for (ConstraintHandler handler : handlers) {
handled |= handler.addConstraintMapping(httpContext, service, constraintMapping);
}
if (!handled) {
log.warnv("Unable to add constraint mapping for constraint of type " + constraintMapping.getClass().toString());
}
}
service.registerLoginConfig("BASIC", "does-not-matter", null, null, httpContext);
return service;
}
protected void addJettyWebXml(WebContainer service) {
String jettyWebXmlLoc;
if (this.jettyWebXmlLocation == null) {
jettyWebXmlLoc = "/WEB-INF/jetty-web.xml";
} else {
jettyWebXmlLoc = this.jettyWebXmlLocation;
}
URL jettyWebXml = bundleContext.getBundle().getResource(jettyWebXmlLoc);
if (jettyWebXml != null) {
log.debug("Found jetty-web XML configuration on bundle classpath on " + jettyWebXmlLoc);
service.registerJettyWebXml(jettyWebXml, httpContext);
} else {
log.debug("Not found jetty-web XML configuration on bundle classpath on " + jettyWebXmlLoc);
}
}
protected void addConstraintMapping(WebContainer service, SecurityConstraintMappingModel constraintMapping) {
String name = constraintMapping.getConstraintName();
if (name == null) {
name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
}
log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getUrl() + ", dataConstraint=" + constraintMapping.getDataConstraint() + ", canAuthenticate="
+ constraintMapping.isAuthentication() + ", roles=" + constraintMapping.getRoles());
service.registerConstraintMapping(name, constraintMapping.getUrl(), constraintMapping.getMapping(), constraintMapping.getDataConstraint(), constraintMapping.isAuthentication(), constraintMapping.getRoles(), httpContext);
}
protected void addConstraintMapping(WebContainer service, ConstraintMapping constraintMapping) {
Constraint constraint = constraintMapping.getConstraint();
String[] roles = constraint.getRoles();
// name property is unavailable on constraint object :/
String name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
int dataConstraint = constraint.getDataConstraint();
String dataConstraintStr;
switch (dataConstraint) {
case Constraint.DC_UNSET: dataConstraintStr = null; break;
case Constraint.DC_NONE: dataConstraintStr = "NONE"; break;
case Constraint.DC_CONFIDENTIAL: dataConstraintStr = "CONFIDENTIAL"; break;
case Constraint.DC_INTEGRAL: dataConstraintStr = "INTEGRAL"; break;
default:
log.warnv("Unknown data constraint: " + dataConstraint);
dataConstraintStr = "CONFIDENTIAL";
}
List<String> rolesList = Arrays.asList(roles);
log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getPathSpec() + ", dataConstraint=" + dataConstraintStr + ", canAuthenticate="
+ constraint.getAuthenticate() + ", roles=" + rolesList);
service.registerConstraintMapping(name, constraintMapping.getPathSpec(), null, dataConstraintStr, constraint.getAuthenticate(), rolesList, httpContext);
}
protected void removingWebContainerCallback(ServiceReference serviceReference) {
WebContainer service = (WebContainer)bundleContext.getService(serviceReference);
if (service != null) {
service.unregisterLoginConfig(httpContext);
service.unregisterConstraintMapping(httpContext);
}
}
private interface ConstraintHandler {
boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm);
}
private static class PaxWebConstraintHandler implements ConstraintHandler {
public boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm) {
if (cm instanceof SecurityConstraintMappingModel) {
SecurityConstraintMappingModel constraintMapping = (SecurityConstraintMappingModel) cm;
String name = constraintMapping.getConstraintName();
if (name == null) {
name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
}
log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getUrl() + ", dataConstraint=" + constraintMapping.getDataConstraint() + ", canAuthenticate="
+ constraintMapping.isAuthentication() + ", roles=" + constraintMapping.getRoles());
service.registerConstraintMapping(name, constraintMapping.getUrl(), constraintMapping.getMapping(), constraintMapping.getDataConstraint(), constraintMapping.isAuthentication(), constraintMapping.getRoles(), httpContext);
return true;
}
return false;
}
}
private static class JettyConstraintHandler implements ConstraintHandler {
public boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm) {
if (cm instanceof ConstraintMapping) {
ConstraintMapping constraintMapping = (ConstraintMapping) cm;
Constraint constraint = constraintMapping.getConstraint();
String[] roles = constraint.getRoles();
// name property is unavailable on constraint object :/
String name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
int dataConstraint = constraint.getDataConstraint();
String dataConstraintStr;
switch (dataConstraint) {
case Constraint.DC_UNSET:
dataConstraintStr = null;
break;
case Constraint.DC_NONE:
dataConstraintStr = "NONE";
break;
case Constraint.DC_CONFIDENTIAL:
dataConstraintStr = "CONFIDENTIAL";
break;
case Constraint.DC_INTEGRAL:
dataConstraintStr = "INTEGRAL";
break;
default:
log.warnv("Unknown data constraint: " + dataConstraint);
dataConstraintStr = "CONFIDENTIAL";
}
List<String> rolesList = Arrays.asList(roles);
log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getPathSpec() + ", dataConstraint=" + dataConstraintStr + ", canAuthenticate="
+ constraint.getAuthenticate() + ", roles=" + rolesList);
service.registerConstraintMapping(name, constraintMapping.getPathSpec(), null, dataConstraintStr, constraint.getAuthenticate(), rolesList, httpContext);
return true;
}
return false;
}
}
}
@@ -1 +0,0 @@
org.keycloak.adapters.osgi.jetty94.KeycloakAuthenticatorService
-45
View File
@@ -1,45 +0,0 @@
<?xml version="1.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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<packaging>pom</packaging>
<name>Keycloak Fuse 7.0 Integration</name>
<properties>
<fuse7.version>7.0.1-SNAPSHOT</fuse7.version>
<tomcat.version>8.0.14</tomcat.version>
<jetty9.version>9.4.2.v20170220</jetty9.version>
</properties>
<modules>
<module>camel-undertow</module>
<module>jetty94</module>
<module>tomcat8</module>
<module>undertow</module>
</modules>
</project>
-115
View File
@@ -1,115 +0,0 @@
<?xml version="1.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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-pax-web-tomcat8</artifactId>
<name>Keycloak Fuse 7.0 Adapter - Tomcat 8</name>
<packaging>bundle</packaging>
<properties>
<keycloak.osgi.export>
org.keycloak.adapters.osgi.tomcat.*;version="${project.version}"
</keycloak.osgi.export>
<keycloak.osgi.import>
!org.keycloak.adapters.osgi.tomcat,
org.keycloak.*;version="${project.version}",
*;resolution:=optional
</keycloak.osgi.import>
<keycloak.osgi.fragment>org.ops4j.pax.web.pax-web-tomcat</keycloak.osgi.fragment>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat8-adapter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
<Fragment-Host>${keycloak.osgi.fragment}</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,41 +0,0 @@
/*
* Copyright 2018 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.tomcat;
import org.ops4j.pax.web.service.AuthenticatorService;
/**
*
* @author hmlnarik
*/
public class KeycloakAuthenticatorService implements AuthenticatorService {
@Override
public <T> T getAuthenticatorService(String method, Class<T> iface) {
if (method == null || iface != org.apache.catalina.Valve.class) {
return null;
}
if ("KEYCLOAK".equalsIgnoreCase(method)) {
return iface.cast(new org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve());
}
return null;
}
}
@@ -1 +0,0 @@
org.keycloak.adapters.osgi.tomcat.KeycloakAuthenticatorService
-158
View File
@@ -1,158 +0,0 @@
<?xml version="1.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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-pax-web-undertow</artifactId>
<name>Keycloak Fuse 7.0 Adapter - Undertow</name>
<packaging>bundle</packaging>
<properties>
<keycloak.osgi.export>
org.keycloak.adapters.osgi.undertow.*;version="${project.version}"
</keycloak.osgi.export>
<keycloak.osgi.import>
!org.keycloak.adapters.osgi.undertow,
org.keycloak.*;version="${project.version}",
org.keycloak.adapters.osgi.*;version="${project.version}",
org.ops4j.pax.web.*;version="[3.0,8)",
javax.servlet.*;version="[2.5,4)";resolution:=optional,
org.apache.cxf.transport.http;resolution:=optional;version="[3,4)",
org.apache.cxf.transport.http_undertow;resolution:=optional;version="[3,4)",
org.apache.cxf.transport.servlet;resolution:=optional;version="[3,4)",
io.undertow.*,
*;resolution:=optional
</keycloak.osgi.import>
<keycloak.osgi.fragment>org.ops4j.pax.web.pax-web-undertow</keycloak.osgi.fragment>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.enterprise</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-runtime</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.web</groupId>
<artifactId>pax-web-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-undertow</artifactId>
<version>${cxf.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-osgi-adapter</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
<Fragment-Host>${keycloak.osgi.fragment}</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,174 +0,0 @@
/*
* Copyright 2018 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.undertow;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.NodesRegistrationManagement;
import org.keycloak.adapters.spi.InMemorySessionIdMapper;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.undertow.UndertowAuthenticationMechanism;
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
import org.keycloak.representations.adapters.config.AdapterConfig;
import io.undertow.security.api.AuthenticationMechanism;
import io.undertow.security.api.AuthenticationMode;
import io.undertow.security.handlers.AuthenticationCallHandler;
import io.undertow.security.handlers.AuthenticationConstraintHandler;
import io.undertow.security.handlers.AuthenticationMechanismsHandler;
import io.undertow.security.handlers.SecurityInitialHandler;
import io.undertow.security.idm.Account;
import io.undertow.security.idm.Credential;
import io.undertow.security.idm.IdentityManager;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.apache.cxf.transport.http_undertow.CXFUndertowHttpHandler;
/**
*
* @author hmlnarik
*/
public class CxfKeycloakAuthHandler implements CXFUndertowHttpHandler {
private static final Logger LOG = Logger.getLogger(CxfKeycloakAuthHandler.class.getName());
private static final IdentityManager IDENTITY_MANAGER = new IdentityManager() {
@Override
public Account verify(Account account) {
return account;
}
@Override
public Account verify(String id, Credential credential) {
throw new IllegalStateException("Should never be called in Keycloak flow");
}
@Override
public Account verify(Credential credential) {
throw new IllegalStateException("Should never be called in Keycloak flow");
}
};
private final UndertowUserSessionManagement userSessionManagement = new UndertowUserSessionManagement();
protected final NodesRegistrationManagement nodesRegistrationManagement = new NodesRegistrationManagement();
protected final SessionIdMapper idMapper = new InMemorySessionIdMapper();
private final AtomicReference<HttpHandler> securityHandler = new AtomicReference<>();
private Pattern skipPattern;
private int confidentialPort = 8443;
private HttpHandler next;
private KeycloakConfigResolver configResolver;
private AdapterConfig adapterConfig;
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
if (shouldSkip(exchange.getRequestPath())) {
next.handleRequest(exchange);
} else {
getSecurityHandler().handleRequest(exchange);
}
}
private HttpHandler getSecurityHandler() {
if (this.securityHandler.get() == null) {
HttpHandler handler = this.next;
handler = new AuthenticationCallHandler(handler);
handler = new AuthenticationConstraintHandler(handler);
AdapterDeploymentContext deploymentContext = buildDeploymentContext();
final List<AuthenticationMechanism> mechanisms
= Collections.<AuthenticationMechanism>singletonList(
new UndertowAuthenticationMechanism(deploymentContext, userSessionManagement, nodesRegistrationManagement, confidentialPort, null));
handler = new AuthenticationMechanismsHandler(handler, mechanisms);
this.securityHandler.compareAndSet(null, new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, IDENTITY_MANAGER, "KEYCLOAK", handler));
}
return this.securityHandler.get();
}
private AdapterDeploymentContext buildDeploymentContext() {
if (configResolver != null) {
LOG.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolver.getClass());
return new AdapterDeploymentContext(configResolver);
} else if (adapterConfig != null) {
KeycloakDeployment kd = KeycloakDeploymentBuilder.build(adapterConfig);
return new AdapterDeploymentContext(kd);
}
LOG.warning("Adapter is unconfigured, Keycloak will deny every request");
return new AdapterDeploymentContext();
}
@Override
public void setNext(HttpHandler nextHandler) {
this.next = nextHandler;
}
private boolean shouldSkip(String requestPath) {
return skipPattern != null && skipPattern.matcher(requestPath).matches();
}
public KeycloakConfigResolver getConfigResolver() {
return configResolver;
}
public void setConfigResolver(KeycloakConfigResolver configResolver) {
this.configResolver = configResolver;
}
public int getConfidentialPort() {
return confidentialPort;
}
public void setConfidentialPort(int confidentialPort) {
this.confidentialPort = confidentialPort;
}
public AdapterConfig getAdapterConfig() {
return adapterConfig;
}
public void setAdapterConfig(AdapterConfig adapterConfig) {
this.adapterConfig = adapterConfig;
}
public String getSkipPattern() {
return skipPattern.pattern();
}
public void setSkipPattern(String skipPattern) {
this.skipPattern = Pattern.compile(skipPattern, Pattern.DOTALL);
}
}
@@ -1,41 +0,0 @@
/*
* Copyright 2018 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.undertow;
import org.ops4j.pax.web.service.AuthenticatorService;
/**
*
* @author hmlnarik
*/
public class KeycloakAuthenticatorService implements AuthenticatorService {
@Override
public <T> T getAuthenticatorService(String method, Class<T> iface) {
if (method == null || iface != io.undertow.servlet.ServletExtension.class) {
return null;
}
if ("KEYCLOAK".equalsIgnoreCase(method)) {
return iface.cast(new org.keycloak.adapters.undertow.KeycloakServletExtension());
}
return null;
}
}
@@ -1,142 +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.undertow;
import org.keycloak.adapters.osgi.PaxWebSecurityConstraintMapping;
import org.jboss.logging.Logger;
import org.ops4j.pax.web.service.WebContainer;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import java.util.List;
/**
* Integration with pax-web, which allows to inject custom security constraint for securing resources by Keycloak.
*
* <p>It assumes that pax-web {@link WebContainer} is used as implementation of OSGI {@link org.osgi.service.http.HttpService}, which
* is true in karaf/fuse environment</p>
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PaxWebIntegrationService {
protected static final Logger log = Logger.getLogger(PaxWebIntegrationService.class);
private BundleContext bundleContext;
private List<PaxWebSecurityConstraintMapping> constraintMappings;
private ServiceTracker webContainerTracker;
private HttpContext httpContext;
public BundleContext getBundleContext() {
return bundleContext;
}
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public List<PaxWebSecurityConstraintMapping> getConstraintMappings() {
return constraintMappings;
}
public void setConstraintMappings(List<PaxWebSecurityConstraintMapping> constraintMappings) {
this.constraintMappings = constraintMappings;
}
protected ServiceTracker getWebContainerTracker() {
return webContainerTracker;
}
protected HttpContext getHttpContext() {
return httpContext;
}
public void setHttpContext(HttpContext httpContext) {
this.httpContext = httpContext;
}
public void start() {
ServiceTrackerCustomizer trackerCustomizer = new ServiceTrackerCustomizer() {
@Override
public Object addingService(ServiceReference reference) {
return addingWebContainerCallback(reference);
}
@Override
public void modifiedService(ServiceReference reference, Object service) {
}
@Override
public void removedService(ServiceReference reference, Object service) {
removingWebContainerCallback(reference);
}
};
webContainerTracker = new ServiceTracker(bundleContext, WebContainer.class.getName(), trackerCustomizer);
webContainerTracker.open();
}
public void stop() {
webContainerTracker.remove(webContainerTracker.getServiceReference());
}
protected WebContainer addingWebContainerCallback(ServiceReference webContainerServiceReference) {
WebContainer service = (WebContainer) bundleContext.getService(webContainerServiceReference);
if (httpContext == null) {
httpContext = service.createDefaultHttpContext();
}
if (constraintMappings == null) {
throw new IllegalStateException("constraintMappings was null!");
}
for (PaxWebSecurityConstraintMapping constraintMapping : constraintMappings) {
addConstraintMapping(service, constraintMapping);
}
service.registerLoginConfig("KEYCLOAK", "specified-in-keycloak-json", null, null, httpContext);
return service;
}
protected void addConstraintMapping(WebContainer service, PaxWebSecurityConstraintMapping cm) {
log.debug("Adding security constraint name=" + cm.getConstraintName() + ", url=" + cm.getUrl() + ", dataConstraint=" + cm.getDataConstraint() + ", canAuthenticate="
+ cm.isAuthentication() + ", roles=" + cm.getRoles());
service.registerConstraintMapping(
cm.getConstraintName(),
cm.getMapping(),
cm.getUrl(),
cm.getDataConstraint(),
cm.isAuthentication(),
cm.getRoles(),
httpContext
);
}
protected void removingWebContainerCallback(ServiceReference serviceReference) {
WebContainer service = (WebContainer)bundleContext.getService(serviceReference);
if (service != null) {
service.unregisterLoginConfig(httpContext);
service.unregisterConstraintMapping(httpContext);
}
}
}
@@ -1 +0,0 @@
org.keycloak.adapters.osgi.undertow.KeycloakAuthenticatorService
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Jetty Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+10 -73
View File
@@ -18,7 +18,7 @@
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import * as Keycloak from './keycloak';
import * as Keycloak from 'keycloak';
export as namespace KeycloakAuthorization;
@@ -35,64 +35,6 @@ declare namespace KeycloakAuthorization {
then(onGrant: (rpt: string) => void, onDeny: () => void, onError: () => void): void;
}
interface AuthorizationRequest {
/**
* An array of objects representing the resource and scopes.
*/
permissions?:ResourcePermission[],
/**
* A permission ticket obtained from a resource server when using UMA authorization protocol.
*/
ticket?:string,
/**
* A boolean value indicating whether the server should create permission requests to the resources
* and scopes referenced by a permission ticket. This parameter will only take effect when used together
* with the ticket parameter as part of a UMA authorization process.
*/
submitRequest?:boolean,
/**
* Defines additional information about this authorization request in order to specify how it should be processed
* by the server.
*/
metadata?:AuthorizationRequestMetadata,
/**
* Defines whether or not this authorization request should include the current RPT. If set to true, the RPT will
* be sent and permissions in the current RPT will be included in the new RPT. Otherwise, only the permissions referenced in this
* authorization request will be granted in the new RPT.
*/
incrementalAuthorization?:boolean
}
interface AuthorizationRequestMetadata {
/**
* A boolean value indicating to the server if resource names should be included in the RPT’s permissions.
* If false, only the resource identifier is included.
*/
responseIncludeResourceName?:any,
/**
* An integer N that defines a limit for the amount of permissions an RPT can have. When used together with
* rpt parameter, only the last N requested permissions will be kept in the RPT.
*/
response_permissions_limit?:number
}
interface ResourcePermission {
/**
* The id or name of a resource.
*/
id:string,
/**
* An array of strings where each value is the name of a scope associated with the resource.
*/
scopes?:string[]
}
interface KeycloakAuthorizationInstance {
rpt: any;
config: { rpt_endpoint: string };
@@ -100,23 +42,18 @@ declare namespace KeycloakAuthorization {
init(): void;
/**
* This method enables client applications to better integrate with resource servers protected by a Keycloak
* policy enforcer using UMA protocol.
*
* The authorization request must be provided with a ticket.
*
* @param authorizationRequest An AuthorizationRequest instance with a valid permission ticket set.
* @returns A promise to set functions to be invoked on grant, deny or error.
*/
authorize(authorizationRequest: AuthorizationRequest): KeycloakAuthorizationPromise;
* This method enables client applications to better integrate with resource servers protected by a Keycloak
* policy enforcer.
*
* In this case, the resource server will respond with a 401 status code and a WWW-Authenticate header holding the
* necessary information to ask a Keycloak server for authorization data using both UMA and Entitlement protocol,
* depending on how the policy enforcer at the resource server was configured.
*/
authorize(wwwAuthenticateHeader: string): KeycloakAuthorizationPromise;
/**
* Obtains all entitlements from a Keycloak server based on a given resourceServerId.
*
* @param resourceServerId The id (client id) of the resource server to obtain permissions from.
* @param authorizationRequest An AuthorizationRequest instance.
* @returns A promise to set functions to be invoked on grant, deny or error.
*/
entitlement(resourceServerId: string, authorizationRequest?: AuthorizationRequest): KeycloakAuthorizationPromise;
entitlement(resourceServerId: string, entitlementRequest: {}): KeycloakAuthorizationPromise;
}
}
@@ -41,9 +41,11 @@
/**
* This method enables client applications to better integrate with resource servers protected by a Keycloak
* policy enforcer using UMA protocol.
* policy enforcer.
*
* The authorization request must be provided with a ticket.
* In this case, the resource server will respond with a 401 status code and a WWW-Authenticate header holding the
* necessary information to ask a Keycloak server for authorization data using both UMA and Entitlement protocol,
* depending on how the policy enforcer at the resource server was configured.
*/
this.authorize = function (authorizationRequest) {
this.then = function (onGrant, onDeny, onError) {
@@ -203,8 +205,6 @@
};
this.init(this);
return this;
};
if ( typeof module === "object" && module && typeof module.exports === "object" ) {
-8
View File
@@ -161,14 +161,6 @@ declare namespace Keycloak {
* the user's profile to a new preferred locale.
*/
kcLocale?: string;
/**
* Specifies arguments that are passed to the Cordova in-app-browser (if applicable).
* Options 'hidden' and 'location' are not affected by these arguments.
* All available options are defined at https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/.
* Example of use: { zoom: "no", hardwareback: "yes" }
*/
cordovaOptions?: { [optionName: string]: string };
}
type KeycloakPromiseCallback<T> = (result: T) => void;
+12 -60
View File
@@ -250,16 +250,7 @@
baseUrl = kc.endpoints.authorize();
}
var scope;
if (options && options.scope) {
if (options.scope.indexOf("openid") != -1) {
scope = options.scope;
} else {
scope = "openid " + options.scope;
}
} else {
scope = "openid";
}
var scope = (options && options.scope) ? "openid " + options.scope : "openid";
var url = baseUrl
+ '?client_id=' + encodeURIComponent(kc.clientId)
@@ -1196,54 +1187,24 @@
return window.open(loginUrl, target, options);
}
};
var shallowCloneCordovaOptions = function (userOptions) {
if (userOptions && userOptions.cordovaOptions) {
return Object.keys(userOptions.cordovaOptions).reduce(function (options, optionName) {
options[optionName] = userOptions.cordovaOptions[optionName];
return options;
}, {});
} else {
return {};
}
};
var formatCordovaOptions = function (cordovaOptions) {
return Object.keys(cordovaOptions).reduce(function (options, optionName) {
options.push(optionName+"="+cordovaOptions[optionName]);
return options;
}, []).join(",");
};
var createCordovaOptions = function (userOptions) {
var cordovaOptions = shallowCloneCordovaOptions(userOptions);
cordovaOptions.location = 'no';
if (userOptions && userOptions.prompt == 'none') {
cordovaOptions.hidden = 'yes';
}
return formatCordovaOptions(cordovaOptions);
};
return {
login: function(options) {
var promise = createPromise();
var cordovaOptions = createCordovaOptions(options);
var o = 'location=no';
if (options && options.prompt == 'none') {
o += ',hidden=yes';
}
var loginUrl = kc.createLoginUrl(options);
var ref = cordovaOpenWindowWrapper(loginUrl, '_blank', cordovaOptions);
var ref = cordovaOpenWindowWrapper(loginUrl, '_blank', o);
var completed = false;
var closed = false;
var closeBrowser = function() {
closed = true;
ref.close();
};
ref.addEventListener('loadstart', function(event) {
if (event.url.indexOf('http://localhost') == 0) {
var callback = parseCallback(event.url);
processCallback(callback, promise);
closeBrowser();
ref.close();
completed = true;
}
});
@@ -1253,29 +1214,21 @@
if (event.url.indexOf('http://localhost') == 0) {
var callback = parseCallback(event.url);
processCallback(callback, promise);
closeBrowser();
ref.close();
completed = true;
} else {
promise.setError();
closeBrowser();
ref.close();
}
}
});
ref.addEventListener('exit', function(event) {
if (!closed) {
promise.setError({
reason: "closed_by_user"
});
}
});
return promise.promise;
},
logout: function(options) {
var promise = createPromise();
var logoutUrl = kc.createLogoutUrl(options);
var ref = cordovaOpenWindowWrapper(logoutUrl, '_blank', 'location=no,hidden=yes');
@@ -1310,8 +1263,7 @@
register : function() {
var registerUrl = kc.createRegisterUrl();
var cordovaOptions = createCordovaOptions(options);
var ref = cordovaOpenWindowWrapper(registerUrl, '_blank', cordovaOptions);
var ref = cordovaOpenWindowWrapper(registerUrl, '_blank', 'location=no');
ref.addEventListener('loadstart', function(event) {
if (event.url.indexOf('http://localhost') == 0) {
ref.close();
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+2 -8
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -36,7 +36,7 @@
org.keycloak.adapters.osgi.*
</keycloak.osgi.export>
<keycloak.osgi.import>
org.ops4j.pax.web.*;version="[3.0,8)",
org.ops4j.pax.web.*;version="[3.0,5)",
javax.servlet.*;version="[2.5,4)";resolution:=optional,
org.eclipse.jetty.*;version="[8.1,10)";resolution:=optional,
org.keycloak.*;version="${project.version}",
@@ -99,12 +99,6 @@
<version>${cxf.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@@ -25,7 +25,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -35,36 +34,14 @@ public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
@Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
String uri = request.getURI();
String relativePath = request.getRelativePath();
String webContext = null;
if (relativePath == null || !uri.contains(relativePath)) {
String[] urlTokens = uri.split("/");
if (urlTokens.length < 4) {
throw new IllegalStateException("Not able to determine the web-context to load the correspondent keycloak.json file");
}
webContext = urlTokens[3];
} else {
URI parsedURI = URI.create(uri);
String path = parsedURI.getPath();
path = path.substring(0, path.indexOf(relativePath));
while (path.startsWith("/")) {
path = path.substring(1);
}
webContext = path;
if ("".equals(webContext)) {
path = relativePath;
while (path.startsWith("/")) {
path = path.substring(1);
}
if (path.contains("/")) {
path = path.substring(0, path.indexOf("/"));
}
webContext = path;
}
String path = request.getURI();
String[] urlTokens = path.split("/");
if (urlTokens.length < 4) {
throw new IllegalStateException("Not able to determine the web-context to load the correspondent keycloak.json file");
}
String webContext = urlTokens[3];
KeycloakDeployment deployment = cache.get(webContext);
if (null == deployment) {
// not found on the simple cache, try to load it from the file system
@@ -77,8 +54,7 @@ public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
keycloakConfig = karafEtc;
}
String absolutePath = keycloakConfig + File.separator + webContext + ("".equals(webContext) ? "" : "-")
+ "keycloak.json";
String absolutePath = keycloakConfig + File.separator + webContext + "-keycloak.json";
InputStream is = null;
try {
is = new FileInputStream(absolutePath);
@@ -29,12 +29,11 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer;
import java.net.URL;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Integration with pax-web in Fuse 6.3, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
* Integration with pax-web, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
* and allows to inject custom security constraint for securing resources by Keycloak.
*
* <p>It assumes that pax-web {@link WebContainer} is used as implementation of OSGI {@link org.osgi.service.http.HttpService}, which
@@ -48,7 +47,7 @@ public class PaxWebIntegrationService {
private BundleContext bundleContext;
private String jettyWebXmlLocation;
private List<Object> constraintMappings;
private List<ConstraintMapping> constraintMappings; // Using jetty constraint mapping just because of compatibility with other fuse services
private ServiceTracker webContainerTracker;
private HttpContext httpContext;
@@ -69,11 +68,11 @@ public class PaxWebIntegrationService {
this.jettyWebXmlLocation = jettyWebXmlLocation;
}
public List<Object> getConstraintMappings() {
public List<ConstraintMapping> getConstraintMappings() {
return constraintMappings;
}
public void setConstraintMappings(List<Object> constraintMappings) {
public void setConstraintMappings(List<ConstraintMapping> constraintMappings) {
this.constraintMappings = constraintMappings;
}
@@ -121,25 +120,8 @@ public class PaxWebIntegrationService {
if (constraintMappings == null) {
throw new IllegalStateException("constraintMappings was null!");
}
List<ConstraintHandler> handlers = new ArrayList<>();
try {
handlers.add(new JettyConstraintHandler());
} catch (Throwable t) {
// Ignore
}
try {
handlers.add(new PaxWebConstraintHandler());
} catch (Throwable t) {
// Ignore
}
for (Object constraintMapping : constraintMappings) {
boolean handled = false;
for (ConstraintHandler handler : handlers) {
handled |= handler.addConstraintMapping(httpContext, service, constraintMapping);
}
if (!handled) {
log.warnv("Unable to add constraint mapping for constraint of type " + constraintMapping.getClass().toString());
}
for (ConstraintMapping constraintMapping : constraintMappings) {
addConstraintMapping(service, constraintMapping);
}
service.registerLoginConfig("BASIC", "does-not-matter", null, null, httpContext);
@@ -164,16 +146,6 @@ public class PaxWebIntegrationService {
}
}
protected void addConstraintMapping(WebContainer service, PaxWebSecurityConstraintMapping constraintMapping) {
String name = constraintMapping.getConstraintName();
if (name == null) {
name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
}
log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getUrl() + ", dataConstraint=" + constraintMapping.getDataConstraint() + ", canAuthenticate="
+ constraintMapping.isAuthentication() + ", roles=" + constraintMapping.getRoles());
service.registerConstraintMapping(name, constraintMapping.getUrl(), constraintMapping.getMapping(), constraintMapping.getDataConstraint(), constraintMapping.isAuthentication(), constraintMapping.getRoles(), httpContext);
}
protected void addConstraintMapping(WebContainer service, ConstraintMapping constraintMapping) {
Constraint constraint = constraintMapping.getConstraint();
String[] roles = constraint.getRoles();
@@ -206,71 +178,4 @@ public class PaxWebIntegrationService {
service.unregisterConstraintMapping(httpContext);
}
}
private interface ConstraintHandler {
boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm);
}
private static class PaxWebConstraintHandler implements ConstraintHandler {
@Override
public boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm) {
if (cm instanceof PaxWebSecurityConstraintMapping) {
PaxWebSecurityConstraintMapping constraintMapping = (PaxWebSecurityConstraintMapping) cm;
String name = constraintMapping.getConstraintName();
if (name == null) {
name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
}
log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getUrl() + ", dataConstraint=" + constraintMapping.getDataConstraint() + ", canAuthenticate="
+ constraintMapping.isAuthentication() + ", roles=" + constraintMapping.getRoles());
service.registerConstraintMapping(name, constraintMapping.getUrl(), constraintMapping.getMapping(), constraintMapping.getDataConstraint(), constraintMapping.isAuthentication(), constraintMapping.getRoles(), httpContext);
return true;
}
return false;
}
}
private static class JettyConstraintHandler implements ConstraintHandler {
@Override
public boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm) {
if (cm instanceof ConstraintMapping) {
ConstraintMapping constraintMapping = (ConstraintMapping) cm;
Constraint constraint = constraintMapping.getConstraint();
String[] roles = constraint.getRoles();
// name property is unavailable on constraint object :/
String name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
int dataConstraint = constraint.getDataConstraint();
String dataConstraintStr;
switch (dataConstraint) {
case Constraint.DC_UNSET:
dataConstraintStr = null;
break;
case Constraint.DC_NONE:
dataConstraintStr = "NONE";
break;
case Constraint.DC_CONFIDENTIAL:
dataConstraintStr = "CONFIDENTIAL";
break;
case Constraint.DC_INTEGRAL:
dataConstraintStr = "INTEGRAL";
break;
default:
log.warnv("Unknown data constraint: " + dataConstraint);
dataConstraintStr = "CONFIDENTIAL";
}
List<String> rolesList = Arrays.asList(roles);
log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getPathSpec() + ", dataConstraint=" + dataConstraintStr + ", canAuthenticate="
+ constraint.getAuthenticate() + ", roles=" + rolesList);
service.registerConstraintMapping(name, constraintMapping.getPathSpec(), null, dataConstraintStr, constraint.getAuthenticate(), rolesList, httpContext);
return true;
}
return false;
}
}
}
}
@@ -1,73 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.keycloak.adapters.osgi;
import java.security.SecureRandom;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author hmlnarik
*/
public class PaxWebSecurityConstraintMapping {
private String constraintName = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
private String mapping;
private String url;
private String dataConstraint = "NONE";
private boolean authentication = true;
private List<String> roles = new LinkedList<>();
public String getConstraintName() {
return constraintName;
}
public void setConstraintName(String constraintName) {
this.constraintName = constraintName;
}
public String getMapping() {
return mapping;
}
public void setMapping(String mapping) {
this.mapping = mapping;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDataConstraint() {
return dataConstraint;
}
public void setDataConstraint(String dataConstraint) {
this.dataConstraint = dataConstraint;
}
public boolean isAuthentication() {
return authentication;
}
public void setAuthentication(boolean authentication) {
this.authentication = authentication;
}
public List<String> getRoles() {
return roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
}
@@ -1,149 +0,0 @@
/*
* Copyright 2018 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.InputStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.AuthenticationError;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.LogoutError;
import static org.junit.Assert.assertNotNull;
public class PathBasedKeycloakConfigResolverTest {
@Test
public void relativeURIsAndContexts() throws Exception {
PathBasedKeycloakConfigResolver resolver = new PathBasedKeycloakConfigResolver();
assertNotNull(populate(resolver, "test")
.resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/a/b/c")));
assertNotNull(populate(resolver, "test")
.resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/a/b")));
// means default context and actually we use first segment
assertNotNull(populate(resolver, "test")
.resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/test/a/b/c")));
assertNotNull(populate(resolver, "test/a")
.resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/b/c")));
assertNotNull(populate(resolver, "")
.resolve(new MockRequest("http://localhost/", "/")));
}
@SuppressWarnings("unchecked")
private PathBasedKeycloakConfigResolver populate(PathBasedKeycloakConfigResolver resolver, String context)
throws Exception {
Field f = PathBasedKeycloakConfigResolver.class.getDeclaredField("cache");
f.setAccessible(true);
Map<String, KeycloakDeployment> cache = (Map<String, KeycloakDeployment>) f.get(resolver);
cache.clear();
cache.put(context, new KeycloakDeployment());
return resolver;
}
private class MockRequest implements OIDCHttpFacade.Request {
private String uri;
private String relativePath;
public MockRequest(String uri, String relativePath) {
this.uri = uri;
this.relativePath = relativePath;
}
@Override
public String getMethod() {
return null;
}
@Override
public String getURI() {
return this.uri;
}
@Override
public String getRelativePath() {
return this.relativePath;
}
@Override
public boolean isSecure() {
return false;
}
@Override
public String getFirstParam(String param) {
return null;
}
@Override
public String getQueryParamValue(String param) {
return null;
}
@Override
public HttpFacade.Cookie getCookie(String cookieName) {
return null;
}
@Override
public String getHeader(String name) {
return null;
}
@Override
public List<String> getHeaders(String name) {
return null;
}
@Override
public InputStream getInputStream() {
return null;
}
@Override
public InputStream getInputStream(boolean buffered) {
return null;
}
@Override
public String getRemoteAddr() {
return null;
}
@Override
public void setError(AuthenticationError error) {
}
@Override
public void setError(LogoutError error) {
}
}
}
+1 -2
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak OIDC Client Adapter Modules</name>
@@ -34,7 +34,6 @@
<module>adapter-core</module>
<module>as7-eap6</module>
<module>installed</module>
<module>fuse7</module>
<module>kcinit</module>
<module>jaxrs-oauth-client</module>
<module>jetty</module>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<artifactId>spring-boot-container-bundle</artifactId>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Tomcat Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -43
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -30,15 +30,6 @@
<name>Keycloak Undertow Integration</name>
<description/>
<properties>
<keycloak.osgi.export>
org.keycloak.adapters.undertow.*
</keycloak.osgi.export>
<keycloak.osgi.import>
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
@@ -114,39 +105,6 @@
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-ClassPath>.</Bundle-ClassPath>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
+1 -1
View File
@@ -22,7 +22,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -46,7 +46,7 @@ import org.wildfly.security.http.Scope;
*/
class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticationMechanism {
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanism.class);
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanismFactory.class);
static final String NAME = "KEYCLOAK";
private final Map<String, ?> properties;
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak WildFly Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Keycloak Adapters</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML EAP Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -66,7 +66,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -120,27 +119,16 @@ public abstract class AbstractSamlAuthenticator extends LoginAuthenticator {
tokenStore.logoutAccount();
}
private static final Pattern PROTOCOL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*:");
protected void forwardToLogoutPage(Request request, HttpServletResponse response, SamlDeployment deployment) {
final String location = deployment.getLogoutPage();
RequestDispatcher disp = request.getRequestDispatcher(deployment.getLogoutPage());
//make sure the login page is never cached
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
try {
//make sure the login page is never cached
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
if (location == null) {
log.warn("Logout page not set.");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} else if (PROTOCOL_PATTERN.matcher(location).find()) {
response.sendRedirect(response.encodeRedirectURL(location));
} else {
RequestDispatcher disp = request.getRequestDispatcher(location);
disp.forward(request, response);
}
disp.forward(request, response);
} catch (ServletException e) {
throw new RuntimeException(e);
} catch (IOException e) {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Jetty Integration</name>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Client Adapter Modules</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Tomcat Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -44,7 +44,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.*;
import java.util.regex.Pattern;
import java.util.Map;
/**
* Keycloak authentication valve
@@ -189,27 +189,16 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
protected abstract GenericPrincipalFactory createPrincipalFactory();
protected abstract boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException;
private static final Pattern PROTOCOL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*:");
protected void forwardToLogoutPage(Request request, HttpServletResponse response,SamlDeployment deployment) {
RequestDispatcher disp = request.getRequestDispatcher(deployment.getLogoutPage());
//make sure the login page is never cached
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
protected void forwardToLogoutPage(Request request, HttpServletResponse response, SamlDeployment deployment) {
final String location = deployment.getLogoutPage();
try {
//make sure the login page is never cached
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
if (location == null) {
log.warn("Logout page not set.");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} else if (PROTOCOL_PATTERN.matcher(location).find()) {
response.sendRedirect(response.encodeRedirectURL(location));
} else {
RequestDispatcher disp = request.getRequestDispatcher(location);
disp.forward(request.getRequest(), response);
}
disp.forward(request.getRequest(), response);
} catch (ServletException e) {
throw new RuntimeException(e);
} catch (IOException e) {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -33,9 +33,6 @@ import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.undertow.UndertowHttpFacade;
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
/**
* Abstract base class for a Keycloak-enabled Undertow AuthenticationMechanism.
@@ -43,9 +40,6 @@ import java.util.regex.Pattern;
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
*/
public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
private static final Logger LOG = Logger.getLogger(AbstractSamlAuthMech.class.getName());
public static final AttachmentKey<AuthChallenge> KEYCLOAK_CHALLENGE_ATTACHMENT_KEY = AttachmentKey.create(AuthChallenge.class);
protected SamlDeploymentContext deploymentContext;
protected UndertowUserSessionManagement sessionManagement;
@@ -74,22 +68,11 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
return StatusCodes.TEMPORARY_REDIRECT;
}
private static final Pattern PROTOCOL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*:");
static void sendRedirect(final HttpServerExchange exchange, final String location) {
if (location == null) {
LOG.log(Level.WARNING, "Logout page not set.");
exchange.setStatusCode(StatusCodes.NOT_FOUND);
exchange.endExchange();
return;
}
if (PROTOCOL_PATTERN.matcher(location).find()) {
exchange.getResponseHeaders().put(Headers.LOCATION, location);
} else {
String loc = exchange.getRequestScheme() + "://" + exchange.getHostAndPort() + location;
exchange.getResponseHeaders().put(Headers.LOCATION, loc);
}
// TODO - String concatenation to construct URLS is extremely error prone - switch to a URI which will better
// handle this.
String loc = exchange.getRequestScheme() + "://" + exchange.getHostAndPort() + location;
exchange.getResponseHeaders().put(Headers.LOCATION, loc);
}
protected void registerNotifications(final SecurityContext securityContext) {
@@ -159,7 +142,7 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
protected void redirectLogout(SamlDeployment deployment, HttpServerExchange exchange) {
String page = deployment.getLogoutPage();
sendRedirect(exchange, page);
exchange.setStatusCode(StatusCodes.FOUND);
exchange.setResponseCode(302);
exchange.endExchange();
}
@@ -113,11 +113,7 @@ public class ServletSamlAuthMech extends AbstractSamlAuthMech {
@Override
protected void redirectLogout(SamlDeployment deployment, HttpServerExchange exchange) {
exchange.getResponseHeaders().add(Headers.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
exchange.getResponseHeaders().add(Headers.PRAGMA, "no-cache");
exchange.getResponseHeaders().add(Headers.EXPIRES, "0");
super.redirectLogout(deployment, exchange);
servePage(exchange, deployment.getLogoutPage());
}
@Override
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -19,7 +19,6 @@ package org.keycloak.adapters.saml.elytron;
import java.net.URI;
import java.util.Map;
import java.util.regex.Pattern;
import javax.security.auth.callback.CallbackHandler;
@@ -40,7 +39,7 @@ import org.wildfly.security.http.Scope;
*/
class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticationMechanism {
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanism.class);
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanismFactory.class);
static final String NAME = "KEYCLOAK-SAML";
private final Map<String, ?> properties;
@@ -143,23 +142,14 @@ class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticat
exchange.getResponse().setStatus(302);
}
private static final Pattern PROTOCOL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*:");
static void sendRedirect(final ElytronHttpFacade exchange, final String location) {
if (location == null) {
LOGGER.warn("Logout page not set.");
exchange.getResponse().setStatus(302);
return;
}
if (PROTOCOL_PATTERN.matcher(location).find()) {
exchange.getResponse().setHeader("Location", location);
} else {
URI uri = exchange.getURI();
String path = uri.getPath();
String relativePath = exchange.getRequest().getRelativePath();
String contextPath = path.substring(0, path.indexOf(relativePath));
String loc = exchange.getURI().getScheme() + "://" + exchange.getURI().getHost() + ":" + exchange.getURI().getPort() + contextPath + location;
exchange.getResponse().setHeader("Location", loc);
}
// TODO - String concatenation to construct URLS is extremely error prone - switch to a URI which will better
// handle this.
URI uri = exchange.getURI();
String path = uri.getPath();
String relativePath = exchange.getRequest().getRelativePath();
String contextPath = path.substring(0, path.indexOf(relativePath));
String loc = exchange.getURI().getScheme() + "://" + exchange.getURI().getHost() + ":" + exchange.getURI().getPort() + contextPath + location;
exchange.getResponse().setHeader("Location", loc);
}
}
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</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>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Final</version>
<version>4.0.0.Beta2</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak Client Adapter SPI Modules</name>
Loaded 100 of 1141 files, more files were not shown because too many files have changed in this diff. Show more