[jboss-cvs] JBossAS SVN: r103928 - projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue Apr 13 14:33:55 EDT 2010


Author: darran.lofthouse at jboss.com
Date: 2010-04-13 14:33:55 -0400 (Tue, 13 Apr 2010)
New Revision: 103928

Added:
   projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation/AdvancedADLoginModule.java
Modified:
   projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation/AdvancedLdapLoginModule.java
Log:
[SECURITY-447] Add new login module to support Active Directory primary group of user.

Added: projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation/AdvancedADLoginModule.java
===================================================================
--- projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation/AdvancedADLoginModule.java	                        (rev 0)
+++ projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation/AdvancedADLoginModule.java	2010-04-13 18:33:55 UTC (rev 103928)
@@ -0,0 +1,151 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+ * by the @authors tag. See the copyright.txt 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;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Properties;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapContext;
+import javax.security.auth.login.LoginException;
+
+import org.jboss.util.Base64;
+
+/**
+ * An extension of the AdvancedLdapLoginModule to also query the primary group
+ * of the user being authenticated - this is not discoverable using the usual 
+ * member and memberOf attributes.
+ * 
+ * @author darran.lofthouse at jboss.com
+ */
+public class AdvancedADLoginModule extends AdvancedLdapLoginModule
+{
+
+   private static final String PRIMARY_GROUP_ID = "primaryGroupID";
+
+   private static final String OBJECT_SID = "objectSid";
+
+   /*
+    * The rolesSearch method is called recursively, we need to ensure it is only called once 
+    * as we are only looking for the primary group of the user.
+    */
+   private boolean skipPrimaryGroupSearch = false;
+
+   @Override
+   protected Properties createBaseProperties()
+   {
+      Properties env = super.createBaseProperties();
+      env.put("java.naming.ldap.attributes.binary", "objectSid");
+      return env;
+   }
+
+   @Override
+   protected void rolesSearch(LdapContext searchContext, String dn) throws LoginException
+   {
+      if (skipPrimaryGroupSearch == false)
+      {
+         skipPrimaryGroupSearch = true;
+
+         try
+         {
+            String[] attrNames =
+            {OBJECT_SID, PRIMARY_GROUP_ID};
+            Attributes result = searchContext.getAttributes(dn, attrNames);
+            Attribute primaryGroupIdAttribute = result.get(PRIMARY_GROUP_ID);
+            Attribute objectSidAttribute = result.get(OBJECT_SID);
+            if (primaryGroupIdAttribute != null && objectSidAttribute != null)
+            {
+               int primaryGroupId = Integer.parseInt((String) primaryGroupIdAttribute.get());
+               byte[] objectSid = (byte[]) objectSidAttribute.get();
+
+               /*
+                * The objectSid of the primary group can be found by taking the object sid
+                * of the user and replacing the last four bytes with the little endian representation
+                * of the primary group id - this new byte[] can then be used in the search.
+                */
+
+               byte[] searchObjectSid = new byte[objectSid.length];
+               System.arraycopy(objectSid, 0, searchObjectSid, 0, objectSid.length - 4);
+
+               ByteBuffer byteBuffer = ByteBuffer.wrap(searchObjectSid, objectSid.length - 4, 4);
+               byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+               byteBuffer.putInt(primaryGroupId);
+
+               if (log.isTraceEnabled())
+               {
+                  String objectSidBase64 = Base64.encodeBytes(objectSid);
+                  String searchObjectSidBase64 = Base64.encodeBytes(searchObjectSid);
+                  log.trace("Using base objectSid " + objectSidBase64 + " and replaced with primary group id "
+                        + primaryGroupId + " to create new search objectSid " + searchObjectSidBase64);
+               }
+
+               String primaryGroupFilter = "(objectSid={0})";
+               Object[] filterArgs =
+               {searchObjectSid};
+
+               NamingEnumeration searchResults = searchContext.search(baseCtxDN, primaryGroupFilter, filterArgs,
+                     roleSearchControls);
+               if (searchResults.hasMore() == true)
+               {
+                  SearchResult searchResult = (SearchResult) searchResults.next();
+                  String baseResultDN = canonicalize(searchResult.getName());
+                  String resultDN = "\"" + baseResultDN + "\"";
+
+                  if (log.isTraceEnabled())
+                  {
+                     log.trace("Search found primary group " + resultDN);
+                  }
+
+                  loadRoleByRoleNameAttributeID(searchContext, resultDN);
+                  recurseRolesSearch(searchContext, baseResultDN);
+               }
+
+            }
+            else
+            {
+               log.trace("primaryGroupIdAttribute or objectSidAttribute was null, skipping primary group search.");
+            }
+
+            super.rolesSearch(searchContext, dn);
+         }
+         catch (NamingException e)
+         {
+            log.trace("Failed to load primary group", e);
+         }
+         finally
+         {
+            skipPrimaryGroupSearch = false;
+         }
+      }
+      else
+      {
+         super.rolesSearch(searchContext, dn);
+      }
+
+   }
+}


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

Modified: projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation/AdvancedLdapLoginModule.java
===================================================================
--- projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation/AdvancedLdapLoginModule.java	2010-04-13 17:44:51 UTC (rev 103927)
+++ projects/security/security-negotiation/trunk/jboss-negotiation-extras/src/main/java/org/jboss/security/negotiation/AdvancedLdapLoginModule.java	2010-04-13 18:33:55 UTC (rev 103928)
@@ -426,13 +426,7 @@
    protected LdapContext constructLdapContext(String dn, Object credential, String authentication)
          throws LoginException
    {
-      Properties env = new Properties();
-      Iterator iter = options.entrySet().iterator();
-      while (iter.hasNext())
-      {
-         Entry entry = (Entry) iter.next();
-         env.put(entry.getKey(), entry.getValue());
-      }
+      Properties env = createBaseProperties();
 
       // Set defaults for key values if they are missing
       String factoryName = env.getProperty(Context.INITIAL_CONTEXT_FACTORY);
@@ -488,6 +482,19 @@
       }
    }
 
+   protected Properties createBaseProperties()
+   {
+      Properties env = new Properties();
+      Iterator iter = options.entrySet().iterator();
+      while (iter.hasNext())
+      {
+         Entry entry = (Entry) iter.next();
+         env.put(entry.getKey(), entry.getValue());
+      }
+
+      return env;
+   }
+
    protected String findUserDN(LdapContext ctx) throws LoginException
    {
 
@@ -632,42 +639,11 @@
             if (roleAttributeIsDN)
             {
                // Query the roleDN location for the value of roleNameAttributeID
-               String roleDN = roleName;
-               roleDN = "\"" + roleDN + "\""; 
-               String[] returnAttribute =
-               {roleNameAttributeID};
-               log.trace("Using roleDN: " + roleDN);
-               try
-               {
-                  Attributes result2 = searchContext.getAttributes(roleDN, returnAttribute);
-                  Attribute roles2 = result2.get(roleNameAttributeID);
-                  if (roles2 != null)
-                  {
-                     for (int m = 0; m < roles2.size(); m++)
-                     {
-                        roleName = (String) roles2.get(m);
-                        addRole(roleName);
-                     }
-                  }
-               }
-               catch (NamingException e)
-               {
-                  log.trace("Failed to query roleNameAttrName", e);
-               }
+               String baseRoleDN = roleName;
+               String roleDN = "\"" + baseRoleDN + "\"";
 
-               if (recurseRoles)
-               {
-                  if (processedRoleDNs.contains(roleDN) == false)
-                  {
-                     processedRoleDNs.add(roleDN);
-                     log.trace("Recursive search for '" + roleDN + "'");
-                     rolesSearch(searchContext, roleDN);
-                  }
-                  else
-                  {
-                     log.trace("Already visited role '" + roleDN + "' ending recursion.");
-                  }
-               }
+               loadRoleByRoleNameAttributeID(searchContext, roleDN);
+               recurseRolesSearch(searchContext, baseRoleDN);
             }
             else
             {
@@ -677,6 +653,47 @@
          }
       }
    }
+   
+   protected void loadRoleByRoleNameAttributeID(LdapContext searchContext, String roleDN)
+   {
+      String[] returnAttribute =
+      {roleNameAttributeID};
+      log.trace("Using roleDN: " + roleDN);
+      try
+      {
+         Attributes result2 = searchContext.getAttributes(roleDN, returnAttribute);
+         Attribute roles2 = result2.get(roleNameAttributeID);
+         if (roles2 != null)
+         {
+            for (int m = 0; m < roles2.size(); m++)
+            {
+               String roleName = (String) roles2.get(m);
+               addRole(roleName);
+            }
+         }
+      }
+      catch (NamingException e)
+      {
+         log.trace("Failed to query roleNameAttrName", e);
+      }
+   }
+   
+   protected void recurseRolesSearch(LdapContext searchContext, String roleDN) throws LoginException
+   {
+      if (recurseRoles)
+      {
+         if (processedRoleDNs.contains(roleDN) == false)
+         {
+            processedRoleDNs.add(roleDN);
+            log.trace("Recursive search for '" + roleDN + "'");
+            rolesSearch(searchContext, roleDN);
+         }
+         else
+         {
+            log.trace("Already visited role '" + roleDN + "' ending recursion.");
+         }
+      }
+   }
 
    protected void traceLdapEnv(Properties env)
    {
@@ -691,7 +708,7 @@
       }
    }
 
-   private String canonicalize(String searchResult)
+   protected String canonicalize(String searchResult)
    {
       String result = searchResult;
       int len = searchResult.length();




More information about the jboss-cvs-commits mailing list