From bccc5fa7b1a880005249750732d52e74ea639378 Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Tue, 15 Mar 2016 16:47:44 +0100 Subject: [PATCH] KEYCLOAK-2054 - Allow to configure proxy for auth-server requests in adapters. Previously the adapter configuration did not support specifying a proxy for auth-server requests issued via the Apache HTTP Client by Keycloak. This made it very difficult to connect an Application with Keycloak that was required to use a proxy. Introduced new `proxy-url` attribute to the adapter configuration which makes it possible to configure a proxy to be used for auth-server requests. Proxy-Host, Proxy-Port and Proxy-Scheme are taken from the configured proxy URL. Note that proxies that require authentication are currently not supported. --- .../keycloak/adapters/HttpClientBuilder.java | 48 +++++++++++++++---- .../adapters/config/AdapterConfig.java | 17 ++++++- .../en/en-US/modules/adapter-config.xml | 11 +++++ 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java index cfcbe19540..63cdab890c 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpClientBuilder.java @@ -17,9 +17,11 @@ package org.keycloak.adapters; +import org.apache.http.HttpHost; import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; @@ -34,9 +36,9 @@ 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 org.keycloak.representations.adapters.config.AdapterConfig; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; @@ -46,6 +48,7 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.IOException; +import java.net.URI; import java.security.KeyStore; import java.security.SecureRandom; import java.security.cert.CertificateException; @@ -112,6 +115,7 @@ public class HttpClientBuilder { protected TimeUnit socketTimeoutUnits = TimeUnit.MILLISECONDS; protected long establishConnectionTimeout = -1; protected TimeUnit establishConnectionTimeoutUnits = TimeUnit.MILLISECONDS; + protected HttpHost proxyHost; /** @@ -121,8 +125,7 @@ public class HttpClientBuilder { * @param unit * @return */ - public HttpClientBuilder socketTimeout(long timeout, TimeUnit unit) - { + public HttpClientBuilder socketTimeout(long timeout, TimeUnit unit) { this.socketTimeout = timeout; this.socketTimeoutUnits = unit; return this; @@ -135,8 +138,7 @@ public class HttpClientBuilder { * @param unit * @return */ - public HttpClientBuilder establishConnectionTimeout(long timeout, TimeUnit unit) - { + public HttpClientBuilder establishConnectionTimeout(long timeout, TimeUnit unit) { this.establishConnectionTimeout = timeout; this.establishConnectionTimeoutUnits = unit; return this; @@ -287,16 +289,20 @@ public class HttpClientBuilder { cm = new SingleClientConnManager(registry); } BasicHttpParams params = new BasicHttpParams(); - if (socketTimeout > -1) - { + + if (proxyHost != null) { + params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost); + } + + if (socketTimeout > -1) { HttpConnectionParams.setSoTimeout(params, (int) socketTimeoutUnits.toMillis(socketTimeout)); } - if (establishConnectionTimeout > -1) - { - HttpConnectionParams.setConnectionTimeout(params, (int)establishConnectionTimeoutUnits.toMillis(establishConnectionTimeout)); + if (establishConnectionTimeout > -1) { + HttpConnectionParams.setConnectionTimeout(params, (int) establishConnectionTimeoutUnits.toMillis(establishConnectionTimeout)); } DefaultHttpClient client = new DefaultHttpClient(cm, params); + if (disableCookieCache) { client.setCookieStore(new CookieStore() { @Override @@ -364,6 +370,28 @@ public class HttpClientBuilder { } else { trustStore(truststore); } + + configureProxyForAuthServerIfProvided(adapterConfig); + return build(); } + + /** + * Configures a the proxy to use for auth-server requests if provided. + *

+ * If the given {@link AdapterConfig} contains the attribute {@code proxy-url} we use the + * given URL as a proxy server, otherwise the proxy configuration is ignored. + *

+ * + * @param adapterConfig + */ + private void configureProxyForAuthServerIfProvided(AdapterConfig adapterConfig) { + + if (adapterConfig == null || adapterConfig.getProxyUrl() == null || adapterConfig.getProxyUrl().trim().isEmpty()) { + return; + } + + URI uri = URI.create(adapterConfig.getProxyUrl()); + this.proxyHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()); + } } \ No newline at end of file diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java index fc3607861d..87b3ab2ad9 100755 --- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java +++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java @@ -35,7 +35,8 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; "allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password", "client-keystore", "client-keystore-password", "client-key-password", "always-refresh-token", - "register-node-at-startup", "register-node-period", "token-store", "principal-attribute" + "register-node-at-startup", "register-node-period", "token-store", "principal-attribute", + "proxy-url" }) public class AdapterConfig extends BaseAdapterConfig { @@ -68,6 +69,12 @@ public class AdapterConfig extends BaseAdapterConfig { @JsonProperty("turn-off-change-session-id-on-login") protected Boolean turnOffChangeSessionIdOnLogin; + /** + * The Proxy url to use for requests to the auth-server, configurable via the adapter config property {@code proxy-url}. + */ + @JsonProperty("proxy-url") + protected String proxyUrl; + public boolean isAllowAnyHostname() { return allowAnyHostname; } @@ -179,4 +186,12 @@ public class AdapterConfig extends BaseAdapterConfig { public void setTurnOffChangeSessionIdOnLogin(Boolean turnOffChangeSessionIdOnLogin) { this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin; } + + public String getProxyUrl() { + return proxyUrl; + } + + public void setProxyUrl(String proxyUrl) { + this.proxyUrl = proxyUrl; + } } diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml b/docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml index cb30f333cd..c6279e999c 100755 --- a/docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml +++ b/docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml @@ -405,6 +405,17 @@ + + proxy-url + + + Defines the proxy to use for requests sent to the auth-server-url. + This is OPTIONAL. Note that only the scheme, + host and port of the proxy URL are used. + Proxies that require authentication are currently not supported. + + +