From e6be8585b4258ed4aff3904d3e638a6a46c99e89 Mon Sep 17 00:00:00 2001 From: Robert Veznaver Date: Wed, 14 Jan 2015 17:11:53 +0100 Subject: [PATCH] add client certificate authentication support --- .../overthere/cifs/CifsConnectionBuilder.java | 12 ++++++ .../cifs/winrm/CifsWinRmConnection.java | 3 ++ .../overthere/cifs/winrm/WinRmClient.java | 40 +++++++++++++++++-- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/xebialabs/overthere/cifs/CifsConnectionBuilder.java b/src/main/java/com/xebialabs/overthere/cifs/CifsConnectionBuilder.java index 8f5c8b3f..4fbe7bd5 100644 --- a/src/main/java/com/xebialabs/overthere/cifs/CifsConnectionBuilder.java +++ b/src/main/java/com/xebialabs/overthere/cifs/CifsConnectionBuilder.java @@ -170,6 +170,18 @@ public class CifsConnectionBuilder implements OverthereConnectionBuilder { */ public static final String WINRM_LOCALE_DEFAULT = "en-US"; + /** + * Set to true for mutual HTTPS authentication + */ + + public static final String WINRM_CLIENT_CERTIFICATE = "winrmClientCertificate"; + + /** + * Default value for HTTPS mutual authentication + */ + + public static final boolean WINRM_CLIENT_CERTIFICATE_DEFAULT = false; + /** * See the online documentation */ diff --git a/src/main/java/com/xebialabs/overthere/cifs/winrm/CifsWinRmConnection.java b/src/main/java/com/xebialabs/overthere/cifs/winrm/CifsWinRmConnection.java index f7fe197d..12713342 100644 --- a/src/main/java/com/xebialabs/overthere/cifs/winrm/CifsWinRmConnection.java +++ b/src/main/java/com/xebialabs/overthere/cifs/winrm/CifsWinRmConnection.java @@ -50,6 +50,8 @@ import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_CONTEXT_DEFAULT; import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_ENABLE_HTTPS_DEFAULT; import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_ENVELOP_SIZE_DEFAULT; +import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_CLIENT_CERTIFICATE; +import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_CLIENT_CERTIFICATE_DEFAULT; import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_HTTPS_CERTIFICATE_TRUST_STRATEGY_DEFAULT; import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_HTTPS_HOSTNAME_VERIFICATION_STRATEGY_DEFAULT; import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_KERBEROS_ADD_PORT_TO_SPN_DEFAULT; @@ -245,6 +247,7 @@ private WinRmClient createWinrmClient() { client.setWinRmTimeout(options.get(WINRM_TIMEMOUT, DEFAULT_WINRM_TIMEOUT)); client.setWinRmEnvelopSize(options.get(WINRM_ENVELOP_SIZE, WINRM_ENVELOP_SIZE_DEFAULT)); client.setWinRmLocale(options.get(WINRM_LOCALE, WINRM_LOCALE_DEFAULT)); + client.setClientCertificate(options.getBoolean(WINRM_CLIENT_CERTIFICATE, WINRM_CLIENT_CERTIFICATE_DEFAULT)); client.setHttpsCertTrustStrategy(options.getEnum(WINRM_HTTPS_CERTIFICATE_TRUST_STRATEGY, WinrmHttpsCertificateTrustStrategy.class, WINRM_HTTPS_CERTIFICATE_TRUST_STRATEGY_DEFAULT)); client.setHttpsHostnameVerifyStrategy(options.getEnum(WINRM_HTTPS_HOSTNAME_VERIFICATION_STRATEGY, WinrmHttpsHostnameVerificationStrategy.class, WINRM_HTTPS_HOSTNAME_VERIFICATION_STRATEGY_DEFAULT)); client.setKerberosUseHttpSpn(options.getBoolean(WINRM_KERBEROS_USE_HTTP_SPN, WINRM_KERBEROS_USE_HTTP_SPN_DEFAULT)); diff --git a/src/main/java/com/xebialabs/overthere/cifs/winrm/WinRmClient.java b/src/main/java/com/xebialabs/overthere/cifs/winrm/WinRmClient.java index a2362f38..d539e3da 100644 --- a/src/main/java/com/xebialabs/overthere/cifs/winrm/WinRmClient.java +++ b/src/main/java/com/xebialabs/overthere/cifs/winrm/WinRmClient.java @@ -23,6 +23,9 @@ package com.xebialabs.overthere.cifs.winrm; import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -35,12 +38,14 @@ import java.net.URL; import java.security.GeneralSecurityException; import java.security.KeyManagementException; +import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -111,6 +116,7 @@ public class WinRmClient { private String winRmTimeout; private int winRmEnvelopSize; private String winRmLocale; + private boolean clientCertificate; private WinrmHttpsCertificateTrustStrategy httpsCertTrustStrategy; private WinrmHttpsHostnameVerificationStrategy httpsHostnameVerifyStrategy; private boolean kerberosUseHttpSpn; @@ -408,6 +414,12 @@ private Document doSendRequest(final Document requestDocument, final SoapAction final HttpContext context = new BasicHttpContext(); final HttpPost request = new HttpPost(targetURL.toURI()); + /* http://www.dmtf.org/sites/default/files/standards/documents/DSP0226_1.0.0.pdf + * Web Services for Management (WS-Management) Specification, v1.0.0, page 119, section C.3.5 */ + if (clientCertificate) { + request.setHeader("Authorization", "http://schemas.dmtf.org/wbem/wsman/1/wsman/secprofile/https/mutual"); + } + if (soapAction != null) { request.setHeader("SOAPAction", soapAction.getValue()); } @@ -442,10 +454,12 @@ private Document doSendRequest(final Document requestDocument, final SoapAction } } - private void configureHttpClient(final DefaultHttpClient httpclient) throws GeneralSecurityException { + private void configureHttpClient(final DefaultHttpClient httpclient) throws GeneralSecurityException, IOException { configureTrust(httpclient); - configureAuthentication(httpclient, BASIC, new BasicUserPrincipal(username)); + if (!clientCertificate) { + configureAuthentication(httpclient, BASIC, new BasicUserPrincipal(username)); + } if (enableKerberos) { String spnServiceClass = kerberosUseHttpSpn ? "HTTP" : "WSMAN"; @@ -463,7 +477,7 @@ private void configureHttpClient(final DefaultHttpClient httpclient) throws Gene } private void configureTrust(final DefaultHttpClient httpclient) throws NoSuchAlgorithmException, - KeyManagementException, KeyStoreException, UnrecoverableKeyException { + KeyManagementException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException { if (!"https".equalsIgnoreCase(targetURL.getProtocol())) { return; @@ -471,7 +485,21 @@ private void configureTrust(final DefaultHttpClient httpclient) throws NoSuchAlg final TrustStrategy trustStrategy = httpsCertTrustStrategy.getStrategy(); final X509HostnameVerifier hostnameVerifier = httpsHostnameVerifyStrategy.getVerifier(); - final SSLSocketFactory socketFactory = new SSLSocketFactory(trustStrategy, hostnameVerifier); + final SSLSocketFactory socketFactory; + + if (clientCertificate) { + KeyStore clientStore = KeyStore.getInstance("PKCS12"); + FileInputStream instream = new FileInputStream(new File(username)); + try { + clientStore.load(instream, password.toCharArray()); + } finally { + instream.close(); + } + socketFactory = new SSLSocketFactory(null, clientStore, password, null, null, trustStrategy, hostnameVerifier); + } else { + socketFactory = new SSLSocketFactory(trustStrategy, hostnameVerifier); + } + final Scheme sch = new Scheme("https", 443, socketFactory); httpclient.getConnectionManager().getSchemeRegistry().register(sch); } @@ -577,6 +605,10 @@ public void setWinRmLocale(String locale) { this.winRmLocale = locale; } + public void setClientCertificate(boolean WinrmClientCertificate) { + this.clientCertificate = WinrmClientCertificate; + } + public void setHttpsCertTrustStrategy(WinrmHttpsCertificateTrustStrategy httpsCertTrustStrategy) { this.httpsCertTrustStrategy = httpsCertTrustStrategy; }