You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2016/12/02 20:39:19 UTC

nifi git commit: NIFI-2325: - Adding support for LDAPS.

Repository: nifi
Updated Branches:
  refs/heads/master 316cae16d -> c5ef07678


NIFI-2325:
- Adding support for LDAPS.

This closes #1275.

Signed-off-by: Andy LoPresto <al...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/c5ef0767
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/c5ef0767
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/c5ef0767

Branch: refs/heads/master
Commit: c5ef0767864b90ee9a013a60405c08ce6192d2bc
Parents: 316cae1
Author: Matt Gilman <ma...@gmail.com>
Authored: Mon Nov 28 16:38:33 2016 -0500
Committer: Andy LoPresto <al...@apache.org>
Committed: Fri Dec 2 12:41:03 2016 -0800

----------------------------------------------------------------------
 .../src/main/asciidoc/administration-guide.adoc |  18 +--
 .../resources/conf/login-identity-providers.xml |  18 +--
 .../nifi/ldap/LdapAuthenticationStrategy.java   |   1 +
 .../java/org/apache/nifi/ldap/LdapProvider.java | 121 ++++++++++++-------
 .../apache/nifi/ldap/LdapsSocketFactory.java    | 106 ++++++++++++++++
 5 files changed, 200 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/c5ef0767/nifi-docs/src/main/asciidoc/administration-guide.adoc
----------------------------------------------------------------------
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index 773cb64..ccbd471 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -307,17 +307,17 @@ nifi.security.user.login.identity.provider=ldap-provider
 [options="header,footer"]
 |==================================================================================================================================================
 | Property Name | Description
-|`Authentication Strategy` | How the connection to the LDAP server is authenticated. Possible values are ANONYMOUS, SIMPLE, or START_TLS.
+|`Authentication Strategy` | How the connection to the LDAP server is authenticated. Possible values are ANONYMOUS, SIMPLE, LDAPS, or START_TLS.
 |`Manager DN` | The DN of the manager that is used to bind to the LDAP server to search for users.
 |`Manager Password` | The password of the manager that is used to bind to the LDAP server to search for users.
-|`TLS - Keystore` | Path to the Keystore that is used when connecting to LDAP using START_TLS.
-|`TLS - Keystore Password` | Password for the Keystore that is used when connecting to LDAP using START_TLS.
-|`TLS - Keystore Type` | Type of the Keystore that is used when connecting to LDAP using START_TLS (i.e. JKS or PKCS12).
-|`TLS - Truststore` | Path to the Truststore that is used when connecting to LDAP using START_TLS.
-|`TLS - Truststore Password` | Password for the Truststore that is used when connecting to LDAP using START_TLS.
-|`TLS - Truststore Type` | Type of the Truststore that is used when connecting to LDAP using START_TLS (i.e. JKS or PKCS12).
-|`TLS - Client Auth` | Client authentication policy when connecting to LDAP using START_TLS. Possible values are REQUIRED, WANT, NONE.
-|`TLS - Protocol` | Protocol to use when connecting to LDAP using START_TLS. (i.e. TLS, TLSv1.1, TLSv1.2, etc).
+|`TLS - Keystore` | Path to the Keystore that is used when connecting to LDAP using LDAPS or START_TLS.
+|`TLS - Keystore Password` | Password for the Keystore that is used when connecting to LDAP using LDAPS or START_TLS.
+|`TLS - Keystore Type` | Type of the Keystore that is used when connecting to LDAP using LDAPS or START_TLS (i.e. JKS or PKCS12).
+|`TLS - Truststore` | Path to the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
+|`TLS - Truststore Password` | Password for the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
+|`TLS - Truststore Type` | Type of the Truststore that is used when connecting to LDAP using LDAPS or START_TLS (i.e. JKS or PKCS12).
+|`TLS - Client Auth` | Client authentication policy when connecting to LDAP using LDAPS or START_TLS. Possible values are REQUIRED, WANT, NONE.
+|`TLS - Protocol` | Protocol to use when connecting to LDAP using LDAPS or START_TLS. (i.e. TLS, TLSv1.1, TLSv1.2, etc).
 |`TLS - Shutdown Gracefully` | Specifies whether the TLS should be shut down gracefully before the target context is closed. Defaults to false.
 |`Referral Strategy` | Strategy for handling referrals. Possible values are FOLLOW, IGNORE, THROW.
 |`Connect Timeout` | Duration of connect timeout. (i.e. 10 secs).

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5ef0767/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/login-identity-providers.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/login-identity-providers.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/login-identity-providers.xml
index 828868a..fbfcfb4 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/login-identity-providers.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/login-identity-providers.xml
@@ -23,25 +23,25 @@
         Identity Provider for users logging in with username/password against an LDAP server.
         
         'Authentication Strategy' - How the connection to the LDAP server is authenticated. Possible
-            values are ANONYMOUS, SIMPLE, or START_TLS.
+            values are ANONYMOUS, SIMPLE, LDAPS, or START_TLS.
         
         'Manager DN' - The DN of the manager that is used to bind to the LDAP server to search for users.
         'Manager Password' - The password of the manager that is used to bind to the LDAP server to
             search for users.
             
-        'TLS - Keystore' - Path to the Keystore that is used when connecting to LDAP using START_TLS.
+        'TLS - Keystore' - Path to the Keystore that is used when connecting to LDAP using LDAPS or START_TLS.
         'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
-            using START_TLS.
+            using LDAPS or START_TLS.
         'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
-            START_TLS (i.e. JKS or PKCS12).
-        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
         'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
-            LDAP using START_TLS.
+            LDAP using LDAPS or START_TLS.
         'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
-            START_TLS (i.e. JKS or PKCS12).
-        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using LDAPS or START_TLS.
             Possible values are REQUIRED, WANT, NONE.
-        'TLS - Protocol' - Protocol to use when connecting to LDAP using START_TLS. (i.e. TLS,
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS or START_TLS. (i.e. TLS,
             TLSv1.1, TLSv1.2, etc).
         'TLS - Shutdown Gracefully' - Specifies whether the TLS should be shut down gracefully 
             before the target context is closed. Defaults to false.

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5ef0767/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java
index 7124ce1..fc64c40 100644
--- a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java
+++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java
@@ -23,5 +23,6 @@ public enum LdapAuthenticationStrategy {
 
     ANONYMOUS,
     SIMPLE,
+    LDAPS,
     START_TLS
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5ef0767/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java
index 4338783..851cf0d 100644
--- a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java
+++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java
@@ -47,6 +47,7 @@ import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
 import org.springframework.security.ldap.search.LdapUserSearch;
 import org.springframework.security.ldap.userdetails.LdapUserDetails;
 
+import javax.naming.Context;
 import javax.net.ssl.SSLContext;
 import java.io.IOException;
 import java.security.KeyManagementException;
@@ -96,11 +97,6 @@ public class LdapProvider implements LoginIdentityProvider {
         setTimeout(configurationContext, baseEnvironment, "Connect Timeout", "com.sun.jndi.ldap.connect.timeout");
         setTimeout(configurationContext, baseEnvironment, "Read Timeout", "com.sun.jndi.ldap.read.timeout");
 
-        // set the base environment is necessary
-        if (!baseEnvironment.isEmpty()) {
-            context.setBaseEnvironmentProperties(baseEnvironment);
-        }
-
         // authentication strategy
         final String rawAuthenticationStrategy = configurationContext.getProperty("Authentication Strategy");
         final LdapAuthenticationStrategy authenticationStrategy;
@@ -126,6 +122,20 @@ public class LdapProvider implements LoginIdentityProvider {
                     case SIMPLE:
                         context.setAuthenticationStrategy(new SimpleDirContextAuthenticationStrategy());
                         break;
+                    case LDAPS:
+                        context.setAuthenticationStrategy(new SimpleDirContextAuthenticationStrategy());
+
+                        // indicate a secure connection
+                        baseEnvironment.put(Context.SECURITY_PROTOCOL, "ssl");
+
+                        // get the configured ssl context
+                        final SSLContext ldapsSslContext = getConfiguredSslContext(configurationContext);
+                        if (ldapsSslContext != null) {
+                            // initialize the ldaps socket factory prior to use
+                            LdapsSocketFactory.initialize(ldapsSslContext.getSocketFactory());
+                            baseEnvironment.put("java.naming.ldap.factory.socket", LdapsSocketFactory.class.getName());
+                        }
+                        break;
                     case START_TLS:
                         final AbstractTlsDirContextAuthenticationStrategy tlsAuthenticationStrategy = new DefaultTlsDirContextAuthenticationStrategy();
 
@@ -136,49 +146,13 @@ public class LdapProvider implements LoginIdentityProvider {
                             tlsAuthenticationStrategy.setShutdownTlsGracefully(shutdownGracefully);
                         }
 
-                        final String rawKeystore = configurationContext.getProperty("TLS - Keystore");
-                        final String rawKeystorePassword = configurationContext.getProperty("TLS - Keystore Password");
-                        final String rawKeystoreType = configurationContext.getProperty("TLS - Keystore Type");
-                        final String rawTruststore = configurationContext.getProperty("TLS - Truststore");
-                        final String rawTruststorePassword = configurationContext.getProperty("TLS - Truststore Password");
-                        final String rawTruststoreType = configurationContext.getProperty("TLS - Truststore Type");
-                        final String rawClientAuth = configurationContext.getProperty("TLS - Client Auth");
-                        final String rawProtocol = configurationContext.getProperty("TLS - Protocol");
-
-                        final ClientAuth clientAuth;
-                        if (StringUtils.isBlank(rawClientAuth)) {
-                            clientAuth = ClientAuth.NONE;
-                        } else {
-                            try {
-                                clientAuth = ClientAuth.valueOf(rawClientAuth);
-                            } catch (final IllegalArgumentException iae) {
-                                throw new ProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
-                                        rawClientAuth, StringUtils.join(ClientAuth.values(), ", ")));
-                            }
-                        }
-
-                        // ensure the protocol is specified
-                        if (StringUtils.isBlank(rawProtocol)) {
-                            throw new ProviderCreationException("TLS - Protocol must be specified.");
-                        }
-
-                        try {
-                            final SSLContext sslContext;
-                            if (StringUtils.isBlank(rawKeystore)) {
-                                sslContext = SslContextFactory.createTrustSslContext(rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, rawProtocol);
-                            } else {
-                                if (StringUtils.isBlank(rawTruststore)) {
-                                    sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType, rawProtocol);
-                                } else {
-                                    sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType,
-                                            rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, clientAuth, rawProtocol);
-                                }
-                            }
-                            tlsAuthenticationStrategy.setSslSocketFactory(sslContext.getSocketFactory());
-                        } catch (final KeyStoreException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyManagementException | IOException e) {
-                            throw new ProviderCreationException(e.getMessage(), e);
+                        // get the configured ssl context
+                        final SSLContext startTlsSslContext = getConfiguredSslContext(configurationContext);
+                        if (startTlsSslContext != null) {
+                            tlsAuthenticationStrategy.setSslSocketFactory(startTlsSslContext.getSocketFactory());
                         }
 
+                        // set the authentication strategy
                         context.setAuthenticationStrategy(tlsAuthenticationStrategy);
                         break;
                 }
@@ -241,6 +215,11 @@ public class LdapProvider implements LoginIdentityProvider {
             }
         }
 
+        // set the base environment is necessary
+        if (!baseEnvironment.isEmpty()) {
+            context.setBaseEnvironmentProperties(baseEnvironment);
+        }
+
         try {
             // handling initializing beans
             context.afterPropertiesSet();
@@ -269,6 +248,56 @@ public class LdapProvider implements LoginIdentityProvider {
         }
     }
 
+    private SSLContext getConfiguredSslContext(final LoginIdentityProviderConfigurationContext configurationContext) {
+        final String rawKeystore = configurationContext.getProperty("TLS - Keystore");
+        final String rawKeystorePassword = configurationContext.getProperty("TLS - Keystore Password");
+        final String rawKeystoreType = configurationContext.getProperty("TLS - Keystore Type");
+        final String rawTruststore = configurationContext.getProperty("TLS - Truststore");
+        final String rawTruststorePassword = configurationContext.getProperty("TLS - Truststore Password");
+        final String rawTruststoreType = configurationContext.getProperty("TLS - Truststore Type");
+        final String rawClientAuth = configurationContext.getProperty("TLS - Client Auth");
+        final String rawProtocol = configurationContext.getProperty("TLS - Protocol");
+
+        // create the ssl context
+        final SSLContext sslContext;
+        try {
+            if (StringUtils.isBlank(rawKeystore) && StringUtils.isBlank(rawTruststore)) {
+                sslContext = null;
+            } else {
+                // ensure the protocol is specified
+                if (StringUtils.isBlank(rawProtocol)) {
+                    throw new ProviderCreationException("TLS - Protocol must be specified.");
+                }
+
+                if (StringUtils.isBlank(rawKeystore)) {
+                    sslContext = SslContextFactory.createTrustSslContext(rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, rawProtocol);
+                } else if (StringUtils.isBlank(rawTruststore)) {
+                    sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType, rawProtocol);
+                } else {
+                    // determine the client auth if specified
+                    final ClientAuth clientAuth;
+                    if (StringUtils.isBlank(rawClientAuth)) {
+                        clientAuth = ClientAuth.NONE;
+                    } else {
+                        try {
+                            clientAuth = ClientAuth.valueOf(rawClientAuth);
+                        } catch (final IllegalArgumentException iae) {
+                            throw new ProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
+                                    rawClientAuth, StringUtils.join(ClientAuth.values(), ", ")));
+                        }
+                    }
+
+                    sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType,
+                            rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, clientAuth, rawProtocol);
+                }
+            }
+        } catch (final KeyStoreException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyManagementException | IOException e) {
+            throw new ProviderCreationException(e.getMessage(), e);
+        }
+
+        return sslContext;
+    }
+
     @Override
     public final AuthenticationResponse authenticate(final LoginCredentials credentials) throws InvalidLoginCredentialsException, IdentityAccessException {
         if (provider == null) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5ef0767/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapsSocketFactory.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapsSocketFactory.java b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapsSocketFactory.java
new file mode 100644
index 0000000..7c4eb87
--- /dev/null
+++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapsSocketFactory.java
@@ -0,0 +1,106 @@
+/*
+ * 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.nifi.ldap;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+/**
+ * SSLSocketFactory used when connecting to a Directory Server over LDAPS.
+ */
+public class LdapsSocketFactory extends SSLSocketFactory {
+
+    // singleton
+    private static LdapsSocketFactory instance;
+
+    // delegate
+    private SSLSocketFactory delegate;
+
+    /**
+     * Initializes the LdapsSocketFactory with the specified SSLSocketFactory. The specified
+     * socket factory will be used as a delegate for all subsequent instances of this class.
+     *
+     * @param sslSocketFactory delegate socket factory
+     */
+    public static void initialize(final SSLSocketFactory sslSocketFactory) {
+        instance = new LdapsSocketFactory(sslSocketFactory);
+    }
+
+    /**
+     * Gets the LdapsSocketFactory that was previously initialized.
+     *
+      * @return socket factory
+     */
+    public static SocketFactory getDefault() {
+        return instance;
+    }
+
+    /**
+     * Creates a new LdapsSocketFactory.
+     *
+     * @param sslSocketFactory delegate socket factory
+     */
+    private LdapsSocketFactory(final SSLSocketFactory sslSocketFactory) {
+        delegate = sslSocketFactory;
+    }
+
+    // delegate methods
+
+    @Override
+    public String[] getSupportedCipherSuites() {
+        return delegate.getSupportedCipherSuites();
+    }
+
+    @Override
+    public String[] getDefaultCipherSuites() {
+        return delegate.getDefaultCipherSuites();
+    }
+
+    @Override
+    public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException {
+        return delegate.createSocket(socket, string, i, bln);
+    }
+
+    @Override
+    public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException {
+        return delegate.createSocket(ia, i, ia1, i1);
+    }
+
+    @Override
+    public Socket createSocket(InetAddress ia, int i) throws IOException {
+        return delegate.createSocket(ia, i);
+    }
+
+    @Override
+    public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException {
+        return delegate.createSocket(string, i, ia, i1);
+    }
+
+    @Override
+    public Socket createSocket(String string, int i) throws IOException, UnknownHostException {
+        return delegate.createSocket(string, i);
+    }
+
+    @Override
+    public Socket createSocket() throws IOException {
+        return delegate.createSocket();
+    }
+}