diff --git a/.gitignore b/.gitignore
index 586adb73..8c631052 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@
target
bin
.metadata
-**/integrationTest.properties
\ No newline at end of file
+**/integrationTest.properties
+/target/
diff --git a/pom.xml b/pom.xml
index 19a045e4..7d818974 100755
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
com.openshift
openshift-java-client
- 2.6.1.Final
+ 2.6.2.Final
jar
OpenShift Java Client
http://openshift.redhat.com
diff --git a/src/main/java/com/openshift/client/OpenShiftConnectionFactory.java b/src/main/java/com/openshift/client/OpenShiftConnectionFactory.java
index 451e604b..43a1585a 100755
--- a/src/main/java/com/openshift/client/OpenShiftConnectionFactory.java
+++ b/src/main/java/com/openshift/client/OpenShiftConnectionFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012 Red Hat, Inc.
+ * Copyright (c) 2012-2014 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
@@ -14,8 +14,10 @@
import java.io.IOException;
import com.openshift.client.IHttpClient.ISSLCertificateCallback;
+import com.openshift.client.configuration.AbstractOpenshiftConfiguration.ConfigurationOptions;
import com.openshift.client.configuration.IOpenShiftConfiguration;
import com.openshift.client.configuration.OpenShiftConfiguration;
+import com.openshift.client.utils.SSLUtils;
import com.openshift.internal.client.AbstractOpenShiftConnectionFactory;
import com.openshift.internal.client.IRestService;
import com.openshift.internal.client.RestService;
@@ -33,7 +35,7 @@
*
*/
public class OpenShiftConnectionFactory extends AbstractOpenShiftConnectionFactory {
- private IOpenShiftConfiguration configuration = null;
+ private IOpenShiftConfiguration configuration;
/**
* Establish a connection with the clientId along with user's password.
* User's login and Server URL are retrieved from the local configuration
@@ -49,11 +51,7 @@ public class OpenShiftConnectionFactory extends AbstractOpenShiftConnectionFacto
* @throws OpenShiftException
*/
public IOpenShiftConnection getConnection(final String clientId, final String password) throws OpenShiftException {
- try {
- configuration = new OpenShiftConfiguration();
- } catch (IOException e) {
- throw new OpenShiftException(e, "Failed to load OpenShift configuration file.");
- }
+ IOpenShiftConfiguration configuration = getConfiguration();
return getConnection(clientId, configuration.getRhlogin(), password, configuration.getLibraServer());
}
@@ -75,12 +73,7 @@ public IOpenShiftConnection getConnection(final String clientId, final String pa
*/
public IOpenShiftConnection getConnection(final String clientId, final String username, final String password)
throws OpenShiftException {
- try {
- configuration = new OpenShiftConfiguration();
- } catch (IOException e) {
- throw new OpenShiftException(e, "Failed to load OpenShift configuration file.");
- }
- return getConnection(clientId, username, password, configuration.getLibraServer());
+ return getConnection(clientId, username, password, getConfiguration().getLibraServer());
}
/**
@@ -115,6 +108,23 @@ public IOpenShiftConnection getConnection(final String clientId, final String us
return getConnection(clientId, username, password, null, null, serverUrl, null);
}
+ public IOpenShiftConnection getConnection(final String clientId, final String username, final String password,
+ final String authKey, final String authIV, final String serverUrl,
+ final ISSLCertificateCallback sslCertificateCallback) throws OpenShiftException {
+ return getConnection(clientId, username, password, authKey, authIV, serverUrl, sslCertificateCallback, createCipherExclusionRegex(getConfiguration()));
+ }
+
+ protected String createCipherExclusionRegex(IOpenShiftConfiguration configuration) {
+ if(configuration.getDisableBadSSLCiphers() == ConfigurationOptions.YES
+ || (configuration.getDisableBadSSLCiphers() == ConfigurationOptions.AUTO) && !SSLUtils.supportsDHECipherKeysOf(1024 + 64)) {
+ // jdk < 1.8 only support DHE cipher keys <= 1024 bit
+ // https://issues.jboss.org/browse/JBIDE-18454
+ return SSLUtils.CIPHER_DHE_REGEX;
+ } else {
+ return null;
+ }
+ }
+
/**
* Establish a connection with the clientId along with user's login and
* password.
@@ -133,31 +143,47 @@ public IOpenShiftConnection getConnection(final String clientId, final String us
* @throws OpenShiftException
*/
public IOpenShiftConnection getConnection(final String clientId, final String username, final String password,
- final String authKey, final String authIV, final String serverUrl,
- final ISSLCertificateCallback sslCertificateCallback) throws OpenShiftException {
- if (configuration == null) {
- try {
- configuration = new OpenShiftConfiguration();
- } catch (IOException e) {
- throw new OpenShiftException(e, "Failed to load OpenShift configuration file.");
- }
- }
+ final String authKey, final String authIV, final String serverUrl,
+ final ISSLCertificateCallback sslCertificateCallback, String exludeSSLCipherRegex)
+ throws OpenShiftException {
Assert.notNull(clientId);
Assert.notNull(username);
Assert.notNull(password);
Assert.notNull(serverUrl);
+ IHttpClient httpClient = createClient(
+ clientId, username, password, authKey, authIV, serverUrl, sslCertificateCallback, exludeSSLCipherRegex);
try {
- IHttpClient httpClient =
- new UrlConnectionHttpClientBuilder()
+ return getConnection(clientId, username, password, serverUrl, httpClient);
+ } catch (IOException e) {
+ throw new OpenShiftException(e, "Failed to establish connection for user ''{0}}''", username);
+ }
+ }
+
+ protected IHttpClient createClient(final String clientId, final String username, final String password,
+ final String authKey, final String authIV, final String serverUrl,
+ final ISSLCertificateCallback sslCertificateCallback, String exludeSSLCipherRegex) {
+ return new UrlConnectionHttpClientBuilder()
.setCredentials(username, password, authKey, authIV)
.setSSLCertificateCallback(sslCertificateCallback)
- .setConfigTimeout(configuration.getTimeout())
+ .setConfigTimeout(getConfiguration().getTimeout())
+ .excludeSSLCipher(exludeSSLCipherRegex)
.client();
- return getConnection(clientId, username, password, serverUrl, httpClient);
+ }
+
+ protected IOpenShiftConfiguration getConfiguration() throws OpenShiftException {
+ if (this.configuration == null) {
+ this.configuration = createConfiguration();
+ }
+ return this.configuration;
+ }
+
+ protected IOpenShiftConfiguration createConfiguration() throws OpenShiftException {
+ try {
+ return new OpenShiftConfiguration();
} catch (IOException e) {
- throw new OpenShiftException(e, "Failed to establish connection for user ''{0}}''", username);
+ throw new OpenShiftException(e, "Failed to load OpenShift configuration file.");
}
}
diff --git a/src/main/java/com/openshift/client/configuration/AbstractOpenshiftConfiguration.java b/src/main/java/com/openshift/client/configuration/AbstractOpenshiftConfiguration.java
index bd0fe743..7fa9d134 100755
--- a/src/main/java/com/openshift/client/configuration/AbstractOpenshiftConfiguration.java
+++ b/src/main/java/com/openshift/client/configuration/AbstractOpenshiftConfiguration.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011 Red Hat, Inc.
+ * Copyright (c) 2011-2014 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
@@ -33,26 +33,42 @@ public abstract class AbstractOpenshiftConfiguration implements IOpenShiftConfig
protected static final String KEY_LIBRA_SERVER = "libra_server";
protected static final String KEY_LIBRA_DOMAIN = "libra_domain";
-
protected static final String KEY_PASSWORD = "rhpassword";
protected static final String KEY_CLIENT_ID = "client_id";
protected static final String KEY_TIMEOUT = "timeout";
- protected static final String DEFAULT_OPENSHIFT_TIMEOUT = "180000"; //3 minutes
+ protected static final String DEFAULT_OPENSHIFT_TIMEOUT = "180000"; // 3mins
+
+ protected static final String KEY_DISABLE_BAD_SSL_CIPHERS = "disable_bad_sslciphers";
private static final Pattern QUOTED_REGEX = Pattern.compile("['\"]*([^'\"]+)['\"]*");
private static final char SINGLEQUOTE = '\'';
-
+
private static final String SYSPROPERTY_PROXY_PORT = "proxyPort";
private static final String SYSPROPERTY_PROXY_HOST = "proxyHost";
private static final String SYSPROPERTY_PROXY_SET = "proxySet";
private Properties properties;
private File file;
-
- // TODO: implement
+
private boolean doSSLChecks = false;
+ public enum ConfigurationOptions {
+ YES, NO, AUTO;
+
+ private static ConfigurationOptions safeValueOf(String string) {
+ if (string == null) {
+ return NO;
+ }
+
+ try {
+ return valueOf(string.toUpperCase());
+ } catch (IllegalArgumentException e) {
+ return NO;
+ }
+ }
+ }
+
protected AbstractOpenshiftConfiguration() throws FileNotFoundException, IOException {
this(null, null);
}
@@ -164,7 +180,7 @@ protected String removeQuotes(String value) {
return value;
}
}
-
+
public String getPassword() {
return properties.getProperty(KEY_PASSWORD);
}
@@ -172,26 +188,37 @@ public String getPassword() {
public String getClientId() {
return properties.getProperty(KEY_CLIENT_ID);
}
+
+ public ConfigurationOptions getDisableBadSSLCiphers() {
+ return ConfigurationOptions.safeValueOf(
+ removeQuotes(properties.getProperty(KEY_DISABLE_BAD_SSL_CIPHERS)));
+ }
+
+ public void setDisableBadSSLCiphers(ConfigurationOptions option) {
+ properties.setProperty(KEY_DISABLE_BAD_SSL_CIPHERS, option.toString());
+ }
public void setEnableSSLCertChecks(boolean doSSLChecks) {
this.doSSLChecks = doSSLChecks;
}
-
+
public boolean getProxySet() {
- String set = properties.getProperty(SYSPROPERTY_PROXY_SET);
-
- if (set != null)
- return Boolean.parseBoolean(removeQuotes(set));
- else
- return false;
+ return toBoolean(removeQuotes(properties.getProperty(SYSPROPERTY_PROXY_SET)));
}
-
+
public String getProxyHost() {
return removeQuotes(properties.getProperty(SYSPROPERTY_PROXY_HOST));
}
-
+
public String getProxyPort() {
return removeQuotes(properties.getProperty(SYSPROPERTY_PROXY_PORT));
}
+ private boolean toBoolean(String string) {
+ if (string != null) {
+ return Boolean.parseBoolean(string);
+ } else {
+ return false;
+ }
+ }
}
diff --git a/src/main/java/com/openshift/client/configuration/DefaultConfiguration.java b/src/main/java/com/openshift/client/configuration/DefaultConfiguration.java
index 693b9189..3863da10 100755
--- a/src/main/java/com/openshift/client/configuration/DefaultConfiguration.java
+++ b/src/main/java/com/openshift/client/configuration/DefaultConfiguration.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011 Red Hat, Inc.
+ * Copyright (c) 2011-2014 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
@@ -14,7 +14,6 @@
import java.io.IOException;
import java.util.Properties;
-import com.openshift.client.IHttpClient;
import com.openshift.client.OpenShiftException;
/**
@@ -36,6 +35,7 @@ protected Properties getProperties(File file, Properties defaultProperties) {
properties.put(KEY_LIBRA_SERVER, LIBRA_SERVER);
properties.put(KEY_LIBRA_DOMAIN, LIBRA_DOMAIN);
properties.put(KEY_TIMEOUT, DEFAULT_OPENSHIFT_TIMEOUT);
+ properties.put(KEY_DISABLE_BAD_SSL_CIPHERS, ConfigurationOptions.NO.toString());
return properties;
}
}
diff --git a/src/main/java/com/openshift/client/configuration/IOpenShiftConfiguration.java b/src/main/java/com/openshift/client/configuration/IOpenShiftConfiguration.java
index d94304b0..73c8b4a3 100644
--- a/src/main/java/com/openshift/client/configuration/IOpenShiftConfiguration.java
+++ b/src/main/java/com/openshift/client/configuration/IOpenShiftConfiguration.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011 Red Hat, Inc.
+ * Copyright (c) 2011-2014 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
@@ -12,25 +12,31 @@
import java.util.Properties;
+import com.openshift.client.configuration.AbstractOpenshiftConfiguration.ConfigurationOptions;
+
/**
* @author André Dietisheim
* @author Corey Daley
*/
public interface IOpenShiftConfiguration {
- public abstract String getRhlogin();
+ public String getRhlogin();
- public abstract void setRhlogin(String rhlogin);
+ public void setRhlogin(String rhlogin);
- public abstract String getLibraServer();
+ public String getLibraServer();
- public abstract void setLibraServer(String libraServer);
+ public void setLibraServer(String libraServer);
- public abstract String getLibraDomain();
+ public String getLibraDomain();
public Integer getTimeout();
- public abstract void setLibraDomain(String libraDomain);
+ public void setLibraDomain(String libraDomain);
+ public ConfigurationOptions getDisableBadSSLCiphers();
+
+ public void setDisableBadSSLCiphers(ConfigurationOptions option);
+
public Properties getProperties();
}
\ No newline at end of file
diff --git a/src/main/java/com/openshift/client/configuration/SystemProperties.java b/src/main/java/com/openshift/client/configuration/SystemProperties.java
index d123b618..6b38cdbe 100644
--- a/src/main/java/com/openshift/client/configuration/SystemProperties.java
+++ b/src/main/java/com/openshift/client/configuration/SystemProperties.java
@@ -37,6 +37,7 @@ protected Properties getProperties(File file, Properties defaultProperties) {
copySystemProperty(KEY_PASSWORD, properties);
copySystemProperty(KEY_CLIENT_ID, properties);
copySystemProperty(KEY_OPENSHIFT_TIMEOUT, properties);
+ copySystemProperty(KEY_DISABLE_BAD_SSL_CIPHERS, properties);
return properties;
}
diff --git a/src/main/java/com/openshift/client/utils/SSLUtils.java b/src/main/java/com/openshift/client/utils/SSLUtils.java
new file mode 100644
index 00000000..39ad1450
--- /dev/null
+++ b/src/main/java/com/openshift/client/utils/SSLUtils.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+package com.openshift.client.utils;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.InvalidParameterException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+
+/**
+ * @author Andre Dietisheim
+ */
+public class SSLUtils {
+
+ private static final String SSL_CONTEXT_NAME = "SSL";
+ public static final String CIPHER_DHE_REGEX = ".*_DHE_.*";
+ private static final String CIPHER_DHE_NAME = "DiffieHellman";
+ private static final int CIPHER_DHE_MINSIZE = 512;
+ private static final int CIPHER_DHE_MAXSIZE = 16384;
+ private static final int CIPHER_DHE_MODULO = 64;
+
+ private SSLUtils() {
+ // inhibit instantiation
+ }
+
+ /**
+ * Returns true if the jdk supports DEH cipher keys in the
+ * given length.
+ * inspired by http://stackoverflow.com/a/18254095/231357
+ *
+ * @param length
+ * @return
+ *
+ */
+ public static boolean supportsDHECipherKeysOf(int length) {
+ try {
+ return isMaxKeysize(length, CIPHER_DHE_MINSIZE, CIPHER_DHE_MAXSIZE, CIPHER_DHE_MODULO,
+ AlgorithmParameterGenerator.getInstance(CIPHER_DHE_NAME));
+ } catch (NoSuchAlgorithmException e1) {
+ return false;
+ }
+ }
+
+ private static boolean isMaxKeysize(int length, int minSize, int maxSize, int modulo,
+ AlgorithmParameterGenerator algorithmParamGen) {
+ int maxLength = 0;
+ for (int i = minSize; i <= maxSize; i += modulo) {
+ try {
+ algorithmParamGen.init(i);
+ } catch (InvalidParameterException e) {
+ break;
+ }
+ maxLength = i;
+ }
+ return maxLength >= length;
+ }
+
+ public static final String[] filterCiphers(String excludedCipherRegex, String[] ciphers) {
+ if (excludedCipherRegex == null
+ || ciphers == null) {
+ return ciphers;
+ }
+
+ List filteredCiphers = new ArrayList();
+ for (String cipher : ciphers) {
+ if (!cipher.matches(excludedCipherRegex)) {
+ filteredCiphers.add(cipher);
+ }
+ }
+ return filteredCiphers.toArray(new String[filteredCiphers.size()]);
+ }
+
+ public static SSLContext getSSLContext(TrustManager trustManager) throws NoSuchAlgorithmException, KeyManagementException {
+ TrustManager[] trustManagers = null;
+ if (trustManager != null) {
+ trustManagers = new TrustManager[] { trustManager };
+ }
+ SSLContext sslContext = SSLContext.getInstance(SSL_CONTEXT_NAME);
+ sslContext.init(null, trustManagers, null);
+ return sslContext;
+ }
+}
diff --git a/src/main/java/com/openshift/internal/client/httpclient/UrlConnectionHttpClient.java b/src/main/java/com/openshift/internal/client/httpclient/UrlConnectionHttpClient.java
index cd7a00e3..5969ecea 100755
--- a/src/main/java/com/openshift/internal/client/httpclient/UrlConnectionHttpClient.java
+++ b/src/main/java/com/openshift/internal/client/httpclient/UrlConnectionHttpClient.java
@@ -12,9 +12,13 @@
import java.io.IOException;
import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.ProtocolException;
+import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
+import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -27,6 +31,7 @@
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
@@ -38,6 +43,7 @@
import com.openshift.client.HttpMethod;
import com.openshift.client.IHttpClient;
import com.openshift.client.utils.Base64Coder;
+import com.openshift.client.utils.SSLUtils;
import com.openshift.internal.client.httpclient.request.IMediaType;
import com.openshift.internal.client.httpclient.request.Parameter;
import com.openshift.internal.client.httpclient.request.ParameterValueMap;
@@ -62,6 +68,7 @@ public class UrlConnectionHttpClient implements IHttpClient {
protected String acceptedVersion;
protected ISSLCertificateCallback sslAuthorizationCallback;
protected Integer configTimeout;
+ private String excludedSSLCipherRegex;
public UrlConnectionHttpClient(
String username, String password, String userAgent, String acceptedMediaType, String version) {
@@ -70,11 +77,11 @@ public UrlConnectionHttpClient(
public UrlConnectionHttpClient(
String username, String password, String userAgent, String acceptedMediaType, String version, String authKey, String authIV) {
- this(username, password, userAgent, acceptedMediaType, version, authKey, authIV, null,null);
+ this(username, password, userAgent, acceptedMediaType, version, authKey, authIV, null,null, null);
}
public UrlConnectionHttpClient(String username, String password, String userAgent, String acceptedMediaType,
- String version, String authKey, String authIV, ISSLCertificateCallback callback, Integer configTimeout) {
+ String version, String authKey, String authIV, ISSLCertificateCallback callback, Integer configTimeout, String excludedSSLCipherRegex) {
this.username = username;
this.password = password;
this.userAgent = userAgent;
@@ -84,6 +91,7 @@ public UrlConnectionHttpClient(String username, String password, String userAgen
this.authIV = authIV;
this.sslAuthorizationCallback = callback;
this.configTimeout = configTimeout;
+ this.excludedSSLCipherRegex = excludedSSLCipherRegex;
}
@Override
@@ -140,11 +148,7 @@ protected String request(HttpMethod httpMethod, URL url, IMediaType requestMedia
connection = createConnection(
url, username, password, authKey, authIV, userAgent, acceptedVersion, acceptedMediaType, sslAuthorizationCallback, timeout);
// PATCH not yet supported by JVM
- if (httpMethod == HttpMethod.PATCH) {
- httpMethod = HttpMethod.POST;
- connection.setRequestProperty("X-Http-Method-Override", "PATCH");
- }
- connection.setRequestMethod(httpMethod.toString());
+ setRequestMethod(httpMethod, connection);
if (!parameters.isEmpty()) {
connection.setDoOutput(true);
setRequestMediaType(requestMediaType, connection);
@@ -159,6 +163,14 @@ protected String request(HttpMethod httpMethod, URL url, IMediaType requestMedia
disconnect(connection);
}
}
+
+ private void setRequestMethod(HttpMethod httpMethod, HttpURLConnection connection) throws ProtocolException {
+ if (httpMethod == HttpMethod.PATCH) {
+ httpMethod = HttpMethod.POST;
+ connection.setRequestProperty("X-Http-Method-Override", "PATCH");
+ }
+ connection.setRequestMethod(httpMethod.toString());
+ }
private void disconnect(HttpURLConnection connection) {
if (connection != null) {
@@ -215,7 +227,11 @@ protected HttpURLConnection createConnection(URL url, String username, String pa
"creating connection to {} using username \"{}\" and password \"{}\"",
new Object[] { url, username, password });
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- setSSLCallback(url, connection);
+ if (isHttps(url)) {
+ HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
+ SSLContext sslContext = setSSLCallback(sslAuthorizationCallback, url, httpsConnection);
+ setFilteredCiphers(excludedSSLCipherRegex, sslContext, httpsConnection);
+ }
setAuthorisation(username, password, authKey, authIV, connection);
connection.setUseCaches(false);
connection.setDoInput(true);
@@ -268,37 +284,71 @@ private void setAuthorisation(String username, String password, String authKey,
}
}
- private void setSSLCallback(URL url, HttpURLConnection connection) {
- if (isHttps(url)
- && sslAuthorizationCallback != null) {
- HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
- httpsConnection.setHostnameVerifier(new CallbackHostnameVerifier());
- setupTrustManagerCallback(httpsConnection);;
+ private SSLContext setSSLCallback(ISSLCertificateCallback sslAuthorizationCallback, URL url, HttpsURLConnection connection) {
+ X509TrustManager trustManager = null;
+ if (sslAuthorizationCallback != null) {
+ connection.setHostnameVerifier(new CallbackHostnameVerifier());
+ trustManager = createCallbackTrustManager(sslAuthorizationCallback, connection);
+ }
+
+ try {
+ SSLContext sslContext = SSLUtils.getSSLContext(trustManager);
+ connection.setSSLSocketFactory(sslContext.getSocketFactory());
+ return sslContext;
+ } catch (GeneralSecurityException e) {
+ LOGGER.warn("Could not install trust manager callback", e);;
+ return null;
}
}
/**
- * Sets the trust manager callbacks to the given connection
+ * Returns the callback trustmanager or null if it could not be created.
*
* @see ISSLCertificateCallback
*/
- private void setupTrustManagerCallback(HttpsURLConnection connection) {
+ private X509TrustManager createCallbackTrustManager(ISSLCertificateCallback sslAuthorizationCallback,HttpsURLConnection connection) {
+ X509TrustManager trustManager = null;
try {
- SSLContext sslContext = SSLContext.getInstance("SSL");
- X509TrustManager trustManager = getCurrentTrustManager();
+ trustManager = getCurrentTrustManager();
if (trustManager == null) {
LOGGER.warn("Could not install trust manager callback, no trustmanager was found.", trustManager);
} else {
- sslContext.init(null, new TrustManager[] {
- new CallbackTrustManager(trustManager, sslAuthorizationCallback) }, null);
- SSLSocketFactory socketFactory = sslContext.getSocketFactory();
- ((HttpsURLConnection) connection).setSSLSocketFactory(socketFactory);
+ trustManager = new CallbackTrustManager(trustManager, sslAuthorizationCallback);
}
} catch (GeneralSecurityException e) {
- LOGGER.warn("Could not install trust manager callback", e);;
+ LOGGER.warn("Could not install trust manager callback.", e);;
}
+ return trustManager;
}
-
+
+ /**
+ * Sets a ssl socket factory that sets a filtered list of ciphers based on
+ * the #excludedSSLCipherRegex to the given connection.
+ *
+ * @param sslContext
+ *
+ * @param sslContext
+ * the ssl context that shall be used
+ * @param url
+ * the url we are connecting to
+ * @param connection
+ * the connection that the cipher filter shall be applied to
+ */
+ protected SSLContext setFilteredCiphers(String excludedSSLCipherRegex, SSLContext sslContext, HttpsURLConnection connection) {
+ if (excludedSSLCipherRegex != null) {
+ connection.setSSLSocketFactory(
+ new EnabledCiphersSSLSocketFactory(
+ SSLUtils.filterCiphers(
+ excludedSSLCipherRegex, getSupportedCiphers(sslContext)), sslContext
+ .getSocketFactory()));
+ }
+ return sslContext;
+ }
+
+ protected String[] getSupportedCiphers(SSLContext sslContext) {
+ return sslContext.getSupportedSSLParameters().getCipherSuites();
+ }
+
private void setConnectTimeout(int timeout, URLConnection connection) {
if (getTimeout(timeout) != NO_TIMEOUT) {
connection.setConnectTimeout(getTimeout(timeout));
@@ -309,7 +359,6 @@ private void setReadTimeout(int timeout, URLConnection connection) {
if (getTimeout(timeout) != NO_TIMEOUT) {
connection.setReadTimeout(getTimeout(timeout));
}
-
}
private int getTimeout(int timeout) {
@@ -331,14 +380,6 @@ private void setRequestMediaType(IMediaType mediaType, HttpURLConnection connect
connection.setRequestProperty(PROPERTY_CONTENT_TYPE, mediaType.getType());
}
- private int getSystemPropertyInteger(String key) {
- try {
- return Integer.parseInt(System.getProperty(key));
- } catch (NumberFormatException e) {
- return NO_TIMEOUT;
- }
- }
-
private X509TrustManager getCurrentTrustManager() throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
@@ -374,7 +415,8 @@ public class CallbackTrustManager implements X509TrustManager {
private X509TrustManager trustManager;
private ISSLCertificateCallback callback;
- private CallbackTrustManager(X509TrustManager currentTrustManager, ISSLCertificateCallback callback) throws NoSuchAlgorithmException, KeyStoreException {
+ private CallbackTrustManager(X509TrustManager currentTrustManager, ISSLCertificateCallback callback)
+ throws NoSuchAlgorithmException, KeyStoreException {
this.trustManager = currentTrustManager;
this.callback = callback;
}
@@ -404,7 +446,71 @@ private class CallbackHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return sslAuthorizationCallback.allowHostname(hostname, session);
}
+ }
+
+ /**
+ * SSL socket factory that wraps a given socket factory and sets given ciphers
+ * to the socket that the wrapped factory creates.
+ *
+ * @see http://stackoverflow.com/questions/6851461/java-why-does-ssl-handshake-give-could-not-generate-dh-keypair-exception/16686994#16686994
+ */
+ private static class EnabledCiphersSSLSocketFactory extends SSLSocketFactory {
+
+ private String[] enabledCiphers;
+ private SSLSocketFactory socketFactory;
+
+ EnabledCiphersSSLSocketFactory(String[] enabledCiphers, SSLSocketFactory socketFactory) {
+ this.enabledCiphers = enabledCiphers;
+ this.socketFactory = socketFactory;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port, InetAddress localHost, int localPort) throws IOException {
+ return setEnabledCiphers((SSLSocket) socketFactory.createSocket(host, port, localHost, localPort));
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+ throws IOException, UnknownHostException {
+ return setEnabledCiphers((SSLSocket) socketFactory.createSocket(host, port, localHost, localPort));
+ }
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ return setEnabledCiphers((SSLSocket) socketFactory.createSocket(host, port));
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+ return setEnabledCiphers((SSLSocket) socketFactory.createSocket(host, port));
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ if (enabledCiphers == null) {
+ return socketFactory.getSupportedCipherSuites();
+ } else {
+ return enabledCiphers;
+ }
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return socketFactory.getDefaultCipherSuites();
+ }
+
+ @Override
+ public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
+ return setEnabledCiphers((SSLSocket) socketFactory.createSocket(socket, host, port, autoClose));
+ }
+
+ private SSLSocket setEnabledCiphers(SSLSocket socket) {
+ if (enabledCiphers == null) {
+ return socket;
+ }
+ socket.setEnabledCipherSuites(enabledCiphers);
+ return socket;
+ }
}
}
diff --git a/src/main/java/com/openshift/internal/client/httpclient/UrlConnectionHttpClientBuilder.java b/src/main/java/com/openshift/internal/client/httpclient/UrlConnectionHttpClientBuilder.java
index 13f9a068..cbcd4ca0 100755
--- a/src/main/java/com/openshift/internal/client/httpclient/UrlConnectionHttpClientBuilder.java
+++ b/src/main/java/com/openshift/internal/client/httpclient/UrlConnectionHttpClientBuilder.java
@@ -28,6 +28,7 @@ public class UrlConnectionHttpClientBuilder {
private String version;
private Integer configTimeout;
private ISSLCertificateCallback callback;
+ private String excludeSSLCipherRegex;
public UrlConnectionHttpClientBuilder setUserAgent(String userAgent) {
this.userAgent = userAgent;
@@ -65,8 +66,13 @@ public UrlConnectionHttpClientBuilder setVersion(String version) {
return this;
}
+ public UrlConnectionHttpClientBuilder excludeSSLCipher(String excludeSSLCipherRegex) {
+ this.excludeSSLCipherRegex = excludeSSLCipherRegex;
+ return this;
+ }
+
public IHttpClient client() {
return new UrlConnectionHttpClient(
- username, password, userAgent, acceptedMediaType, version, authKey, authIV, callback, configTimeout);
+ username, password, userAgent, acceptedMediaType, version, authKey, authIV, callback, configTimeout, excludeSSLCipherRegex);
}
}
diff --git a/src/test/java/com/openshift/client/fakes/PayLoadReturningHttpClientFake.java b/src/test/java/com/openshift/client/fakes/PayLoadReturningHttpClientFake.java
index 3886990e..237e7d76 100644
--- a/src/test/java/com/openshift/client/fakes/PayLoadReturningHttpClientFake.java
+++ b/src/test/java/com/openshift/client/fakes/PayLoadReturningHttpClientFake.java
@@ -45,6 +45,7 @@ protected PayLoadReturningHttpClientFake(OpenShiftTestConfiguration configuratio
null,
null,
null,
+ null,
null);
}
diff --git a/src/test/java/com/openshift/client/fakes/SSLCipherOpenShiftConnectionFactoryFake.java b/src/test/java/com/openshift/client/fakes/SSLCipherOpenShiftConnectionFactoryFake.java
new file mode 100644
index 00000000..68caeeba
--- /dev/null
+++ b/src/test/java/com/openshift/client/fakes/SSLCipherOpenShiftConnectionFactoryFake.java
@@ -0,0 +1,103 @@
+package com.openshift.client.fakes;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+
+import com.openshift.client.IHttpClient;
+import com.openshift.client.IHttpClient.ISSLCertificateCallback;
+import com.openshift.client.IOpenShiftConnection;
+import com.openshift.client.OpenShiftException;
+import com.openshift.client.configuration.AbstractOpenshiftConfiguration.ConfigurationOptions;
+import com.openshift.client.configuration.IOpenShiftConfiguration;
+import com.openshift.client.utils.OpenShiftTestConfiguration;
+import com.openshift.client.utils.SSLUtils;
+import com.openshift.client.utils.TestConnectionFactory;
+import com.openshift.internal.client.APIResource;
+import com.openshift.internal.client.IRestService;
+import com.openshift.internal.client.httpclient.UrlConnectionHttpClient;
+import com.openshift.internal.client.response.Link;
+
+public class SSLCipherOpenShiftConnectionFactoryFake extends TestConnectionFactory {
+
+ private FilteredCiphersClientFake client;
+ private ConfigurationOptions disableBadCiphers;
+
+ public SSLCipherOpenShiftConnectionFactoryFake(ConfigurationOptions disableBadCiphers) {
+ this.disableBadCiphers = disableBadCiphers;
+ }
+
+ public String[] getSupportedCiphers() throws MalformedURLException, IOException, KeyManagementException, NoSuchAlgorithmException {
+ getConnection(); // create client
+ junit.framework.Assert.assertNotNull("http client was not created yet", client);
+ return client.getSupportedCiphers(SSLUtils.getSSLContext(null));
+ }
+
+ public String[] getFilteredCiphers() throws MalformedURLException, IOException {
+ getConnection(); // create client
+ junit.framework.Assert.assertNotNull("http client was not created yet", client);
+ return client.getFilteredCiphers();
+ }
+
+ @Override
+ protected IOpenShiftConfiguration createConfiguration() throws OpenShiftException {
+ try {
+ return new OpenShiftTestConfiguration() {
+
+ @Override
+ public ConfigurationOptions getDisableBadSSLCiphers() {
+ return disableBadCiphers;
+ }
+
+ };
+ } catch (IOException e) {
+ throw new OpenShiftException(e, "Could not create OpenShift configuration");
+ }
+ }
+
+ @Override
+ protected IHttpClient createClient(String clientId, String username, String password, String authKey,
+ String authIV, String serverUrl, ISSLCertificateCallback sslCertificateCallback,
+ String exludeSSLCipherRegex) {
+ return this.client = new FilteredCiphersClientFake(clientId, username, password, null, null, null, authKey, authIV,
+ sslCertificateCallback, IHttpClient.NO_TIMEOUT, exludeSSLCipherRegex);
+ }
+
+ @Override
+ protected IOpenShiftConnection getConnection(IRestService service, final String login, final String password) throws IOException, OpenShiftException {
+ return new APIResource(login, password, service, new HashMap()) {};
+ }
+
+ public class FilteredCiphersClientFake extends UrlConnectionHttpClient {
+
+ private FilteredCiphersClientFake(String clientId, String username, String password, String userAgent, String mediaType,
+ String acceptVersion, String authKey, String authIv, ISSLCertificateCallback callback, int timeout,
+ String excludedSSLCipherRegex) {
+ super(username, password, userAgent, mediaType, acceptVersion, authKey, authIv, callback, timeout,
+ excludedSSLCipherRegex);
+
+ }
+
+ @Override
+ protected String[] getSupportedCiphers(SSLContext sslContext) {
+ try {
+ return SSLUtils.getSSLContext(null).getServerSocketFactory().getSupportedCipherSuites();
+ } catch (GeneralSecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String[] getFilteredCiphers() throws MalformedURLException, IOException {
+ HttpsURLConnection connection = (HttpsURLConnection) createConnection(new URL("https://localhost"), username, password, authKey,
+ authIV, userAgent, acceptedVersion, acceptedMediaType, null, IHttpClient.NO_TIMEOUT);
+ return connection.getSSLSocketFactory().getSupportedCipherSuites();
+ }
+ }
+}
diff --git a/src/test/java/com/openshift/client/utils/OpenShiftTestConfiguration.java b/src/test/java/com/openshift/client/utils/OpenShiftTestConfiguration.java
index 461dfaa3..e71e48d9 100644
--- a/src/test/java/com/openshift/client/utils/OpenShiftTestConfiguration.java
+++ b/src/test/java/com/openshift/client/utils/OpenShiftTestConfiguration.java
@@ -20,9 +20,6 @@
import com.openshift.client.configuration.AbstractOpenshiftConfiguration;
import com.openshift.client.configuration.DefaultConfiguration;
import com.openshift.client.configuration.IOpenShiftConfiguration;
-import com.openshift.client.configuration.SystemConfiguration;
-import com.openshift.client.configuration.SystemProperties;
-import com.openshift.client.configuration.UserConfiguration;
import com.openshift.client.fakes.SystemConfigurationFake;
import com.openshift.client.fakes.SystemPropertiesFake;
import com.openshift.client.fakes.UserConfigurationFake;
diff --git a/src/test/java/com/openshift/internal/client/ConfigurationTest.java b/src/test/java/com/openshift/internal/client/ConfigurationTest.java
index 7f0e799a..6fe36747 100644
--- a/src/test/java/com/openshift/internal/client/ConfigurationTest.java
+++ b/src/test/java/com/openshift/internal/client/ConfigurationTest.java
@@ -10,6 +10,7 @@
******************************************************************************/
package com.openshift.internal.client;
+import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -27,6 +28,7 @@
import org.junit.Test;
import com.openshift.client.OpenShiftException;
+import com.openshift.client.configuration.AbstractOpenshiftConfiguration.ConfigurationOptions;
import com.openshift.client.configuration.DefaultConfiguration;
import com.openshift.client.configuration.IOpenShiftConfiguration;
import com.openshift.client.configuration.SystemConfiguration;
@@ -258,4 +260,42 @@ public void fallsBackToDefaultUrl() throws OpenShiftException, IOException {
assertTrue(configuration.getLibraServer().contains(DefaultConfiguration.LIBRA_SERVER));
assertNull(configuration.getRhlogin());
}
+
+ @Test
+ public void disableBadSSLCiphersShouldDefaultToNo() throws OpenShiftException, IOException {
+ // pre-condition
+ SystemConfiguration systemConfiguration = new SystemConfigurationFake(new DefaultConfiguration()) {
+
+ @Override
+ protected void init(Properties properties) {
+ properties.put(KEY_DISABLE_BAD_SSL_CIPHERS, "bingobongo");
+ }
+
+ };
+
+ // operation
+ ConfigurationOptions option = systemConfiguration.getDisableBadSSLCiphers();
+
+ // verification
+ assertThat(option).isEqualTo(ConfigurationOptions.NO);
+ }
+
+ @Test
+ public void disableBadSSLCiphersShouldbeYes() throws OpenShiftException, IOException {
+ // pre-condition
+ SystemConfiguration systemConfiguration = new SystemConfigurationFake(new DefaultConfiguration()) {
+
+ @Override
+ protected void init(Properties properties) {
+ properties.put(KEY_DISABLE_BAD_SSL_CIPHERS, "\"yes\"");
+ }
+
+ };
+
+ // operation
+ ConfigurationOptions option = systemConfiguration.getDisableBadSSLCiphers();
+
+ // verification
+ assertThat(option).isEqualTo(ConfigurationOptions.YES);
+ }
}
diff --git a/src/test/java/com/openshift/internal/client/httpclient/HttpClientTest.java b/src/test/java/com/openshift/internal/client/httpclient/HttpClientTest.java
index 219d6ac2..997079c9 100755
--- a/src/test/java/com/openshift/internal/client/httpclient/HttpClientTest.java
+++ b/src/test/java/com/openshift/internal/client/httpclient/HttpClientTest.java
@@ -19,14 +19,12 @@
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.security.KeyStoreException;
import java.security.cert.X509Certificate;
-import java.util.Properties;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
@@ -40,9 +38,7 @@
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
-import com.openshift.client.configuration.*;
-import com.openshift.client.fakes.*;
-import com.openshift.internal.client.TestTimer;
+import org.fest.assertions.Condition;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -52,11 +48,20 @@
import com.openshift.client.IHttpClient;
import com.openshift.client.IHttpClient.ISSLCertificateCallback;
import com.openshift.client.OpenShiftException;
+import com.openshift.client.configuration.AbstractOpenshiftConfiguration.ConfigurationOptions;
+import com.openshift.client.configuration.IOpenShiftConfiguration;
+import com.openshift.client.fakes.HttpServerFake;
+import com.openshift.client.fakes.HttpsServerFake;
+import com.openshift.client.fakes.OpenShiftConfigurationFake;
+import com.openshift.client.fakes.PayLoadReturningHttpClientFake;
+import com.openshift.client.fakes.SSLCipherOpenShiftConnectionFactoryFake;
+import com.openshift.client.fakes.WaitingHttpServerFake;
import com.openshift.client.utils.Base64Coder;
import com.openshift.client.utils.ExceptionCauseMatcher;
+import com.openshift.client.utils.SSLUtils;
+import com.openshift.internal.client.TestTimer;
import com.openshift.internal.client.httpclient.request.FormUrlEncodedMediaType;
import com.openshift.internal.client.httpclient.request.StringParameter;
-import sun.net.www.http.HttpClient;
/**
* @author Andre Dietisheim
@@ -623,6 +628,26 @@ public Long call() throws Exception {
}
}
+ @Test
+ public void shouldFilterBadSSLCiphers() throws Throwable {
+ // pre-conditions
+ // operations
+ SSLCipherOpenShiftConnectionFactoryFake factory =
+ new SSLCipherOpenShiftConnectionFactoryFake(ConfigurationOptions.YES);
+ // verification
+ assertThat(factory.getFilteredCiphers()).satisfies(new NoDHECiphersCondition());
+ }
+
+ @Test
+ public void shouldNotFilterBadSSLCiphers() throws Throwable {
+ // pre-conditions
+ // operations
+ SSLCipherOpenShiftConnectionFactoryFake factory =
+ new SSLCipherOpenShiftConnectionFactoryFake(ConfigurationOptions.NO);
+ // verification
+ assertThat(factory.getSupportedCiphers()).isEqualTo(factory.getFilteredCiphers());
+ }
+
private HttpServerFake startHttpServerFake(String statusLine) throws Exception {
int port = new Random().nextInt(9 * 1024) + 1024;
HttpServerFake serverFake = null;
@@ -653,16 +678,20 @@ private WaitingHttpServerFake startWaitingHttpServerFake(int delay) throws Excep
return serverFake;
}
- private class UserAgentClientFake extends UrlConnectionHttpClientFake {
-
- public UserAgentClientFake(String userAgent) {
- super(userAgent, null);
- }
-
- public String getUserAgent(HttpURLConnection connection) {
- return connection.getRequestProperty(PROPERTY_USER_AGENT);
+ private static final class NoDHECiphersCondition extends Condition