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.
+ }
+ });
+
+ }
+
+ if (this.routePlanner != null) {
+ clientBuilder.setRoutePlanner(this.routePlanner);
+ }
+
+ return clientBuilder.build();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public HttpClient build(AdapterHttpClientConfig adapterConfig) {
+ disableCookieCache(true); // 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);
+ }
+ }
+
+ HttpClientBuilder.HostnameVerificationPolicy policy = HttpClientBuilder.HostnameVerificationPolicy.WILDCARD;
+ if (adapterConfig.isAllowAnyHostname())
+ policy = HttpClientBuilder.HostnameVerificationPolicy.ANY;
+ connectionPoolSize(adapterConfig.getConnectionPoolSize());
+ hostnameVerification(policy);
+ if (adapterConfig.isDisableTrustManager()) {
+ disableTrustManager();
+ } else {
+ trustStore(truststore);
+ }
+
+ configureProxyForAuthServerIfProvided(adapterConfig);
+
+ if (socketTimeout == -1 && adapterConfig.getSocketTimeout() > 0) {
+ socketTimeout(adapterConfig.getSocketTimeout(), TimeUnit.MILLISECONDS);
+ }
+
+ if (establishConnectionTimeout == -1 && adapterConfig.getConnectionTimeout() > 0) {
+ establishConnectionTimeout(adapterConfig.getConnectionTimeout(), TimeUnit.MILLISECONDS);
+ }
+
+ if (connectionTTL == -1 && adapterConfig.getConnectionTTL() > 0) {
+ connectionTTL(adapterConfig.getConnectionTTL(), TimeUnit.MILLISECONDS);
+ }
+
+ return build();
+ }
+
+ /**
+ * Configures a the proxy to use for auth-server requests if provided.
+ *
+ * If the given {@link AdapterHttpClientConfig} 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(AdapterHttpClientConfig 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/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java
index 7842f4b..aa7cc71 100644
--- a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java
+++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java
@@ -23,12 +23,16 @@ import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.Callable;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -51,7 +55,9 @@ import org.alfresco.util.PropertyCheck;
import org.alfresco.web.site.servlet.SSOAuthenticationFilter;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
@@ -60,9 +66,11 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.params.ConnRouteParams;
import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.OAuth2Constants;
@@ -128,6 +136,7 @@ import de.acosix.alfresco.keycloak.share.config.KeycloakAdapterConfigElement;
import de.acosix.alfresco.keycloak.share.config.KeycloakAuthenticationConfigElement;
import de.acosix.alfresco.keycloak.share.config.KeycloakConfigConstants;
import de.acosix.alfresco.keycloak.share.remote.AccessTokenAwareSlingshotAlfrescoConnector;
+import de.acosix.alfresco.keycloak.share.util.HttpClientBuilder;
import de.acosix.alfresco.keycloak.share.util.NameValueMapAdapter;
import de.acosix.alfresco.keycloak.share.util.RefreshableAccessTokenHolder;
@@ -519,6 +528,25 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
{
final ExtendedAdapterConfig adapterConfiguration = keycloakAdapterConfig.buildAdapterConfiguration();
this.keycloakDeployment = KeycloakDeploymentBuilder.build(adapterConfiguration);
+
+ // we need to recreate the HttpClient to configure the forced route URL
+ this.keycloakDeployment.setClient(new Callable() {
+ private HttpClient client;
+ @Override
+ public HttpClient call() throws Exception {
+ if (client == null) {
+ synchronized (this) {
+ if (client == null) {
+ client = new HttpClientBuilder()
+ .routePlanner(createForcedRoutePlanner(adapterConfiguration))
+ .build(adapterConfiguration);
+ }
+ }
+ }
+ return client;
+ }
+ });
+
final String forcedRouteUrl = adapterConfiguration.getForcedRouteUrl();
if (forcedRouteUrl != null && !forcedRouteUrl.isEmpty())
{
@@ -1879,4 +1907,47 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
}
params.setParameter(ConnRoutePNames.FORCED_ROUTE, route);
}
+
+ protected HttpRoute createRoute(ExtendedAdapterConfig adapterConfig, HttpHost routeHost) throws UnknownHostException, MalformedURLException {
+ boolean secure = "https".equalsIgnoreCase(routeHost.getSchemeName());
+
+ if (adapterConfig.getProxyUrl() != null) {
+ // useful in parsing the URL for just what is needed for HttpHost
+ URL proxyUrl = new URL(adapterConfig.getProxyUrl());
+ HttpHost proxyHost = new HttpHost(proxyUrl.getHost(), proxyUrl.getPort(), proxyUrl.getProtocol());
+ return new HttpRoute(routeHost, InetAddress.getLocalHost(), proxyHost, secure);
+ } else {
+ return new HttpRoute(routeHost, InetAddress.getLocalHost(), secure);
+ }
+ }
+
+ protected HttpRoute createForcedRoute(ExtendedAdapterConfig adapterConfig) throws UnknownHostException, MalformedURLException {
+ // useful in parsing the URL for just what is needed for HttpHost
+ URL forcedRouteUrl = new URL(adapterConfig.getForcedRouteUrl());
+ HttpHost forcedRouteHost = new HttpHost(forcedRouteUrl.getHost(), forcedRouteUrl.getPort(), forcedRouteUrl.getProtocol());
+ return this.createRoute(adapterConfig, forcedRouteHost);
+ }
+
+ protected HttpRoutePlanner createForcedRoutePlanner(ExtendedAdapterConfig adapterConfig) throws MalformedURLException {
+ URL authServerUrl = new URL(adapterConfig.getAuthServerUrl());
+ final HttpHost authServerHost = new HttpHost(authServerUrl.getHost(), authServerUrl.getPort(), authServerUrl.getProtocol());
+
+ return new HttpRoutePlanner() {
+ @Override
+ public HttpRoute determineRoute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
+ try {
+ if (authServerHost.equals(target)) {
+ LOGGER.trace("Rerouting to forced route");
+ HttpRoute route = createForcedRoute(adapterConfig);
+ LOGGER.trace("Rerouting to forced route: {}", route);
+ return route;
+ } else {
+ return createRoute(adapterConfig, target);
+ }
+ } catch (IOException ie) {
+ throw new HttpException(ie.getMessage(), ie);
+ }
+ }
+ };
+ }
}