keycloak-aplcache
Changes
adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/AdapterHttpClientConfig.java 75(+75 -0)
adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientAdapterException.java 32(+32 -0)
Details
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 63cdab8..e6d6588 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
@@ -38,7 +38,7 @@ import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.keycloak.common.util.EnvUtil;
import org.keycloak.common.util.KeystoreUtil;
-import org.keycloak.representations.adapters.config.AdapterConfig;
+import org.keycloak.representations.adapters.config.AdapterHttpClientConfig;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@@ -333,7 +333,7 @@ public class HttpClientBuilder {
}
}
- public HttpClient build(AdapterConfig adapterConfig) {
+ public HttpClient build(AdapterHttpClientConfig adapterConfig) {
disableCookieCache(); // disable cookie cache as we don't want sticky sessions for load balancing
String truststorePath = adapterConfig.getTruststore();
@@ -379,13 +379,13 @@ public class HttpClientBuilder {
/**
* Configures a the proxy to use for auth-server requests if provided.
* <p>
- * If the given {@link AdapterConfig} contains the attribute {@code proxy-url} we use the
+ * 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.
* </p>
*
* @param adapterConfig
*/
- private void configureProxyForAuthServerIfProvided(AdapterConfig adapterConfig) {
+ private void configureProxyForAuthServerIfProvided(AdapterHttpClientConfig adapterConfig) {
if (adapterConfig == null || adapterConfig.getProxyUrl() == null || adapterConfig.getProxyUrl().trim().isEmpty()) {
return;
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/AdapterHttpClientConfig.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/AdapterHttpClientConfig.java
new file mode 100644
index 0000000..5c94fdb
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/AdapterHttpClientConfig.java
@@ -0,0 +1,75 @@
+/*
+ * 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.cloned;
+
+/**
+ * Configuration options relevant for configuring http client that can be used by adapter.
+ *
+ * NOTE: keep in sync with core/src/main/java/org/keycloak/representations/adapters/config/AdapterHttpClientConfig.java until unified.
+ *
+ * @author hmlnarik
+ */
+public interface AdapterHttpClientConfig {
+
+ /**
+ * Returns truststore filename.
+ */
+ public String getTruststore();
+
+ /**
+ * Returns truststore password.
+ */
+ public String getTruststorePassword();
+
+ /**
+ * Returns keystore with client keys.
+ */
+ public String getClientKeystore();
+
+ /**
+ * Returns keystore password.
+ */
+ public String getClientKeystorePassword();
+
+ /**
+ * Returns boolean flag whether any hostname verification is done on the server's
+ * certificate, {@code true} means that verification is not done.
+ * @return
+ */
+ public boolean isAllowAnyHostname();
+
+ /**
+ * Returns boolean flag whether any trust management and hostname verification is done.
+ * <p>
+ * <i>NOTE</i> Disabling trust manager 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 boolean isDisableTrustManager();
+
+ /**
+ * Returns size of connection pool.
+ */
+ public int getConnectionPoolSize();
+
+ /**
+ * Returns URL of HTTP proxy.
+ */
+ public String getProxyUrl();
+
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpAdapterUtils.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpAdapterUtils.java
new file mode 100644
index 0000000..0fa330e
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpAdapterUtils.java
@@ -0,0 +1,78 @@
+/*
+ * 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.cloned;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+
+import java.io.IOException;
+import java.io.InputStream;
+import javax.xml.crypto.dsig.keyinfo.KeyInfo;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.util.EntityUtils;
+import org.keycloak.adapters.saml.descriptor.parsers.SamlDescriptorIDPKeysExtractor;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.saml.common.exceptions.ParsingException;
+
+/**
+ * @author <a href="mailto:hmlnarik@redhat.com">Hynek Mlnařík</a>
+ */
+public class HttpAdapterUtils {
+
+ public static MultivaluedHashMap<String, KeyInfo> downloadKeysFromSamlDescriptor(HttpClient client, String descriptorUrl) throws HttpClientAdapterException {
+ try {
+ HttpGet httpRequest = new HttpGet(descriptorUrl);
+ HttpResponse response = client.execute(httpRequest);
+ int status = response.getStatusLine().getStatusCode();
+ if (status != HttpStatus.SC_OK) {
+ EntityUtils.consumeQuietly(response.getEntity());
+ throw new HttpClientAdapterException("Unexpected status = " + status);
+ }
+
+ HttpEntity entity = response.getEntity();
+ if (entity == null) {
+ throw new HttpClientAdapterException("There was no entity.");
+ }
+
+ MultivaluedHashMap<String, KeyInfo> res;
+ try (InputStream is = entity.getContent()) {
+ res = extractKeysFromSamlDescriptor(is);
+ }
+
+ EntityUtils.consumeQuietly(entity);
+
+ return res;
+ } catch (IOException | ParsingException e) {
+ throw new HttpClientAdapterException("IO error", e);
+ }
+ }
+
+ /**
+ * Parses SAML descriptor and extracts keys from it.
+ * @param xmlStream
+ * @return List of KeyInfo objects containing keys from the descriptor.
+ * @throws IOException
+ */
+ public static MultivaluedHashMap<String, KeyInfo> extractKeysFromSamlDescriptor(InputStream xmlStream) throws ParsingException {
+ Object res = new SamlDescriptorIDPKeysExtractor().parse(xmlStream);
+ return (MultivaluedHashMap<String, KeyInfo>) res;
+ }
+
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientAdapterException.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientAdapterException.java
new file mode 100644
index 0000000..e0371ad
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientAdapterException.java
@@ -0,0 +1,32 @@
+/*
+ * 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.cloned;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class HttpClientAdapterException extends Exception {
+
+ public HttpClientAdapterException(String message) {
+ super(message);
+ }
+
+ public HttpClientAdapterException(String message, Throwable t) {
+ super(message, t);
+ }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientBuilder.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientBuilder.java
new file mode 100644
index 0000000..7e26c01
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientBuilder.java
@@ -0,0 +1,396 @@
+/*
+ * 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.cloned;
+
+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;
+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.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.net.URI;
+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;
+ protected HttpHost proxyHost;
+
+
+ /**
+ * 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 (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));
+ }
+ 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(AdapterHttpClientConfig 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);
+ }
+
+ configureProxyForAuthServerIfProvided(adapterConfig);
+
+ return build();
+ }
+
+ /**
+ * Configures a the proxy to use for auth-server requests if provided.
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/SniSSLSocketFactory.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/SniSSLSocketFactory.java
new file mode 100644
index 0000000..8c064b0
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/SniSSLSocketFactory.java
@@ -0,0 +1,143 @@
+/*
+ * 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.cloned;
+
+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.InvocationTargetException;
+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.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * SSLSocketFactory that uses Server Name Indication (SNI) TLS extension.
+ *
+ * <p>
+ * Originally copied from <b>keycloak-adapter-core</b> project.
+ *
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ * @author <a href="mailto:hmlnarik@redhat.com">Hynek Mlnařík</a>
+ */
+public class SniSSLSocketFactory extends SSLSocketFactory {
+
+ private static final 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>() {
+ @Override
+ public Method run() throws NoSuchMethodException {
+ return socket.getClass().getMethod("setHost", String.class);
+ }
+ });
+
+ setHostMethod.invoke(socket, hostname);
+ LOG.log(Level.FINEST, "Applied SNI to socket for host {0}", hostname);
+ } catch (PrivilegedActionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ LOG.log(Level.WARNING, "Failed to apply SNI to SSLSocket", e);
+ }
+ }
+ return socket;
+ }
+}
diff --git a/adapters/saml/core/src/test/java/org/keycloak/adapters/cloned/HttpAdapterUtilsTest.java b/adapters/saml/core/src/test/java/org/keycloak/adapters/cloned/HttpAdapterUtilsTest.java
new file mode 100644
index 0000000..2c03ef8
--- /dev/null
+++ b/adapters/saml/core/src/test/java/org/keycloak/adapters/cloned/HttpAdapterUtilsTest.java
@@ -0,0 +1,82 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.adapters.cloned;
+
+import java.io.InputStream;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import javax.xml.crypto.dsig.keyinfo.KeyInfo;
+import javax.xml.crypto.dsig.keyinfo.KeyName;
+import javax.xml.crypto.dsig.keyinfo.X509Data;
+import static org.hamcrest.CoreMatchers.*;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.keycloak.adapters.saml.config.parsers.ConfigXmlConstants;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.dom.saml.v2.metadata.KeyTypes;
+import org.keycloak.saml.common.exceptions.ParsingException;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class HttpAdapterUtilsTest {
+
+ private <T> T getContent(List<Object> objects, Class<T> clazz) {
+ for (Object o : objects) {
+ if (clazz.isInstance(o)) {
+ return (T) o;
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void testExtractKeysFromSamlDescriptor() throws ParsingException {
+ InputStream xmlStream = HttpAdapterUtilsTest.class.getResourceAsStream("saml-descriptor-valid.xml");
+ MultivaluedHashMap<String, KeyInfo> res = HttpAdapterUtils.extractKeysFromSamlDescriptor(xmlStream);
+
+ assertThat(res, notNullValue());
+ assertThat(res.keySet(), hasItems(KeyTypes.SIGNING.value()));
+ assertThat(res.get(ConfigXmlConstants.SIGNING_ATTR), notNullValue());
+ assertThat(res.get(ConfigXmlConstants.SIGNING_ATTR).size(), equalTo(2));
+
+ KeyInfo ki;
+ KeyName keyName;
+ X509Data x509data;
+ X509Certificate x509certificate;
+
+ ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(0);
+ assertThat(ki.getContent().size(), equalTo(2));
+ assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
+ assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
+
+ keyName = getContent(ki.getContent(), KeyName.class);
+ assertThat(keyName.getName(), equalTo("rJkJlvowmv1Id74GznieaAC5jU5QQp_ILzuG-GsweTI"));
+
+ x509data = getContent(ki.getContent(), X509Data.class);
+ assertThat(x509data, notNullValue());
+ x509certificate = getContent(x509data.getContent(), X509Certificate.class);
+ assertThat(x509certificate, notNullValue());
+ assertThat(x509certificate.getSigAlgName(), equalTo("SHA256withRSA"));
+
+ ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(1);
+ assertThat(ki.getContent().size(), equalTo(2));
+ assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
+ assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
+
+ keyName = getContent(ki.getContent(), KeyName.class);
+ assertThat(keyName.getName(), equalTo("BzYc4GwL8HVrAhNyNdp-lTah2DvU9jU03kby9Ynohr4"));
+
+ x509data = getContent(ki.getContent(), X509Data.class);
+ assertThat(x509data, notNullValue());
+ x509certificate = getContent(x509data.getContent(), X509Certificate.class);
+ assertThat(x509certificate, notNullValue());
+ assertThat(x509certificate.getSigAlgName(), equalTo("SHA256withRSA"));
+
+ }
+
+}
diff --git a/adapters/saml/core/src/test/resources/org/keycloak/adapters/cloned/saml-descriptor-valid.xml b/adapters/saml/core/src/test/resources/org/keycloak/adapters/cloned/saml-descriptor-valid.xml
new file mode 100644
index 0000000..8dd3e41
--- /dev/null
+++ b/adapters/saml/core/src/test/resources/org/keycloak/adapters/cloned/saml-descriptor-valid.xml
@@ -0,0 +1,62 @@
+<?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.
+
+-->
+<EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Name="urn:keycloak">
+ <EntityDescriptor entityID="http://localhost:8081/auth/realms/master">
+ <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+ <KeyDescriptor use="signing">
+ <dsig:KeyInfo>
+ <dsig:KeyName>rJkJlvowmv1Id74GznieaAC5jU5QQp_ILzuG-GsweTI</dsig:KeyName>
+ <dsig:X509Data>
+ <dsig:X509Certificate>
+ MIICmzCCAYMCBgFX/9ccIDANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMTYxMDI2MDcxMjUwWhcNMjYxMDI2MDgxNDMwWjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPjDrM890OoFWLIU5xNT+v8B8EkpOGY1y/9Yi/yQd95uG/p5LaywiPsw+lPy4tSn1pH/2SxNDST2zynKPDd1lYDev43m0sC2FfD2H73q3udQRqSOxW1e8FrTrGDIHxb82UNrCPlu+fH+xYSkigrkOvLvPigTwSIcu8vgs0lk9FqJ81ty3Wj2e9lS7JJGAJ3pC7rp39VLdJSKbfyj/v2RYBeG5Pscncl8cjUOHUq5u19hThjkU2jOBzgIK2JS0bNmzSfH1eBTZMoCQBI1UJ1IbA8tqjQwpOXc+JkPBRU8T/JUQoQlSR6DTcPFvDgH2oGZYFHFfUontZqtz8jrIt2pxBAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAK5VgQp1x1FKgabFI6W/iGuy9ZCRoAixOOEGGkDps6dOEFgTQKTy5D/FZts9KuNxhhiD+NvS0d5BKYa5ITPLVPnGucgYkZhz+/+GhxmbjeQr0eJPaY7ZgLfH3tPA6tfdIkA0iE1En1sKEwt6R6DZjh9jtP9laoUoddTvYaFLJpZ2u1Ik94q6ZqX0fS/RKchaBHjhg6MtqCcHt07CBKHh8XNmKPXVSJC/p0MjyXv+qLaNNqyaAvAw6P6DX1hNjzrdkuaaHGXhu6kkezZUVlDWAm9cd1ppqalSK6ggy7yMW1NWTd/NYOPsFU2TS8DDPzRo14s1Qvw4v+TY6yT0NURJPQA=
+ </dsig:X509Certificate>
+ </dsig:X509Data>
+ </dsig:KeyInfo>
+ </KeyDescriptor>
+ <KeyDescriptor use="signing">
+ <dsig:KeyInfo>
+ <dsig:KeyName>BzYc4GwL8HVrAhNyNdp-lTah2DvU9jU03kby9Ynohr4</dsig:KeyName>
+ <dsig:X509Data>
+ <dsig:X509Certificate>
+ MIICmzCCAYMCBgFX/9eK7TANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMTYxMDI2MDcxMzE4WhcNMjYxMDI2MDgxNDU4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCDLT+40/BWzWPSVmpaSaZRs5lBMQ9VP9TCoXkby4PHqxIWRecTPM8fcNkPNPE/tiR2tUIpMXPDzgXNFA/EMoB3V1OEVXPecjKtiZczdR6pi75CBx7PJ2fSXg6xpjhZmHu0k7x591GZdP8Iiu2E6b9QA2p5VXgNgfuP07XzgabnSvIrLG60Imus3u6C2qA/QEuY7EYQWrFooriYLW6B8s3xU8R1a92SLMT8JsfMWXi+1CzAhIbVvdwUwkhVDDhAU6pUek88QQgxodd3FAMksoijCGFN1yrCkovlFhKb3j9AC6Icd9eeJuwYddN/nMeMGEDOeCcAGBACiaUisjUvZDw1AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHAHbBI0CRfdw5ZHxHAjgSQvSj41c/4cfwln4Q7X3I5lMBbW3tcgond6Ku9eU46FzG5VpgXIgvEf4u0O9jUnxLlO50+t2SHwQ1RwHdBWQngVSZCRzscq3KrSzx1hx88qLyqcPrr3QtR92fYipDjENxttT/qJtDMrXlwLZEITlHDoneX319USYB9C4zlrCIsQ5XxQTTyCx886Pz15DSVSRxVp61HGk6ROsX/DG5/xwInlzgMZ0r3JWnAjtAaXqUrcwH9FXxco+xkiqKW79bGhWGQI9sXXvQSSNAaENMIUhxtd9uOi1l5e0EkKHE2fHlYyfdUDnFJWwSMXd/NM+hVI4Lw=
+ </dsig:X509Certificate>
+ </dsig:X509Data>
+ </dsig:KeyInfo>
+ </KeyDescriptor>
+ <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
+ <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
+ <NameIDFormat>
+ urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
+ </NameIDFormat>
+ <NameIDFormat>
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ </NameIDFormat>
+ <NameIDFormat>
+ urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
+ </NameIDFormat>
+ <NameIDFormat>
+ urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
+ </NameIDFormat>
+ <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
+ <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
+ <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
+ </IDPSSODescriptor>
+ </EntityDescriptor>
+</EntitiesDescriptor>
\ 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 c4818b4..0ba327d 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
@@ -39,7 +39,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
"proxy-url", "turn-off-change-session-id-on-login", "token-minimum-time-to-live", "min-time-between-jwks-requests",
"policy-enforcer"
})
-public class AdapterConfig extends BaseAdapterConfig {
+public class AdapterConfig extends BaseAdapterConfig implements AdapterHttpClientConfig {
@JsonProperty("allow-any-hostname")
protected boolean allowAnyHostname;
@@ -82,6 +82,7 @@ public class AdapterConfig extends BaseAdapterConfig {
@JsonProperty("proxy-url")
protected String proxyUrl;
+ @Override
public boolean isAllowAnyHostname() {
return allowAnyHostname;
}
@@ -90,6 +91,7 @@ public class AdapterConfig extends BaseAdapterConfig {
this.allowAnyHostname = allowAnyHostname;
}
+ @Override
public boolean isDisableTrustManager() {
return disableTrustManager;
}
@@ -98,6 +100,7 @@ public class AdapterConfig extends BaseAdapterConfig {
this.disableTrustManager = disableTrustManager;
}
+ @Override
public String getTruststore() {
return truststore;
}
@@ -106,6 +109,7 @@ public class AdapterConfig extends BaseAdapterConfig {
this.truststore = truststore;
}
+ @Override
public String getTruststorePassword() {
return truststorePassword;
}
@@ -114,6 +118,7 @@ public class AdapterConfig extends BaseAdapterConfig {
this.truststorePassword = truststorePassword;
}
+ @Override
public String getClientKeystore() {
return clientKeystore;
}
@@ -122,6 +127,7 @@ public class AdapterConfig extends BaseAdapterConfig {
this.clientKeystore = clientKeystore;
}
+ @Override
public String getClientKeystorePassword() {
return clientKeystorePassword;
}
@@ -138,6 +144,7 @@ public class AdapterConfig extends BaseAdapterConfig {
this.clientKeyPassword = clientKeyPassword;
}
+ @Override
public int getConnectionPoolSize() {
return connectionPoolSize;
}
@@ -202,6 +209,7 @@ public class AdapterConfig extends BaseAdapterConfig {
this.policyEnforcerConfig = policyEnforcerConfig;
}
+ @Override
public String getProxyUrl() {
return proxyUrl;
}
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterHttpClientConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterHttpClientConfig.java
new file mode 100644
index 0000000..fa4c87e
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterHttpClientConfig.java
@@ -0,0 +1,75 @@
+/*
+ * 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.representations.adapters.config;
+
+/**
+ * Configuration options relevant for configuring http client that can be used by adapter.
+ *
+ * NOTE: keep in sync with adapters/saml/core/src/main/java/org/keycloak/adapters/AdapterHttpClientConfig.java until unified.
+ *
+ * @author hmlnarik
+ */
+public interface AdapterHttpClientConfig {
+
+ /**
+ * Returns truststore filename.
+ */
+ public String getTruststore();
+
+ /**
+ * Returns truststore password.
+ */
+ public String getTruststorePassword();
+
+ /**
+ * Returns keystore with client keys.
+ */
+ public String getClientKeystore();
+
+ /**
+ * Returns keystore password.
+ */
+ public String getClientKeystorePassword();
+
+ /**
+ * Returns boolean flag whether any hostname verification is done on the server's
+ * certificate, {@code true} means that verification is not done.
+ * @return
+ */
+ public boolean isAllowAnyHostname();
+
+ /**
+ * Returns boolean flag whether any trust management and hostname verification is done.
+ * <p>
+ * <i>NOTE</i> Disabling trust manager 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 boolean isDisableTrustManager();
+
+ /**
+ * Returns size of connection pool.
+ */
+ public int getConnectionPoolSize();
+
+ /**
+ * Returns URL of HTTP proxy.
+ */
+ public String getProxyUrl();
+
+}