You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2010/12/22 14:47:14 UTC

svn commit: r1051897 - in /karaf/trunk: jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java manual/src/main/webapp/developers-guide/security-framework.conf

Author: gnodet
Date: Wed Dec 22 13:47:13 2010
New Revision: 1051897

URL: http://svn.apache.org/viewvc?rev=1051897&view=rev
Log:
[KARAF-307] Add support for SSL on the LDAPLoginModule

Modified:
    karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java
    karaf/trunk/manual/src/main/webapp/developers-guide/security-framework.conf

Modified: karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java?rev=1051897&r1=1051896&r2=1051897&view=diff
==============================================================================
--- karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java (original)
+++ karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/ldap/LDAPLoginModule.java Wed Dec 22 13:47:13 2010
@@ -17,17 +17,21 @@ package org.apache.karaf.jaas.modules.ld
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.karaf.jaas.config.KeystoreManager;
 import org.apache.karaf.jaas.modules.AbstractKarafLoginModule;
 import org.apache.karaf.jaas.modules.RolePrincipal;
 import org.apache.karaf.jaas.modules.UserPrincipal;
+import org.osgi.framework.ServiceReference;
 
 import javax.naming.Context;
 import javax.naming.NamingEnumeration;
 import javax.naming.directory.*;
+import javax.net.ssl.SSLSocketFactory;
 import javax.security.auth.Subject;
 import javax.security.auth.callback.*;
 import javax.security.auth.login.LoginException;
 import java.io.IOException;
+import java.security.GeneralSecurityException;
 import java.security.Principal;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -39,6 +43,7 @@ import java.util.Map;
  * </p>
  *
  * @author jbonofre
+ * @author gnodet
  */
 public class LDAPLoginModule extends AbstractKarafLoginModule {
 
@@ -56,6 +61,13 @@ public class LDAPLoginModule extends Abs
     public final static String ROLE_SEARCH_SUBTREE = "role.search.subtree";
     public final static String AUTHENTICATION = "authentication";
     public final static String INITIAL_CONTEXT_FACTORY = "initial.context.factory";
+    public final static String SSL = "ssl";
+    public final static String SSL_PROVIDER = "ssl.provider";
+    public final static String SSL_PROTOCOL = "ssl.protocol";
+    public final static String SSL_ALGORITHM = "ssl.algorithm";
+    public final static String SSL_KEYSTORE = "ssl.keystore";
+    public final static String SSL_KEYALIAS = "ssl.keyalias";
+    public final static String SSL_TRUSTSTORE = "ssl.truststore";
 
     public final static String DEFAULT_INITIAL_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
 
@@ -71,6 +83,13 @@ public class LDAPLoginModule extends Abs
     private boolean roleSearchSubtree = true;
     private String authentication = "simple";
     private String initialContextFactory = null;
+    private boolean ssl;
+    private String sslProvider;
+    private String sslProtocol;
+    private String sslAlgorithm;
+    private String sslKeystore;
+    private String sslKeyAlias;
+    private String sslTrustStore;
 
     public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
         super.initialize(subject, callbackHandler, options);
@@ -79,15 +98,11 @@ public class LDAPLoginModule extends Abs
         connectionPassword = (String) options.get(CONNECTION_PASSWORD);
         userBaseDN =  (String) options.get(USER_BASE_DN);
         userFilter = (String) options.get(USER_FILTER);
-        if (options.get(USER_SEARCH_SUBTREE) != null) {
-            userSearchSubtree = Boolean.getBoolean((String) options.get(USER_SEARCH_SUBTREE));
-        }
+        userSearchSubtree = Boolean.parseBoolean((String) options.get(USER_SEARCH_SUBTREE));
         roleBaseDN = (String) options.get(ROLE_BASE_DN);
         roleFilter = (String) options.get(ROLE_FILTER);
         roleNameAttribute = (String) options.get(ROLE_NAME_ATTRIBUTE);
-        if (options.get(ROLE_SEARCH_SUBTREE) != null) {
-            roleSearchSubtree = Boolean.getBoolean((String) options.get(ROLE_SEARCH_SUBTREE));
-        }
+        roleSearchSubtree = Boolean.parseBoolean((String) options.get(ROLE_SEARCH_SUBTREE));
         initialContextFactory = (String) options.get(INITIAL_CONTEXT_FACTORY);
         if (initialContextFactory == null) {
             initialContextFactory = DEFAULT_INITIAL_CONTEXT_FACTORY;
@@ -98,9 +113,30 @@ public class LDAPLoginModule extends Abs
         } else if (!connectionURL.startsWith("ldap:")) {
             LOG.error("Invalid LDAP URL.");
         }
+        if (options.get(SSL) != null) {
+            ssl = Boolean.parseBoolean((String) options.get(SSL));
+        } else {
+            ssl = connectionURL.startsWith("ldaps:");
+        }
+        sslProvider = (String) options.get(SSL_PROVIDER);
+        sslProtocol = (String) options.get(SSL_PROTOCOL);
+        sslAlgorithm = (String) options.get(SSL_ALGORITHM);
+        sslKeystore = (String) options.get(SSL_KEYSTORE);
+        sslKeyAlias = (String) options.get(SSL_KEYALIAS);
+        sslTrustStore = (String) options.get(SSL_TRUSTSTORE);
     }
 
     public boolean login() throws LoginException {
+        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+        try {
+            return doLogin();
+        } finally {
+            ManagedSSLSocketFactory.setSocketFactory(null);
+            Thread.currentThread().setContextClassLoader(tccl);
+        }
+    }
+
+    protected boolean doLogin() throws LoginException {
         Callback[] callbacks = new Callback[2];
         callbacks[0] = new NameCallback("Username: ");
         callbacks[1] = new PasswordCallback("Password: ", false);
@@ -133,8 +169,11 @@ public class LDAPLoginModule extends Abs
             env.put(Context.SECURITY_PRINCIPAL, connectionUsername);
             env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
         }
+        if (ssl) {
+            setupSsl(env);
+        }
         LOG.debug("Get the user DN.");
-        String userDN = null;
+        String userDN;
         try {
             LOG.debug("Initialize the JNDI LDAP Dir Context.");
             DirContext context = new InitialDirContext(env);
@@ -205,6 +244,24 @@ public class LDAPLoginModule extends Abs
         return true;
     }
 
+    protected void setupSsl(Hashtable env) throws LoginException {
+        ServiceReference ref = null;
+        try {
+            LOG.debug("Setting up SSL");
+            env.put(Context.SECURITY_PROTOCOL, "ssl");
+            env.put("java.naming.ldap.factory.socket", ManagedSSLSocketFactory.class.getName());
+            ref = bundleContext.getServiceReference(KeystoreManager.class.getName());
+            KeystoreManager manager = (KeystoreManager) bundleContext.getService(ref);
+            SSLSocketFactory factory = manager.createSSLFactory(sslProvider, sslProtocol, sslAlgorithm, sslKeystore, sslKeyAlias, sslTrustStore);
+            ManagedSSLSocketFactory.setSocketFactory(factory);
+            Thread.currentThread().setContextClassLoader(ManagedSSLSocketFactory.class.getClassLoader());
+        } catch (Exception e) {
+            throw new LoginException("Unable to setup SSL support for LDAP: " + e.getMessage());
+        } finally {
+            bundleContext.ungetService(ref);
+        }
+    }
+
     public boolean abort() throws LoginException {
         return true;
     }
@@ -215,4 +272,22 @@ public class LDAPLoginModule extends Abs
         return true;
     }
 
+    public static abstract class ManagedSSLSocketFactory extends SSLSocketFactory {
+
+        private static final ThreadLocal<SSLSocketFactory> factories = new ThreadLocal<SSLSocketFactory>();
+
+        public static void setSocketFactory(SSLSocketFactory factory) {
+            factories.set(factory);
+        }
+
+        public static SSLSocketFactory getDefault() {
+            SSLSocketFactory factory = factories.get();
+            if (factory == null) {
+                throw new IllegalStateException("No SSLSocketFactory parameters have been set!");
+            }
+            return factory;
+        }
+
+    }
+
 }

Modified: karaf/trunk/manual/src/main/webapp/developers-guide/security-framework.conf
URL: http://svn.apache.org/viewvc/karaf/trunk/manual/src/main/webapp/developers-guide/security-framework.conf?rev=1051897&r1=1051896&r2=1051897&view=diff
==============================================================================
--- karaf/trunk/manual/src/main/webapp/developers-guide/security-framework.conf (original)
+++ karaf/trunk/manual/src/main/webapp/developers-guide/security-framework.conf Wed Dec 22 13:47:13 2010
@@ -83,7 +83,6 @@ Here are two example using this schema:
 {pygmentize}
 {pygmentize:xml}
 <jaas:keystore xmlns:jaas="http://karaf.apache.org/xmlns/jaas/v1.0.0"
-               id="keystore"
                name="ks"
                rank="1"
                path="classpath:privatestore.jks"
@@ -199,6 +198,13 @@ The LDAPLoginModule supports the followi
 | {{role.search.subtree}}     | If "true", the role lookup will be recursive (SUBTREE). If "false", the role lookup will be performed only at the first level (ONELEVEL). |
 | {{authentication}}          | Define the authentication backend used on the LDAP server. The default is simple. |
 | {{initial.context.factory}} | Define the initial context factory used to connect to the LDAP server. The default is com.sun.jndi.ldap.LdapCtxFactory |
+| {{ssl}}                     | If "true" or if the protocol on the {{connection.url}} is {{ldaps}}, an SSL connection will be used |
+| {{ssl.provider}}            | The provider name to use for SSL |
+| {{ssl.protocol}}            | The protocol name to use for SSL (SSL for example)|
+| {{ssl.algorithm}}           | The algorithm to use for the KeyManagerFactory and TrustManagerFactory  (PKIX for example) |
+| {{ssl.keystore}}            | The key store name to use for SSL.  The key store must be deployed using a {{jaas:keystore}} configuration.  |
+| {{ssl.keyalias}}            | The key alias to use for SSL |
+| {{ssl.truststore}}          | The trust store name to use for SSL.  The trust store must be deployed using a {{jaas:keystore}} configuration.  |
 
 A example of LDAPLoginModule usage follows:
 
@@ -218,6 +224,33 @@ A example of LDAPLoginModule usage follo
 </jaas:config>
 {pygmentize}
 
+If you want to use an SSL connection, the following configuration can be used as an example:
+{pygmentize:xml}
+<ext:property-placeholder />
+
+<jaas:config name="karaf" rank="1">
+    <jaas:module className="org.apache.karaf.jaas.modules.ldap.LDAPLoginModule" flags="required">
+        connection.url = ldaps://localhost:10636
+        user.base.dn = ou=users,ou=system
+        user.filter = (uid=%u)
+        user.search.subtree = true
+        role.base.dn = ou=groups,ou=system
+        role.filter = (uniqueMember=uid=%u)
+        role.name.attribute = cn
+        role.search.subtree = true
+        authentication = simple
+        ssl.protocol=SSL
+        ssl.truststore=ks
+        ssl.algorithm=PKIX
+    </jaas:module>
+</jaas:config>
+
+<jaas:keystore name="ks"
+               path="file:///${karaf.home}/etc/trusted.ks"
+               keystorePassword="secret" />
+{pygmentize}
+
+
 h2. Encryption service
 
 The [EncryptionService|http://svn.apache.org/repos/asf/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/EncryptionService.java] is a service registered in the OSGi registry providing means to encrypt and check encrypted passwords.  This service acts as a factory for [Encryption|http://svn.apache.org/repos/asf/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/Encryption.java] objects actually performing the encryption.