mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
remove resteasy ClientRequest
This commit is contained in:
parent
8d493381a9
commit
666827b7cb
36
connections/http-client/pom.xml
Executable file
36
connections/http-client/pom.xml
Executable file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0"?>
|
||||
<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.2.0.RC1-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-connections-http-client</artifactId>
|
||||
<name>Keycloak Connections Apache HttpClient</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,141 @@
|
||||
package org.keycloak.connections.httpclient;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.EntityBuilder;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.util.EnvUtil;
|
||||
import org.keycloak.util.KeystoreUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class DefaultHttpClientFactory implements HttpClientFactory {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DefaultHttpClientFactory.class);
|
||||
|
||||
private volatile CloseableHttpClient httpClient;
|
||||
|
||||
@Override
|
||||
public HttpClientProvider create(KeycloakSession session) {
|
||||
return new HttpClientProvider() {
|
||||
@Override
|
||||
public HttpClient getHttpClient() {
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int postText(String uri, String text) throws IOException {
|
||||
HttpPost request = new HttpPost(uri);
|
||||
request.setEntity(EntityBuilder.create().setText(text).setContentType(ContentType.TEXT_PLAIN).build());
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
try {
|
||||
return response.getStatusLine().getStatusCode();
|
||||
} finally {
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null) {
|
||||
InputStream is = entity.getContent();
|
||||
if (is != null) is.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream get(String uri) throws IOException {
|
||||
HttpGet request = new HttpGet(uri);
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity == null) return null;
|
||||
return entity.getContent();
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
httpClient.close();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
long socketTimeout = config.getLong("socketTimeoutMillis", -1L);
|
||||
long establishConnectionTimeout = config.getLong("establishConnectionTimeoutMillis", -1L);
|
||||
long connectionTTL = config.getLong("connectionTTLMillis", -1L);
|
||||
int maxPooledPerRoute = config.getInt("maxPooledPerRoute", 0);
|
||||
int connectionPoolSize = config.getInt("connectionPoolSize", 200);
|
||||
boolean disableTrustManager = config.getBoolean("disableTrustManager", true);
|
||||
boolean disableCookies = config.getBoolean("disableCookies", true);
|
||||
String hostnameVerificationPolicy = config.get("hostnameVerificationPolicy", "WILDCARD");
|
||||
HttpClientBuilder.HostnameVerificationPolicy hostnamePolicy = HttpClientBuilder.HostnameVerificationPolicy.valueOf(hostnameVerificationPolicy);
|
||||
String truststore = config.get("truststore");
|
||||
String truststorePassword = config.get("truststorePassword");
|
||||
String clientKeystore = config.get("clientKeyStore");
|
||||
String clientKeystorePassword = config.get("clientKeyStorePassword");
|
||||
String clientPrivateKeyPassword = config.get("clientPrivateKeyPassword");
|
||||
|
||||
HttpClientBuilder builder = new HttpClientBuilder();
|
||||
builder.socketTimeout(socketTimeout, TimeUnit.MILLISECONDS)
|
||||
.establishConnectionTimeout(establishConnectionTimeout, TimeUnit.MILLISECONDS)
|
||||
.connectionTTL(connectionTTL, TimeUnit.MILLISECONDS)
|
||||
.maxPooledPerRoute(maxPooledPerRoute)
|
||||
.connectionPoolSize(connectionPoolSize)
|
||||
.hostnameVerification(hostnamePolicy)
|
||||
.disableCookies(disableCookies);
|
||||
if (disableTrustManager) builder.disableTrustManager();
|
||||
if (truststore != null) {
|
||||
truststore = EnvUtil.replace(truststore);
|
||||
try {
|
||||
builder.trustStore(KeystoreUtil.loadKeyStore(truststore, truststorePassword));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to load truststore", e);
|
||||
}
|
||||
}
|
||||
if (clientKeystore != null) {
|
||||
clientKeystore = EnvUtil.replace(clientKeystore);
|
||||
try {
|
||||
KeyStore clientCertKeystore = KeystoreUtil.loadKeyStore(clientKeystore, clientKeystorePassword);
|
||||
builder.keyStore(clientCertKeystore, clientPrivateKeyPassword);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to load keystore", e);
|
||||
}
|
||||
}
|
||||
httpClient = builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,281 @@
|
||||
package org.keycloak.connections.httpclient;
|
||||
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.SSLContexts;
|
||||
import org.apache.http.conn.ssl.StrictHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.X509HostnameVerifier;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
|
||||
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.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
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 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;
|
||||
protected boolean disableCookies = false;
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable cookie management.
|
||||
*/
|
||||
public HttpClientBuilder disableCookies(boolean disable) {
|
||||
this.disableTrustManager = disable;
|
||||
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 CloseableHttpClient 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 {
|
||||
SSLConnectionSocketFactory sslsf = null;
|
||||
SSLContext theContext = sslContext;
|
||||
if (disableTrustManager) {
|
||||
theContext = SSLContext.getInstance("TLS");
|
||||
theContext.init(null, new TrustManager[]{new PassthroughTrustManager()},
|
||||
new SecureRandom());
|
||||
verifier = new AllowAllHostnameVerifier();
|
||||
sslsf = new SSLConnectionSocketFactory(theContext, verifier);
|
||||
} else if (theContext != null) {
|
||||
sslsf = new SSLConnectionSocketFactory(theContext, verifier);
|
||||
} else if (clientKeyStore != null || truststore != null) {
|
||||
theContext = createSslContext("TLS", clientKeyStore, clientPrivateKeyPassword, truststore, null);
|
||||
sslsf = new SSLConnectionSocketFactory(theContext, verifier);
|
||||
} else {
|
||||
final SSLContext tlsContext = SSLContext.getInstance("TLS");
|
||||
tlsContext.init(null, null, null);
|
||||
sslsf = new SSLConnectionSocketFactory(tlsContext, verifier);
|
||||
}
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout((int) establishConnectionTimeout)
|
||||
.setSocketTimeout((int) socketTimeout).build();
|
||||
|
||||
org.apache.http.impl.client.HttpClientBuilder builder = HttpClients.custom()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setSSLSocketFactory(sslsf)
|
||||
.setMaxConnTotal(connectionPoolSize)
|
||||
.setMaxConnPerRoute(maxPooledPerRoute);
|
||||
if (disableCookies) builder.disableCookieManagement();
|
||||
return builder.build();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private SSLContext createSslContext(
|
||||
final String algorithm,
|
||||
final KeyStore keystore,
|
||||
final String keyPassword,
|
||||
final KeyStore truststore,
|
||||
final SecureRandom random)
|
||||
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
|
||||
return SSLContexts.custom()
|
||||
.useProtocol(algorithm)
|
||||
.setSecureRandom(random)
|
||||
.loadKeyMaterial(keystore, keyPassword != null ? keyPassword.toCharArray() : null)
|
||||
.loadTrustMaterial(truststore)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package org.keycloak.connections.httpclient;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface HttpClientFactory extends ProviderFactory<HttpClientProvider> {
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package org.keycloak.connections.httpclient;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface HttpClientProvider extends Provider {
|
||||
HttpClient getHttpClient();
|
||||
|
||||
/**
|
||||
* Helper method
|
||||
*
|
||||
* @param uri
|
||||
* @param text
|
||||
* @return http response status
|
||||
* @throws IOException
|
||||
*/
|
||||
public int postText(String uri, String text) throws IOException;
|
||||
|
||||
/**
|
||||
* Helper method
|
||||
*
|
||||
* @param uri
|
||||
* @return response stream, you must close this stream or leaks will happen
|
||||
* @throws IOException
|
||||
*/
|
||||
public InputStream get(String uri) throws IOException;
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package org.keycloak.connections.httpclient;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class HttpClientSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "connectionsHttpClient";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return HttpClientProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return HttpClientFactory.class;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
org.keycloak.connections.httpclient.DefaultHttpClientFactory
|
||||
@ -0,0 +1 @@
|
||||
org.keycloak.connections.httpclient.HttpClientSpi
|
||||
@ -19,6 +19,7 @@
|
||||
<module>mongo</module>
|
||||
<module>file</module>
|
||||
<module>mongo-update</module>
|
||||
<module>http-client</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package org.keycloak.adapters;
|
||||
package org.keycloak.util;
|
||||
|
||||
import org.keycloak.constants.GenericConstants;
|
||||
|
||||
5
dependencies/server-min/pom.xml
vendored
5
dependencies/server-min/pom.xml
vendored
@ -135,6 +135,11 @@
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-single-file</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-connections-http-client</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -169,6 +169,10 @@
|
||||
|
||||
<!-- server all dependencies -->
|
||||
|
||||
<module-def name="org.keycloak.keycloak-connections-http-client">
|
||||
<maven-resource group="org.keycloak" artifact="keycloak-connections-http-client"/>
|
||||
</module-def>
|
||||
|
||||
<module-def name="org.keycloak.keycloak-connections-jpa">
|
||||
<maven-resource group="org.keycloak" artifact="keycloak-connections-jpa"/>
|
||||
</module-def>
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
|
||||
|
||||
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-http-client">
|
||||
<resources>
|
||||
<!-- Insert resources here -->
|
||||
</resources>
|
||||
<exports>
|
||||
<include path="META-INF/**"/>
|
||||
</exports>
|
||||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-core"/>
|
||||
<module name="org.keycloak.keycloak-model-api"/>
|
||||
<module name="org.jboss.logging"/>
|
||||
<module name="javax.api"/>
|
||||
<module name="org.apache.httpcomponents" slot="4.3" />
|
||||
</dependencies>
|
||||
|
||||
</module>
|
||||
@ -21,6 +21,7 @@
|
||||
<module name="javax.ws.rs.api"/>
|
||||
<module name="org.jboss.resteasy.resteasy-jaxrs"/>
|
||||
<module name="org.jboss.resteasy.resteasy-multipart-provider"/>
|
||||
<module name="org.keycloak.keycloak-connections-http-client" services="import"/>
|
||||
|
||||
<module name="javax.api"/>
|
||||
</dependencies>
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
<module name="org.keycloak.keycloak-broker-saml" services="import"/>
|
||||
<module name="org.keycloak.keycloak-connections-infinispan" services="import"/>
|
||||
<module name="org.keycloak.keycloak-connections-jpa" services="import"/>
|
||||
<module name="org.keycloak.keycloak-connections-http-client" services="import"/>
|
||||
<module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/>
|
||||
<module name="org.keycloak.keycloak-connections-mongo" services="import"/>
|
||||
<module name="org.keycloak.keycloak-connections-mongo-update" services="import"/>
|
||||
|
||||
2
integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/AbstractKeycloakLoginModule.java
Normal file → Executable file
2
integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/AbstractKeycloakLoginModule.java
Normal file → Executable file
@ -24,7 +24,7 @@ import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.VerificationException;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.FindFile;
|
||||
import org.keycloak.util.FindFile;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
|
||||
@ -35,6 +35,11 @@
|
||||
<artifactId>wildfly-controller</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-model-api</artifactId>
|
||||
|
||||
5
pom.xml
5
pom.xml
@ -557,6 +557,11 @@
|
||||
<artifactId>keycloak-connections-mongo</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-connections-http-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-connections-mongo-update</artifactId>
|
||||
|
||||
@ -3,7 +3,6 @@ package org.keycloak.proxy;
|
||||
import io.undertow.Undertow;
|
||||
import io.undertow.security.api.AuthenticationMechanism;
|
||||
import io.undertow.security.api.AuthenticationMode;
|
||||
import io.undertow.security.handlers.AuthenticationCallHandler;
|
||||
import io.undertow.security.handlers.AuthenticationMechanismsHandler;
|
||||
import io.undertow.security.handlers.SecurityInitialHandler;
|
||||
import io.undertow.security.idm.Account;
|
||||
@ -24,7 +23,7 @@ import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.map.annotate.JsonSerialize;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.FindFile;
|
||||
import org.keycloak.util.FindFile;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
@ -35,7 +34,6 @@ import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
|
||||
import org.keycloak.enums.SslRequired;
|
||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||
import org.keycloak.util.CertificateUtils;
|
||||
import org.keycloak.util.PemUtils;
|
||||
import org.keycloak.util.SystemPropertiesJsonParserFactory;
|
||||
import org.xnio.Option;
|
||||
|
||||
|
||||
@ -33,6 +33,11 @@
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-connections-http-client</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
package org.keycloak.protocol.saml;
|
||||
|
||||
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.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.client.ClientRequest;
|
||||
import org.jboss.resteasy.client.ClientResponse;
|
||||
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
|
||||
import org.keycloak.connections.httpclient.HttpClientProvider;
|
||||
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||
import org.keycloak.dom.saml.v2.protocol.ResponseType;
|
||||
@ -37,7 +42,9 @@ import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.PublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -515,35 +522,38 @@ public class SamlProtocol implements LoginProtocol {
|
||||
}
|
||||
|
||||
|
||||
ApacheHttpClient4Executor executor = ResourceAdminManager.createExecutor();
|
||||
|
||||
|
||||
try {
|
||||
ClientRequest request = executor.createRequest(logoutUrl);
|
||||
request.formParameter(GeneralConstants.SAML_REQUEST_KEY, logoutRequestString);
|
||||
request.formParameter("BACK_CHANNEL_LOGOUT", "BACK_CHANNEL_LOGOUT"); // for Picketlink adapter, todo remove this
|
||||
ClientResponse response = null;
|
||||
HttpClient httpClient = session.getProvider(HttpClientProvider.class).getHttpClient();
|
||||
for (int i = 0; i < 2; i++) { // follow redirects once
|
||||
try {
|
||||
response = request.post();
|
||||
response.releaseConnection();
|
||||
// Undertow will redirect root urls not ending in "/" to root url + "/". Test for this weird behavior
|
||||
if (response.getStatus() == 302 && !logoutUrl.endsWith("/")) {
|
||||
String redirect = (String)response.getHeaders().getFirst(HttpHeaders.LOCATION);
|
||||
String withSlash = logoutUrl + "/";
|
||||
if (withSlash.equals(redirect)) {
|
||||
request = executor.createRequest(withSlash);
|
||||
request.formParameter(GeneralConstants.SAML_REQUEST_KEY, logoutRequestString);
|
||||
request.formParameter("BACK_CHANNEL_LOGOUT", "BACK_CHANNEL_LOGOUT"); // for Picketlink adapter, todo remove this
|
||||
response = request.post();
|
||||
response.releaseConnection();
|
||||
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
|
||||
formparams.add(new BasicNameValuePair(GeneralConstants.SAML_REQUEST_KEY, logoutRequestString));
|
||||
formparams.add(new BasicNameValuePair("BACK_CHANNEL_LOGOUT", "BACK_CHANNEL_LOGOUT")); // for Picketlink todo remove this
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
HttpPost post = new HttpPost(logoutUrl);
|
||||
post.setEntity(form);
|
||||
HttpResponse response = httpClient.execute(post);
|
||||
try {
|
||||
int status = response.getStatusLine().getStatusCode();
|
||||
if (status == 302 && !logoutUrl.endsWith("/")) {
|
||||
String redirect = response.getFirstHeader(HttpHeaders.LOCATION).getValue();
|
||||
String withSlash = logoutUrl + "/";
|
||||
if (withSlash.equals(redirect)) {
|
||||
logoutUrl = withSlash;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null) {
|
||||
InputStream is = entity.getContent();
|
||||
if (is != null) is.close();
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (IOException e) {
|
||||
logger.warn("failed to send saml logout", e);
|
||||
}
|
||||
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -34,6 +34,11 @@
|
||||
<artifactId>keycloak-core-jaxrs</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-connections-http-client</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-forms-common-freemarker</artifactId>
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
package org.keycloak.protocol.oidc;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
@ -166,14 +165,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
|
||||
public void backchannelLogout(UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
if (!(clientSession.getClient() instanceof ClientModel)) return;
|
||||
ClientModel app = clientSession.getClient();
|
||||
// TODO: Probably non-effective to build executor every time from scratch. Should be likely shared for whole OIDCLoginProtocolFactory
|
||||
ApacheHttpClient4Executor executor = ResourceAdminManager.createExecutor();
|
||||
|
||||
try {
|
||||
new ResourceAdminManager().logoutClientSession(uriInfo.getRequestUri(), realm, app, clientSession, executor);
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
}
|
||||
new ResourceAdminManager(session).logoutClientSession(uriInfo.getRequestUri(), realm, app, clientSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
package org.keycloak.services.managers;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.client.ClientRequest;
|
||||
import org.jboss.resteasy.client.ClientResponse;
|
||||
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
|
||||
import org.keycloak.TokenIdGenerator;
|
||||
import org.keycloak.connections.httpclient.HttpClientProvider;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
@ -18,15 +15,14 @@ import org.keycloak.representations.adapters.action.GlobalRequestResult;
|
||||
import org.keycloak.representations.adapters.action.LogoutAction;
|
||||
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
|
||||
import org.keycloak.representations.adapters.action.TestAvailabilityAction;
|
||||
import org.keycloak.services.util.HttpClientBuilder;
|
||||
import org.keycloak.services.util.ResolveRelative;
|
||||
import org.keycloak.util.KeycloakUriBuilder;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
import org.keycloak.util.StringPropertyReplacer;
|
||||
import org.keycloak.util.Time;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -44,11 +40,10 @@ public class ResourceAdminManager {
|
||||
protected static Logger logger = Logger.getLogger(ResourceAdminManager.class);
|
||||
private static final String CLIENT_SESSION_HOST_PROPERTY = "${application.session.host}";
|
||||
|
||||
public static ApacheHttpClient4Executor createExecutor() {
|
||||
HttpClient client = new HttpClientBuilder()
|
||||
.disableTrustManager() // todo fix this, should have a trust manager or a good default
|
||||
.build();
|
||||
return new ApacheHttpClient4Executor(client);
|
||||
private KeycloakSession session;
|
||||
|
||||
public ResourceAdminManager(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public static String resolveUri(URI requestUri, String uri) {
|
||||
@ -101,23 +96,17 @@ public class ResourceAdminManager {
|
||||
}
|
||||
|
||||
protected void logoutUserSessions(URI requestUri, RealmModel realm, List<UserSessionModel> userSessions) {
|
||||
ApacheHttpClient4Executor executor = createExecutor();
|
||||
// Map from "app" to clientSessions for this app
|
||||
MultivaluedHashMap<ClientModel, ClientSessionModel> clientSessions = new MultivaluedHashMap<ClientModel, ClientSessionModel>();
|
||||
for (UserSessionModel userSession : userSessions) {
|
||||
putClientSessions(clientSessions, userSession);
|
||||
}
|
||||
|
||||
try {
|
||||
// Map from "app" to clientSessions for this app
|
||||
MultivaluedHashMap<ClientModel, ClientSessionModel> clientSessions = new MultivaluedHashMap<ClientModel, ClientSessionModel>();
|
||||
for (UserSessionModel userSession : userSessions) {
|
||||
putClientSessions(clientSessions, userSession);
|
||||
}
|
||||
logger.debugv("logging out {0} resources ", clientSessions.size());
|
||||
//logger.infov("logging out resources: {0}", clientSessions);
|
||||
|
||||
logger.debugv("logging out {0} resources ", clientSessions.size());
|
||||
//logger.infov("logging out resources: {0}", clientSessions);
|
||||
|
||||
for (Map.Entry<ClientModel, List<ClientSessionModel>> entry : clientSessions.entrySet()) {
|
||||
logoutClientSessions(requestUri, realm, entry.getKey(), entry.getValue(), executor);
|
||||
}
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
for (Map.Entry<ClientModel, List<ClientSessionModel>> entry : clientSessions.entrySet()) {
|
||||
logoutClientSessions(requestUri, realm, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,32 +117,25 @@ public class ResourceAdminManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void logoutUserFromClient(URI requestUri, RealmModel realm, ClientModel resource, UserModel user, KeycloakSession session) {
|
||||
ApacheHttpClient4Executor executor = createExecutor();
|
||||
|
||||
try {
|
||||
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
|
||||
List<ClientSessionModel> ourAppClientSessions = null;
|
||||
if (userSessions != null) {
|
||||
MultivaluedHashMap<ClientModel, ClientSessionModel> clientSessions = new MultivaluedHashMap<ClientModel, ClientSessionModel>();
|
||||
for (UserSessionModel userSession : userSessions) {
|
||||
putClientSessions(clientSessions, userSession);
|
||||
}
|
||||
ourAppClientSessions = clientSessions.get(resource);
|
||||
public void logoutUserFromClient(URI requestUri, RealmModel realm, ClientModel resource, UserModel user) {
|
||||
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
|
||||
List<ClientSessionModel> ourAppClientSessions = null;
|
||||
if (userSessions != null) {
|
||||
MultivaluedHashMap<ClientModel, ClientSessionModel> clientSessions = new MultivaluedHashMap<ClientModel, ClientSessionModel>();
|
||||
for (UserSessionModel userSession : userSessions) {
|
||||
putClientSessions(clientSessions, userSession);
|
||||
}
|
||||
|
||||
logoutClientSessions(requestUri, realm, resource, ourAppClientSessions, executor);
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
ourAppClientSessions = clientSessions.get(resource);
|
||||
}
|
||||
|
||||
logoutClientSessions(requestUri, realm, resource, ourAppClientSessions);
|
||||
}
|
||||
|
||||
public boolean logoutClientSession(URI requestUri, RealmModel realm, ClientModel resource, ClientSessionModel clientSession, ApacheHttpClient4Executor client) {
|
||||
return logoutClientSessions(requestUri, realm, resource, Arrays.asList(clientSession), client);
|
||||
public boolean logoutClientSession(URI requestUri, RealmModel realm, ClientModel resource, ClientSessionModel clientSession) {
|
||||
return logoutClientSessions(requestUri, realm, resource, Arrays.asList(clientSession));
|
||||
}
|
||||
|
||||
protected boolean logoutClientSessions(URI requestUri, RealmModel realm, ClientModel resource, List<ClientSessionModel> clientSessions, ApacheHttpClient4Executor client) {
|
||||
protected boolean logoutClientSessions(URI requestUri, RealmModel realm, ClientModel resource, List<ClientSessionModel> clientSessions) {
|
||||
String managementUrl = getManagementUrl(requestUri, resource);
|
||||
if (managementUrl != null) {
|
||||
|
||||
@ -184,7 +166,7 @@ public class ResourceAdminManager {
|
||||
String host = entry.getKey();
|
||||
List<String> sessionIds = entry.getValue();
|
||||
String currentHostMgmtUrl = managementUrl.replace(CLIENT_SESSION_HOST_PROPERTY, host);
|
||||
allPassed = sendLogoutRequest(realm, resource, sessionIds, userSessions, client, 0, currentHostMgmtUrl) && allPassed;
|
||||
allPassed = sendLogoutRequest(realm, resource, sessionIds, userSessions, 0, currentHostMgmtUrl) && allPassed;
|
||||
}
|
||||
|
||||
return allPassed;
|
||||
@ -195,7 +177,7 @@ public class ResourceAdminManager {
|
||||
allSessionIds.addAll(currentIds);
|
||||
}
|
||||
|
||||
return sendLogoutRequest(realm, resource, allSessionIds, userSessions, client, 0, managementUrl);
|
||||
return sendLogoutRequest(realm, resource, allSessionIds, userSessions, 0, managementUrl);
|
||||
}
|
||||
} else {
|
||||
logger.debugv("Can't logout {0}: no management url", resource.getClientId());
|
||||
@ -206,36 +188,25 @@ public class ResourceAdminManager {
|
||||
// Methods for logout all
|
||||
|
||||
public GlobalRequestResult logoutAll(URI requestUri, RealmModel realm) {
|
||||
ApacheHttpClient4Executor executor = createExecutor();
|
||||
realm.setNotBefore(Time.currentTime());
|
||||
List<ClientModel> resources = realm.getClients();
|
||||
logger.debugv("logging out {0} resources ", resources.size());
|
||||
|
||||
try {
|
||||
realm.setNotBefore(Time.currentTime());
|
||||
List<ClientModel> resources = realm.getClients();
|
||||
logger.debugv("logging out {0} resources ", resources.size());
|
||||
|
||||
GlobalRequestResult finalResult = new GlobalRequestResult();
|
||||
for (ClientModel resource : resources) {
|
||||
GlobalRequestResult currentResult = logoutClient(requestUri, realm, resource, executor, realm.getNotBefore());
|
||||
finalResult.addAll(currentResult);
|
||||
}
|
||||
return finalResult;
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
GlobalRequestResult finalResult = new GlobalRequestResult();
|
||||
for (ClientModel resource : resources) {
|
||||
GlobalRequestResult currentResult = logoutClient(requestUri, realm, resource, realm.getNotBefore());
|
||||
finalResult.addAll(currentResult);
|
||||
}
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
public GlobalRequestResult logoutClient(URI requestUri, RealmModel realm, ClientModel resource) {
|
||||
ApacheHttpClient4Executor executor = createExecutor();
|
||||
try {
|
||||
resource.setNotBefore(Time.currentTime());
|
||||
return logoutClient(requestUri, realm, resource, executor, resource.getNotBefore());
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
}
|
||||
resource.setNotBefore(Time.currentTime());
|
||||
return logoutClient(requestUri, realm, resource, resource.getNotBefore());
|
||||
}
|
||||
|
||||
|
||||
protected GlobalRequestResult logoutClient(URI requestUri, RealmModel realm, ClientModel resource, ApacheHttpClient4Executor executor, int notBefore) {
|
||||
protected GlobalRequestResult logoutClient(URI requestUri, RealmModel realm, ClientModel resource, int notBefore) {
|
||||
List<String> mgmtUrls = getAllManagementUrls(requestUri, resource);
|
||||
if (mgmtUrls.isEmpty()) {
|
||||
logger.debug("No management URL or no registered cluster nodes for the client " + resource.getClientId());
|
||||
@ -247,7 +218,7 @@ public class ResourceAdminManager {
|
||||
// Propagate this to all hosts
|
||||
GlobalRequestResult result = new GlobalRequestResult();
|
||||
for (String mgmtUrl : mgmtUrls) {
|
||||
if (sendLogoutRequest(realm, resource, null, null, executor, notBefore, mgmtUrl)) {
|
||||
if (sendLogoutRequest(realm, resource, null, null, notBefore, mgmtUrl)) {
|
||||
result.addSuccessRequest(mgmtUrl);
|
||||
} else {
|
||||
result.addFailedRequest(mgmtUrl);
|
||||
@ -256,54 +227,37 @@ public class ResourceAdminManager {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean sendLogoutRequest(RealmModel realm, ClientModel resource, List<String> adapterSessionIds, List<String> userSessions, ApacheHttpClient4Executor client, int notBefore, String managementUrl) {
|
||||
protected boolean sendLogoutRequest(RealmModel realm, ClientModel resource, List<String> adapterSessionIds, List<String> userSessions, int notBefore, String managementUrl) {
|
||||
LogoutAction adminAction = new LogoutAction(TokenIdGenerator.generateId(), Time.currentTime() + 30, resource.getClientId(), adapterSessionIds, notBefore, userSessions);
|
||||
String token = new TokenManager().encodeToken(realm, adminAction);
|
||||
if (logger.isDebugEnabled()) logger.debugv("logout resource {0} url: {1} sessionIds: " + adapterSessionIds, resource.getClientId(), managementUrl);
|
||||
ClientRequest request = client.createRequest(UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_LOGOUT).build().toString());
|
||||
ClientResponse response;
|
||||
URI target = UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_LOGOUT).build();
|
||||
try {
|
||||
response = request.body(MediaType.TEXT_PLAIN_TYPE, token).post();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Logout for client '" + resource.getClientId() + "' failed", e);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
boolean success = response.getStatus() == 204 || response.getStatus() == 200;
|
||||
int status = session.getProvider(HttpClientProvider.class).postText(target.toString(), token);
|
||||
boolean success = status == 204 || status == 200;
|
||||
logger.debugf("logout success for %s: %s", managementUrl, success);
|
||||
return success;
|
||||
} finally {
|
||||
response.releaseConnection();
|
||||
} catch (IOException e) {
|
||||
logger.warn("Logout for client '" + resource.getClientId() + "' failed", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public GlobalRequestResult pushRealmRevocationPolicy(URI requestUri, RealmModel realm) {
|
||||
ApacheHttpClient4Executor executor = createExecutor();
|
||||
|
||||
try {
|
||||
GlobalRequestResult finalResult = new GlobalRequestResult();
|
||||
for (ClientModel client : realm.getClients()) {
|
||||
GlobalRequestResult currentResult = pushRevocationPolicy(requestUri, realm, client, realm.getNotBefore(), executor);
|
||||
finalResult.addAll(currentResult);
|
||||
}
|
||||
return finalResult;
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
GlobalRequestResult finalResult = new GlobalRequestResult();
|
||||
for (ClientModel client : realm.getClients()) {
|
||||
GlobalRequestResult currentResult = pushRevocationPolicy(requestUri, realm, client, realm.getNotBefore());
|
||||
finalResult.addAll(currentResult);
|
||||
}
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
public GlobalRequestResult pushClientRevocationPolicy(URI requestUri, RealmModel realm, ClientModel client) {
|
||||
ApacheHttpClient4Executor executor = createExecutor();
|
||||
|
||||
try {
|
||||
return pushRevocationPolicy(requestUri, realm, client, client.getNotBefore(), executor);
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
}
|
||||
return pushRevocationPolicy(requestUri, realm, client, client.getNotBefore());
|
||||
}
|
||||
|
||||
|
||||
protected GlobalRequestResult pushRevocationPolicy(URI requestUri, RealmModel realm, ClientModel resource, int notBefore, ApacheHttpClient4Executor executor) {
|
||||
protected GlobalRequestResult pushRevocationPolicy(URI requestUri, RealmModel realm, ClientModel resource, int notBefore) {
|
||||
List<String> mgmtUrls = getAllManagementUrls(requestUri, resource);
|
||||
if (mgmtUrls.isEmpty()) {
|
||||
logger.debugf("No management URL or no registered cluster nodes for the client %s", resource.getClientId());
|
||||
@ -315,7 +269,7 @@ public class ResourceAdminManager {
|
||||
// Propagate this to all hosts
|
||||
GlobalRequestResult result = new GlobalRequestResult();
|
||||
for (String mgmtUrl : mgmtUrls) {
|
||||
if (sendPushRevocationPolicyRequest(realm, resource, notBefore, executor, mgmtUrl)) {
|
||||
if (sendPushRevocationPolicyRequest(realm, resource, notBefore, mgmtUrl)) {
|
||||
result.addSuccessRequest(mgmtUrl);
|
||||
} else {
|
||||
result.addFailedRequest(mgmtUrl);
|
||||
@ -324,24 +278,19 @@ public class ResourceAdminManager {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean sendPushRevocationPolicyRequest(RealmModel realm, ClientModel resource, int notBefore, ApacheHttpClient4Executor client, String managementUrl) {
|
||||
protected boolean sendPushRevocationPolicyRequest(RealmModel realm, ClientModel resource, int notBefore, String managementUrl) {
|
||||
PushNotBeforeAction adminAction = new PushNotBeforeAction(TokenIdGenerator.generateId(), Time.currentTime() + 30, resource.getClientId(), notBefore);
|
||||
String token = new TokenManager().encodeToken(realm, adminAction);
|
||||
logger.infov("pushRevocation resource: {0} url: {1}", resource.getClientId(), managementUrl);
|
||||
ClientRequest request = client.createRequest(UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_PUSH_NOT_BEFORE).build().toString());
|
||||
ClientResponse response;
|
||||
URI target = UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_PUSH_NOT_BEFORE).build();
|
||||
try {
|
||||
response = request.body(MediaType.TEXT_PLAIN_TYPE, token).post();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to send revocation request", e);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
boolean success = response.getStatus() == 204 || response.getStatus() == 200;
|
||||
int status = session.getProvider(HttpClientProvider.class).postText(target.toString(), token);
|
||||
boolean success = status == 204 || status == 200;
|
||||
logger.debugf("pushRevocation success for %s: %s", managementUrl, success);
|
||||
return success;
|
||||
} finally {
|
||||
response.releaseConnection();
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to send revocation request", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,45 +301,35 @@ public class ResourceAdminManager {
|
||||
return new GlobalRequestResult();
|
||||
}
|
||||
|
||||
ApacheHttpClient4Executor executor = createExecutor();
|
||||
|
||||
try {
|
||||
if (logger.isDebugEnabled()) logger.debug("Sending test nodes availability: " + mgmtUrls);
|
||||
if (logger.isDebugEnabled()) logger.debug("Sending test nodes availability: " + mgmtUrls);
|
||||
|
||||
// Propagate this to all hosts
|
||||
GlobalRequestResult result = new GlobalRequestResult();
|
||||
for (String mgmtUrl : mgmtUrls) {
|
||||
if (sendTestNodeAvailabilityRequest(realm, client, executor, mgmtUrl)) {
|
||||
result.addSuccessRequest(mgmtUrl);
|
||||
} else {
|
||||
result.addFailedRequest(mgmtUrl);
|
||||
}
|
||||
// Propagate this to all hosts
|
||||
GlobalRequestResult result = new GlobalRequestResult();
|
||||
for (String mgmtUrl : mgmtUrls) {
|
||||
if (sendTestNodeAvailabilityRequest(realm, client, mgmtUrl)) {
|
||||
result.addSuccessRequest(mgmtUrl);
|
||||
} else {
|
||||
result.addFailedRequest(mgmtUrl);
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
executor.getHttpClient().getConnectionManager().shutdown();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean sendTestNodeAvailabilityRequest(RealmModel realm, ClientModel client, ApacheHttpClient4Executor httpClient, String managementUrl) {
|
||||
protected boolean sendTestNodeAvailabilityRequest(RealmModel realm, ClientModel client, String managementUrl) {
|
||||
TestAvailabilityAction adminAction = new TestAvailabilityAction(TokenIdGenerator.generateId(), Time.currentTime() + 30, client.getClientId());
|
||||
String token = new TokenManager().encodeToken(realm, adminAction);
|
||||
logger.debugv("testNodes availability resource: {0} url: {1}", client.getClientId(), managementUrl);
|
||||
ClientRequest request = httpClient.createRequest(UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_TEST_AVAILABLE).build().toString());
|
||||
ClientResponse response;
|
||||
URI target = UriBuilder.fromUri(managementUrl).path(AdapterConstants.K_TEST_AVAILABLE).build();
|
||||
try {
|
||||
response = request.body(MediaType.TEXT_PLAIN_TYPE, token).post();
|
||||
} catch (Exception e) {
|
||||
int status = session.getProvider(HttpClientProvider.class).postText(target.toString(), token);
|
||||
boolean success = status == 204 || status == 200;
|
||||
logger.debugf("testAvailability success for %s: %s", managementUrl, success);
|
||||
return success;
|
||||
} catch (IOException e) {
|
||||
logger.warn("Availability test failed for uri '" + managementUrl + "'", e);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
boolean success = response.getStatus() == 204 || response.getStatus() == 200;
|
||||
logger.debugf("testAvailability success for %s: %s", managementUrl, success);
|
||||
return success;
|
||||
} finally {
|
||||
response.releaseConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ public class ClientResource {
|
||||
@POST
|
||||
public GlobalRequestResult pushRevocation() {
|
||||
auth.requireManage();
|
||||
return new ResourceAdminManager().pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client);
|
||||
return new ResourceAdminManager(session).pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -341,7 +341,7 @@ public class ClientResource {
|
||||
@POST
|
||||
public GlobalRequestResult logoutAll() {
|
||||
auth.requireManage();
|
||||
return new ResourceAdminManager().logoutClient(uriInfo.getRequestUri(), realm, client);
|
||||
return new ResourceAdminManager(session).logoutClient(uriInfo.getRequestUri(), realm, client);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,7 +356,7 @@ public class ClientResource {
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
new ResourceAdminManager().logoutUserFromClient(uriInfo.getRequestUri(), realm, client, user, session);
|
||||
new ResourceAdminManager(session).logoutUserFromClient(uriInfo.getRequestUri(), realm, client, user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -410,7 +410,7 @@ public class ClientResource {
|
||||
auth.requireManage();
|
||||
logger.debug("Test availability of cluster nodes");
|
||||
|
||||
return new ResourceAdminManager().testNodesAvailability(uriInfo.getRequestUri(), realm, client);
|
||||
return new ResourceAdminManager(session).testNodesAvailability(uriInfo.getRequestUri(), realm, client);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
|
||||
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
|
||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.broker.provider.IdentityProvider;
|
||||
import org.keycloak.broker.provider.IdentityProviderFactory;
|
||||
import org.keycloak.connections.httpclient.HttpClientProvider;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
@ -16,7 +16,6 @@ import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.social.SocialIdentityProvider;
|
||||
|
||||
@ -93,16 +92,18 @@ public class IdentityProvidersResource {
|
||||
|
||||
String providerId = data.get("providerId").toString();
|
||||
String from = data.get("fromUrl").toString();
|
||||
ApacheHttpClient4Executor executor = ResourceAdminManager.createExecutor();
|
||||
InputStream inputStream = null;
|
||||
InputStream inputStream = session.getProvider(HttpClientProvider.class).get(from);
|
||||
try {
|
||||
inputStream = executor.createRequest(from).getTarget(InputStream.class);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
|
||||
Map<String, String> config;
|
||||
config = providerFactory.parseConfig(inputStream);
|
||||
return config;
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
|
||||
Map<String, String> config = providerFactory.parseConfig(inputStream);
|
||||
return config;
|
||||
}
|
||||
|
||||
@GET
|
||||
|
||||
@ -254,7 +254,7 @@ public class RealmAdminResource {
|
||||
@POST
|
||||
public GlobalRequestResult pushRevocation() {
|
||||
auth.requireManage();
|
||||
return new ResourceAdminManager().pushRealmRevocationPolicy(uriInfo.getRequestUri(), realm);
|
||||
return new ResourceAdminManager(session).pushRealmRevocationPolicy(uriInfo.getRequestUri(), realm);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,7 +266,7 @@ public class RealmAdminResource {
|
||||
@POST
|
||||
public GlobalRequestResult logoutAll() {
|
||||
session.sessions().removeUserSessions(realm);
|
||||
return new ResourceAdminManager().logoutAll(uriInfo.getRequestUri(), realm);
|
||||
return new ResourceAdminManager(session).logoutAll(uriInfo.getRequestUri(), realm);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,7 +364,6 @@ public class RealmAdminResource {
|
||||
* Query events. Returns all events, or will query based on URL query parameters listed here
|
||||
*
|
||||
* @param client app or oauth client name
|
||||
* @param types type type
|
||||
* @param user user id
|
||||
* @param ipAddress
|
||||
* @param firstResult
|
||||
|
||||
@ -359,7 +359,7 @@ public class AdapterTestStrategy extends ExternalResource {
|
||||
realm = session.realms().getRealmByName("demo");
|
||||
// need to cleanup so other tests don't fail, so invalidate http sessions on remote clients.
|
||||
UserModel user = session.users().getUserByUsername("bburke@redhat.com", realm);
|
||||
new ResourceAdminManager().logoutUser(null, realm, user, session);
|
||||
new ResourceAdminManager(session).logoutUser(null, realm, user, session);
|
||||
realm.setSsoSessionIdleTimeout(originalIdle);
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
@ -67,6 +67,13 @@
|
||||
"interval": 900
|
||||
},
|
||||
|
||||
"connectionsHttpClient": {
|
||||
"default": {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"connectionsJpa": {
|
||||
"default": {
|
||||
"url": "${keycloak.connectionsJpa.url:jdbc:h2:mem:test}",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user