You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2017/02/08 15:05:39 UTC
svn commit: r1782199 - in /chemistry/opencmis/trunk:
chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/
chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemi...
Author: fmui
Date: Wed Feb 8 15:05:38 2017
New Revision: 1782199
URL: http://svn.apache.org/viewvc?rev=1782199&view=rev
Log:
added support for client certificate authentication
Added:
chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/ClientCertificateAuthenticationProvider.java (with props)
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java
chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/BasicLoginTab.java
chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/DiscoverLoginTab.java
chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java
Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java?rev=1782199&r1=1782198&r2=1782199&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java Wed Feb 8 15:05:38 2017
@@ -399,6 +399,35 @@ public class SessionParameterMap extends
}
/**
+ * Turns Client Certificate authentication on and and basic authentication
+ * and UsernameToken authentication off.
+ *
+ * @param keyfilePath
+ * the path to the JKS key file
+ * @param passphrase
+ * the pass phrase for the key file
+ */
+ public void setCertificateAuthentication(String keyfilePath, String passphrase) {
+ if (keyfilePath == null) {
+ throw new IllegalArgumentException("Key file path mut be set!");
+ }
+
+ put(SessionParameter.AUTH_HTTP_BASIC, false);
+ put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
+ put(SessionParameter.AUTH_OAUTH_BEARER, false);
+
+ put(SessionParameter.CLIENT_CERT_KEYFILE, keyfilePath);
+ if (passphrase == null) {
+ remove(SessionParameter.CLIENT_CERT_PASSPHRASE);
+ } else {
+ put(SessionParameter.CLIENT_CERT_PASSPHRASE, passphrase);
+ }
+
+ put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS,
+ "org.apache.chemistry.opencmis.client.bindings.spi.ClientCertificateAuthenticationProvider");
+ }
+
+ /**
* Turns simple OAuth 2.0 bearer token authentication on and basic
* authentication and UsernameToken authentication off.
* <p>
Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/ClientCertificateAuthenticationProvider.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/ClientCertificateAuthenticationProvider.java?rev=1782199&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/ClientCertificateAuthenticationProvider.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/ClientCertificateAuthenticationProvider.java Wed Feb 8 15:05:38 2017
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.chemistry.opencmis.client.bindings.spi;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.util.Enumeration;
+import java.util.Locale;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.apache.chemistry.opencmis.commons.SessionParameter;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
+import org.apache.chemistry.opencmis.commons.impl.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Client Certificate Authentication Provider.
+ *
+ * Enables the use of SSL client certificates for authentication. It requires
+ * the path to a JKS key file and its pass phrase.
+ *
+ * <pre>
+ * {@code
+ * SessionFactory factory = ...
+ *
+ * Map<String, String> parameter = new HashMap<String, String>();
+ *
+ * parameter.put(SessionParameter.ATOMPUB_URL, "https://localhost/cmis/atom");
+ * parameter.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
+ * parameter.put(SessionParameter.REPOSITORY_ID, "myRepository");
+ *
+ * parameter.put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS, "org.apache.chemistry.opencmis.client.bindings.spi.ClientCertificateAuthenticationProvider");
+ *
+ * parameter.put(SessionParameter.CLIENT_CERT_KEYFILE, "/path/to/mycert.jks");
+ * parameter.put(SessionParameter.CLIENT_CERT_PASSPHRASE, "changeme");
+ *
+ * ...
+ * Session session = factory.createSession(parameter);
+ * }
+ * </pre>
+ *
+ */
+public class ClientCertificateAuthenticationProvider extends StandardAuthenticationProvider {
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClientCertificateAuthenticationProvider.class);
+
+ private SSLSocketFactory socketFactory;
+
+ @Override
+ public void setSession(BindingSession session) {
+ super.setSession(session);
+
+ if (socketFactory == null) {
+ Object keyfile = getSession().get(SessionParameter.CLIENT_CERT_KEYFILE);
+ if (keyfile instanceof String) {
+ Object passphrase = getSession().get(SessionParameter.CLIENT_CERT_PASSPHRASE);
+
+ String keyfileStr = ((String) keyfile).trim();
+ String passphraseStr = passphrase instanceof String ? ((String) passphrase).trim() : null;
+
+ socketFactory = createSSLSocketFactory(keyfileStr, passphraseStr);
+ }
+ }
+ }
+
+ @Override
+ public SSLSocketFactory getSSLSocketFactory() {
+ return socketFactory;
+ }
+
+ protected SSLSocketFactory createSSLSocketFactory(String keyFile, String passphrase) {
+ assert keyFile != null;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Using key file '{}'", keyFile);
+ }
+
+ try {
+ char[] passphraseChars = passphrase == null ? null : passphrase.toCharArray();
+
+ KeyStore keyStore;
+
+ String ext = getExtension(keyFile);
+ if ("p12".equals(ext) || "pfx".equals(ext)) {
+ keyStore = KeyStore.getInstance("PKCS12");
+ } else {
+ keyStore = KeyStore.getInstance("JKS");
+ }
+
+ // read key store
+ InputStream keyStream = null;
+ try {
+ keyStream = new BufferedInputStream(new FileInputStream(keyFile));
+ keyStore.load(keyStream, passphraseChars);
+ } finally {
+ IOUtils.closeQuietly(keyStream);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Key store type: {}", keyStore.getType());
+
+ StringBuilder sb = new StringBuilder();
+ Enumeration<String> aliases = keyStore.aliases();
+ while (aliases.hasMoreElements()) {
+ if (sb.length() > 0) {
+ sb.append(", ");
+ }
+ sb.append(aliases.nextElement());
+ }
+
+ LOG.debug("Aliases in key store: {}", sb.toString());
+ }
+
+ // create socket factory
+ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
+ keyManagerFactory.init(keyStore, passphraseChars);
+
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(keyManagerFactory.getKeyManagers(), null, null);
+
+ return context.getSocketFactory();
+ } catch (FileNotFoundException fnfe) {
+ throw new CmisRuntimeException("Key file '" + keyFile + "' not found!", fnfe);
+ } catch (Exception e) {
+ throw new CmisRuntimeException("Cannot set up client certificate: " + e.toString(), e);
+ }
+ }
+
+ private String getExtension(String filename) {
+ int x = filename.lastIndexOf('.');
+ if (x > -1) {
+ return filename.substring(x + 1).toLowerCase(Locale.ENGLISH);
+ }
+
+ return null;
+ }
+}
Propchange: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/ClientCertificateAuthenticationProvider.java
------------------------------------------------------------------------------
svn:eol-style = LF
Modified: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java?rev=1782199&r1=1782198&r2=1782199&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java Wed Feb 8 15:05:38 2017
@@ -705,6 +705,11 @@ public final class SessionParameter {
public static final String OAUTH_EXPIRATION_TIMESTAMP = "org.apache.chemistry.opencmis.oauth.expirationTimestamp";
public static final String OAUTH_DEFAULT_TOKEN_LIFETIME = "org.apache.chemistry.opencmis.oauth.defaultTokenLifetime";
+ // --- client certificates ---
+
+ public static final String CLIENT_CERT_KEYFILE = "org.apache.chemistry.opencmis.clientcerts.keyfile";
+ public static final String CLIENT_CERT_PASSPHRASE = "org.apache.chemistry.opencmis.clientcerts.passphrase";
+
// --- connection ---
public static final String HTTP_INVOKER_CLASS = "org.apache.chemistry.opencmis.binding.httpinvoker.classname";
Modified: chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/BasicLoginTab.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/BasicLoginTab.java?rev=1782199&r1=1782198&r2=1782199&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/BasicLoginTab.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/BasicLoginTab.java Wed Feb 8 15:05:38 2017
@@ -65,6 +65,7 @@ public class BasicLoginTab extends Abstr
private JRadioButton authenticationStandardButton;
private JRadioButton authenticationNTLMButton;
private JRadioButton authenticationOAuthButton;
+ private JRadioButton authenticationCertButton;
private JRadioButton compressionOnButton;
private JRadioButton compressionOffButton;
private JRadioButton clientCompressionOnButton;
@@ -90,7 +91,8 @@ public class BasicLoginTab extends Abstr
createBindingButtons(this);
- usernameField = createTextField(this, "Username:", "Enter the user name.");
+ usernameField = createTextField(this, "Username:",
+ "<html>Enter the user name.<br>(Or bearer token for OAuth authentication or key file path for client certificate authentication.)");
usernameField.setText(System.getProperty(SYSPROP_USER, ""));
passwordField = createPasswordField(this, "Password:", "Enter the users password.");
@@ -167,16 +169,19 @@ public class BasicLoginTab extends Abstr
.equals("standard"));
boolean ntlm = (System.getProperty(SYSPROP_AUTHENTICATION, "").toLowerCase(Locale.ENGLISH).equals("ntlm"));
boolean oauth = (System.getProperty(SYSPROP_AUTHENTICATION, "").toLowerCase(Locale.ENGLISH).equals("oauth"));
- boolean none = !standard && !ntlm;
+ boolean cert = (System.getProperty(SYSPROP_AUTHENTICATION, "").toLowerCase(Locale.ENGLISH).equals("cert"));
+ boolean none = !standard && !ntlm && !oauth && !cert;
authenticationNoneButton = new JRadioButton("None", none);
authenticationStandardButton = new JRadioButton("Standard", standard);
authenticationNTLMButton = new JRadioButton("NTLM", ntlm);
authenticationOAuthButton = new JRadioButton("OAuth 2.0 (Bearer Token)", oauth);
+ authenticationCertButton = new JRadioButton("Client Certificate", cert);
ButtonGroup authenticationGroup = new ButtonGroup();
authenticationGroup.add(authenticationNoneButton);
authenticationGroup.add(authenticationStandardButton);
authenticationGroup.add(authenticationNTLMButton);
authenticationGroup.add(authenticationOAuthButton);
+ authenticationGroup.add(authenticationCertButton);
authenticationContainer.add(authenticationNoneButton);
authenticationContainer.add(Box.createRigidArea(WorkbenchScale.scaleDimension(new Dimension(10, 0))));
authenticationContainer.add(authenticationStandardButton);
@@ -184,14 +189,17 @@ public class BasicLoginTab extends Abstr
authenticationContainer.add(authenticationNTLMButton);
authenticationContainer.add(Box.createRigidArea(WorkbenchScale.scaleDimension(new Dimension(10, 0))));
authenticationContainer.add(authenticationOAuthButton);
+ authenticationContainer.add(Box.createRigidArea(WorkbenchScale.scaleDimension(new Dimension(10, 0))));
+ authenticationContainer.add(authenticationCertButton);
JLabel authenticatioLabel = new JLabel("Authentication:", SwingConstants.TRAILING);
pane.add(authenticatioLabel);
pane.add(createHelp("<html>Select the authentication method.<br>"
+ "The <b>Standard authentication</b> is Basic Auth and should work with most repositories.<br>"
+ "The <b>NTLM authentication</b> should be used with caution! It's very likely that some CMIS operations will fail.<br>"
- + "The <b>OAuth authentication</b> requires a bearer token in the username field. The token will not be refreshed when it expires."
- + "Use the OAuthAuthenticationProvider for full OAuth support."));
+ + "The <b>OAuth authentication</b> requires a bearer token in the username field. The token will not be refreshed when it expires. "
+ + "Use the OAuthAuthenticationProvider for full OAuth support.<br>"
+ + "The <b>Client Certificate authentication</b> requires a JKS key file path the username field and the passphrase in the password field."));
pane.add(authenticationContainer);
}
@@ -281,6 +289,8 @@ public class BasicLoginTab extends Abstr
authentication = ClientSession.Authentication.NTLM;
} else if (authenticationOAuthButton.isSelected()) {
authentication = ClientSession.Authentication.OAUTH_BEARER;
+ } else if (authenticationCertButton.isSelected()) {
+ authentication = ClientSession.Authentication.CLIENT_CERT;
}
Locale locale = null;
Modified: chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/DiscoverLoginTab.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/DiscoverLoginTab.java?rev=1782199&r1=1782198&r2=1782199&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/DiscoverLoginTab.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/DiscoverLoginTab.java Wed Feb 8 15:05:38 2017
@@ -51,6 +51,8 @@ import javax.swing.table.DefaultTableCel
import javax.swing.table.TableColumn;
import org.apache.chemistry.opencmis.client.api.CmisEndpointDocumentReader;
+import org.apache.chemistry.opencmis.client.bindings.spi.ClientCertificateAuthenticationProvider;
+import org.apache.chemistry.opencmis.client.bindings.spi.OAuthAuthenticationProvider;
import org.apache.chemistry.opencmis.client.runtime.CmisEndpointDocumentReaderImpl;
import org.apache.chemistry.opencmis.commons.SessionParameter;
import org.apache.chemistry.opencmis.commons.endpoints.CmisAuthentication;
@@ -188,6 +190,13 @@ public class DiscoverLoginTab extends Ab
parameters.put(SessionParameter.OAUTH_CLIENT_ID, "");
parameters.put(SessionParameter.OAUTH_CLIENT_SECRET, "");
parameters.put(SessionParameter.OAUTH_CODE, "");
+ parameters.put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS, OAuthAuthenticationProvider.class.getName());
+ } else if (CmisAuthentication.AUTH_CERT.equals(auth.getType())) {
+ // client cert parameters
+ parameters.put(SessionParameter.CLIENT_CERT_KEYFILE, "");
+ parameters.put(SessionParameter.CLIENT_CERT_PASSPHRASE, "");
+ parameters.put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS,
+ ClientCertificateAuthenticationProvider.class.getName());
} else if (!CmisAuthentication.AUTH_NONE.equals(auth.getType())
&& !parameters.containsKey(SessionParameter.AUTHENTICATION_PROVIDER_CLASS)) {
// a custom authentication provider is required here
@@ -243,8 +252,8 @@ public class DiscoverLoginTab extends Ab
allEnpointsMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- String json = CmisEndpointsDocumentHelper.write(((CmisAuthenticationModel) getModel())
- .getCmisEndpointsDocument());
+ String json = CmisEndpointsDocumentHelper
+ .write(((CmisAuthenticationModel) getModel()).getCmisEndpointsDocument());
copyTableToClipboard(json);
}
});
@@ -407,8 +416,8 @@ public class DiscoverLoginTab extends Ab
}
@Override
- public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
- boolean hasFocus, int row, int column) {
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+ int row, int column) {
Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// make sure that the text fit into the row
Modified: chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java?rev=1782199&r1=1782198&r2=1782199&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-workbench/chemistry-opencmis-workbench/src/main/java/org/apache/chemistry/opencmis/workbench/model/ClientSession.java Wed Feb 8 15:05:38 2017
@@ -73,7 +73,7 @@ public class ClientSession {
public static final String MAX_FOLDER_CHILDREN = FOLDER_PREFIX + "maxChildren";
public enum Authentication {
- NONE, STANDARD, NTLM, OAUTH_BEARER
+ NONE, STANDARD, NTLM, OAUTH_BEARER, CLIENT_CERT
}
private static final Set<String> FOLDER_PROPERTY_SET = new HashSet<String>();
@@ -153,6 +153,9 @@ public class ClientSession {
case OAUTH_BEARER:
parameters.setOAuthBearerTokenAuthentication(username);
break;
+ case CLIENT_CERT:
+ parameters.setCertificateAuthentication(username, password);
+ break;
default:
parameters.setNoAuthentication();
}
@@ -411,7 +414,7 @@ public class ClientSession {
};
try {
- SSLContext sc = SSLContext.getInstance("SSL");
+ SSLContext sc = SSLContext.getInstance("TSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(accepctAllHostnames);