Compare commits

..
Author SHA1 Message Date
Stian Thorgersen 5f348bb7d8 Version bump 2015-07-29 13:05:52 +02:00
6910 changed files with 290752 additions and 424013 deletions

No files matched your search

+8 -9
View File
@@ -1,20 +1,19 @@
language: java
env:
global:
- MAVEN_SKIP_RC=true
- MAVEN_OPTS="-Xms512m -Xmx2048m"
jdk:
- oraclejdk8
before_script:
- export MAVEN_SKIP_RC=true
cache:
directories:
- $HOME/.m2
install:
- mvn install -Pdistribution -DskipTests=true -B -V -q
before_cache:
- rm -rf $HOME/.m2/repository/org/keycloak
install: mvn install -Pdistribution -DskipTests=true -B -V
script:
- mvn test -B
- mvn -file testsuite/integration-arquillian test -B
sudo: false
+14 -16
View File
@@ -1,15 +1,13 @@
Keycloak
========
Open Source Identity and Access Management for modern Applications and Services.
For more information about Keycloak visit [Keycloak homepage](http://keycloak.org) and [Keycloak blog](http://blog.keycloak.org).
Keycloak is an SSO Service for web apps and REST services. For more information visit [http://keycloak.org](http://keycloak.org).
Building
--------
Ensure you have JDK 8 (or newer), Maven 3.2.1 (or newer) and Git installed
Ensure you have JDK 7 (or newer), Maven 3.2.1 (or newer) and Git installed
java -version
mvn -version
@@ -50,22 +48,22 @@ To start Keycloak from the appliance distribution first build the distribution i
To stop the server press `Ctrl + C`.
Help and Documentation
----------------------
* [Documentation](http://keycloak.jboss.org/docs) - User Guide, Admin REST API and Javadocs
* [User Mailing List](https://lists.jboss.org/mailman/listinfo/keycloak-user) - Mailing list to ask for help and general questions about Keycloak
* [JIRA](https://issues.jboss.org/projects/KEYCLOAK) - Issue tracker for bugs and feature requests
Contributing
------------
* See [Hacking on Keycloak](misc/HackingOnKeycloak.md)
Documentation
-------------
* [User Guide, Admin REST API and Javadocs](http://keycloak.jboss.org/docs)
* Developer documentation
* [Hacking on Keycloak](misc/HackingOnKeycloak.md) - How to become a Keycloak contributor
* [Testsuite](misc/Testsuite.md) - Details about testsuite, but also how to quickly run Keycloak during development and a few test tools (OTP generation, LDAP server, Mail server)
* [Database Testing](misc/DatabaseTesting.md) - How to do testing of Keycloak on different databases
* [Updating Database](misc/UpdatingDatabaseSchema.md) - How to change the Keycloak database
* [Developer Mailing List](https://lists.jboss.org/mailman/listinfo/keycloak-dev) - Mailing list to discuss development of Keycloak
* [Hacking on Keycloak](misc/HackingOnKeycloak.md) - how to become a Keycloak contributor
* [Testsuite](misc/Testsuite.md) - details about testsuite, but also how to quickly run Keycloak during development and a few test tools (OTP generation, LDAP server, Mail server)
* [Database Testing](misc/DatabaseTesting.md) - how to do testing of Keycloak on different databases
* [Updating Database](misc/UpdatingDatabaseSchema.md) - how to change the Keycloak database
* [Release Process](misc/ReleaseProcess.md) - how to release Keycloak
License
-140
View File
@@ -1,140 +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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-adapter-core</artifactId>
<name>Keycloak Adapter Core</name>
<description/>
<properties>
<keycloak.osgi.export>
org.keycloak.adapters.*
</keycloak.osgi.export>
<keycloak.osgi.import>
org.keycloak.*;version="${project.version}",
org.apache.http.*;version=${apache.httpcomponents.version},
org.apache.karaf.jaas.boot.principal;resolution:=optional,
org.apache.karaf.jaas.modules;resolution:=optional,
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</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-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>
</project>
@@ -1,61 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.keycloak.adapters.spi.AdapterSessionStore;
/**
* Abstraction for storing token info on adapter side. Intended to be per-request object
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface AdapterTokenStore extends AdapterSessionStore {
/**
* Impl can validate if current token exists and perform refreshing if it exists and is expired
*/
void checkCurrentToken();
/**
* Check if we are logged already (we have already valid and successfully refreshed accessToken). Establish security context if yes
*
* @param authenticator used for actual request authentication
* @return true if we are logged-in already
*/
boolean isCached(RequestAuthenticator authenticator);
/**
* Finish successful OAuth2 login and store validated account
*
* @param account
*/
void saveAccountInfo(OidcKeycloakAccount account);
/**
* Handle logout on store side and possibly propagate logout call to Keycloak
*/
void logout();
/**
* Callback invoked after successful token refresh
*
* @param securityContext context where refresh was performed
*/
void refreshCallback(RefreshableKeycloakSecurityContext securityContext);
}
@@ -1,94 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.representations.AccessToken;
import org.keycloak.common.util.UriUtils;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class AdapterUtils {
private static Logger log = Logger.getLogger(AdapterUtils.class);
public static String generateId() {
return UUID.randomUUID().toString();
}
public static Set<String> getRolesFromSecurityContext(RefreshableKeycloakSecurityContext session) {
Set<String> roles = null;
AccessToken accessToken = session.getToken();
if (session.getDeployment().isUseResourceRoleMappings()) {
if (log.isTraceEnabled()) {
log.trace("useResourceRoleMappings");
}
AccessToken.Access access = accessToken.getResourceAccess(session.getDeployment().getResourceName());
if (access != null) roles = access.getRoles();
} else {
if (log.isTraceEnabled()) {
log.trace("use realm role mappings");
}
AccessToken.Access access = accessToken.getRealmAccess();
if (access != null) roles = access.getRoles();
}
if (roles == null) roles = Collections.emptySet();
if (log.isTraceEnabled()) {
log.trace("Setting roles: ");
for (String role : roles) {
log.trace(" role: " + role);
}
}
return roles;
}
public static String getPrincipalName(KeycloakDeployment deployment, AccessToken token) {
String attr = "sub";
if (deployment.getPrincipalAttribute() != null) attr = deployment.getPrincipalAttribute();
String name = null;
if ("sub".equals(attr)) {
name = token.getSubject();
} else if ("email".equals(attr)) {
name = token.getEmail();
} else if ("preferred_username".equals(attr)) {
name = token.getPreferredUsername();
} else if ("name".equals(attr)) {
name = token.getName();
} else if ("given_name".equals(attr)) {
name = token.getGivenName();
} else if ("family_name".equals(attr)) {
name = token.getFamilyName();
} else if ("nickname".equals(attr)) {
name = token.getNickName();
}
if (name == null) name = token.getSubject();
return name;
}
public static KeycloakPrincipal<RefreshableKeycloakSecurityContext> createPrincipal(KeycloakDeployment deployment, RefreshableKeycloakSecurityContext securityContext) {
return new KeycloakPrincipal<RefreshableKeycloakSecurityContext>(getPrincipalName(deployment, securityContext.getToken()), securityContext);
}
}
@@ -1,126 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jboss.logging.Logger;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.common.util.Base64;
import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.util.JsonSerialization;
import org.keycloak.common.util.KeycloakUriBuilder;
import java.util.List;
/**
* Basic auth request authenticator.
*/
public class BasicAuthRequestAuthenticator extends BearerTokenRequestAuthenticator {
protected Logger log = Logger.getLogger(BasicAuthRequestAuthenticator.class);
public BasicAuthRequestAuthenticator(KeycloakDeployment deployment) {
super(deployment);
}
public AuthOutcome authenticate(HttpFacade exchange) {
List<String> authHeaders = exchange.getRequest().getHeaders("Authorization");
if (authHeaders == null || authHeaders.size() == 0) {
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.NO_AUTHORIZATION_HEADER, null, null);
return AuthOutcome.NOT_ATTEMPTED;
}
tokenString = null;
for (String authHeader : authHeaders) {
String[] split = authHeader.trim().split("\\s+");
if (split == null || split.length != 2) continue;
if (!split[0].equalsIgnoreCase("Basic")) continue;
tokenString = split[1];
}
if (tokenString == null) {
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, null, null);
return AuthOutcome.NOT_ATTEMPTED;
}
AccessTokenResponse atr=null;
try {
String userpw=new String(Base64.decode(tokenString));
String[] parts=userpw.split(":");
atr = getToken(parts[0], parts[1]);
tokenString = atr.getToken();
} catch (Exception e) {
log.debug("Failed to obtain token", e);
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, "no_token", e.getMessage());
return AuthOutcome.FAILED;
}
return authenticateToken(exchange, atr.getToken());
}
private AccessTokenResponse getToken(String username, String password) throws Exception {
AccessTokenResponse tokenResponse=null;
HttpClient client = deployment.getClient();
HttpPost post = new HttpPost(
KeycloakUriBuilder.fromUri(deployment.getAuthServerBaseUrl())
.path(ServiceUrlConstants.TOKEN_PATH).build(deployment.getRealm()));
java.util.List <NameValuePair> formparams = new java.util.ArrayList <NameValuePair>();
formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
formparams.add(new BasicNameValuePair("username", username));
formparams.add(new BasicNameValuePair("password", password));
ClientCredentialsProviderUtils.setClientCredentials(deployment, post, formparams);
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
post.setEntity(form);
HttpResponse response = client.execute(post);
int status = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
if (status != 200) {
EntityUtils.consumeQuietly(entity);
throw new java.io.IOException("Bad status: " + status);
}
if (entity == null) {
throw new java.io.IOException("No Entity");
}
java.io.InputStream is = entity.getContent();
try {
tokenResponse = JsonSerialization.readValue(is, AccessTokenResponse.class);
} finally {
try {
is.close();
} catch (java.io.IOException ignored) { }
}
return (tokenResponse);
}
}
@@ -1,172 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.jboss.logging.Logger;
import org.keycloak.RSATokenVerifier;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.common.VerificationException;
import org.keycloak.representations.AccessToken;
import javax.security.cert.X509Certificate;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class BearerTokenRequestAuthenticator {
protected Logger log = Logger.getLogger(BearerTokenRequestAuthenticator.class);
protected String tokenString;
protected AccessToken token;
protected String surrogate;
protected AuthChallenge challenge;
protected KeycloakDeployment deployment;
public BearerTokenRequestAuthenticator(KeycloakDeployment deployment) {
this.deployment = deployment;
}
public AuthChallenge getChallenge() {
return challenge;
}
public String getTokenString() {
return tokenString;
}
public AccessToken getToken() {
return token;
}
public String getSurrogate() {
return surrogate;
}
public AuthOutcome authenticate(HttpFacade exchange) {
List<String> authHeaders = exchange.getRequest().getHeaders("Authorization");
if (authHeaders == null || authHeaders.size() == 0) {
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.NO_BEARER_TOKEN, null, null);
return AuthOutcome.NOT_ATTEMPTED;
}
tokenString = null;
for (String authHeader : authHeaders) {
String[] split = authHeader.trim().split("\\s+");
if (split == null || split.length != 2) continue;
if (!split[0].equalsIgnoreCase("Bearer")) continue;
tokenString = split[1];
}
if (tokenString == null) {
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.NO_BEARER_TOKEN, null, null);
return AuthOutcome.NOT_ATTEMPTED;
}
return (authenticateToken(exchange, tokenString));
}
protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) {
try {
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
} catch (VerificationException e) {
log.error("Failed to verify token", e);
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.INVALID_TOKEN, "invalid_token", e.getMessage());
return AuthOutcome.FAILED;
}
if (token.getIssuedAt() < deployment.getNotBefore()) {
log.error("Stale token");
challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.STALE_TOKEN, "invalid_token", "Stale token");
return AuthOutcome.FAILED;
}
boolean verifyCaller = false;
if (deployment.isUseResourceRoleMappings()) {
verifyCaller = token.isVerifyCaller(deployment.getResourceName());
} else {
verifyCaller = token.isVerifyCaller();
}
surrogate = null;
if (verifyCaller) {
if (token.getTrustedCertificates() == null || token.getTrustedCertificates().size() == 0) {
log.warn("No trusted certificates in token");
challenge = clientCertChallenge();
return AuthOutcome.FAILED;
}
// for now, we just make sure Undertow did two-way SSL
// assume JBoss Web verifies the client cert
X509Certificate[] chain = new X509Certificate[0];
try {
chain = exchange.getCertificateChain();
} catch (Exception ignore) {
}
if (chain == null || chain.length == 0) {
log.warn("No certificates provided by undertow to verify the caller");
challenge = clientCertChallenge();
return AuthOutcome.FAILED;
}
surrogate = chain[0].getSubjectDN().getName();
}
return AuthOutcome.AUTHENTICATED;
}
protected AuthChallenge clientCertChallenge() {
return new AuthChallenge() {
@Override
public int getResponseCode() {
return 0;
}
@Override
public boolean challenge(HttpFacade exchange) {
// do the same thing as client cert auth
return false;
}
};
}
protected AuthChallenge challengeResponse(HttpFacade facade, final OIDCAuthenticationError.Reason reason, final String error, final String description) {
StringBuilder header = new StringBuilder("Bearer realm=\"");
header.append(deployment.getRealm()).append("\"");
if (error != null) {
header.append(", error=\"").append(error).append("\"");
}
if (description != null) {
header.append(", error_description=\"").append(description).append("\"");
}
final String challenge = header.toString();
return new AuthChallenge() {
@Override
public int getResponseCode() {
return 401;
}
@Override
public boolean challenge(HttpFacade facade) {
OIDCAuthenticationError error = new OIDCAuthenticationError(reason, description);
facade.getRequest().setError(error);
facade.getResponse().addHeader("WWW-Authenticate", challenge);
facade.getResponse().sendError(401);
return true;
}
};
}
}
@@ -1,33 +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;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface CorsHeaders {
String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
String ORIGIN = "Origin";
String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
}
@@ -1,369 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.StrictHostnameVerifier;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.common.util.EnvUtil;
import org.keycloak.common.util.KeystoreUtil;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Abstraction for creating HttpClients. Allows SSL configuration.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class HttpClientBuilder {
public static enum HostnameVerificationPolicy {
/**
* Hostname verification is not done on the server's certificate
*/
ANY,
/**
* Allows wildcards in subdomain names i.e. *.foo.com
*/
WILDCARD,
/**
* CN must match hostname connecting to
*/
STRICT
}
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
private static class PassthroughTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
protected KeyStore truststore;
protected KeyStore clientKeyStore;
protected String clientPrivateKeyPassword;
protected boolean disableTrustManager;
protected boolean disableCookieCache = true;
protected HostnameVerificationPolicy policy = HostnameVerificationPolicy.WILDCARD;
protected SSLContext sslContext;
protected int connectionPoolSize = 100;
protected int maxPooledPerRoute = 0;
protected long connectionTTL = -1;
protected TimeUnit connectionTTLUnit = TimeUnit.MILLISECONDS;
protected HostnameVerifier verifier = null;
protected long socketTimeout = -1;
protected TimeUnit socketTimeoutUnits = TimeUnit.MILLISECONDS;
protected long establishConnectionTimeout = -1;
protected TimeUnit establishConnectionTimeoutUnits = TimeUnit.MILLISECONDS;
/**
* Socket inactivity timeout
*
* @param timeout
* @param unit
* @return
*/
public HttpClientBuilder socketTimeout(long timeout, TimeUnit unit)
{
this.socketTimeout = timeout;
this.socketTimeoutUnits = unit;
return this;
}
/**
* When trying to make an initial socket connection, what is the timeout?
*
* @param timeout
* @param unit
* @return
*/
public HttpClientBuilder establishConnectionTimeout(long timeout, TimeUnit unit)
{
this.establishConnectionTimeout = timeout;
this.establishConnectionTimeoutUnits = unit;
return this;
}
public HttpClientBuilder connectionTTL(long ttl, TimeUnit unit) {
this.connectionTTL = ttl;
this.connectionTTLUnit = unit;
return this;
}
public HttpClientBuilder maxPooledPerRoute(int maxPooledPerRoute) {
this.maxPooledPerRoute = maxPooledPerRoute;
return this;
}
public HttpClientBuilder connectionPoolSize(int connectionPoolSize) {
this.connectionPoolSize = connectionPoolSize;
return this;
}
/**
* Disable trust management and hostname verification. <i>NOTE</i> this is a security
* hole, so only set this option if you cannot or do not want to verify the identity of the
* host you are communicating with.
*/
public HttpClientBuilder disableTrustManager() {
this.disableTrustManager = true;
return this;
}
public HttpClientBuilder disableCookieCache() {
this.disableCookieCache = true;
return this;
}
/**
* SSL policy used to verify hostnames
*
* @param policy
* @return
*/
public HttpClientBuilder hostnameVerification(HostnameVerificationPolicy policy) {
this.policy = policy;
return this;
}
public HttpClientBuilder sslContext(SSLContext sslContext) {
this.sslContext = sslContext;
return this;
}
public HttpClientBuilder trustStore(KeyStore truststore) {
this.truststore = truststore;
return this;
}
public HttpClientBuilder keyStore(KeyStore keyStore, String password) {
this.clientKeyStore = keyStore;
this.clientPrivateKeyPassword = password;
return this;
}
public HttpClientBuilder keyStore(KeyStore keyStore, char[] password) {
this.clientKeyStore = keyStore;
this.clientPrivateKeyPassword = new String(password);
return this;
}
static class VerifierWrapper implements X509HostnameVerifier {
protected HostnameVerifier verifier;
VerifierWrapper(HostnameVerifier verifier) {
this.verifier = verifier;
}
@Override
public void verify(String host, SSLSocket ssl) throws IOException {
if (!verifier.verify(host, ssl.getSession())) throw new SSLException("Hostname verification failure");
}
@Override
public void verify(String host, X509Certificate cert) throws SSLException {
throw new SSLException("This verification path not implemented");
}
@Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
throw new SSLException("This verification path not implemented");
}
@Override
public boolean verify(String s, SSLSession sslSession) {
return verifier.verify(s, sslSession);
}
}
public HttpClient build() {
X509HostnameVerifier verifier = null;
if (this.verifier != null) verifier = new VerifierWrapper(this.verifier);
else {
switch (policy) {
case ANY:
verifier = new AllowAllHostnameVerifier();
break;
case WILDCARD:
verifier = new BrowserCompatHostnameVerifier();
break;
case STRICT:
verifier = new StrictHostnameVerifier();
break;
}
}
try {
SSLSocketFactory sslsf = null;
SSLContext theContext = sslContext;
if (disableTrustManager) {
theContext = SSLContext.getInstance("SSL");
theContext.init(null, new TrustManager[]{new PassthroughTrustManager()},
new SecureRandom());
verifier = new AllowAllHostnameVerifier();
sslsf = new SniSSLSocketFactory(theContext, verifier);
} else if (theContext != null) {
sslsf = new SniSSLSocketFactory(theContext, verifier);
} else if (clientKeyStore != null || truststore != null) {
sslsf = new SniSSLSocketFactory(SSLSocketFactory.TLS, clientKeyStore, clientPrivateKeyPassword, truststore, null, verifier);
} else {
final SSLContext tlsContext = SSLContext.getInstance(SSLSocketFactory.TLS);
tlsContext.init(null, null, null);
sslsf = new SniSSLSocketFactory(tlsContext, verifier);
}
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
Scheme httpsScheme = new Scheme("https", 443, sslsf);
registry.register(httpsScheme);
ClientConnectionManager cm = null;
if (connectionPoolSize > 0) {
ThreadSafeClientConnManager tcm = new ThreadSafeClientConnManager(registry, connectionTTL, connectionTTLUnit);
tcm.setMaxTotal(connectionPoolSize);
if (maxPooledPerRoute == 0) maxPooledPerRoute = connectionPoolSize;
tcm.setDefaultMaxPerRoute(maxPooledPerRoute);
cm = tcm;
} else {
cm = new SingleClientConnManager(registry);
}
BasicHttpParams params = new BasicHttpParams();
if (socketTimeout > -1)
{
HttpConnectionParams.setSoTimeout(params, (int) socketTimeoutUnits.toMillis(socketTimeout));
}
if (establishConnectionTimeout > -1)
{
HttpConnectionParams.setConnectionTimeout(params, (int)establishConnectionTimeoutUnits.toMillis(establishConnectionTimeout));
}
DefaultHttpClient client = new DefaultHttpClient(cm, params);
if (disableCookieCache) {
client.setCookieStore(new CookieStore() {
@Override
public void addCookie(Cookie cookie) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<Cookie> getCookies() {
return Collections.emptyList();
}
@Override
public boolean clearExpired(Date date) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void clear() {
//To change body of implemented methods use File | Settings | File Templates.
}
});
}
return client;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public HttpClient build(AdapterConfig adapterConfig) {
disableCookieCache(); // disable cookie cache as we don't want sticky sessions for load balancing
String truststorePath = adapterConfig.getTruststore();
if (truststorePath != null) {
truststorePath = EnvUtil.replace(truststorePath);
String truststorePassword = adapterConfig.getTruststorePassword();
try {
this.truststore = KeystoreUtil.loadKeyStore(truststorePath, truststorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load truststore", e);
}
}
String clientKeystore = adapterConfig.getClientKeystore();
if (clientKeystore != null) {
clientKeystore = EnvUtil.replace(clientKeystore);
String clientKeystorePassword = adapterConfig.getClientKeystorePassword();
try {
KeyStore clientCertKeystore = KeystoreUtil.loadKeyStore(clientKeystore, clientKeystorePassword);
keyStore(clientCertKeystore, clientKeystorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load keystore", e);
}
}
int size = 10;
if (adapterConfig.getConnectionPoolSize() > 0)
size = adapterConfig.getConnectionPoolSize();
HttpClientBuilder.HostnameVerificationPolicy policy = HttpClientBuilder.HostnameVerificationPolicy.WILDCARD;
if (adapterConfig.isAllowAnyHostname())
policy = HttpClientBuilder.HostnameVerificationPolicy.ANY;
connectionPoolSize(size);
hostnameVerification(policy);
if (adapterConfig.isDisableTrustManager()) {
disableTrustManager();
} else {
trustStore(truststore);
}
return build();
}
}
@@ -1,63 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.keycloak.adapters.spi.AuthenticationError;
/**
* Object that describes the OIDC error that happened.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OIDCAuthenticationError implements AuthenticationError {
public static enum Reason {
NO_BEARER_TOKEN,
NO_REDIRECT_URI,
INVALID_STATE_COOKIE,
OAUTH_ERROR,
SSL_REQUIRED,
CODE_TO_TOKEN_FAILURE,
INVALID_TOKEN,
STALE_TOKEN,
NO_AUTHORIZATION_HEADER
}
private Reason reason;
private String description;
public OIDCAuthenticationError(Reason reason, String description) {
this.reason = reason;
this.description = description;
}
public Reason getReason() {
return reason;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "OIDCAuthenticationError [reason=" + reason + ", description=" + description + "]";
}
}
@@ -1,32 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.spi.HttpFacade;
/**
* Bridge between core adapter and HTTP Engine
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface OIDCHttpFacade extends HttpFacade {
KeycloakSecurityContext getSecurityContext();
}
@@ -1,29 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.spi.KeycloakAccount;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface OidcKeycloakAccount extends KeycloakAccount {
KeycloakSecurityContext getKeycloakSecurityContext();
}
@@ -1,239 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
import org.keycloak.constants.AdapterConstants;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.common.util.HostUtils;
import org.keycloak.util.JsonSerialization;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.StreamUtil;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ServerRequest {
public static class HttpFailure extends Exception {
private int status;
private String error;
public HttpFailure(int status, String error) {
this.status = status;
this.error = error;
}
public int getStatus() {
return status;
}
public String getError() {
return error;
}
}
public static void invokeLogout(KeycloakDeployment deployment, String refreshToken) throws IOException, HttpFailure {
HttpClient client = deployment.getClient();
URI uri = deployment.getLogoutUrl().clone().build();
List<NameValuePair> formparams = new ArrayList<>();
formparams.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
HttpPost post = new HttpPost(uri);
ClientCredentialsProviderUtils.setClientCredentials(deployment, post, formparams);
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
post.setEntity(form);
HttpResponse response = client.execute(post);
int status = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
if (status != 204) {
error(status, entity);
}
if (entity == null) {
return;
}
InputStream is = entity.getContent();
if (is != null) is.close();
}
public static AccessTokenResponse invokeAccessCodeToToken(KeycloakDeployment deployment, String code, String redirectUri, String sessionId) throws IOException, HttpFailure {
List<NameValuePair> formparams = new ArrayList<>();
redirectUri = stripOauthParametersFromRedirect(redirectUri);
formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, "authorization_code"));
formparams.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
formparams.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, redirectUri));
if (sessionId != null) {
formparams.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, sessionId));
formparams.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, HostUtils.getHostName()));
}
HttpPost post = new HttpPost(deployment.getTokenUrl());
ClientCredentialsProviderUtils.setClientCredentials(deployment, post, formparams);
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
post.setEntity(form);
HttpResponse response = deployment.getClient().execute(post);
int status = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
if (status != 200) {
error(status, entity);
}
if (entity == null) {
throw new HttpFailure(status, null);
}
InputStream is = entity.getContent();
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
int c;
while ((c = is.read()) != -1) {
os.write(c);
}
byte[] bytes = os.toByteArray();
String json = new String(bytes);
try {
return JsonSerialization.readValue(json, AccessTokenResponse.class);
} catch (IOException e) {
throw new IOException(json, e);
}
} finally {
try {
is.close();
} catch (IOException ignored) {
}
}
}
public static AccessTokenResponse invokeRefresh(KeycloakDeployment deployment, String refreshToken) throws IOException, HttpFailure {
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
formparams.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
HttpPost post = new HttpPost(deployment.getTokenUrl());
ClientCredentialsProviderUtils.setClientCredentials(deployment, post, formparams);
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
post.setEntity(form);
HttpResponse response = deployment.getClient().execute(post);
int status = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
if (status != 200) {
error(status, entity);
}
if (entity == null) {
throw new HttpFailure(status, null);
}
InputStream is = entity.getContent();
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
int c;
while ((c = is.read()) != -1) {
os.write(c);
}
byte[] bytes = os.toByteArray();
String json = new String(bytes);
try {
return JsonSerialization.readValue(json, AccessTokenResponse.class);
} catch (IOException e) {
throw new IOException(json, e);
}
} finally {
try {
is.close();
} catch (IOException ignored) {
}
}
}
public static void invokeRegisterNode(KeycloakDeployment deployment, String host) throws HttpFailure, IOException {
String registerNodeUrl = deployment.getRegisterNodeUrl();
invokeClientManagementRequest(deployment, host, registerNodeUrl);
}
public static void invokeUnregisterNode(KeycloakDeployment deployment, String host) throws HttpFailure, IOException {
String unregisterNodeUrl = deployment.getUnregisterNodeUrl();
invokeClientManagementRequest(deployment, host, unregisterNodeUrl);
}
public static void invokeClientManagementRequest(KeycloakDeployment deployment, String host, String endpointUrl) throws HttpFailure, IOException {
if (endpointUrl == null) {
throw new IOException("You need to configure URI for register/unregister node for application " + deployment.getResourceName());
}
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair(AdapterConstants.CLIENT_CLUSTER_HOST, host));
HttpPost post = new HttpPost(endpointUrl);
ClientCredentialsProviderUtils.setClientCredentials(deployment, post, formparams);
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
post.setEntity(form);
HttpResponse response = deployment.getClient().execute(post);
int status = response.getStatusLine().getStatusCode();
if (status != 204) {
HttpEntity entity = response.getEntity();
error(status, entity);
}
}
public static void error(int status, HttpEntity entity) throws HttpFailure, IOException {
String body = null;
if (entity != null) {
InputStream is = entity.getContent();
try {
body = StreamUtil.readString(is);
} catch (IOException e) {
} finally {
try {
is.close();
} catch (IOException ignored) {
}
}
}
throw new HttpFailure(status, body);
}
protected static String stripOauthParametersFromRedirect(String uri) {
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
.replaceQueryParam(OAuth2Constants.CODE, null)
.replaceQueryParam(OAuth2Constants.STATE, null);
return builder.build().toString();
}
}
@@ -1,134 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.apache.http.HttpHost;
import org.apache.http.conn.scheme.HostNameResolver;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.protocol.HttpContext;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.AccessController;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedExceptionAction;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
public class SniSSLSocketFactory extends SSLSocketFactory {
private static Logger log = Logger.getLogger(SniSSLSocketFactory.class.getName());
public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, HostNameResolver nameResolver) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(algorithm, keystore, keyPassword, truststore, random, nameResolver);
}
public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, TrustStrategy trustStrategy, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(algorithm, keystore, keyPassword, truststore, random, trustStrategy, hostnameVerifier);
}
public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(algorithm, keystore, keyPassword, truststore, random, hostnameVerifier);
}
public SniSSLSocketFactory(KeyStore keystore, String keystorePassword, KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(keystore, keystorePassword, truststore);
}
public SniSSLSocketFactory(KeyStore keystore, String keystorePassword) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(keystore, keystorePassword);
}
public SniSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
}
public SniSSLSocketFactory(TrustStrategy trustStrategy, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(trustStrategy, hostnameVerifier);
}
public SniSSLSocketFactory(TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(trustStrategy);
}
public SniSSLSocketFactory(SSLContext sslContext) {
super(sslContext);
}
public SniSSLSocketFactory(SSLContext sslContext, HostNameResolver nameResolver) {
super(sslContext, nameResolver);
}
public SniSSLSocketFactory(SSLContext sslContext, X509HostnameVerifier hostnameVerifier) {
super(sslContext, hostnameVerifier);
}
public SniSSLSocketFactory(SSLContext sslContext, String[] supportedProtocols, String[] supportedCipherSuites, X509HostnameVerifier hostnameVerifier) {
super(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
}
public SniSSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier) {
super(socketfactory, hostnameVerifier);
}
public SniSSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory, String[] supportedProtocols, String[] supportedCipherSuites, X509HostnameVerifier hostnameVerifier) {
super(socketfactory, supportedProtocols, supportedCipherSuites, hostnameVerifier);
}
@Override
public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context) throws IOException {
return super.connectSocket(connectTimeout, applySNI(socket, host.getHostName()), host, remoteAddress, localAddress, context);
}
@Override
public Socket createLayeredSocket(Socket socket, String target, int port, HttpContext context) throws IOException {
return super.createLayeredSocket(applySNI(socket, target), target, port, context);
}
private Socket applySNI(final Socket socket, String hostname) {
if (socket instanceof SSLSocket) {
try {
Method setHostMethod = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
public Method run() throws NoSuchMethodException {
return socket.getClass().getMethod("setHost", String.class);
}
});
setHostMethod.invoke(socket, hostname);
log.finest("Applied SNI to socket for: " + hostname);
} catch (Exception e) {
log.log(Level.WARNING, "Failed to apply SNI to SSLSocket", e);
}
}
return socket;
}
}
@@ -1,78 +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.authentication;
import java.util.Map;
import org.keycloak.adapters.KeycloakDeployment;
/**
* The simple SPI for authenticating clients/applications . It's used by adapter during all OIDC backchannel requests to Keycloak server
* (codeToToken exchange, refresh token or backchannel logout) . You can also use it in your application during direct access grants or service account request
* (See the service-account example from Keycloak demo for more info)
*
* When you implement this SPI on the adapter (application) side, you also need to implement org.keycloak.authentication.ClientAuthenticator on the server side,
* so your server is able to authenticate client
*
* You must specify a file
* META-INF/services/org.keycloak.adapters.authentication.ClientCredentialsProvider in the WAR that this class is contained in (or in the JAR that is attached to the WEB-INF/lib or as jboss module
* if you want to share the implementation among more WARs).
*
* NOTE: The SPI is not finished and method signatures are still subject to change in future versions (for example to support
* authentication with client certificate)
*
* @see ClientIdAndSecretCredentialsProvider
* @see JWTClientCredentialsProvider
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface ClientCredentialsProvider {
/**
* Return the ID of the provider. Use this ID in the keycloak.json configuration as the subelement of the "credentials" element
*
* For example if your provider has ID "kerberos-keytab" , use the configuration like this in keycloak.json
*
* "credentials": {
*
* "kerberos-keytab": {
* "keytab": "/tmp/foo"
* }
* }
*
* @return
*/
String getId();
/**
* Called by adapter during deployment of your application. You can for example read configuration and init your authenticator here
*
* @param deployment the adapter configuration
* @param config the configuration of your provider read from keycloak.json . For the kerberos-keytab example above, it will return map with the single key "keytab" with value "/tmp/foo"
*/
void init(KeycloakDeployment deployment, Object config);
/**
* Called every time adapter needs to perform backchannel request
*
* @param deployment Fully resolved deployment
* @param requestHeaders You should put any HTTP request headers you want to use for authentication of client. These headers will be attached to the HTTP request sent to Keycloak server
* @param formParams You should put any request parameters you want to use for authentication of client. These parameters will be attached to the HTTP request sent to Keycloak server
*/
void setClientCredentials(KeycloakDeployment deployment, Map<String, String> requestHeaders, Map<String, String> formParams);
}
@@ -1,116 +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.authentication;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.jboss.logging.Logger;
import org.keycloak.adapters.KeycloakDeployment;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ClientCredentialsProviderUtils {
private static Logger logger = Logger.getLogger(ClientCredentialsProviderUtils.class);
public static ClientCredentialsProvider bootstrapClientAuthenticator(KeycloakDeployment deployment) {
String clientId = deployment.getResourceName();
Map<String, Object> clientCredentials = deployment.getResourceCredentials();
String authenticatorId;
if (clientCredentials == null || clientCredentials.isEmpty()) {
authenticatorId = ClientIdAndSecretCredentialsProvider.PROVIDER_ID;
} else {
authenticatorId = (String) clientCredentials.get("provider");
if (authenticatorId == null) {
// If there is just one credential type, use provider from it
if (clientCredentials.size() == 1) {
authenticatorId = clientCredentials.keySet().iterator().next();
} else {
throw new RuntimeException("Can't identify clientAuthenticator from the configuration of client '" + clientId + "' . Check your adapter configurations");
}
}
}
logger.debugf("Using provider '%s' for authentication of client '%s'", authenticatorId, clientId);
Map<String, ClientCredentialsProvider> authenticators = new HashMap<>();
loadAuthenticators(authenticators, ClientCredentialsProviderUtils.class.getClassLoader());
loadAuthenticators(authenticators, Thread.currentThread().getContextClassLoader());
ClientCredentialsProvider authenticator = authenticators.get(authenticatorId);
if (authenticator == null) {
throw new RuntimeException("Couldn't find ClientCredentialsProvider implementation class with id: " + authenticatorId + ". Loaded authentication providers: " + authenticators.keySet());
}
Object config = (clientCredentials==null) ? null : clientCredentials.get(authenticatorId);
authenticator.init(deployment, config);
return authenticator;
}
private static void loadAuthenticators(Map<String, ClientCredentialsProvider> authenticators, ClassLoader classLoader) {
Iterator<ClientCredentialsProvider> iterator = ServiceLoader.load(ClientCredentialsProvider.class, classLoader).iterator();
while (iterator.hasNext()) {
try {
ClientCredentialsProvider authenticator = iterator.next();
logger.debugf("Loaded clientCredentialsProvider %s", authenticator.getId());
authenticators.put(authenticator.getId(), authenticator);
} catch (ServiceConfigurationError e) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to load clientCredentialsProvider with classloader: " + classLoader, e);
}
}
}
}
/**
* Use this method when calling backchannel request directly from your application. See service-account example from demo for more details
*/
public static void setClientCredentials(KeycloakDeployment deployment, Map<String, String> requestHeaders, Map<String, String> formparams) {
ClientCredentialsProvider authenticator = deployment.getClientAuthenticator();
authenticator.setClientCredentials(deployment, requestHeaders, formparams);
}
/**
* Don't use directly from your JEE apps to avoid HttpClient linkage errors! Instead use the method {@link #setClientCredentials(KeycloakDeployment, Map, Map)}
*/
public static void setClientCredentials(KeycloakDeployment deployment, HttpPost post, List<NameValuePair> formparams) {
Map<String, String> reqHeaders = new HashMap<>();
Map<String, String> reqParams = new HashMap<>();
setClientCredentials(deployment, reqHeaders, reqParams);
for (Map.Entry<String, String> header : reqHeaders.entrySet()) {
post.setHeader(header.getKey(), header.getValue());
}
for (Map.Entry<String, String> param : reqParams.entrySet()) {
formparams.add(new BasicNameValuePair(param.getKey(), param.getValue()));
}
}
}
@@ -1,66 +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.authentication;
import java.util.Map;
import org.jboss.logging.Logger;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.util.BasicAuthHelper;
/**
* Traditional OAuth2 authentication of clients based on client_id and client_secret
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ClientIdAndSecretCredentialsProvider implements ClientCredentialsProvider {
private static Logger logger = Logger.getLogger(ClientCredentialsProviderUtils.class);
public static final String PROVIDER_ID = CredentialRepresentation.SECRET;
private String clientSecret;
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public void init(KeycloakDeployment deployment, Object config) {
clientSecret = (String) config;
}
@Override
public void setClientCredentials(KeycloakDeployment deployment, Map<String, String> requestHeaders, Map<String, String> formParams) {
String clientId = deployment.getResourceName();
if (!deployment.isPublicClient()) {
if (clientSecret != null) {
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
requestHeaders.put("Authorization", authorization);
} else {
logger.warnf("Client '%s' doesn't have secret available", clientId);
}
} else {
formParams.put(OAuth2Constants.CLIENT_ID, clientId);
}
}
}
@@ -1,137 +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.authentication;
import java.security.PrivateKey;
import java.util.Map;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.common.util.KeystoreUtil;
import org.keycloak.common.util.Time;
/**
* Client authentication based on JWT signed by client private key .
* See <a href="https://tools.ietf.org/html/rfc7519">specs</a> for more details.
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
public static final String PROVIDER_ID = "jwt";
private PrivateKey privateKey;
private int tokenTimeout;
@Override
public String getId() {
return PROVIDER_ID;
}
public void setPrivateKey(PrivateKey privateKey) {
this.privateKey = privateKey;
}
public void setTokenTimeout(int tokenTimeout) {
this.tokenTimeout = tokenTimeout;
}
@Override
public void init(KeycloakDeployment deployment, Object config) {
if (config == null || !(config instanceof Map)) {
throw new RuntimeException("Configuration of jwt credentials is missing or incorrect for client '" + deployment.getResourceName() + "'. Check your adapter configuration");
}
Map<String, Object> cfg = (Map<String, Object>) config;
String clientKeystoreFile = (String) cfg.get("client-keystore-file");
if (clientKeystoreFile == null) {
throw new RuntimeException("Missing parameter client-keystore-file in configuration of jwt for client " + deployment.getResourceName());
}
String clientKeystoreType = (String) cfg.get("client-keystore-type");
KeystoreUtil.KeystoreFormat clientKeystoreFormat = clientKeystoreType==null ? KeystoreUtil.KeystoreFormat.JKS : Enum.valueOf(KeystoreUtil.KeystoreFormat.class, clientKeystoreType.toUpperCase());
String clientKeystorePassword = (String) cfg.get("client-keystore-password");
if (clientKeystorePassword == null) {
throw new RuntimeException("Missing parameter client-keystore-password in configuration of jwt for client " + deployment.getResourceName());
}
String clientKeyPassword = (String) cfg.get("client-key-password");
if (clientKeyPassword == null) {
clientKeyPassword = clientKeystorePassword;
}
String clientKeyAlias = (String) cfg.get("client-key-alias");
if (clientKeyAlias == null) {
clientKeyAlias = deployment.getResourceName();
}
this.privateKey = KeystoreUtil.loadPrivateKeyFromKeystore(clientKeystoreFile, clientKeystorePassword, clientKeyPassword, clientKeyAlias, clientKeystoreFormat);
this.tokenTimeout = asInt(cfg, "token-timeout", 10);
}
// TODO: Generic method for this?
private Integer asInt(Map<String, Object> cfg, String cfgKey, int defaultValue) {
Object cfgObj = cfg.get(cfgKey);
if (cfgObj == null) {
return defaultValue;
}
if (cfgObj instanceof String) {
return Integer.parseInt(cfgObj.toString());
} else if (cfgObj instanceof Number) {
return ((Number) cfgObj).intValue();
} else {
throw new IllegalArgumentException("Can't parse " + cfgKey + " from the config. Value is " + cfgObj);
}
}
@Override
public void setClientCredentials(KeycloakDeployment deployment, Map<String, String> requestHeaders, Map<String, String> formParams) {
String signedToken = createSignedRequestToken(deployment.getResourceName(), deployment.getRealmInfoUrl());
formParams.put(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT);
formParams.put(OAuth2Constants.CLIENT_ASSERTION, signedToken);
}
public String createSignedRequestToken(String clientId, String realmInfoUrl) {
JsonWebToken jwt = createRequestToken(clientId, realmInfoUrl);
return new JWSBuilder()
.jsonContent(jwt)
.rsa256(privateKey);
}
protected JsonWebToken createRequestToken(String clientId, String realmInfoUrl) {
JsonWebToken reqToken = new JsonWebToken();
reqToken.id(AdapterUtils.generateId());
reqToken.issuer(clientId);
reqToken.subject(clientId);
reqToken.audience(realmInfoUrl);
int now = Time.currentTime();
reqToken.issuedAt(now);
reqToken.expiration(now + this.tokenTimeout);
reqToken.notBefore(now);
return reqToken;
}
}
@@ -1,45 +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.jaas;
import org.jboss.logging.Logger;
import org.keycloak.common.VerificationException;
/**
* Login module, which allows to authenticate Keycloak access token in environments, which rely on JAAS
* <p/>
* It expects login based on username and password where username doesn't matter and password is keycloak access token.
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class BearerTokenLoginModule extends AbstractKeycloakLoginModule {
private static final Logger log = Logger.getLogger(BearerTokenLoginModule.class);
@Override
protected Auth doAuth(String username, String password) throws VerificationException {
// Should do some checking of authenticated username if it's equivalent to passed value?
return bearerAuth(password);
}
@Override
protected Logger getLogger() {
return log;
}
}
@@ -1,53 +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.jaas;
import java.io.Serializable;
import java.security.Principal;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class RolePrincipal implements Principal, Serializable {
private String roleName = null;
public RolePrincipal(String roleName) {
this.roleName = roleName;
}
public boolean equals (Object p) {
if (! (p instanceof RolePrincipal))
return false;
return getName().equals(((RolePrincipal)p).getName());
}
public int hashCode () {
return getName().hashCode();
}
public String getName () {
return this.roleName;
}
public String toString ()
{
return getName();
}
}
@@ -1,19 +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.
#
org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider
org.keycloak.adapters.authentication.JWTClientCredentialsProvider
@@ -1,78 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.junit.Test;
import org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider;
import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
import org.keycloak.common.enums.RelativeUrlsUsed;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.enums.TokenStore;
import org.keycloak.common.util.PemUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class KeycloakDeploymentBuilderTest {
@Test
public void load() throws Exception {
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak.json"));
assertEquals("demo", deployment.getRealm());
assertEquals("customer-portal", deployment.getResourceName());
assertEquals(PemUtils.decodePublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"), deployment.getRealmKey());
assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/auth", deployment.getAuthUrl().build().toString());
assertEquals(SslRequired.EXTERNAL, deployment.getSslRequired());
assertTrue(deployment.isUseResourceRoleMappings());
assertTrue(deployment.isCors());
assertEquals(1000, deployment.getCorsMaxAge());
assertEquals("POST, PUT, DELETE, GET", deployment.getCorsAllowedMethods());
assertEquals("X-Custom, X-Custom2", deployment.getCorsAllowedHeaders());
assertTrue(deployment.isBearerOnly());
assertTrue(deployment.isPublicClient());
assertTrue(deployment.isEnableBasicAuth());
assertTrue(deployment.isExposeToken());
assertEquals("234234-234234-234234", deployment.getResourceCredentials().get("secret"));
assertEquals(ClientIdAndSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
assertEquals(20, ((ThreadSafeClientConnManager) deployment.getClient().getConnectionManager()).getMaxTotal());
assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/token", deployment.getTokenUrl());
assertEquals(RelativeUrlsUsed.NEVER, deployment.getRelativeUrls());
assertTrue(deployment.isAlwaysRefreshToken());
assertTrue(deployment.isRegisterNodeAtStartup());
assertEquals(1000, deployment.getRegisterNodePeriod());
assertEquals(TokenStore.COOKIE, deployment.getTokenStore());
assertEquals("email", deployment.getPrincipalAttribute());
}
@Test
public void loadNoClientCredentials() throws Exception {
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-no-credentials.json"));
assertEquals(ClientIdAndSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
}
@Test
public void loadJwtCredentials() throws Exception {
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-jwt.json"));
assertEquals(JWTClientCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
}
}
@@ -1,13 +0,0 @@
{
"realm": "demo",
"resource": "customer-portal",
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "https://localhost:8443/auth",
"ssl-required": "external",
"credentials": {
"jwt": {
"client-keystore-file": "classpath:keystore.jks",
"client-keystore-password": "storepass"
}
}
}
@@ -1,8 +0,0 @@
{
"realm": "demo",
"resource": "customer-portal",
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "https://localhost:8443/auth",
"public-client": true,
"expose-token": true
}
@@ -1,32 +0,0 @@
{
"realm": "demo",
"resource": "customer-portal",
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "https://localhost:8443/auth",
"ssl-required": "external",
"use-resource-role-mappings": true,
"enable-cors": true,
"cors-max-age": 1000,
"cors-allowed-methods": "POST, PUT, DELETE, GET",
"cors-allowed-headers": "X-Custom, X-Custom2",
"bearer-only": true,
"public-client": true,
"enable-basic-auth": true,
"expose-token": true,
"credentials": {
"secret": "234234-234234-234234"
},
"connection-pool-size": 20,
"disable-trust-manager": true,
"allow-any-hostname": true,
"truststore": "classpath:/cacerts.jks",
"truststore-password": "changeit",
"client-keystore": "classpath:/keystore.jks",
"client-keystore-password": "storepass",
"client-key-password": "keypass",
"always-refresh-token": true,
"register-node-at-startup": true,
"register-node-period": 1000,
"token-store": "cookie",
"principal-attribute": "email"
}
@@ -1,102 +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-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>1.9.6.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-as7-adapter-spi</artifactId>
<name>Keycloak AS7 SPI</name>
<description/>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.web</groupId>
<artifactId>jbossweb</artifactId>
<version>7.0.17.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-web</artifactId>
<version>7.1.2.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat-adapter-spi</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>catalina</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</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>
</plugins>
</build>
</project>
@@ -1,46 +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.jbossweb;
import org.apache.catalina.Realm;
import org.junit.Assert;
import org.junit.Test;
import javax.security.auth.Subject;
import java.lang.reflect.Constructor;
import java.security.Principal;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class JBossWebPrincipalFactoryTest {
@Test
public void test() {
Constructor constructor = JBossWebPrincipalFactory.findJBossGenericPrincipalConstructor();
Assert.assertNotNull(constructor);
Assert.assertEquals(Realm.class, constructor.getParameterTypes()[0]);
Assert.assertEquals(String.class, constructor.getParameterTypes()[1]);
Assert.assertEquals(List.class, constructor.getParameterTypes()[3]);
Assert.assertEquals(Principal.class, constructor.getParameterTypes()[4]);
Assert.assertEquals(Object.class, constructor.getParameterTypes()[6]);
Assert.assertEquals(Subject.class, constructor.getParameterTypes()[8]);
}
}
-134
View File
@@ -1,134 +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-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>1.9.6.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-as7-adapter</artifactId>
<name>Keycloak AS7 Integration</name>
<description/>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jboss-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.web</groupId>
<artifactId>jbossweb</artifactId>
<version>7.0.17.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-web</artifactId>
<version>7.1.2.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat-core-adapter</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>catalina</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</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>
</plugins>
</build>
</project>
@@ -1,72 +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.jbossweb;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.realm.GenericPrincipal;
import org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve;
import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.Principal;
import java.util.List;
/**
* Keycloak authentication valve
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorValve {
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws java.io.IOException {
return authenticateInternal(request, response, config);
}
@Override
protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
if (loginConfig == null) return false;
LoginConfig config = (LoginConfig)loginConfig;
if (config.getErrorPage() == null) return false;
forwardToErrorPage(request, (Response)response, config);
return true;
}
@Override
public void start() throws LifecycleException {
StandardContext standardContext = (StandardContext) context;
standardContext.addLifecycleListener(this);
super.start();
}
public void logout(Request request) {
logoutInternal(request);
}
@Override
protected GenericPrincipalFactory createPrincipalFactory() {
return new JBossWebPrincipalFactory();
}
}
@@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-integration-pom</artifactId>
<version>1.9.6.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-as7-subsystem</artifactId>
<name>Keycloak AS7 Subsystem</name>
<description/>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.8.1</version>
<configuration>
<redirectTestOutputToFile>false</redirectTestOutputToFile>
<enableAssertions>true</enableAssertions>
<argLine>-Xmx512m</argLine>
<systemProperties>
<property>
<name>jboss.home</name>
<value>${jboss.home}</value>
</property>
</systemProperties>
<includes>
<include>**/*TestCase.java</include>
</includes>
<forkMode>once</forkMode>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-naming</artifactId>
<version>${jboss.as.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-server</artifactId>
<version>${jboss.as.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-ee</artifactId>
<version>${jboss.as.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-web</artifactId>
<version>${jboss.as.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.0.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging-processor</artifactId>
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
projects that depend on this project.-->
<scope>provided</scope>
<optional>true</optional>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.msc</groupId>
<artifactId>jboss-msc</artifactId>
<version>1.0.2.GA</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -1,62 +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.subsystem.as7;
import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.ServiceVerificationHandler;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceController;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
/**
* Add a credential to a deployment.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
*/
public class CredentialAddHandler extends AbstractAddStepHandler {
protected Collection<AttributeDefinition> attributes = new LinkedList<>();
public CredentialAddHandler(AttributeDefinition... attrs) {
for (AttributeDefinition attr : attrs) {
attributes.add(attr);
}
}
@Override
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
if (attributes != null) {
for (AttributeDefinition attr : attributes) {
attr.validateAndSet(operation, model);
}
}
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.addCredential(operation, context.resolveExpressions(model));
}
}
@@ -1,63 +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.subsystem.as7;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationEntry;
import org.jboss.dmr.ModelType;
/**
* Defines attributes and operations for a credential.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
public class CredentialDefinition extends SimpleResourceDefinition {
public static final String TAG_NAME = "credential";
protected static final AttributeDefinition VALUE =
new SimpleAttributeDefinitionBuilder("value", ModelType.STRING, false)
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
.build();
public CredentialDefinition() {
super(PathElement.pathElement(TAG_NAME),
KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
new CredentialAddHandler(VALUE),
CredentialRemoveHandler.INSTANCE);
}
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
super.registerOperations(resourceRegistration);
resourceRegistration.registerOperationHandler(ModelDescriptionConstants.DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, GenericSubsystemDescribeHandler.INSTANCE, false, OperationEntry.EntryType.PRIVATE);
}
@Override
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
super.registerAttributes(resourceRegistration);
resourceRegistration.registerReadWriteAttribute(VALUE, null, new CredentialReadWriteAttributeHandler());
}
}
@@ -1,50 +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.subsystem.as7;
import org.jboss.as.controller.AbstractWriteAttributeHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.dmr.ModelNode;
/**
* Update a credential value.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
*/
public class CredentialReadWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
@Override
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
ModelNode resolvedValue, ModelNode currentValue, AbstractWriteAttributeHandler.HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.updateCredential(operation, attributeName, resolvedValue);
hh.setHandback(ckService);
return false;
}
@Override
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
ckService.updateCredential(operation, attributeName, valueToRestore);
}
}
@@ -1,42 +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.subsystem.as7;
import org.jboss.as.controller.AbstractRemoveStepHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.dmr.ModelNode;
/**
* Remove a credential from a deployment.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
*/
public final class CredentialRemoveHandler extends AbstractRemoveStepHandler {
public static CredentialRemoveHandler INSTANCE = new CredentialRemoveHandler();
private CredentialRemoveHandler() {}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.removeCredential(operation);
}
}
@@ -1,129 +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.subsystem.as7;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.web.deployment.WarMetaData;
import org.jboss.logging.Logger;
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.metadata.web.jboss.ValveMetaData;
import org.jboss.metadata.web.spec.LoginConfigMetaData;
import org.keycloak.adapters.jbossweb.KeycloakAuthenticatorValve;
import org.keycloak.subsystem.as7.logging.KeycloakLogger;
import java.util.ArrayList;
import java.util.List;
/**
* Pass authentication data (keycloak.json) as a servlet context param so it can be read by the KeycloakServletExtension.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
*/
public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitProcessor {
protected Logger log = Logger.getLogger(KeycloakAdapterConfigDeploymentProcessor.class);
// This param name is defined again in Keycloak Undertow Integration class
// org.keycloak.adapters.undertow.KeycloakServletExtension. We have this value in
// two places to avoid dependency between Keycloak Subsystem and Keyclaok Undertow Integration.
public static final String AUTH_DATA_PARAM_NAME = "org.keycloak.json.adapterConfig";
@Override
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
String deploymentName = deploymentUnit.getName();
// if it's not a web-app there's nothing to secure
WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
if (warMetaData == null) {
return;
}
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
if (webMetaData == null) {
webMetaData = new JBossWebMetaData();
warMetaData.setMergedJBossWebMetaData(webMetaData);
}
KeycloakAdapterConfigService service = KeycloakAdapterConfigService.getInstance();
// otherwise
LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
boolean hasSubsystemConfig = service.isSecureDeployment(deploymentName);
boolean webRequiresKC = loginConfig != null && "KEYCLOAK".equalsIgnoreCase(loginConfig.getAuthMethod());
if (hasSubsystemConfig || webRequiresKC) {
log.debug("Setting up KEYCLOAK auth method for WAR: " + deploymentName);
// if secure-deployment configuration exists for web app, we force KEYCLOAK auth method on it
if (hasSubsystemConfig) {
addJSONData(service.getJSON(deploymentName), warMetaData);
if (loginConfig != null) {
loginConfig.setAuthMethod("KEYCLOAK");
loginConfig.setRealmName(service.getRealmName(deploymentName));
} else {
log.warn("Failed to set up KEYCLOAK auth method for WAR: " + deploymentName + " (loginConfig == null)");
}
}
addValve(webMetaData);
KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
}
}
private void addValve(JBossWebMetaData webMetaData) {
List<ValveMetaData> valves = webMetaData.getValves();
if (valves == null) {
valves = new ArrayList<ValveMetaData>(1);
webMetaData.setValves(valves);
}
ValveMetaData valve = new ValveMetaData();
valve.setValveClass(KeycloakAuthenticatorValve.class.getName());
valve.setModule("org.keycloak.keycloak-as7-adapter");
//log.info("******* adding Keycloak valve to: " + deploymentName);
valves.add(valve);
}
private void addJSONData(String json, WarMetaData warMetaData) {
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
if (webMetaData == null) {
webMetaData = new JBossWebMetaData();
warMetaData.setMergedJBossWebMetaData(webMetaData);
}
List<ParamValueMetaData> contextParams = webMetaData.getContextParams();
if (contextParams == null) {
contextParams = new ArrayList<ParamValueMetaData>();
}
ParamValueMetaData param = new ParamValueMetaData();
param.setParamName(AUTH_DATA_PARAM_NAME);
param.setParamValue(json);
contextParams.add(param);
webMetaData.setContextParams(contextParams);
}
@Override
public void undeploy(DeploymentUnit du) {
}
}
@@ -1,192 +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.subsystem.as7;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.jboss.logging.Logger;
import java.util.HashMap;
import java.util.Map;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
/**
* This service keeps track of the entire Keycloak management model so as to provide
* adapter configuration to each deployment at deploy time.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
public final class KeycloakAdapterConfigService {
protected Logger log = Logger.getLogger(KeycloakAdapterConfigService.class);
private static final String CREDENTIALS_JSON_NAME = "credentials";
private static final KeycloakAdapterConfigService INSTANCE = new KeycloakAdapterConfigService();
public static KeycloakAdapterConfigService getInstance() {
return INSTANCE;
}
private final Map<String, ModelNode> realms = new HashMap<String, ModelNode>();
// keycloak-secured deployments
private final Map<String, ModelNode> secureDeployments = new HashMap<String, ModelNode>();
private KeycloakAdapterConfigService() {
}
public void addRealm(ModelNode operation, ModelNode model) {
this.realms.put(realmNameFromOp(operation), model.clone());
}
public void updateRealm(ModelNode operation, String attrName, ModelNode resolvedValue) {
ModelNode realm = this.realms.get(realmNameFromOp(operation));
realm.get(attrName).set(resolvedValue);
}
public void removeRealm(ModelNode operation) {
this.realms.remove(realmNameFromOp(operation));
}
public void addSecureDeployment(ModelNode operation, ModelNode model) {
ModelNode deployment = model.clone();
this.secureDeployments.put(deploymentNameFromOp(operation), deployment);
}
public void updateSecureDeployment(ModelNode operation, String attrName, ModelNode resolvedValue) {
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
deployment.get(attrName).set(resolvedValue);
}
public void removeSecureDeployment(ModelNode operation) {
this.secureDeployments.remove(deploymentNameFromOp(operation));
}
public void addCredential(ModelNode operation, ModelNode model) {
ModelNode credentials = credentialsFromOp(operation);
if (!credentials.isDefined()) {
credentials = new ModelNode();
}
String credentialName = credentialNameFromOp(operation);
if (!credentialName.contains(".")) {
credentials.get(credentialName).set(model.get("value").asString());
} else {
String[] parts = credentialName.split("\\.");
String provider = parts[0];
String property = parts[1];
ModelNode credential = credentials.get(provider);
if (!credential.isDefined()) {
credential = new ModelNode();
}
credential.get(property).set(model.get("value").asString());
credentials.set(provider, credential);
}
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
deployment.get(CREDENTIALS_JSON_NAME).set(credentials);
}
public void removeCredential(ModelNode operation) {
ModelNode credentials = credentialsFromOp(operation);
if (!credentials.isDefined()) {
throw new RuntimeException("Can not remove credential. No credential defined for deployment in op " + operation.toString());
}
String credentialName = credentialNameFromOp(operation);
credentials.remove(credentialName);
}
public void updateCredential(ModelNode operation, String attrName, ModelNode resolvedValue) {
ModelNode credentials = credentialsFromOp(operation);
if (!credentials.isDefined()) {
throw new RuntimeException("Can not update credential. No credential defined for deployment in op " + operation.toString());
}
String credentialName = credentialNameFromOp(operation);
credentials.get(credentialName).set(resolvedValue);
}
private ModelNode credentialsFromOp(ModelNode operation) {
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
return deployment.get(CREDENTIALS_JSON_NAME);
}
private String realmNameFromOp(ModelNode operation) {
return valueFromOpAddress(RealmDefinition.TAG_NAME, operation);
}
private String deploymentNameFromOp(ModelNode operation) {
return valueFromOpAddress(SecureDeploymentDefinition.TAG_NAME, operation);
}
private String credentialNameFromOp(ModelNode operation) {
return valueFromOpAddress(CredentialDefinition.TAG_NAME, operation);
}
private String valueFromOpAddress(String addrElement, ModelNode operation) {
String deploymentName = getValueOfAddrElement(operation.get(ADDRESS), addrElement);
if (deploymentName == null) throw new RuntimeException("Can't find '" + addrElement + "' in address " + operation.toString());
return deploymentName;
}
private String getValueOfAddrElement(ModelNode address, String elementName) {
for (ModelNode element : address.asList()) {
if (element.has(elementName)) return element.get(elementName).asString();
}
return null;
}
public String getRealmName(String deploymentName) {
ModelNode deployment = this.secureDeployments.get(deploymentName);
return deployment.get(RealmDefinition.TAG_NAME).asString();
}
public String getJSON(String deploymentName) {
ModelNode deployment = this.secureDeployments.get(deploymentName);
String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
ModelNode realm = this.realms.get(realmName);
ModelNode json = new ModelNode();
json.get(RealmDefinition.TAG_NAME).set(realmName);
// Realm values set first. Some can be overridden by deployment values.
if (realm != null) setJSONValues(json, realm);
setJSONValues(json, deployment);
return json.toJSONString(true);
}
private void setJSONValues(ModelNode json, ModelNode values) {
for (Property prop : values.asPropertyList()) {
String name = prop.getName();
ModelNode value = prop.getValue();
if (value.isDefined()) {
json.get(name).set(value);
}
}
}
public boolean isSecureDeployment(String deploymentName) {
//log.info("********* CHECK KEYCLOAK DEPLOYMENT: deployments.size()" + deployments.size());
return this.secureDeployments.containsKey(deploymentName);
}
}
@@ -1,86 +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.subsystem.as7;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.server.deployment.module.ModuleDependency;
import org.jboss.as.server.deployment.module.ModuleSpecification;
import org.jboss.as.web.deployment.WarMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.metadata.web.spec.LoginConfigMetaData;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoader;
/**
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
public abstract class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
private static final ModuleIdentifier KEYCLOAK_JBOSS_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-jboss-adapter-core");
private static final ModuleIdentifier KEYCLOAK_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-adapter-core");
private static final ModuleIdentifier KEYCLOAK_CORE = ModuleIdentifier.create("org.keycloak.keycloak-core");
private static final ModuleIdentifier KEYCLOAK_COMMON = ModuleIdentifier.create("org.keycloak.keycloak-common");
@Override
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
String deploymentName = deploymentUnit.getName();
if (!KeycloakAdapterConfigService.getInstance().isSecureDeployment(deploymentName)) {
WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
if (warMetaData == null) {
return;
}
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
if (webMetaData == null) {
return;
}
LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
if (loginConfig == null) return;
if (loginConfig.getAuthMethod() == null) return;
if (!loginConfig.getAuthMethod().equals("KEYCLOAK")) return;
}
final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
final ModuleLoader moduleLoader = Module.getBootModuleLoader();
addCommonModules(moduleSpecification, moduleLoader);
addPlatformSpecificModules(moduleSpecification, moduleLoader);
}
private void addCommonModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
// ModuleDependency(ModuleLoader moduleLoader, ModuleIdentifier identifier, boolean optional, boolean export, boolean importServices, boolean userSpecified)
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_JBOSS_CORE_ADAPTER, false, false, false, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE_ADAPTER, false, false, false, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE, false, false, false, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_COMMON, false, false, false, false));
}
abstract protected void addPlatformSpecificModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader);
@Override
public void undeploy(DeploymentUnit du) {
}
}
@@ -1,36 +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.subsystem.as7;
import org.jboss.as.server.deployment.module.ModuleDependency;
import org.jboss.as.server.deployment.module.ModuleSpecification;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoader;
/**
* @author <a href="mailto:marko.strukelj@gmail.com">Marko Strukelj</a>
*/
public class KeycloakDependencyProcessorAS7 extends KeycloakDependencyProcessor {
private static final ModuleIdentifier KEYCLOAK_AS7_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-as7-adapter");
@Override
protected void addPlatformSpecificModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
// ModuleDependency(ModuleLoader moduleLoader, ModuleIdentifier identifier, boolean optional, boolean export, boolean importServices, boolean userSpecified)
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_AS7_ADAPTER, false, false, true, false));
}}
@@ -1,84 +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.subsystem.as7;
import org.jboss.as.controller.Extension;
import org.jboss.as.controller.ExtensionContext;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.ResourceDefinition;
import org.jboss.as.controller.SubsystemRegistration;
import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
import org.jboss.as.controller.parsing.ExtensionParsingContext;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.keycloak.subsystem.as7.logging.KeycloakLogger;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
/**
* Main Extension class for the subsystem.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
public class KeycloakExtension implements Extension {
public static final String SUBSYSTEM_NAME = "keycloak";
public static final String NAMESPACE = "urn:jboss:domain:keycloak:1.1";
private static final KeycloakSubsystemParser PARSER = new KeycloakSubsystemParser();
static final PathElement PATH_SUBSYSTEM = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
private static final String RESOURCE_NAME = KeycloakExtension.class.getPackage().getName() + ".LocalDescriptions";
private static final int MGMT_API_VERSION_MAJOR = 1;
private static final int MGMT_API_VERSION_MINOR = 1;
static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
private static final ResourceDefinition KEYCLOAK_SUBSYSTEM_RESOURCE = new KeycloakSubsystemDefinition();
static final RealmDefinition REALM_DEFINITION = new RealmDefinition();
static final SecureDeploymentDefinition SECURE_DEPLOYMENT_DEFINITION = new SecureDeploymentDefinition();
static final CredentialDefinition CREDENTIAL_DEFINITION = new CredentialDefinition();
public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
for (String kp : keyPrefix) {
prefix.append('.').append(kp);
}
return new StandardResourceDescriptionResolver(prefix.toString(), RESOURCE_NAME, KeycloakExtension.class.getClassLoader(), true, false);
}
/**
* {@inheritDoc}
*/
@Override
public void initializeParsers(final ExtensionParsingContext context) {
context.setSubsystemXmlMapping(SUBSYSTEM_NAME, KeycloakExtension.NAMESPACE, PARSER);
}
/**
* {@inheritDoc}
*/
@Override
public void initialize(final ExtensionContext context) {
KeycloakLogger.ROOT_LOGGER.debug("Activating Keycloak Extension");
final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, MGMT_API_VERSION_MAJOR, MGMT_API_VERSION_MINOR);
ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
registration.registerSubModel(REALM_DEFINITION);
ManagementResourceRegistration secureDeploymentRegistration = registration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION);
secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
subsystem.registerXMLElementWriter(PARSER);
}
}
@@ -1,60 +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.subsystem.as7;
import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.ServiceVerificationHandler;
import org.jboss.as.server.AbstractDeploymentChainStep;
import org.jboss.as.server.DeploymentProcessorTarget;
import org.jboss.as.server.deployment.Phase;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceController;
import java.util.List;
/**
* The Keycloak subsystem add update handler.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
static final KeycloakSubsystemAdd INSTANCE = new KeycloakSubsystemAdd();
@Override
protected void performBoottime(final OperationContext context, ModelNode operation, final ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) {
context.addStep(new AbstractDeploymentChainStep() {
@Override
protected void execute(DeploymentProcessorTarget processorTarget) {
processorTarget.addDeploymentProcessor(Phase.DEPENDENCIES, 0, new KeycloakDependencyProcessorAS7());
processorTarget.addDeploymentProcessor(
Phase.POST_MODULE, // PHASE
Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
new KeycloakAdapterConfigDeploymentProcessor());
}
}, OperationContext.Stage.RUNTIME);
}
@Override
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
model.setEmptyObject();
}
}
@@ -1,47 +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.subsystem.as7;
import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationEntry;
/**
* Definition of subsystem=keycloak.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
protected KeycloakSubsystemDefinition() {
super(KeycloakExtension.SUBSYSTEM_PATH,
KeycloakExtension.getResourceDescriptionResolver("subsystem"),
KeycloakSubsystemAdd.INSTANCE,
ReloadRequiredRemoveStepHandler.INSTANCE
);
}
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
super.registerOperations(resourceRegistration);
resourceRegistration.registerOperationHandler(ModelDescriptionConstants.DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, GenericSubsystemDescribeHandler.INSTANCE, false, OperationEntry.EntryType.PRIVATE);
}
}
@@ -1,294 +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.subsystem.as7;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.parsing.ParseUtils;
import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLElementWriter;
import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.jboss.staxmapper.XMLExtendedStreamWriter;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* The subsystem parser, which uses stax to read and write to and from xml
*/
class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>, XMLElementWriter<SubsystemMarshallingContext> {
/**
* {@inheritDoc}
*/
@Override
public void readElement(final XMLExtendedStreamReader reader, final List<ModelNode> list) throws XMLStreamException {
// Require no attributes
ParseUtils.requireNoAttributes(reader);
ModelNode addKeycloakSub = Util.createAddOperation(PathAddress.pathAddress(KeycloakExtension.PATH_SUBSYSTEM));
list.add(addKeycloakSub);
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
if (reader.getLocalName().equals(RealmDefinition.TAG_NAME)) {
readRealm(reader, list);
}
else if (reader.getLocalName().equals(SecureDeploymentDefinition.TAG_NAME)) {
readDeployment(reader, list);
}
}
}
// used for debugging
private int nextTag(XMLExtendedStreamReader reader) throws XMLStreamException {
return reader.nextTag();
}
private void readRealm(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
String realmName = readNameAttribute(reader);
ModelNode addRealm = new ModelNode();
addRealm.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
PathElement.pathElement(RealmDefinition.TAG_NAME, realmName));
addRealm.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
String tagName = reader.getLocalName();
SimpleAttributeDefinition def = RealmDefinition.lookup(tagName);
if (def == null) throw new XMLStreamException("Unknown realm tag " + tagName);
def.parseAndSetParameter(reader.getElementText(), addRealm, reader);
}
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
//TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
}
list.add(addRealm);
}
private void readDeployment(XMLExtendedStreamReader reader, List<ModelNode> resourcesToAdd) throws XMLStreamException {
String name = readNameAttribute(reader);
ModelNode addSecureDeployment = new ModelNode();
addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name));
addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>();
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
String tagName = reader.getLocalName();
if (tagName.equals(CredentialDefinition.TAG_NAME)) {
readCredential(reader, addr, credentialsToAdd);
continue;
}
SimpleAttributeDefinition def = SecureDeploymentDefinition.lookup(tagName);
if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName);
def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader);
}
/**
* TODO need to check realm-ref first.
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
//TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
}
*/
// Must add credentials after the deployment is added.
resourcesToAdd.add(addSecureDeployment);
resourcesToAdd.addAll(credentialsToAdd);
}
public void readCredential(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> credentialsToAdd) throws XMLStreamException {
String name = readNameAttribute(reader);
Map<String, String> values = new HashMap<>();
String textValue = null;
while (reader.hasNext()) {
int next = reader.next();
if (next == CHARACTERS) {
// text value of credential element (like for "secret" )
String text = reader.getText();
if (text == null || text.trim().isEmpty()) {
continue;
}
textValue = text;
} else if (next == START_ELEMENT) {
String key = reader.getLocalName();
reader.next();
String value = reader.getText();
reader.next();
values.put(key, value);
} else if (next == END_ELEMENT) {
break;
}
}
if (textValue != null) {
ModelNode addCredential = getCredentialToAdd(parent, name, textValue);
credentialsToAdd.add(addCredential);
} else {
for (Map.Entry<String, String> entry : values.entrySet()) {
ModelNode addCredential = getCredentialToAdd(parent, name + "" + entry.getKey(), entry.getValue());
credentialsToAdd.add(addCredential);
}
}
}
private ModelNode getCredentialToAdd(PathAddress parent, String name, String value) {
ModelNode addCredential = new ModelNode();
addCredential.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(parent, PathElement.pathElement(CredentialDefinition.TAG_NAME, name));
addCredential.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
addCredential.get(CredentialDefinition.VALUE.getName()).set(value);
return addCredential;
}
// expects that the current tag will have one single attribute called "name"
private String readNameAttribute(XMLExtendedStreamReader reader) throws XMLStreamException {
String name = null;
for (int i = 0; i < reader.getAttributeCount(); i++) {
String attr = reader.getAttributeLocalName(i);
if (attr.equals("name")) {
name = reader.getAttributeValue(i);
continue;
}
throw ParseUtils.unexpectedAttribute(reader, i);
}
if (name == null) {
throw ParseUtils.missingRequired(reader, Collections.singleton("name"));
}
return name;
}
/**
* {@inheritDoc}
*/
@Override
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
writeRealms(writer, context);
writeSecureDeployments(writer, context);
writer.writeEndElement();
}
private void writeRealms(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
if (!context.getModelNode().get(RealmDefinition.TAG_NAME).isDefined()) {
return;
}
for (Property realm : context.getModelNode().get(RealmDefinition.TAG_NAME).asPropertyList()) {
writer.writeStartElement(RealmDefinition.TAG_NAME);
writer.writeAttribute("name", realm.getName());
ModelNode realmElements = realm.getValue();
for (AttributeDefinition element : RealmDefinition.ALL_ATTRIBUTES) {
element.marshallAsElement(realmElements, writer);
}
writer.writeEndElement();
}
}
private void writeSecureDeployments(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
if (!context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).isDefined()) {
return;
}
for (Property deployment : context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).asPropertyList()) {
writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME);
writer.writeAttribute("name", deployment.getName());
ModelNode deploymentElements = deployment.getValue();
for (AttributeDefinition element : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
element.marshallAsElement(deploymentElements, writer);
}
ModelNode credentials = deploymentElements.get(CredentialDefinition.TAG_NAME);
if (credentials.isDefined()) {
writeCredentials(writer, credentials);
}
writer.writeEndElement();
}
}
private void writeCredentials(XMLExtendedStreamWriter writer, ModelNode credentials) throws XMLStreamException {
Map<String, Object> parsed = new LinkedHashMap<>();
for (Property credential : credentials.asPropertyList()) {
String credName = credential.getName();
String credValue = credential.getValue().get(CredentialDefinition.VALUE.getName()).asString();
if (credName.indexOf('.') > -1) {
String[] parts = credName.split("\\.");
String provider = parts[0];
String propKey = parts[1];
Map<String, String> currentProviderMap = (Map<String, String>) parsed.get(provider);
if (currentProviderMap == null) {
currentProviderMap = new LinkedHashMap<>();
parsed.put(provider, currentProviderMap);
}
currentProviderMap.put(propKey, credValue);
} else {
parsed.put(credName, credValue);
}
}
for (Map.Entry<String, Object> entry : parsed.entrySet()) {
writer.writeStartElement(CredentialDefinition.TAG_NAME);
writer.writeAttribute("name", entry.getKey());
Object value = entry.getValue();
if (value instanceof String) {
writeCharacters(writer, (String) value);
} else {
Map<String, String> credentialProps = (Map<String, String>) value;
for (Map.Entry<String, String> prop : credentialProps.entrySet()) {
writer.writeStartElement(prop.getKey());
writeCharacters(writer, prop.getValue());
writer.writeEndElement();
}
}
writer.writeEndElement();
}
}
// code taken from org.jboss.as.controller.AttributeMarshaller
private void writeCharacters(XMLExtendedStreamWriter writer, String content) throws XMLStreamException {
if (content.indexOf('\n') > -1) {
// Multiline content. Use the overloaded variant that staxmapper will format
writer.writeCharacters(content);
} else {
// Staxmapper will just output the chars without adding newlines if this is used
char[] chars = content.toCharArray();
writer.writeCharacters(chars, 0, chars.length);
}
}
}
@@ -1,58 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.subsystem.as7;
import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.ServiceVerificationHandler;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceController;
import java.util.List;
/**
* Add a new realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
public final class RealmAddHandler extends AbstractAddStepHandler {
public static RealmAddHandler INSTANCE = new RealmAddHandler();
private RealmAddHandler() {}
@Override
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
for (AttributeDefinition attrib : RealmDefinition.ALL_ATTRIBUTES) {
attrib.validateAndSet(operation, model);
}
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
//TODO: externalize message
throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
}
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.addRealm(operation, context.resolveExpressions(model));
}
}
@@ -1,89 +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.subsystem.as7;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Defines attributes and operations for the Realm
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
class RealmDefinition extends SimpleResourceDefinition {
public static final String TAG_NAME = "realm";
protected static final List<SimpleAttributeDefinition> REALM_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
}
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
ALL_ATTRIBUTES.addAll(REALM_ONLY_ATTRIBUTES);
ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
}
private static final Map<String, SimpleAttributeDefinition> DEFINITION_LOOKUP = new HashMap<String, SimpleAttributeDefinition>();
static {
for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
DEFINITION_LOOKUP.put(def.getXmlName(), def);
}
}
private static final RealmWriteAttributeHandler realmAttrHandler = new RealmWriteAttributeHandler(ALL_ATTRIBUTES.toArray(new SimpleAttributeDefinition[0]));
public RealmDefinition() {
super(PathElement.pathElement("realm"),
KeycloakExtension.getResourceDescriptionResolver("realm"),
RealmAddHandler.INSTANCE,
RealmRemoveHandler.INSTANCE);
}
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
super.registerOperations(resourceRegistration);
resourceRegistration.registerOperationHandler(ModelDescriptionConstants.DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, GenericSubsystemDescribeHandler.INSTANCE, false, OperationEntry.EntryType.PRIVATE);
}
@Override
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
super.registerAttributes(resourceRegistration);
for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
//TODO: use subclass of realmAttrHandler that can call RealmDefinition.validateTruststoreSetIfRequired
resourceRegistration.registerReadWriteAttribute(attrDef, null, realmAttrHandler);
}
}
public static SimpleAttributeDefinition lookup(String name) {
return DEFINITION_LOOKUP.get(name);
}
}
@@ -1,41 +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.subsystem.as7;
import org.jboss.as.controller.AbstractRemoveStepHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.dmr.ModelNode;
/**
* Remove a realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
final class RealmRemoveHandler extends AbstractRemoveStepHandler {
public static RealmRemoveHandler INSTANCE = new RealmRemoveHandler();
private RealmRemoveHandler() {}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.removeRealm(operation);
}
}
@@ -1,56 +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.subsystem.as7;
import org.jboss.as.controller.AbstractWriteAttributeHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.dmr.ModelNode;
import java.util.List;
/**
* Update an attribute on a realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
class RealmWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
public RealmWriteAttributeHandler(AttributeDefinition... definitions) {
super(definitions);
}
@Override
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
ModelNode resolvedValue, ModelNode currentValue, HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.updateRealm(operation, attributeName, resolvedValue);
hh.setHandback(ckService);
return false;
}
@Override
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
ckService.updateRealm(operation, attributeName, valueToRestore);
}
}
@@ -1,54 +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.subsystem.as7;
import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.ServiceVerificationHandler;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceController;
import java.util.List;
/**
* Add a deployment to a realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
final class SecureDeploymentAddHandler extends AbstractAddStepHandler {
public static SecureDeploymentAddHandler INSTANCE = new SecureDeploymentAddHandler();
private SecureDeploymentAddHandler() {
}
@Override
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
for (AttributeDefinition attr : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
attr.validateAndSet(operation, model);
}
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.addSecureDeployment(operation, context.resolveExpressions(model));
}
}
@@ -1,132 +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.subsystem.as7;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationEntry;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Defines attributes and operations for a secure-deployment.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
class SecureDeploymentDefinition extends SimpleResourceDefinition {
public static final String TAG_NAME = "secure-deployment";
protected static final SimpleAttributeDefinition REALM =
new SimpleAttributeDefinitionBuilder("realm", ModelType.STRING, true)
.setXmlName("realm")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition RESOURCE =
new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true)
.setXmlName("resource")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition USE_RESOURCE_ROLE_MAPPINGS =
new SimpleAttributeDefinitionBuilder("use-resource-role-mappings", ModelType.BOOLEAN, true)
.setXmlName("use-resource-role-mappings")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition BEARER_ONLY =
new SimpleAttributeDefinitionBuilder("bearer-only", ModelType.BOOLEAN, true)
.setXmlName("bearer-only")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition ENABLE_BASIC_AUTH =
new SimpleAttributeDefinitionBuilder("enable-basic-auth", ModelType.BOOLEAN, true)
.setXmlName("enable-basic-auth")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition PUBLIC_CLIENT =
new SimpleAttributeDefinitionBuilder("public-client", ModelType.BOOLEAN, true)
.setXmlName("public-client")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
DEPLOYMENT_ONLY_ATTRIBUTES.add(REALM);
DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
}
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
ALL_ATTRIBUTES.addAll(DEPLOYMENT_ONLY_ATTRIBUTES);
ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
}
private static final Map<String, SimpleAttributeDefinition> DEFINITION_LOOKUP = new HashMap<String, SimpleAttributeDefinition>();
static {
for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
DEFINITION_LOOKUP.put(def.getXmlName(), def);
}
}
private static SecureDeploymentWriteAttributeHandler attrHandler = new SecureDeploymentWriteAttributeHandler(ALL_ATTRIBUTES);
public SecureDeploymentDefinition() {
super(PathElement.pathElement(TAG_NAME),
KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
SecureDeploymentAddHandler.INSTANCE,
SecureDeploymentRemoveHandler.INSTANCE);
}
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
super.registerOperations(resourceRegistration);
resourceRegistration.registerOperationHandler(ModelDescriptionConstants.DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, GenericSubsystemDescribeHandler.INSTANCE, false, OperationEntry.EntryType.PRIVATE);
}
@Override
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
super.registerAttributes(resourceRegistration);
for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
resourceRegistration.registerReadWriteAttribute(attrDef, null, attrHandler);
}
}
public static SimpleAttributeDefinition lookup(String name) {
return DEFINITION_LOOKUP.get(name);
}
}
@@ -1,41 +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.subsystem.as7;
import org.jboss.as.controller.AbstractRemoveStepHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.dmr.ModelNode;
/**
* Remove a secure-deployment from a realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
final class SecureDeploymentRemoveHandler extends AbstractRemoveStepHandler {
public static SecureDeploymentRemoveHandler INSTANCE = new SecureDeploymentRemoveHandler();
private SecureDeploymentRemoveHandler() {}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.removeSecureDeployment(operation);
}
}
@@ -1,59 +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.subsystem.as7;
import org.jboss.as.controller.AbstractWriteAttributeHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.dmr.ModelNode;
import java.util.List;
/**
* Update an attribute on a secure-deployment.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
class SecureDeploymentWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
public SecureDeploymentWriteAttributeHandler(List<SimpleAttributeDefinition> definitions) {
this(definitions.toArray(new AttributeDefinition[definitions.size()]));
}
public SecureDeploymentWriteAttributeHandler(AttributeDefinition... definitions) {
super(definitions);
}
@Override
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
ModelNode resolvedValue, ModelNode currentValue, HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
hh.setHandback(ckService);
ckService.updateSecureDeployment(operation, attributeName, resolvedValue);
return false;
}
@Override
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
ckService.updateSecureDeployment(operation, attributeName, valueToRestore);
}
}
@@ -1,227 +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.subsystem.as7;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.operations.validation.IntRangeValidator;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import java.util.ArrayList;
import java.util.List;
/**
* Defines attributes that can be present in both a realm and an application (secure-deployment).
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
class SharedAttributeDefinitons {
protected static final SimpleAttributeDefinition REALM_PUBLIC_KEY =
new SimpleAttributeDefinitionBuilder("realm-public-key", ModelType.STRING, true)
.setXmlName("realm-public-key")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition AUTH_SERVER_URL =
new SimpleAttributeDefinitionBuilder("auth-server-url", ModelType.STRING, true)
.setXmlName("auth-server-url")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition SSL_REQUIRED =
new SimpleAttributeDefinitionBuilder("ssl-required", ModelType.STRING, true)
.setXmlName("ssl-required")
.setAllowExpression(true)
.setDefaultValue(new ModelNode("external"))
.build();
protected static final SimpleAttributeDefinition ALLOW_ANY_HOSTNAME =
new SimpleAttributeDefinitionBuilder("allow-any-hostname", ModelType.BOOLEAN, true)
.setXmlName("allow-any-hostname")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition DISABLE_TRUST_MANAGER =
new SimpleAttributeDefinitionBuilder("disable-trust-manager", ModelType.BOOLEAN, true)
.setXmlName("disable-trust-manager")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE =
new SimpleAttributeDefinitionBuilder("truststore", ModelType.STRING, true)
.setXmlName("truststore")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition TRUSTSTORE_PASSWORD =
new SimpleAttributeDefinitionBuilder("truststore-password", ModelType.STRING, true)
.setXmlName("truststore-password")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CONNECTION_POOL_SIZE =
new SimpleAttributeDefinitionBuilder("connection-pool-size", ModelType.INT, true)
.setXmlName("connection-pool-size")
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0, true))
.build();
protected static final SimpleAttributeDefinition ENABLE_CORS =
new SimpleAttributeDefinitionBuilder("enable-cors", ModelType.BOOLEAN, true)
.setXmlName("enable-cors")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition CLIENT_KEYSTORE =
new SimpleAttributeDefinitionBuilder("client-keystore", ModelType.STRING, true)
.setXmlName("client-keystore")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CLIENT_KEYSTORE_PASSWORD =
new SimpleAttributeDefinitionBuilder("client-keystore-password", ModelType.STRING, true)
.setXmlName("client-keystore-password")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CLIENT_KEY_PASSWORD =
new SimpleAttributeDefinitionBuilder("client-key-password", ModelType.STRING, true)
.setXmlName("client-key-password")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CORS_MAX_AGE =
new SimpleAttributeDefinitionBuilder("cors-max-age", ModelType.INT, true)
.setXmlName("cors-max-age")
.setAllowExpression(true)
.setValidator(new IntRangeValidator(-1, true))
.build();
protected static final SimpleAttributeDefinition CORS_ALLOWED_HEADERS =
new SimpleAttributeDefinitionBuilder("cors-allowed-headers", ModelType.STRING, true)
.setXmlName("cors-allowed-headers")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CORS_ALLOWED_METHODS =
new SimpleAttributeDefinitionBuilder("cors-allowed-methods", ModelType.STRING, true)
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition EXPOSE_TOKEN =
new SimpleAttributeDefinitionBuilder("expose-token", ModelType.BOOLEAN, true)
.setXmlName("expose-token")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition AUTH_SERVER_URL_FOR_BACKEND_REQUESTS =
new SimpleAttributeDefinitionBuilder("auth-server-url-for-backend-requests", ModelType.STRING, true)
.setXmlName("auth-server-url-for-backend-requests")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition ALWAYS_REFRESH_TOKEN =
new SimpleAttributeDefinitionBuilder("always-refresh-token", ModelType.BOOLEAN, true)
.setXmlName("always-refresh-token")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition REGISTER_NODE_AT_STARTUP =
new SimpleAttributeDefinitionBuilder("register-node-at-startup", ModelType.BOOLEAN, true)
.setXmlName("register-node-at-startup")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition REGISTER_NODE_PERIOD =
new SimpleAttributeDefinitionBuilder("register-node-period", ModelType.INT, true)
.setXmlName("register-node-period")
.setAllowExpression(true)
.setValidator(new IntRangeValidator(-1, true))
.build();
protected static final SimpleAttributeDefinition TOKEN_STORE =
new SimpleAttributeDefinitionBuilder("token-store", ModelType.STRING, true)
.setXmlName("token-store")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition PRINCIPAL_ATTRIBUTE =
new SimpleAttributeDefinitionBuilder("principal-attribute", ModelType.STRING, true)
.setXmlName("principal-attribute")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
ATTRIBUTES.add(REALM_PUBLIC_KEY);
ATTRIBUTES.add(AUTH_SERVER_URL);
ATTRIBUTES.add(TRUSTSTORE);
ATTRIBUTES.add(TRUSTSTORE_PASSWORD);
ATTRIBUTES.add(SSL_REQUIRED);
ATTRIBUTES.add(ALLOW_ANY_HOSTNAME);
ATTRIBUTES.add(DISABLE_TRUST_MANAGER);
ATTRIBUTES.add(CONNECTION_POOL_SIZE);
ATTRIBUTES.add(ENABLE_CORS);
ATTRIBUTES.add(CLIENT_KEYSTORE);
ATTRIBUTES.add(CLIENT_KEYSTORE_PASSWORD);
ATTRIBUTES.add(CLIENT_KEY_PASSWORD);
ATTRIBUTES.add(CORS_MAX_AGE);
ATTRIBUTES.add(CORS_ALLOWED_HEADERS);
ATTRIBUTES.add(CORS_ALLOWED_METHODS);
ATTRIBUTES.add(EXPOSE_TOKEN);
ATTRIBUTES.add(AUTH_SERVER_URL_FOR_BACKEND_REQUESTS);
ATTRIBUTES.add(ALWAYS_REFRESH_TOKEN);
ATTRIBUTES.add(REGISTER_NODE_AT_STARTUP);
ATTRIBUTES.add(REGISTER_NODE_PERIOD);
ATTRIBUTES.add(TOKEN_STORE);
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
}
/**
* truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.
*
* @param attributes The full set of attributes.
*
* @return <code>true</code> if the attributes are valid, <code>false</code> otherwise.
*/
public static boolean validateTruststoreSetIfRequired(ModelNode attributes) {
if (isSet(attributes, DISABLE_TRUST_MANAGER)) {
return true;
}
if (isSet(attributes, SSL_REQUIRED) && attributes.get(SSL_REQUIRED.getName()).asString().equals("none")) {
return true;
}
//TODO, look into alternatives & requires properties on AttributeDefinition
return isSet(attributes, TRUSTSTORE) && isSet(attributes, TRUSTSTORE_PASSWORD);
}
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
ModelNode attribute = attributes.get(def.getName());
if (def.getType() == ModelType.BOOLEAN) {
return attribute.isDefined() && attribute.asBoolean();
}
return attribute.isDefined() && !attribute.asString().isEmpty();
}
}
@@ -1,59 +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.subsystem.as7;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.dmr.ModelNode;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Util {
public static ModelNode createAddOperation(final PathAddress address) {
return createOperation(ModelDescriptionConstants.ADD, address);
}
public static ModelNode createAddOperation() {
return createEmptyOperation(ModelDescriptionConstants.ADD, null);
}
public static ModelNode createRemoveOperation(final PathAddress address) {
return createOperation(ModelDescriptionConstants.REMOVE, address);
}
public static ModelNode createOperation(final String operationName, final PathAddress address) {
return createEmptyOperation(operationName, address);
}
public static ModelNode createEmptyOperation(String operationName, final PathAddress address) {
ModelNode op = new ModelNode();
op.get(OP).set(operationName);
if (address != null) {
op.get(OP_ADDR).set(address.toModelNode());
} else {
// Just establish the standard structure; caller can fill in address later
op.get(OP_ADDR);
}
return op;
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.subsystem.as7.logging;
import org.jboss.logging.BasicLogger;
import org.jboss.logging.LogMessage;
import org.jboss.logging.Logger;
import org.jboss.logging.Message;
import org.jboss.logging.MessageLogger;
import static org.jboss.logging.Logger.Level.DEBUG;
import static org.jboss.logging.Logger.Level.INFO;
/**
* This interface to be fleshed out later when error messages are fully externalized.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
@MessageLogger(projectCode = "KEYCLOAK")
public interface KeycloakLogger extends BasicLogger {
/**
* A logger with a category of the package name.
*/
KeycloakLogger ROOT_LOGGER = Logger.getMessageLogger(KeycloakLogger.class, "org.jboss.keycloak");
@LogMessage(level = INFO)
@Message(value = "Keycloak subsystem override for deployment %s")
void deploymentSecured(String deployment);
@LogMessage(level = DEBUG)
@Message(value = "Keycloak has overriden and secured deployment %s")
void warSecured(String deployment);
}
@@ -1,34 +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.subsystem.as7.logging;
import org.jboss.logging.MessageBundle;
import org.jboss.logging.Messages;
/**
* This interface to be fleshed out later when error messages are fully externalized.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2012 Red Hat Inc.
*/
@MessageBundle(projectCode = "TLIP")
public interface KeycloakMessages {
/**
* The messages
*/
KeycloakMessages MESSAGES = Messages.getBundle(KeycloakMessages.class);
}
@@ -1,18 +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.
#
org.keycloak.subsystem.as7.KeycloakExtension
@@ -1,89 +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.
#
keycloak.subsystem=Keycloak adapter subsystem
keycloak.subsystem.add=Operation Adds Keycloak adapter subsystem
keycloak.subsystem.remove=Operation removes Keycloak adapter subsystem
keycloak.subsystem.realm=A Keycloak realm.
keycloak.subsystem.secure-deployment=A deployment secured by Keycloak.
keycloak.realm=A Keycloak realm.
keycloak.realm.add=Add a realm definition to the subsystem.
keycloak.realm.remove=Remove a realm from the subsystem.
keycloak.realm.realm-public-key=Public key of the realm
keycloak.realm.auth-server-url=Base URL of the Realm Auth Server
keycloak.realm.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
keycloak.realm.ssl-required=Specify if SSL is required (valid values are all, external and none)
keycloak.realm.allow-any-hostname=SSL Setting
keycloak.realm.truststore=Truststore used for adapter client HTTPS requests
keycloak.realm.truststore-password=Password of the Truststore
keycloak.realm.connection-pool-size=Connection pool size for the client used by the adapter
keycloak.realm.enable-cors=Enable Keycloak CORS support
keycloak.realm.client-keystore=n/a
keycloak.realm.client-keystore-password=n/a
keycloak.realm.client-key-password=n/a
keycloak.realm.cors-max-age=CORS max-age header
keycloak.realm.cors-allowed-headers=CORS allowed headers
keycloak.realm.cors-allowed-methods=CORS allowed methods
keycloak.realm.expose-token=Enable secure URL that exposes access token
keycloak.realm.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.realm.always-refresh-token=Refresh token on every single web request
keycloak.realm.register-node-at-startup=Cluster setting
keycloak.realm.register-node-period=how often to re-register node
keycloak.realm.token-store=cookie or session storage for auth session data
keycloak.realm.principal-attribute=token attribute to use to set Principal name
keycloak.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
keycloak.secure-deployment.realm=Keycloak realm
keycloak.secure-deployment.remove=Remove a deployment to be secured by Keycloak
keycloak.secure-deployment.realm-public-key=Public key of the realm
keycloak.secure-deployment.auth-server-url=Base URL of the Realm Auth Server
keycloak.secure-deployment.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
keycloak.secure-deployment.ssl-required=Specify if SSL is required (valid values are all, external and none)
keycloak.secure-deployment.allow-any-hostname=SSL Setting
keycloak.secure-deployment.truststore=Truststore used for adapter client HTTPS requests
keycloak.secure-deployment.truststore-password=Password of the Truststore
keycloak.secure-deployment.connection-pool-size=Connection pool size for the client used by the adapter
keycloak.secure-deployment.resource=Application name
keycloak.secure-deployment.use-resource-role-mappings=Use resource level permissions from token
keycloak.secure-deployment.credentials=Adapter credentials
keycloak.secure-deployment.bearer-only=Bearer Token Auth only
keycloak.secure-deployment.enable-basic-auth=Enable Basic Authentication
keycloak.secure-deployment.public-client=Public client
keycloak.secure-deployment.enable-cors=Enable Keycloak CORS support
keycloak.secure-deployment.client-keystore=n/a
keycloak.secure-deployment.client-keystore-password=n/a
keycloak.secure-deployment.client-key-password=n/a
keycloak.secure-deployment.cors-max-age=CORS max-age header
keycloak.secure-deployment.cors-allowed-headers=CORS allowed headers
keycloak.secure-deployment.cors-allowed-methods=CORS allowed methods
keycloak.secure-deployment.expose-token=Enable secure URL that exposes access token
keycloak.secure-deployment.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.secure-deployment.always-refresh-token=Refresh token on every single web request
keycloak.secure-deployment.register-node-at-startup=Cluster setting
keycloak.secure-deployment.register-node-period=how often to re-register node
keycloak.secure-deployment.token-store=cookie or session storage for auth session data
keycloak.secure-deployment.principal-attribute=token attribute to use to set Principal name
keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
keycloak.secure-deployment.credential=Credential value
keycloak.credential=Credential
keycloak.credential.value=Credential value
keycloak.credential.add=Credential add
keycloak.credential.remove=Credential remove
@@ -1,88 +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.subsystem.as7;
import org.jboss.dmr.ModelNode;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
public class RealmDefinitionTestCase {
private ModelNode model;
@Before
public void setUp() {
model = new ModelNode();
model.get("realm").set("demo");
model.get("resource").set("customer-portal");
model.get("realm-public-key").set("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB");
model.get("auth-url").set("http://localhost:8080/auth-server/realms/demo/protocol/openid-connect/login");
model.get("code-url").set("http://localhost:8080/auth-server/realms/demo/protocol/openid-connect/access/codes");
model.get("expose-token").set(true);
ModelNode credential = new ModelNode();
credential.get("password").set("password");
model.get("credentials").set(credential);
}
@Test
public void testIsTruststoreSetIfRequired() throws Exception {
model.get("ssl-required").set("none");
model.get("disable-trust-manager").set(true);
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-required").set("none");
model.get("disable-trust-manager").set(false);
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-required").set("all");
model.get("disable-trust-manager").set(true);
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-required").set("all");
model.get("disable-trust-manager").set(false);
Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-required").set("external");
model.get("disable-trust-manager").set(false);
Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-required").set("all");
model.get("disable-trust-manager").set(false);
model.get("truststore").set("foo");
Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-required").set("all");
model.get("disable-trust-manager").set(false);
model.get("truststore").set("foo");
model.get("truststore-password").set("password");
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
model.get("ssl-required").set("external");
model.get("disable-trust-manager").set(false);
model.get("truststore").set("foo");
model.get("truststore-password").set("password");
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
}
}
-38
View File
@@ -1,38 +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.
-->
<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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
<description/>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-as7-integration-pom</artifactId>
<packaging>pom</packaging>
<modules>
<module>as7-adapter-spi</module>
<module>as7-adapter</module>
<module>as7-subsystem</module>
</modules>
</project>
-81
View File
@@ -1,81 +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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-installed-adapter</artifactId>
<name>Keycloak Installed Application</name>
<description/>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</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>
</plugins>
</build>
</project>
-103
View File
@@ -1,103 +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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-jaxrs-oauth-client</artifactId>
<name>Keycloak JAX-RS OAuth Client</name>
<description/>
<dependencies>
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</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>
</plugins>
</build>
</project>
@@ -1,31 +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.jaxrs;
import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@PreMatching
@Priority(Priorities.AUTHENTICATION)
public interface JaxrsBearerTokenFilter extends ContainerRequestFilter {
}
@@ -1,214 +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.jaxrs;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import javax.security.cert.X509Certificate;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.SecurityContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.AuthenticationError;
import org.keycloak.adapters.spi.LogoutError;
import org.keycloak.common.util.HostUtils;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class JaxrsHttpFacade implements OIDCHttpFacade {
protected final ContainerRequestContext requestContext;
protected final SecurityContext securityContext;
protected final RequestFacade requestFacade = new RequestFacade();
protected final ResponseFacade responseFacade = new ResponseFacade();
protected KeycloakSecurityContext keycloakSecurityContext;
protected boolean responseFinished;
public JaxrsHttpFacade(ContainerRequestContext containerRequestContext, SecurityContext securityContext) {
this.requestContext = containerRequestContext;
this.securityContext = securityContext;
}
protected class RequestFacade implements OIDCHttpFacade.Request {
@Override
public String getFirstParam(String param) {
throw new RuntimeException("NOT IMPLEMENTED");
}
@Override
public String getMethod() {
return requestContext.getMethod();
}
@Override
public String getURI() {
return requestContext.getUriInfo().getRequestUri().toString();
}
@Override
public boolean isSecure() {
return securityContext.isSecure();
}
@Override
public String getQueryParamValue(String param) {
MultivaluedMap<String, String> queryParams = requestContext.getUriInfo().getQueryParameters();
if (queryParams == null)
return null;
return queryParams.getFirst(param);
}
@Override
public Cookie getCookie(String cookieName) {
Map<String, javax.ws.rs.core.Cookie> cookies = requestContext.getCookies();
if (cookies == null)
return null;
javax.ws.rs.core.Cookie cookie = cookies.get(cookieName);
if (cookie == null)
return null;
return new Cookie(cookie.getName(), cookie.getValue(), cookie.getVersion(), cookie.getDomain(), cookie.getPath());
}
@Override
public String getHeader(String name) {
return requestContext.getHeaderString(name);
}
@Override
public List<String> getHeaders(String name) {
MultivaluedMap<String, String> headers = requestContext.getHeaders();
return (headers == null) ? null : headers.get(name);
}
@Override
public InputStream getInputStream() {
return requestContext.getEntityStream();
}
@Override
public String getRemoteAddr() {
// TODO: implement properly
return HostUtils.getIpAddress();
}
@Override
public void setError(AuthenticationError error) {
requestContext.setProperty(AuthenticationError.class.getName(), error);
}
@Override
public void setError(LogoutError error) {
requestContext.setProperty(LogoutError.class.getName(), error);
}
}
protected class ResponseFacade implements OIDCHttpFacade.Response {
private javax.ws.rs.core.Response.ResponseBuilder responseBuilder = javax.ws.rs.core.Response.status(204);
@Override
public void setStatus(int status) {
responseBuilder.status(status);
}
@Override
public void addHeader(String name, String value) {
responseBuilder.header(name, value);
}
@Override
public void setHeader(String name, String value) {
responseBuilder.header(name, value);
}
@Override
public void resetCookie(String name, String path) {
// For now doesn't need to be supported
throw new IllegalStateException("Not supported yet");
}
@Override
public void setCookie(String name, String value, String path, String domain, int maxAge, boolean secure, boolean httpOnly) {
// For now doesn't need to be supported
throw new IllegalStateException("Not supported yet");
}
@Override
public OutputStream getOutputStream() {
// For now doesn't need to be supported
throw new IllegalStateException("Not supported yet");
}
@Override
public void sendError(int code) {
javax.ws.rs.core.Response response = responseBuilder.status(code).build();
requestContext.abortWith(response);
responseFinished = true;
}
@Override
public void sendError(int code, String message) {
javax.ws.rs.core.Response response = responseBuilder.status(code).entity(message).build();
requestContext.abortWith(response);
responseFinished = true;
}
@Override
public void end() {
javax.ws.rs.core.Response response = responseBuilder.build();
requestContext.abortWith(response);
responseFinished = true;
}
}
@Override
public KeycloakSecurityContext getSecurityContext() {
return keycloakSecurityContext;
}
public void setSecurityContext(KeycloakSecurityContext securityContext) {
this.keycloakSecurityContext = securityContext;
}
@Override
public Request getRequest() {
return requestFacade;
}
@Override
public Response getResponse() {
return responseFacade;
}
@Override
public X509Certificate[] getCertificateChain() {
throw new IllegalStateException("Not supported yet");
}
public boolean isResponseFinished() {
return responseFinished;
}
}
-160
View File
@@ -1,160 +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>1.9.6.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-jetty-core</artifactId>
<name>Keycloak Jetty Core Integration</name>
<properties>
<jetty9.version>8.1.17.v20150415</jetty9.version>
<keycloak.osgi.export>
org.keycloak.adapters.jetty.core.*
</keycloak.osgi.export>
<keycloak.osgi.import>
org.eclipse.jetty.*;version="[8.1,10)";resolution:=optional,
javax.servlet.*;version="[2.5,4)";resolution:=optional,
org.keycloak.*;version="${project.version}",
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<description />
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</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>
</project>
@@ -1,125 +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.jetty.core;
import org.eclipse.jetty.server.Request;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.spi.AdapterSessionStore;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OidcKeycloakAccount;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
import javax.servlet.http.HttpSession;
/**
* Handle storage of token info in HTTP Session. Per-request object
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class JettySessionTokenStore implements AdapterTokenStore {
private static final Logger log = Logger.getLogger(JettySessionTokenStore.class);
private Request request;
protected KeycloakDeployment deployment;
protected AdapterSessionStore sessionStore;
public JettySessionTokenStore(Request request, KeycloakDeployment deployment, AdapterSessionStore sessionStore) {
this.request = request;
this.deployment = deployment;
this.sessionStore = sessionStore;
}
@Override
public void checkCurrentToken() {
if (request.getSession(false) == null) return;
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) request.getSession().getAttribute(KeycloakSecurityContext.class.getName());
if (session == null) return;
// just in case session got serialized
if (session.getDeployment() == null) session.setCurrentRequestInfo(deployment, this);
if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
// not be updated
boolean success = session.refreshExpiredToken(false);
if (success && session.isActive()) return;
// Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
request.getSession().removeAttribute(KeycloakSecurityContext.class.getName());
request.getSession().invalidate();
}
@Override
public boolean isCached(RequestAuthenticator authenticator) {
if (request.getSession(false) == null || request.getSession().getAttribute(KeycloakSecurityContext.class.getName()) == null)
return false;
log.debug("remote logged in already. Establish state from session");
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) request.getSession().getAttribute(KeycloakSecurityContext.class.getName());
if (!deployment.getRealm().equals(securityContext.getRealm())) {
log.debug("Account from cookie is from a different realm than for the request.");
return false;
}
securityContext.setCurrentRequestInfo(deployment, this);
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
JettyRequestAuthenticator jettyAuthenticator = (JettyRequestAuthenticator) authenticator;
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = AdapterUtils.createPrincipal(deployment, securityContext);
jettyAuthenticator.principal = principal;
restoreRequest();
return true;
}
@Override
public void saveAccountInfo(OidcKeycloakAccount account) {
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) account.getKeycloakSecurityContext();
request.getSession().setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
}
@Override
public void logout() {
HttpSession session = request.getSession(false);
if (session != null) {
session.removeAttribute(KeycloakSecurityContext.class.getName());
}
}
@Override
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
// no-op
}
@Override
public void saveRequest() {
sessionStore.saveRequest();
}
@Override
public boolean restoreRequest() {
return sessionStore.restoreRequest();
}
}
@@ -1,41 +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.jetty.core;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import javax.servlet.http.HttpServletResponse;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OIDCJettyHttpFacade extends JettyHttpFacade implements OIDCHttpFacade {
public OIDCJettyHttpFacade(org.eclipse.jetty.server.Request request, HttpServletResponse response) {
super(request, response);
}
@Override
public KeycloakSecurityContext getSecurityContext() {
return (KeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName());
}
}
-159
View File
@@ -1,159 +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>1.9.6.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-jetty81-adapter</artifactId>
<name>Keycloak Jetty 8.1.x Integration</name>
<properties>
<jetty9.version>8.1.17.v20150415</jetty9.version>
<keycloak.osgi.export>
org.keycloak.adapters.jetty.*
</keycloak.osgi.export>
<keycloak.osgi.import>
javax.servlet.*;version="[2.5,4)";resolution:=optional,
org.keycloak.*;version="${project.version}",
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<description />
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</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>
</project>
@@ -1,111 +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.jetty;
import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.spi.AdapterSessionStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import org.keycloak.common.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JettyAdapterSessionStore implements AdapterSessionStore {
public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
protected Request myRequest;
public JettyAdapterSessionStore(Request request) {
this.myRequest = request; // for IDE/compilation purposes
}
protected MultiMap<String> extractFormParameters(Request base_request) {
MultiMap<String> formParameters = new MultiMap<String>();
base_request.extractParameters();
return base_request.getParameters();
}
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
base_request.setParameters(j_post);
}
public boolean restoreRequest() {
HttpSession session = myRequest.getSession(false);
if (session == null) return false;
synchronized (session) {
String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
if (j_uri != null) {
// check if the request is for the same url as the original and restore
// params if it was a post
StringBuffer buf = myRequest.getRequestURL();
if (myRequest.getQueryString() != null)
buf.append("?").append(myRequest.getQueryString());
if (j_uri.equals(buf.toString())) {
String method = (String)session.getAttribute(JettyHttpFacade.__J_METHOD);
myRequest.setMethod(method);
MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
if (j_post != null) {
myRequest.setContentType("application/x-www-form-urlencoded");
MultiMap<String> map = new MultiMap<String>();
for (String key : j_post.keySet()) {
for (String val : j_post.getList(key)) {
map.add(key, val);
}
}
restoreFormParameters(map, myRequest);
}
session.removeAttribute(FormAuthenticator.__J_URI);
session.removeAttribute(JettyHttpFacade.__J_METHOD);
session.removeAttribute(FormAuthenticator.__J_POST);
}
return true;
}
}
return false;
}
public void saveRequest() {
// remember the current URI
HttpSession session = myRequest.getSession();
synchronized (session) {
// But only if it is not set already, or we save every uri that leads to a login form redirect
if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
StringBuffer buf = myRequest.getRequestURL();
if (myRequest.getQueryString() != null)
buf.append("?").append(myRequest.getQueryString());
session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
session.setAttribute(JettyHttpFacade.__J_METHOD, myRequest.getMethod());
if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
MultiMap<String> formParameters = extractFormParameters(myRequest);
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
for (String key : formParameters.keySet()) {
for (Object value : formParameters.getValues(key)) {
map.add(key, (String) value);
}
}
session.setAttribute(CACHED_FORM_PARAMETERS, map);
}
}
}
}
}
@@ -1,63 +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.jetty;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
import javax.servlet.ServletRequest;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticator {
public KeycloakJettyAuthenticator() {
super();
}
@Override
public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
}
@Override
protected Request resolveRequest(ServletRequest req) {
return (req instanceof Request)?(Request)req: AbstractHttpConnection.getCurrentConnection().getRequest();
}
@Override
protected Authentication createAuthentication(UserIdentity userIdentity) {
return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
@Override
public void logout() {
logoutCurrent(AbstractHttpConnection.getCurrentConnection().getRequest());
}
};
}
}
-170
View File
@@ -1,170 +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>1.9.6.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-jetty91-adapter</artifactId>
<name>Keycloak Jetty 9.1.x Integration</name>
<properties>
<jetty9.version>9.1.5.v20140505</jetty9.version>
<keycloak.osgi.export>
org.keycloak.adapters.jetty.*
</keycloak.osgi.export>
<keycloak.osgi.import>
org.eclipse.jetty.*;version="[9.1,9.2)";resolution:=optional,
javax.servlet.*;version="[3.0,4)";resolution:=optional,
org.keycloak.*;version="${project.version}",
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<description />
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</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>
</project>
@@ -1,47 +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.jetty;
import org.eclipse.jetty.server.Request;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.spi.HttpFacade;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Jetty91RequestAuthenticator extends JettyRequestAuthenticator {
public Jetty91RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort, Request request) {
super(facade, deployment, tokenStore, sslRedirectPort, request);
}
@Override
protected String changeHttpSessionId(boolean create) {
Request request = this.request;
HttpSession session = request.getSession(false);
if (session == null) {
return request.getSession(true).getId();
}
if (!deployment.isTurnOffChangeSessionIdOnLogin()) return request.changeSessionId();
else return session.getId();
}
}
@@ -1,111 +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.jetty;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.spi.AdapterSessionStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import org.keycloak.common.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JettyAdapterSessionStore implements AdapterSessionStore {
public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
protected Request myRequest;
public JettyAdapterSessionStore(Request request) {
this.myRequest = request; // for IDE/compilation purposes
}
protected MultiMap<String> extractFormParameters(Request base_request) {
base_request.extractParameters();
return base_request.getParameters();
}
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
base_request.setParameters(j_post);
}
public boolean restoreRequest() {
HttpSession session = myRequest.getSession(false);
if (session == null) return false;
synchronized (session) {
String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
if (j_uri != null) {
// check if the request is for the same url as the original and restore
// params if it was a post
StringBuffer buf = myRequest.getRequestURL();
if (myRequest.getQueryString() != null)
buf.append("?").append(myRequest.getQueryString());
if (j_uri.equals(buf.toString())) {
String method = (String)session.getAttribute(JettyHttpFacade.__J_METHOD);
myRequest.setMethod(HttpMethod.valueOf(method.toUpperCase()), method);
MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
if (j_post != null) {
myRequest.setContentType("application/x-www-form-urlencoded");
MultiMap<String> map = new MultiMap<String>();
for (String key : j_post.keySet()) {
for (String val : j_post.getList(key)) {
map.add(key, val);
}
}
restoreFormParameters(map, myRequest);
}
session.removeAttribute(FormAuthenticator.__J_URI);
session.removeAttribute(JettyHttpFacade.__J_METHOD);
session.removeAttribute(FormAuthenticator.__J_POST);
}
return true;
}
}
return false;
}
public void saveRequest() {
// remember the current URI
HttpSession session = myRequest.getSession();
synchronized (session) {
// But only if it is not set already, or we save every uri that leads to a login form redirect
if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
StringBuffer buf = myRequest.getRequestURL();
if (myRequest.getQueryString() != null)
buf.append("?").append(myRequest.getQueryString());
session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
session.setAttribute(JettyHttpFacade.__J_METHOD, myRequest.getMethod());
if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
MultiMap<String> formParameters = extractFormParameters(myRequest);
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
for (String key : formParameters.keySet()) {
for (Object value : formParameters.getValues(key)) {
map.add(key, (String) value);
}
}
session.setAttribute(CACHED_FORM_PARAMETERS, map);
}
}
}
}
}
@@ -1,72 +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.jetty;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import javax.servlet.ServletRequest;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticator {
public KeycloakJettyAuthenticator() {
super();
}
@Override
public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
}
@Override
protected Request resolveRequest(ServletRequest req) {
return (req instanceof Request) ? (Request)req : HttpChannel.getCurrentHttpChannel().getRequest();
}
@Override
protected Authentication createAuthentication(UserIdentity userIdentity) {
return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
@Override
public void logout() {
logoutCurrent(HttpChannel.getCurrentHttpChannel().getRequest());
}
};
}
@Override
protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade,
KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
return new Jetty91RequestAuthenticator(facade, deployment, tokenStore, -1, request);
}
}
-156
View File
@@ -1,156 +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>1.9.6.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-jetty92-adapter</artifactId>
<name>Keycloak Jetty 9.2.x Integration</name>
<properties>
<jetty9.version>9.2.4.v20141103</jetty9.version>
<keycloak.osgi.export>
org.keycloak.adapters.jetty.*
</keycloak.osgi.export>
<keycloak.osgi.import>
org.eclipse.jetty.*;resolution:=optional,
javax.servlet.*;version="[3.0,4)";resolution:=optional,
org.keycloak.*;version="${project.version}",
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<description />
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</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>
</project>
@@ -1,47 +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.jetty;
import org.eclipse.jetty.server.Request;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.spi.HttpFacade;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Jetty92RequestAuthenticator extends JettyRequestAuthenticator {
public Jetty92RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort, Request request) {
super(facade, deployment, tokenStore, sslRedirectPort, request);
}
@Override
protected String changeHttpSessionId(boolean create) {
Request request = this.request;
HttpSession session = request.getSession(false);
if (session == null) {
return request.getSession(true).getId();
}
if (!deployment.isTurnOffChangeSessionIdOnLogin()) return request.changeSessionId();
else return session.getId();
}
}
@@ -1,112 +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.jetty;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.spi.AdapterSessionStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import org.keycloak.common.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JettyAdapterSessionStore implements AdapterSessionStore {
public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
protected Request myRequest;
public JettyAdapterSessionStore(Request request) {
this.myRequest = request; // for IDE/compilation purposes
}
protected MultiMap<String> extractFormParameters(Request base_request) {
MultiMap<String> formParameters = new MultiMap<String>();
base_request.extractFormParameters(formParameters);
return formParameters;
}
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
base_request.setContentParameters(j_post);
}
public boolean restoreRequest() {
HttpSession session = myRequest.getSession(false);
if (session == null) return false;
synchronized (session) {
String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
if (j_uri != null) {
// check if the request is for the same url as the original and restore
// params if it was a post
StringBuffer buf = myRequest.getRequestURL();
if (myRequest.getQueryString() != null)
buf.append("?").append(myRequest.getQueryString());
if (j_uri.equals(buf.toString())) {
String method = (String)session.getAttribute(JettyHttpFacade.__J_METHOD);
myRequest.setMethod(HttpMethod.valueOf(method.toUpperCase()), method);
MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
if (j_post != null) {
myRequest.setContentType("application/x-www-form-urlencoded");
MultiMap<String> map = new MultiMap<String>();
for (String key : j_post.keySet()) {
for (String val : j_post.getList(key)) {
map.add(key, val);
}
}
restoreFormParameters(map, myRequest);
}
session.removeAttribute(FormAuthenticator.__J_URI);
session.removeAttribute(JettyHttpFacade.__J_METHOD);
session.removeAttribute(FormAuthenticator.__J_POST);
}
return true;
}
}
return false;
}
public void saveRequest() {
// remember the current URI
HttpSession session = myRequest.getSession();
synchronized (session) {
// But only if it is not set already, or we save every uri that leads to a login form redirect
if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
StringBuffer buf = myRequest.getRequestURL();
if (myRequest.getQueryString() != null)
buf.append("?").append(myRequest.getQueryString());
session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
session.setAttribute(JettyHttpFacade.__J_METHOD, myRequest.getMethod());
if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
MultiMap<String> formParameters = extractFormParameters(myRequest);
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
for (String key : formParameters.keySet()) {
for (Object value : formParameters.getValues(key)) {
map.add(key, (String) value);
}
}
session.setAttribute(CACHED_FORM_PARAMETERS, map);
}
}
}
}
}
@@ -1,70 +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.jetty;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import javax.servlet.ServletRequest;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticator {
public KeycloakJettyAuthenticator() {
super();
}
@Override
protected Request resolveRequest(ServletRequest req) {
return (req instanceof Request) ? (Request)req : HttpChannel.getCurrentHttpChannel().getRequest();
}
@Override
protected Authentication createAuthentication(UserIdentity userIdentity) {
return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
@Override
public void logout() {
logoutCurrent(HttpChannel.getCurrentHttpChannel().getRequest());
}
};
}
@Override
public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
}
@Override
protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade,
KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
return new Jetty92RequestAuthenticator(facade, deployment, tokenStore, -1, request);
}
}
-39
View File
@@ -1,39 +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.
-->
<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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Jetty Integration</name>
<description/>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-jetty-integration-pom</artifactId>
<packaging>pom</packaging>
<modules>
<module>jetty-core</module>
<module>jetty8.1</module>
<module>jetty9.2</module>
<module>jetty9.1</module>
</modules>
</project>
-66
View File
@@ -1,66 +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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-js-adapter</artifactId>
<name>Keycloak JS Integration</name>
<description />
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.samaxes.maven</groupId>
<artifactId>minify-maven-plugin</artifactId>
<executions>
<execution>
<id>min-js</id>
<phase>compile</phase>
<configuration>
<charset>utf-8</charset>
<webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
<jsSourceDir>.</jsSourceDir>
<jsSourceFiles>
<jsSourceFile>keycloak.js</jsSourceFile>
</jsSourceFiles>
<webappTargetDir>${project.build.directory}/classes</webappTargetDir>
<jsTargetDir>.</jsTargetDir>
<jsFinalFile>keycloak.js</jsFinalFile>
</configuration>
<goals>
<goal>minify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
File diff suppressed because it is too large. Load diff
@@ -1,49 +0,0 @@
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<script>
function getCookie(cname)
{
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++)
{
var c = ca[i].trim();
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return null;
}
function receiveMessage(event)
{
if (event.origin !== "ORIGIN") {
console.log(event.origin + " does not match built origin");
return;
}
var data = JSON.parse(event.data);
data.loggedIn = false;
var cookie = getCookie('KEYCLOAK_SESSION');
if (cookie) {
data.loggedIn = true;
data.session = cookie;
}
event.source.postMessage(JSON.stringify(data),
event.origin);
}
window.addEventListener("message", receiveMessage, false);
</script>
-149
View File
@@ -1,149 +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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-osgi-adapter</artifactId>
<name>Keycloak OSGI Adapter</name>
<packaging>jar</packaging>
<properties>
<jetty9.version>8.1.17.v20150415</jetty9.version>
<keycloak.osgi.export>
org.keycloak.adapters.osgi.*
</keycloak.osgi.export>
<keycloak.osgi.import>
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}",
org.apache.cxf.transport.http;resolution:=optional;version="[3,4)",
org.apache.cxf.transport.servlet;resolution:=optional;version="[3,4)",
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
<scope>provided</scope>
</dependency>
<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-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.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-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>
</project>
@@ -1,71 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.osgi;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.OIDCHttpFacade;
public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
private final Map<String, KeycloakDeployment> cache = new ConcurrentHashMap<String, KeycloakDeployment>();
@Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
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
String keycloakConfig = (String) System.getProperties().get("keycloak.config");
if(keycloakConfig == null || "".equals(keycloakConfig.trim())){
String karafEtc = (String) System.getProperties().get("karaf.etc");
if(karafEtc == null || "".equals(karafEtc.trim())){
throw new IllegalStateException("Neither \"keycloak.config\" nor \"karaf.etc\" java properties are set. Please set one of them.");
}
keycloakConfig = karafEtc;
}
String absolutePath = keycloakConfig + File.separator + webContext + "-keycloak.json";
InputStream is = null;
try {
is = new FileInputStream(absolutePath);
} catch (FileNotFoundException e){
throw new IllegalStateException("Not able to find the file " + absolutePath);
}
deployment = KeycloakDeploymentBuilder.build(is);
cache.put(webContext, deployment);
}
return deployment;
}
}
@@ -1,255 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.osgi;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import javax.servlet.Servlet;
import org.apache.cxf.transport.http.DestinationRegistry;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
import org.jboss.logging.Logger;
import org.ops4j.pax.web.service.WebContainer;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.http.HttpContext;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* Service, which allows to remove previously registered servlets in karaf/fuse environment. It assumes that particular servlet was previously
* registered as service in OSGI container under {@link javax.servlet.Servlet} interface.
*
* <p>The point is to register automatically registered builtin servlet endpoints (like "/cxf" for instance) to allow secure them
* by Keycloak and re-register them again</p>
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ServletReregistrationService {
private static final String CXF_SERVLET_PREFIX = "org.apache.cxf.servlet.";
protected static final Logger log = Logger.getLogger(ServletReregistrationService.class);
private static final List<String> FILTERED_PROPERTIES = Arrays.asList("objectClass", "service.id");
private BundleContext bundleContext;
private ServiceReference managedServiceReference;
private ServiceTracker webContainerTracker;
private String alias;
public BundleContext getBundleContext() {
return bundleContext;
}
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public void start() {
if ( managedServiceReference == null) {
return;
}
Dictionary properties = obtainProperties();
alias = (String)getProp(properties, CXF_SERVLET_PREFIX + "context", "/cxf");
if(alias == null){
alias = "/cxf";
}
WebContainer externalWebContainer = findExternalWebContainer();
if (externalWebContainer == null) {
return;
}
// Unregister servlet from external container now
try {
externalWebContainer.unregister(alias);
log.debug("Original servlet with alias " + getAlias() + " unregistered successfully from external web container.");
} catch (IllegalStateException e) {
log.warn("Can't unregister servlet due to: " + e.getMessage());
}
final Dictionary finalProperties = properties;
ServiceTrackerCustomizer trackerCustomizer = new ServiceTrackerCustomizer() {
@Override
public Object addingService(ServiceReference webContainerServiceReference) {
WebContainer ourWebContainer = (WebContainer) bundleContext.getService(webContainerServiceReference);
registerServlet(ourWebContainer, finalProperties);
log.debugv("Servlet with alias " + getAlias() + " registered to secured web container");
return ourWebContainer;
}
@Override
public void modifiedService(ServiceReference reference, Object service) {
}
@Override
public void removedService(ServiceReference webContainerServiceReference, Object service) {
WebContainer ourWebContainer = (WebContainer) bundleContext.getService(webContainerServiceReference);
String alias = getAlias();
ourWebContainer.unregister(alias);
log.debug("Servlet with alias " + getAlias() + " unregistered from secured web container");
}
};
webContainerTracker = new ServiceTracker(bundleContext, WebContainer.class.getName(), trackerCustomizer);
webContainerTracker.open();
}
public void stop() {
// Stop tracking our container now and removing reference. This should unregister servlet from our container via trackerCustomizer.removedService (if it's not already unregistered)
webContainerTracker.remove(webContainerTracker.getServiceReference());
// Re-register servlet back to original context
WebContainer externalWebContainer = findExternalWebContainer();
registerServlet(externalWebContainer, obtainProperties());
log.debug("Servlet with alias " + getAlias() + " registered back to external web container");
}
private String getAlias() {
return alias;
}
/**
* Code comes from org.apache.cxf.transport.http.osgi.ServletExporter#updated(java.util.Dictionary)
* @param webContainer
* @param properties
*/
protected void registerServlet(WebContainer webContainer, Dictionary properties) {
HttpContext httpContext = webContainer.createDefaultHttpContext();
ServiceReference destinationServiceServiceReference = bundleContext.getServiceReference("org.apache.cxf.transport.http.DestinationRegistry");
DestinationRegistry destinationRegistry = (DestinationRegistry) bundleContext.getService(destinationServiceServiceReference);
Servlet servlet = new CXFNonSpringServlet(destinationRegistry, false);
try {
if (properties == null) {
properties = new Properties();
}
Properties sprops = new Properties();
sprops.put("init-prefix",
getProp(properties, CXF_SERVLET_PREFIX + "init-prefix", ""));
sprops.put("servlet-name",
getProp(properties, CXF_SERVLET_PREFIX + "name", "cxf-osgi-transport-servlet"));
sprops.put("hide-service-list-page",
getProp(properties, CXF_SERVLET_PREFIX + "hide-service-list-page", "false"));
sprops.put("disable-address-updates",
getProp(properties, CXF_SERVLET_PREFIX + "disable-address-updates", "true"));
sprops.put("base-address",
getProp(properties, CXF_SERVLET_PREFIX + "base-address", ""));
sprops.put("service-list-path",
getProp(properties, CXF_SERVLET_PREFIX + "service-list-path", ""));
sprops.put("static-resources-list",
getProp(properties, CXF_SERVLET_PREFIX + "static-resources-list", ""));
sprops.put("redirects-list",
getProp(properties, CXF_SERVLET_PREFIX + "redirects-list", ""));
sprops.put("redirect-servlet-name",
getProp(properties, CXF_SERVLET_PREFIX + "redirect-servlet-name", ""));
sprops.put("redirect-servlet-path",
getProp(properties, CXF_SERVLET_PREFIX + "redirect-servlet-path", ""));
sprops.put("service-list-all-contexts",
getProp(properties, CXF_SERVLET_PREFIX + "service-list-all-contexts", ""));
sprops.put("service-list-page-authenticate",
getProp(properties, CXF_SERVLET_PREFIX + "service-list-page-authenticate", "false"));
sprops.put("service-list-page-authenticate-realm",
getProp(properties, CXF_SERVLET_PREFIX + "service-list-page-authenticate-realm", "karaf"));
sprops.put("use-x-forwarded-headers",
getProp(properties, CXF_SERVLET_PREFIX + "use-x-forwarded-headers", "false"));
// Accept extra properties by default, can be disabled if it is really needed
if (Boolean.valueOf(getProp(properties, CXF_SERVLET_PREFIX + "support.extra.properties", "true").toString())) {
Enumeration keys = properties.keys();
while (keys.hasMoreElements()) {
String nextKey = keys.nextElement().toString();
if (!nextKey.startsWith(CXF_SERVLET_PREFIX)) {
sprops.put(nextKey, properties.get(nextKey));
}
}
}
Hashtable<String, Object> servletInitParams = new Hashtable<String, Object>();
Enumeration keys = sprops.keys();
while(keys.hasMoreElements()){
String propName = (String) keys.nextElement();
if (!FILTERED_PROPERTIES.contains(propName)) {
servletInitParams.put(propName, sprops.getProperty(propName));
}
}
// Try to register servlet in given web container now
webContainer.registerServlet(alias, servlet, servletInitParams, httpContext);
} catch (Exception e) {
log.error("Can't register servlet in web container", e);
}
}
/**
* Find web container in the bundle, where was servlet originally registered
*
* @return web container or null
*/
protected WebContainer findExternalWebContainer() {
BundleContext servletBundleContext = managedServiceReference.getBundle().getBundleContext();
ServiceReference webContainerReference = servletBundleContext.getServiceReference(WebContainer.class.getName());
if (webContainerReference == null) {
log.warn("Not found webContainer reference for bundle " + servletBundleContext);
return null;
} else {
return (WebContainer) servletBundleContext.getService(webContainerReference);
}
}
private Dictionary obtainProperties(){
Dictionary properties = null;
ServiceReference reference = bundleContext.getServiceReference(ConfigurationAdmin.class.getName());
ConfigurationAdmin admin = (ConfigurationAdmin) bundleContext.getService(reference);
try {
Configuration configuration = admin.getConfiguration("org.apache.cxf.osgi");
properties = configuration.getProperties();
} catch (Exception e){
log.warn("Unable to obtain cxf osgi configadmin reference.", e);
}
return properties;
}
private Object getProp(Dictionary properties, String key, Object defaultValue) {
Object value = null;
if(properties != null){
value = properties.get(key);
}
return value == null ? defaultValue : value;
}
public ServiceReference getManagedServiceReference() {
return managedServiceReference;
}
public void setManagedServiceReference(ServiceReference managedServiceReference) {
this.managedServiceReference = managedServiceReference;
}
}
-49
View File
@@ -1,49 +0,0 @@
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<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>1.9.6.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak OIDC Client Adapter Modules</name>
<description/>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-oidc-client-adapter-pom</artifactId>
<packaging>pom</packaging>
<modules>
<module>adapter-core</module>
<module>as7-eap6</module>
<module>installed</module>
<module>jaxrs-oauth-client</module>
<module>jetty</module>
<module>js</module>
<module>osgi-adapter</module>
<module>servlet-filter</module>
<module>servlet-oauth-client</module>
<module>spring-boot</module>
<module>spring-security</module>
<module>tomcat</module>
<module>undertow</module>
<module>wildfly</module>
</modules>
</project>
-100
View File
@@ -1,100 +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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-servlet-filter-adapter</artifactId>
<name>Keycloak Servlet Filter Adapter Integration</name>
<description/>
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-servlet-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</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>
</plugins>
</build>
</project>
@@ -1,124 +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.servlet;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OAuthRequestAuthenticator;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.OidcKeycloakAccount;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
import org.keycloak.adapters.spi.KeycloakAccount;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.Principal;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
* @version $Revision: 1 $
*/
public class FilterRequestAuthenticator extends RequestAuthenticator {
private static final Logger log = Logger.getLogger(""+FilterRequestAuthenticator.class);
protected HttpServletRequest request;
public FilterRequestAuthenticator(KeycloakDeployment deployment,
AdapterTokenStore tokenStore,
OIDCHttpFacade facade,
HttpServletRequest request,
int sslRedirectPort) {
super(facade, deployment, tokenStore, sslRedirectPort);
this.request = request;
}
@Override
protected OAuthRequestAuthenticator createOAuthAuthenticator() {
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort, tokenStore);
}
@Override
protected void completeOAuthAuthentication(final KeycloakPrincipal<RefreshableKeycloakSecurityContext> skp) {
final RefreshableKeycloakSecurityContext securityContext = skp.getKeycloakSecurityContext();
final Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
OidcKeycloakAccount account = new OidcKeycloakAccount() {
@Override
public Principal getPrincipal() {
return skp;
}
@Override
public Set<String> getRoles() {
return roles;
}
@Override
public KeycloakSecurityContext getKeycloakSecurityContext() {
return securityContext;
}
};
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
this.tokenStore.saveAccountInfo(account);
}
@Override
protected void completeBearerAuthentication(final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
final RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
final Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
if (log.isLoggable(Level.FINE)) {
log.fine("Completing bearer authentication. Bearer roles: " + roles);
}
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
OidcKeycloakAccount account = new OidcKeycloakAccount() {
@Override
public Principal getPrincipal() {
return principal;
}
@Override
public Set<String> getRoles() {
return roles;
}
@Override
public KeycloakSecurityContext getKeycloakSecurityContext() {
return securityContext;
}
};
// need this here to obtain UserPrincipal
request.setAttribute(KeycloakAccount.class.getName(), account);
}
@Override
protected String changeHttpSessionId(boolean create) {
HttpSession session = request.getSession(create);
return session != null ? session.getId() : null;
}
}
@@ -1,178 +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.servlet;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.AuthenticatedActionsHandler;
import org.keycloak.adapters.spi.InMemorySessionIdMapper;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.NodesRegistrationManagement;
import org.keycloak.adapters.PreAuthActionsHandler;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.spi.UserSessionManagement;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakOIDCFilter implements Filter {
protected AdapterDeploymentContext deploymentContext;
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
protected NodesRegistrationManagement nodesRegistrationManagement;
private final static Logger log = Logger.getLogger(""+KeycloakOIDCFilter.class);
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
String configResolverClass = filterConfig.getInitParameter("keycloak.config.resolver");
if (configResolverClass != null) {
try {
KeycloakConfigResolver configResolver = (KeycloakConfigResolver) getClass().getClassLoader().loadClass(configResolverClass).newInstance();
deploymentContext = new AdapterDeploymentContext(configResolver);
log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
} catch (Exception ex) {
log.log(Level.FINE, "The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()});
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
}
} else {
String fp = filterConfig.getInitParameter("keycloak.config.file");
InputStream is = null;
if (fp != null) {
try {
is = new FileInputStream(fp);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
} else {
String path = "/WEB-INF/keycloak.json";
String pathParam = filterConfig.getInitParameter("keycloak.config.path");
if (pathParam != null) path = pathParam;
is = filterConfig.getServletContext().getResourceAsStream(path);
}
KeycloakDeployment kd;
if (is == null) {
log.fine("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
kd = new KeycloakDeployment();
} else {
kd = KeycloakDeploymentBuilder.build(is);
}
deploymentContext = new AdapterDeploymentContext(kd);
log.fine("Keycloak is using a per-deployment configuration.");
}
filterConfig.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
nodesRegistrationManagement = new NodesRegistrationManagement();
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
log.fine("Keycloak OIDC Filter");
//System.err.println("Keycloak OIDC Filter: " + ((HttpServletRequest)req).getRequestURL().toString());
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
OIDCServletHttpFacade facade = new OIDCServletHttpFacade(request, response);
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
if (deployment == null || !deployment.isConfigured()) {
response.sendError(403);
log.fine("deployment not configured");
return;
}
PreAuthActionsHandler preActions = new PreAuthActionsHandler(new UserSessionManagement() {
@Override
public void logoutAll() {
if (idMapper != null) {
idMapper.clear();
}
}
@Override
public void logoutHttpSessions(List<String> ids) {
log.fine("**************** logoutHttpSessions");
//System.err.println("**************** logoutHttpSessions");
for (String id : ids) {
log.finest("removed idMapper: " + id);
idMapper.removeSession(id);
}
}
}, deploymentContext, facade);
if (preActions.handleRequest()) {
//System.err.println("**************** preActions.handleRequest happened!");
return;
}
nodesRegistrationManagement.tryRegister(deployment);
OIDCFilterSessionStore tokenStore = new OIDCFilterSessionStore(request, facade, 100000, deployment, idMapper);
tokenStore.checkCurrentToken();
FilterRequestAuthenticator authenticator = new FilterRequestAuthenticator(deployment, tokenStore, facade, request, 8443);
AuthOutcome outcome = authenticator.authenticate();
if (outcome == AuthOutcome.AUTHENTICATED) {
log.fine("AUTHENTICATED");
if (facade.isEnded()) {
return;
}
AuthenticatedActionsHandler actions = new AuthenticatedActionsHandler(deployment, facade);
if (actions.handledRequest()) {
return;
} else {
HttpServletRequestWrapper wrapper = tokenStore.buildWrapper();
chain.doFilter(wrapper, res);
return;
}
}
AuthChallenge challenge = authenticator.getChallenge();
if (challenge != null) {
log.fine("challenge");
challenge.challenge(facade);
return;
}
response.sendError(403);
}
@Override
public void destroy() {
}
}
@@ -1,197 +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.servlet;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.KeycloakAccount;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OidcKeycloakAccount;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
import org.keycloak.adapters.spi.SessionIdMapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;
import java.io.Serializable;
import java.security.Principal;
import java.util.Set;
import java.util.logging.Logger;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OIDCFilterSessionStore extends FilterSessionStore implements AdapterTokenStore {
protected final KeycloakDeployment deployment;
private static final Logger log = Logger.getLogger("" + OIDCFilterSessionStore.class);
protected final SessionIdMapper idMapper;
public OIDCFilterSessionStore(HttpServletRequest request, HttpFacade facade, int maxBuffer, KeycloakDeployment deployment, SessionIdMapper idMapper) {
super(request, facade, maxBuffer);
this.deployment = deployment;
this.idMapper = idMapper;
}
public HttpServletRequestWrapper buildWrapper() {
HttpSession session = request.getSession(false);
KeycloakAccount account = null;
if (session != null) {
account = (KeycloakAccount) session.getAttribute(KeycloakAccount.class.getName());
if (account == null) {
account = (KeycloakAccount) request.getAttribute(KeycloakAccount.class.getName());
}
}
if (account == null) {
account = (KeycloakAccount) request.getAttribute(KeycloakAccount.class.getName());
}
return buildWrapper(session, account);
}
@Override
public void checkCurrentToken() {
HttpSession httpSession = request.getSession(false);
if (httpSession == null) return;
SerializableKeycloakAccount account = (SerializableKeycloakAccount)httpSession.getAttribute(KeycloakAccount.class.getName());
if (account == null) {
return;
}
RefreshableKeycloakSecurityContext session = account.getKeycloakSecurityContext();
if (session == null) return;
// just in case session got serialized
if (session.getDeployment() == null) session.setCurrentRequestInfo(deployment, this);
if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
// not be updated
boolean success = session.refreshExpiredToken(false);
if (success && session.isActive()) return;
// Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
//log.fine("Cleanup and expire session " + httpSession.getId() + " after failed refresh");
cleanSession(httpSession);
httpSession.invalidate();
}
protected void cleanSession(HttpSession session) {
session.removeAttribute(KeycloakAccount.class.getName());
session.removeAttribute(KeycloakSecurityContext.class.getName());
clearSavedRequest(session);
}
@Override
public boolean isCached(RequestAuthenticator authenticator) {
HttpSession httpSession = request.getSession(false);
if (httpSession == null) return false;
SerializableKeycloakAccount account = (SerializableKeycloakAccount) httpSession.getAttribute(KeycloakAccount.class.getName());
if (account == null) {
return false;
}
log.fine("remote logged in already. Establish state from session");
RefreshableKeycloakSecurityContext securityContext = account.getKeycloakSecurityContext();
if (!deployment.getRealm().equals(securityContext.getRealm())) {
log.fine("Account from cookie is from a different realm than for the request.");
cleanSession(httpSession);
return false;
}
if (idMapper != null && !idMapper.hasSession(httpSession.getId())) {
log.fine("idMapper does not have session: " + httpSession.getId());
//System.err.println("idMapper does not have session: " + httpSession.getId());
cleanSession(httpSession);
return false;
}
securityContext.setCurrentRequestInfo(deployment, this);
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
needRequestRestore = restoreRequest();
return true;
}
public static class SerializableKeycloakAccount implements OidcKeycloakAccount, Serializable {
protected Set<String> roles;
protected Principal principal;
protected RefreshableKeycloakSecurityContext securityContext;
public SerializableKeycloakAccount(Set<String> roles, Principal principal, RefreshableKeycloakSecurityContext securityContext) {
this.roles = roles;
this.principal = principal;
this.securityContext = securityContext;
}
@Override
public Principal getPrincipal() {
return principal;
}
@Override
public Set<String> getRoles() {
return roles;
}
@Override
public RefreshableKeycloakSecurityContext getKeycloakSecurityContext() {
return securityContext;
}
}
@Override
public void saveAccountInfo(OidcKeycloakAccount account) {
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) account.getKeycloakSecurityContext();
Set<String> roles = account.getRoles();
SerializableKeycloakAccount sAccount = new SerializableKeycloakAccount(roles, account.getPrincipal(), securityContext);
HttpSession httpSession = request.getSession();
httpSession.setAttribute(KeycloakAccount.class.getName(), sAccount);
httpSession.setAttribute(KeycloakSecurityContext.class.getName(), sAccount.getKeycloakSecurityContext());
if (idMapper != null) idMapper.map(account.getKeycloakSecurityContext().getToken().getClientSession(), account.getPrincipal().getName(), httpSession.getId());
//String username = securityContext.getToken().getSubject();
//log.fine("userSessionManagement.login: " + username);
}
@Override
public void logout() {
HttpSession httpSession = request.getSession(false);
if (httpSession != null) {
SerializableKeycloakAccount account = (SerializableKeycloakAccount) httpSession.getAttribute(KeycloakAccount.class.getName());
if (account != null) {
account.getKeycloakSecurityContext().logout(deployment);
}
cleanSession(httpSession);
}
}
@Override
public void servletRequestLogout() {
logout();
}
@Override
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
// no-op
}
}
@@ -1,40 +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.servlet;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OIDCServletHttpFacade extends ServletHttpFacade implements OIDCHttpFacade {
public OIDCServletHttpFacade(HttpServletRequest request, HttpServletResponse response) {
super(request, response);
}
@Override
public KeycloakSecurityContext getSecurityContext() {
return (KeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName());
}
}
@@ -1,99 +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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-servlet-oauth-client</artifactId>
<name>Keycloak Servlet OAuth Client</name>
<description/>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</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>
</plugins>
</build>
</project>
@@ -1,100 +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.servlet;
import java.util.Map;
import org.keycloak.AbstractOAuthClient;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.common.enums.RelativeUrlsUsed;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class KeycloakDeploymentDelegateOAuthClient extends AbstractOAuthClient {
private KeycloakDeployment deployment;
public KeycloakDeployment getDeployment() {
return deployment;
}
public void setDeployment(KeycloakDeployment deployment) {
this.deployment = deployment;
}
@Override
public String getClientId() {
return deployment.getResourceName();
}
@Override
public void setClientId(String clientId) {
deployment.setResourceName(clientId);
}
@Override
public Map<String, Object> getCredentials() {
return deployment.getResourceCredentials();
}
@Override
public void setCredentials(Map<String, Object> credentials) {
deployment.setResourceCredentials(credentials);
}
@Override
public String getAuthUrl() {
throw new IllegalStateException("Illegal to call this method. Use KeycloakDeployment to resolve correct deployment for this request");
}
@Override
public void setAuthUrl(String authUrl) {
throw new IllegalStateException("Illegal to call this method");
}
@Override
public String getTokenUrl() {
throw new IllegalStateException("Illegal to call this method. Use KeycloakDeployment to resolve correct deployment for this request");
}
@Override
public void setTokenUrl(String tokenUrl) {
throw new IllegalStateException("Illegal to call this method");
}
@Override
public boolean isPublicClient() {
return deployment.isPublicClient();
}
@Override
public void setPublicClient(boolean publicClient) {
deployment.setPublicClient(publicClient);
}
@Override
public RelativeUrlsUsed getRelativeUrlsUsed() {
return deployment.getRelativeUrls();
}
@Override
public void setRelativeUrlsUsed(RelativeUrlsUsed relativeUrlsUsed) {
throw new IllegalStateException("Illegal to call this method");
}
}
@@ -1,285 +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.servlet;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.ServerRequest;
import org.keycloak.adapters.spi.AuthenticationError;
import org.keycloak.adapters.spi.LogoutError;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.IDToken;
import org.keycloak.common.util.KeycloakUriBuilder;
import javax.security.cert.X509Certificate;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
/**
* closes client
*/
public void stop() {
getDeployment().getClient().getConnectionManager().shutdown();
}
private AccessTokenResponse resolveBearerToken(HttpServletRequest request, String redirectUri, String code) throws IOException, ServerRequest.HttpFailure {
// Don't send sessionId in oauth clients for now
KeycloakDeployment resolvedDeployment = resolveDeployment(getDeployment(), request);
return ServerRequest.invokeAccessCodeToToken(resolvedDeployment, code, redirectUri, null);
}
/**
* Start the process of obtaining an access token by redirecting the browser
* to the authentication server
*
* @param relativePath path relative to context root you want auth server to redirect back to
* @param request
* @param response
* @throws IOException
*/
public void redirectRelative(String relativePath, HttpServletRequest request, HttpServletResponse response) throws IOException {
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(request.getRequestURL().toString())
.replacePath(request.getContextPath())
.replaceQuery(null)
.path(relativePath);
String redirect = builder.toTemplate();
redirect(redirect, request, response);
}
/**
* Start the process of obtaining an access token by redirecting the browser
* to the authentication server
*
* @param redirectUri full URI you want auth server to redirect back to
* @param request
* @param response
* @throws IOException
*/
public void redirect(String redirectUri, HttpServletRequest request, HttpServletResponse response) throws IOException {
String state = getStateCode();
KeycloakDeployment resolvedDeployment = resolveDeployment(getDeployment(), request);
String authUrl = resolvedDeployment.getAuthUrl().clone().build().toString();
KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(authUrl)
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.CLIENT_ID, getClientId())
.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
.queryParam(OAuth2Constants.STATE, state);
if (scope != null) {
uriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
}
URI url = uriBuilder.build();
String stateCookiePath = this.stateCookiePath;
if (stateCookiePath == null) stateCookiePath = request.getContextPath();
if (stateCookiePath.equals("")) stateCookiePath = "/";
Cookie cookie = new Cookie(stateCookieName, state);
cookie.setSecure(isSecure);
cookie.setPath(stateCookiePath);
response.addCookie(cookie);
response.sendRedirect(url.toString());
}
protected String getCookieValue(String name, HttpServletRequest request) {
if (request.getCookies() == null) return null;
for (Cookie cookie : request.getCookies()) {
if (cookie.getName().equals(name)) return cookie.getValue();
}
return null;
}
protected String getCode(HttpServletRequest request) {
String query = request.getQueryString();
if (query == null) return null;
String[] params = query.split("&");
for (String param : params) {
int eq = param.indexOf('=');
if (eq == -1) continue;
String name = param.substring(0, eq);
if (!name.equals(OAuth2Constants.CODE)) continue;
return param.substring(eq + 1);
}
return null;
}
/**
* Obtain the code parameter from the url after being redirected back from the auth-server. Then
* do an authenticated request back to the auth-server to turn the access code into an access token.
*
* @param request
* @return
* @throws IOException
* @throws org.keycloak.adapters.ServerRequest.HttpFailure
*/
public AccessTokenResponse getBearerToken(HttpServletRequest request) throws IOException, ServerRequest.HttpFailure {
String error = request.getParameter(OAuth2Constants.ERROR);
if (error != null) throw new IOException("OAuth error: " + error);
String redirectUri = request.getRequestURL().append("?").append(request.getQueryString()).toString();
String stateCookie = getCookieValue(stateCookieName, request);
if (stateCookie == null) throw new IOException("state cookie not set");
// we can call get parameter as this should be a redirect
String state = request.getParameter(OAuth2Constants.STATE);
String code = request.getParameter(OAuth2Constants.CODE);
if (state == null) throw new IOException("state parameter was null");
if (!state.equals(stateCookie)) {
throw new IOException("state parameter invalid");
}
if (code == null) throw new IOException("code parameter was null");
return resolveBearerToken(request, redirectUri, code);
}
public AccessTokenResponse refreshToken(HttpServletRequest request, String refreshToken) throws IOException, ServerRequest.HttpFailure {
KeycloakDeployment resolvedDeployment = resolveDeployment(getDeployment(), request);
return ServerRequest.invokeRefresh(resolvedDeployment, refreshToken);
}
public static IDToken extractIdToken(String idToken) {
if (idToken == null) return null;
try {
JWSInput input = new JWSInput(idToken);
return input.readJsonContent(IDToken.class);
} catch (JWSInputException e) {
throw new RuntimeException(e);
}
}
private KeycloakDeployment resolveDeployment(KeycloakDeployment baseDeployment, HttpServletRequest request) {
ServletFacade facade = new ServletFacade(request);
return new AdapterDeploymentContext(baseDeployment).resolveDeployment(facade);
}
public static class ServletFacade implements OIDCHttpFacade {
private final HttpServletRequest servletRequest;
private ServletFacade(HttpServletRequest servletRequest) {
this.servletRequest = servletRequest;
}
@Override
public KeycloakSecurityContext getSecurityContext() {
throw new IllegalStateException("Not yet implemented");
}
@Override
public Request getRequest() {
return new Request() {
@Override
public String getFirstParam(String param) {
return servletRequest.getParameter(param);
}
@Override
public String getMethod() {
return servletRequest.getMethod();
}
@Override
public String getURI() {
return servletRequest.getRequestURL().toString();
}
@Override
public boolean isSecure() {
return servletRequest.isSecure();
}
@Override
public String getQueryParamValue(String param) {
return servletRequest.getParameter(param);
}
@Override
public Cookie getCookie(String cookieName) {
// TODO
return null;
}
@Override
public String getHeader(String name) {
return servletRequest.getHeader(name);
}
@Override
public List<String> getHeaders(String name) {
// TODO
return null;
}
@Override
public InputStream getInputStream() {
try {
return servletRequest.getInputStream();
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
@Override
public String getRemoteAddr() {
return servletRequest.getRemoteAddr();
}
@Override
public void setError(AuthenticationError error) {
servletRequest.setAttribute(AuthenticationError.class.getName(), error);
}
@Override
public void setError(LogoutError error) {
servletRequest.setAttribute(LogoutError.class.getName(), error);
}
};
}
@Override
public Response getResponse() {
throw new IllegalStateException("Not yet implemented");
}
@Override
public X509Certificate[] getCertificateChain() {
throw new IllegalStateException("Not yet implemented");
}
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.servlet;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.representations.adapters.config.AdapterConfig;
import java.io.InputStream;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ServletOAuthClientBuilder {
public static ServletOAuthClient build(InputStream is) {
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(is);
ServletOAuthClient client = new ServletOAuthClient();
client.setDeployment(deployment);
return client;
}
public static ServletOAuthClient build(AdapterConfig adapterConfig) {
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(adapterConfig);
ServletOAuthClient client = new ServletOAuthClient();
client.setDeployment(deployment);
return client;
}
public static void build(InputStream is, ServletOAuthClient oauthClient) {
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(is);
oauthClient.setDeployment(deployment);
}
}
@@ -1,42 +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.servlet;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.common.enums.RelativeUrlsUsed;
import org.keycloak.representations.idm.CredentialRepresentation;
import static org.junit.Assert.assertEquals;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ServletOAuthClientBuilderTest {
@Test
public void testBuilder() {
ServletOAuthClient oauthClient = ServletOAuthClientBuilder.build(getClass().getResourceAsStream("/keycloak.json"));
Assert.assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/auth", oauthClient.getDeployment().getAuthUrl().clone().build().toString());
Assert.assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/token", oauthClient.getDeployment().getTokenUrl());
assertEquals(RelativeUrlsUsed.NEVER, oauthClient.getRelativeUrlsUsed());
Assert.assertEquals("customer-portal", oauthClient.getClientId());
Assert.assertEquals("234234-234234-234234", oauthClient.getCredentials().get(CredentialRepresentation.SECRET));
Assert.assertEquals(true, oauthClient.isPublicClient());
}
}
@@ -1,27 +0,0 @@
{
"realm": "demo",
"resource": "customer-portal",
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "https://localhost:8443/auth",
"ssl-required": "external",
"use-resource-role-mappings": true,
"enable-cors": true,
"cors-max-age": 1000,
"cors-allowed-methods": "POST, PUT, DELETE, GET",
"cors-allowed-headers": "X-Custom, X-Custom2",
"bearer-only": true,
"public-client": true,
"enable-basic-auth": true,
"expose-token": true,
"credentials": {
"secret": "234234-234234-234234"
},
"connection-pool-size": 20,
"disable-trust-manager": true,
"allow-any-hostname": true,
"always-refresh-token": true,
"register-node-at-startup": true,
"register-node-period": 1000,
"token-store": "cookie",
"principal-attribute": "email"
}
-89
View File
@@ -1,89 +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>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-spring-boot-adapter</artifactId>
<name>Keycloak Spring Boot Integration</name>
<description/>
<properties>
<spring-boot.version>1.2.1.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat8-adapter</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-jetty92-adapter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,45 +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.springboot;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.representations.adapters.config.AdapterConfig;
public class KeycloakSpringBootConfigResolver implements org.keycloak.adapters.KeycloakConfigResolver {
private KeycloakDeployment keycloakDeployment;
private static AdapterConfig adapterConfig;
@Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
if (keycloakDeployment != null) {
return keycloakDeployment;
}
keycloakDeployment = KeycloakDeploymentBuilder.build(KeycloakSpringBootConfigResolver.adapterConfig);
return keycloakDeployment;
}
static void setAdapterConfig(AdapterConfig adapterConfig) {
KeycloakSpringBootConfigResolver.adapterConfig = adapterConfig;
}
}
-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-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.9.6.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-spring-security-adapter</artifactId>
<name>Keycloak Spring Security Integration</name>
<description/>
<properties>
<spring.version>3.2.7.RELEASE</spring.version>
<spring-security.version>3.2.7.RELEASE</spring-security.version>
<mockito.version>1.9.5</mockito.version>
<apache-httpcomponents.version>4.3.6</apache-httpcomponents.version>
</properties>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${apache-httpcomponents.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,96 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.springsecurity;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
/**
* {@link FactoryBean} that creates an {@link AdapterDeploymentContext} given a {@link Resource} defining the Keycloak
* client configuration or a {@link KeycloakConfigResolver} for multi-tenant environments.
*
* @author <a href="mailto:thomas.raehalme@aitiofinland.com">Thomas Raehalme</a>
*/
public class AdapterDeploymentContextFactoryBean
implements FactoryBean<AdapterDeploymentContext>, InitializingBean {
private static final Logger log =
LoggerFactory.getLogger(AdapterDeploymentContextFactoryBean.class);
private final Resource keycloakConfigFileResource;
private final KeycloakConfigResolver keycloakConfigResolver;
private AdapterDeploymentContext adapterDeploymentContext;
public AdapterDeploymentContextFactoryBean(Resource keycloakConfigFileResource) {
this.keycloakConfigFileResource = Objects.requireNonNull(keycloakConfigFileResource);
this.keycloakConfigResolver = null;
}
public AdapterDeploymentContextFactoryBean(KeycloakConfigResolver keycloakConfigResolver) {
this.keycloakConfigResolver = Objects.requireNonNull(keycloakConfigResolver);
this.keycloakConfigFileResource = null;
}
@Override
public Class<?> getObjectType() {
return AdapterDeploymentContext.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void afterPropertiesSet() throws Exception {
if (keycloakConfigResolver != null) {
adapterDeploymentContext = new AdapterDeploymentContext(keycloakConfigResolver);
}
else {
log.info("Loading Keycloak deployment from configuration file: {}", keycloakConfigFileResource);
KeycloakDeployment deployment = loadKeycloakDeployment();
adapterDeploymentContext = new AdapterDeploymentContext(deployment);
}
}
private KeycloakDeployment loadKeycloakDeployment() throws IOException {
if (!keycloakConfigFileResource.isReadable()) {
throw new FileNotFoundException(String.format("Unable to locate Keycloak configuration file: %s",
keycloakConfigFileResource.getFilename()));
}
return KeycloakDeploymentBuilder.build(keycloakConfigFileResource.getInputStream());
}
@Override
public AdapterDeploymentContext getObject() throws Exception {
return adapterDeploymentContext;
}
}
Loaded 100 of 6910 files, more files were not shown because too many files have changed in this diff. Show more