[jboss-cvs] JBossAS SVN: r75286 - in projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation: spnego and 1 other directory.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue Jul 1 20:28:58 EDT 2008


Author: darran.lofthouse at jboss.com
Date: 2008-07-01 20:28:57 -0400 (Tue, 01 Jul 2008)
New Revision: 75286

Added:
   projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/AdvancedLdapLoginModule.java
   projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/IdentityLoginModule.java
Modified:
   projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/DecodeAction.java
   projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/LdapExtLoginModule.java
Log:
[SECURITY-133] New LDAP login module for enhanced GSSAPI capabilities and second in chain improvements.

Modified: projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/DecodeAction.java
===================================================================
--- projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/DecodeAction.java	2008-07-02 00:05:51 UTC (rev 75285)
+++ projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/DecodeAction.java	2008-07-02 00:28:57 UTC (rev 75286)
@@ -37,7 +37,7 @@
  * @author Scott.Stark at jboss.org
  * @version $Revision$
  */
-class DecodeAction implements PrivilegedExceptionAction
+public class DecodeAction implements PrivilegedExceptionAction
 {
    String password;
    ObjectName serviceName;
@@ -66,7 +66,7 @@
       String secretPassword = new String(secret, "UTF-8");
       return secretPassword.toCharArray();
    }
-   static char[] decode(String password, ObjectName serviceName)
+   public static char[] decode(String password, ObjectName serviceName)
       throws Exception
    {
       DecodeAction action = new DecodeAction(password, serviceName);

Modified: projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/LdapExtLoginModule.java
===================================================================
--- projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/LdapExtLoginModule.java	2008-07-02 00:05:51 UTC (rev 75285)
+++ projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/prototype/LdapExtLoginModule.java	2008-07-02 00:28:57 UTC (rev 75286)
@@ -180,7 +180,7 @@
     @return and empty password String
     */
    protected String getUsersPassword() throws LoginException
-   {
+   {      
       return "";
    }
 

Added: projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/AdvancedLdapLoginModule.java
===================================================================
--- projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/AdvancedLdapLoginModule.java	                        (rev 0)
+++ projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/AdvancedLdapLoginModule.java	2008-07-02 00:28:57 UTC (rev 75286)
@@ -0,0 +1,411 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.security.negotiation.spnego;
+
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.acl.Group;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Map.Entry;
+
+import javax.management.ObjectName;
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.LdapContext;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.jboss.security.SimpleGroup;
+import org.jboss.security.auth.spi.AbstractServerLoginModule;
+import org.jboss.security.negotiation.prototype.DecodeAction;
+
+/**
+ * Another LDAP LoginModule to take into account requirements
+ * for different authentication mechanisms and full support
+ * for password-stacking set to useFirstPass.
+ * 
+ * This is essentially a complete refactoring of the LdapExtLoginModule
+ * but with enough restructuring to seperate out the three login steps: -
+ *  -1 Find the user
+ *  -2 Authenticate as the user
+ *  -3 Find the users roles
+ * Configuration should allow for any of the three actions to be
+ * skipped based on the requirements for the environment making
+ * use of this login module. 
+ *
+ * 
+ * @author darran
+ *
+ */
+public class AdvancedLdapLoginModule extends AbstractServerLoginModule
+{
+
+   /*
+    * Configuration Option Constants 
+    */
+
+   // Search Context Settings
+   private static final String BIND_AUTHENTICATION = "bindAuthentication";
+
+   private static final String BIND_DN = "bindDN";
+
+   private static final String BIND_CREDENTIAL = "bindCredential";
+
+   private static final String SECURITY_DOMAIN = "jaasSecurityDomain";
+
+   // User Search Settings
+   private static final String BASE_CTX_DN = "baseCtxDN";
+
+   private static final String BASE_FILTER = "baseFilter";
+
+   private static final String SEARCH_TIME_LIMIT = "searchTimeLimit";
+
+   /*
+    * Other Constants
+    */
+
+   private static final String AUTH_TYPE_GSSAPI = "GSSAPI";
+
+   private static final String AUTH_TYPE_SIMPLE = "simple";
+
+   private static final String DEFAULT_LDAP_CTX_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
+
+   private static final String DEFAULT_URL = "ldap://localhost:389";
+
+   private static final String DEFAULT_SSL_URL = "ldap://localhost:686";
+
+   private static final String PROTOCOL_SSL = "SSL";
+
+   /*
+    * Configuration Options
+    */
+   // Search Context Settings
+   protected String bindAuthentication;
+
+   protected String bindDn;
+
+   protected String bindCredential;
+
+   protected String jaasSecurityDomain;
+
+   // User Search Settings
+   protected String baseCtxDN;
+
+   protected String baseFilter;
+
+   protected int searchTimeLimit = 10000;
+
+   /*
+    * Module State 
+    */
+   /** The login identity */
+   private Principal identity;
+
+   /** The proof of login identity */
+   private char[] credential;
+
+   private transient SimpleGroup userRoles = new SimpleGroup("Roles");
+   
+   @Override
+   public void initialize(Subject subject, CallbackHandler handler, Map sharedState, Map options)
+   {
+      super.initialize(subject, handler, sharedState, options);
+
+      // Search Context Settings
+      bindAuthentication = (String) options.get(BIND_AUTHENTICATION);
+      bindDn = (String) options.get(BIND_DN);
+      bindCredential = (String) options.get(BIND_CREDENTIAL);
+      jaasSecurityDomain = (String) options.get(SECURITY_DOMAIN);
+
+      // User Search Settings
+      baseCtxDN = (String) options.get(BASE_CTX_DN);
+      baseFilter = (String) options.get(BASE_FILTER);
+
+      String temp = (String) options.get(SEARCH_TIME_LIMIT);
+      if (temp != null)
+      {
+         try
+         {
+            searchTimeLimit = Integer.parseInt(temp);
+         }
+         catch (NumberFormatException e)
+         {
+            log.warn("Failed to parse: " + temp + ", using searchTimeLimit=" + searchTimeLimit);
+         }
+      }
+   }
+
+   @Override
+   public boolean login() throws LoginException
+   {
+      /*
+       * The super.login() check is required to decide if
+       * the current user needs to be authenticated, however
+       * the actual user and roles search should proceed based
+       * on their own options.
+       */
+
+      Boolean result = null;
+
+      AuthorizeAction action = new AuthorizeAction();
+      if (AUTH_TYPE_GSSAPI.equals(bindAuthentication))
+      {
+         log.trace("Using GSSAPI to connect to LDAP");
+         LoginContext lc = new LoginContext(jaasSecurityDomain);
+         lc.login();
+         Subject serverSubject = lc.getSubject();
+
+         if (log.isDebugEnabled())
+         {
+            log.debug("Subject = " + serverSubject);
+            log.debug("Logged in '" + lc + "' LoginContext");
+         }
+
+         result = (Boolean) Subject.doAs(serverSubject, action);
+         lc.logout();
+      }
+      else
+      {
+         result = action.run();
+      }
+
+      return result.booleanValue();
+
+   }
+
+   @Override
+   protected Principal getIdentity()
+   {
+      return identity;
+   }
+
+   @Override
+   protected Group[] getRoleSets() throws LoginException
+   {
+      Group[] roleSets = {userRoles};
+      return roleSets;
+   }
+
+   protected Boolean authorize() throws Exception
+   {
+      // Obtain the username and password
+      processIdentityAndCredential();
+      log.trace("Identity - " + getIdentity().getName());
+      // Initialise search ctx
+      String bindCredential = this.bindCredential;
+      if (AUTH_TYPE_GSSAPI.equals(bindAuthentication) == false)
+      {
+         if (jaasSecurityDomain != null)
+         {
+            ObjectName serviceName = new ObjectName(jaasSecurityDomain);
+            char[] tmp = DecodeAction.decode(bindCredential, serviceName);
+            bindCredential = new String(tmp);
+         }
+      }
+
+      LdapContext searchContext = constructLdapContext(bindDn, bindCredential, bindAuthentication);
+      log.debug("Obtained LdapContext");
+
+      // Search for user in LDAP
+      String userDN = findUserDN(searchContext);
+
+      // If authentication required authenticate as user
+      // Search for roles in LDAP
+
+      return Boolean.FALSE;
+   }
+
+   /**
+    * Either retrieve existing values based on useFirstPass or use 
+    * CallBackHandler to obtain the values.
+    */
+   protected void processIdentityAndCredential() throws Exception
+   {
+      if (super.login() == true)
+      {
+         Object username = sharedState.get("javax.security.auth.login.name");
+         if (username instanceof Principal)
+            identity = (Principal) username;
+         else
+         {
+            String name = username.toString();
+            try
+            {
+               identity = createIdentity(name);
+            }
+            catch (Exception e)
+            {
+               log.debug("Failed to create principal", e);
+               throw new LoginException("Failed to create principal: " + e.getMessage());
+            }
+         }
+         // We have no further use for a credential so no need to retrieve it.
+      }
+      else
+      {
+         NameCallback nc = new NameCallback("User name: ", "guest");
+         PasswordCallback pc = new PasswordCallback("Password: ", false);
+         Callback[] callbacks =
+         {nc, pc};
+         String password = null;
+
+         callbackHandler.handle(callbacks);
+
+         String username = nc.getName();
+         identity = createIdentity(username);
+         credential = pc.getPassword();
+         pc.clearPassword();
+
+      }
+   }
+
+   protected LdapContext constructLdapContext(String dn, Object credential, String authentication)
+         throws NamingException
+   {
+      Properties env = new Properties();
+      Iterator iter = options.entrySet().iterator();
+      while (iter.hasNext())
+      {
+         Entry entry = (Entry) iter.next();
+         env.put(entry.getKey(), entry.getValue());
+      }
+
+      // Set defaults for key values if they are missing
+      String factoryName = env.getProperty(Context.INITIAL_CONTEXT_FACTORY);
+      if (factoryName == null)
+      {
+         factoryName = DEFAULT_LDAP_CTX_FACTORY;
+         env.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryName);
+      }
+
+      // If this method is called with an authentication type then use that.
+      if (authentication != null && authentication.length() > 0)
+      {
+         env.setProperty(Context.SECURITY_AUTHENTICATION, authentication);
+      }
+      else
+      {
+         String authType = env.getProperty(Context.SECURITY_AUTHENTICATION);
+         if (authType == null)
+            env.setProperty(Context.SECURITY_AUTHENTICATION, AUTH_TYPE_SIMPLE);
+      }
+
+      String protocol = env.getProperty(Context.SECURITY_PROTOCOL);
+      String providerURL = (String) options.get(Context.PROVIDER_URL);
+      if (providerURL == null)
+      {
+         if (PROTOCOL_SSL.equals(protocol))
+         {
+            providerURL = DEFAULT_SSL_URL;
+         }
+         else
+         {
+            providerURL = DEFAULT_URL;
+         }
+         env.setProperty(Context.PROVIDER_URL, providerURL);
+      }
+
+      // Assume the caller of this method has checked the requirements for the principal and
+      // credentials.
+      if (dn != null)
+         env.setProperty(Context.SECURITY_PRINCIPAL, dn);
+      if (credential != null)
+         env.put(Context.SECURITY_CREDENTIALS, credential);
+      traceLdapEnv(env);
+      return new InitialLdapContext(env, null);
+   }
+
+   protected String findUserDN(LdapContext ctx) throws Exception
+   {
+      SearchControls constraints = new SearchControls();
+      constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
+      constraints.setReturningAttributes(new String[0]);
+      constraints.setTimeLimit(searchTimeLimit);
+
+      NamingEnumeration results = null;
+
+      Object[] filterArgs =
+      {getIdentity().getName()};
+      results = ctx.search(baseCtxDN, baseFilter, filterArgs, constraints);
+      if (results.hasMore() == false)
+      {
+         results.close();
+         throw new NamingException("Search of baseDN(" + baseCtxDN + ") found no matches");
+      }
+
+      SearchResult sr = (SearchResult) results.next();
+      String name = sr.getName();
+      String userDN = null;
+      if (sr.isRelative() == true)
+         userDN = name + "," + baseCtxDN;
+      else
+         throw new NamingException("Can't follow referal for authentication: " + name);
+
+      results.close();
+      results = null;
+
+      log.trace("findUserDN - " + userDN);
+      return userDN;
+   }
+
+   protected void traceLdapEnv(Properties env)
+   {
+      if (log.isTraceEnabled())
+      {
+         Properties tmp = new Properties();
+         tmp.putAll(env);
+         String credentials = tmp.getProperty(Context.SECURITY_CREDENTIALS);
+         if (credentials != null && credentials.length() > 0)
+            tmp.setProperty(Context.SECURITY_CREDENTIALS, "***");
+         log.trace("Logging into LDAP server, env=" + tmp.toString());
+      }
+   }
+
+   private class AuthorizeAction implements PrivilegedAction<Boolean>
+   {
+
+      public Boolean run()
+      {
+         try
+         {
+            return authorize();
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException(e);
+         }
+      }
+
+   }
+
+}


Property changes on: projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/AdvancedLdapLoginModule.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/IdentityLoginModule.java
===================================================================
--- projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/IdentityLoginModule.java	                        (rev 0)
+++ projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/IdentityLoginModule.java	2008-07-02 00:28:57 UTC (rev 75286)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.security.negotiation.spnego;
+
+import javax.security.auth.login.LoginException;
+
+/**
+ * 
+ * @author darran.lofthouse at jboss.com
+ */
+public class IdentityLoginModule extends org.jboss.security.auth.spi.IdentityLoginModule
+{
+
+   @Override
+   public boolean login() throws LoginException
+   {
+      if (super.login() == true)
+      {
+         sharedState.put("javax.security.auth.login.password", new Object());
+         return true;
+      }
+      return false;
+   }
+
+}


Property changes on: projects/security/security-negotiation/trunk/jboss-negotiation/src/main/java/org/jboss/security/negotiation/spnego/IdentityLoginModule.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF




More information about the jboss-cvs-commits mailing list