Переглянути джерело

A whole bunch of changes to the LDAP Authentication process. It should be both more object oriented, and faster.

[Note] I am checking this in in advance of having time to actually test it.
[Note] This class will probably be renamed to replace the current LdapPasswordAuthenticationDao .
Robert Sanders 20 роки тому
батько
коміт
a163fc48ef

+ 177 - 0
sandbox/src/main/java/org/acegisecurity/providers/dao/ldap/LdapPassword2AuthenticationDao.java

@@ -0,0 +1,177 @@
+/**
+ * 
+ */
+package net.sf.acegisecurity.providers.dao.ldap;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchResult;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.dao.DataAccessException;
+import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.UserDetails;
+import net.sf.acegisecurity.providers.dao.PasswordAuthenticationDao;
+
+/**
+ * Re-written version of the ACEGI LDAP code, 
+ *  designed to be cleaner; it is partially based on 
+ *  the description of the mod_auth_ldap logic:  http://httpd.apache.org/docs-2.0/mod/mod_auth_ldap.html
+ *  
+ * 
+ *
+ */
+public class LdapPassword2AuthenticationDao implements PasswordAuthenticationDao {
+
+    public static final String BAD_CREDENTIALS_EXCEPTION_MESSAGE = "Invalid username, password or context";
+    
+    private static final transient Log logger = LogFactory.getLog(LdapPassword2AuthenticationDao.class);
+    
+    /** Ldap base settings. */
+    private LdapSupport ldapSupport;
+    
+    /** Array of LdapSearchBean which will be used to search the context.
+     */
+    private UserSearchBean[] ldapSearchBeans;
+    
+    private String defaultRole;
+
+    public UserDetails loadUserByUsernameAndPassword(String username, String password) throws DataAccessException, BadCredentialsException {
+        if ((password == null) || (password.length() == 0)) {
+            throw new BadCredentialsException("Empty password");
+        }
+        
+        UserSearchResults userSearchResults = getUserBySearch(username);
+        if (null == userSearchResults) {
+            throw new BadCredentialsException(BAD_CREDENTIALS_EXCEPTION_MESSAGE);
+        }
+        
+        DirContext userDirContext = null;
+        try {
+            userDirContext = loginToUserDirContext( userSearchResults.getUserLoginName(), password );
+            if (null == userDirContext) {
+                throw new BadCredentialsException(BAD_CREDENTIALS_EXCEPTION_MESSAGE);
+            }
+            
+            String[] roleAttrs =  userSearchResults.getUserSearchBean().getRoleAttributes();
+            GrantedAuthority[] roles = getUserRolesLdap(userDirContext, roleAttrs);
+
+            if ((roles == null) && (null != defaultRole)) {
+                roles = new GrantedAuthority[] { new GrantedAuthorityImpl(defaultRole) };
+            }
+            if (null != roles) {
+                return new User( userSearchResults.getUserLoginName(), 
+                    password, 
+                    true,
+                    true, 
+                    true,
+                    true, 
+                    roles);
+            } else {
+                logger.info("User was able to login, but had no role information; username = [" + username + "]");
+                throw new BadCredentialsException(BAD_CREDENTIALS_EXCEPTION_MESSAGE);
+            }
+        } finally {
+            try {
+                if (null != userDirContext) {
+                    userDirContext.close();
+                }
+            } catch (NamingException e) {
+                logger.warn("Unable to properly close userDirContext.", e);
+            }
+        }
+    }
+    
+    protected UserSearchResults getUserBySearch(String username) throws DataAccessException, BadCredentialsException {
+        InitialDirContext ctx = ldapSupport.getInitialContext();
+        UserSearchResults userSearchResults = null;
+        try {
+            for (int i = 0; (i < ldapSearchBeans.length) && (null == userSearchResults); i++) {
+                try {
+                    userSearchResults = ldapSearchBeans[i].searchForUser(ctx, username);
+                } catch (NamingException nx) {
+                    logger.warn(nx);
+                }
+            }
+        } finally {
+            try {
+                ctx.close();
+            } catch (NamingException e) {
+                logger.warn("Unable to properly close JNDI LDAP connection.", e);
+            }
+        }
+        return userSearchResults;
+    }
+    
+    
+    protected DirContext loginToUserDirContext(String username, String password) {
+        Hashtable baseEnv = ldapSupport.getEnvironment();
+        baseEnv.put(Context.SECURITY_PRINCIPAL, username);
+        baseEnv.put(Context.SECURITY_CREDENTIALS, password);
+        try {
+            return new InitialDirContext(baseEnv);
+        } catch (NamingException e) {
+            throw new BadCredentialsException(BAD_CREDENTIALS_EXCEPTION_MESSAGE, e);
+        }
+    }
+    
+    
+    protected GrantedAuthority[] getUserRolesLdap(DirContext ctx, String[] roleAttrs) {
+        try {
+            NamingEnumeration enm = ctx.search((Name)null, null, roleAttrs, null);
+            if (!enm.hasMore()) {
+                return null;
+            }
+            
+            // LDAP Search result which SHOULD contain the user's roles
+            SearchResult searchResult = (SearchResult)enm.next();
+            Attributes attrs = searchResult.getAttributes();
+            
+            
+            ArrayList roleList = new ArrayList(attrs.size());
+            NamingEnumeration attrEnm = attrs.getAll();
+            while (attrEnm.hasMore()) {
+                Attribute attr = (Attribute)attrEnm.next();
+                for (int i = 0; i < attr.size(); i++) {
+                    roleList.add( new GrantedAuthorityImpl((String)attr.get(i)) );
+                }
+            }
+            
+            GrantedAuthorityImpl[] roles = new GrantedAuthorityImpl[ roleList.size() ];
+            return (GrantedAuthorityImpl[])roleList.toArray(roles);
+        } catch (NamingException e) {
+            // TODO Convert to authentication exception
+            e.printStackTrace();
+        } 
+        return null;
+    }
+
+    /**
+     * @return Returns the defaultRole.
+     */
+    public String getDefaultRole() {
+        return defaultRole;
+    }
+
+    /**
+     * @param defaultRole The defaultRole to set.
+     */
+    public void setDefaultRole(String defaultRole) {
+        this.defaultRole = defaultRole;
+    }
+    
+    
+}