Ver Fonte

Merged from the refactoring branch. Needs user tested, and better documented; but its stable enough that I'm committing it.

Robert Sanders há 20 anos atrás
pai
commit
72e3a24c22

+ 296 - 900
sandbox/src/main/java/org/acegisecurity/providers/dao/ldap/LdapPasswordAuthenticationDao.java

@@ -1,918 +1,314 @@
-/* Copyright 2004, 2005 Acegi Technology Pty Limited
-*
-* Licensed 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 net.sf.acegisecurity.providers.dao.ldap;
 
-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;
-import net.sf.acegisecurity.providers.dao.User;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.dao.DataAccessException;
-import org.springframework.dao.DataAccessResourceFailureException;
-
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Hashtable;
-import java.util.List;
 
 import javax.naming.AuthenticationException;
-import javax.naming.CommunicationException;
-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.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.InitialDirContext;
-import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
 
-/**
-* <p>
-* LdapPasswordAuthenticationDao allows you to authenticate user's against LDAP Directories via JNDI.  
-* LDAP administrators have a wide variety of options available to them when configuring a server, 
-* so the LdapPasswordAuthenticationDao has a wide variety of ways that it can be configured. </p>
-* 
-* <STYLE TYPE="text/css"><!--
-* .syntax0 {
-* color: #000000;
-* }
-* .syntax1 {
-* color: #cc0000;
-* }
-* .syntax2 {
-* color: #ff8400;
-* }
-* .syntax3 {
-* color: #6600cc;
-* }
-* .syntax4 {
-* color: #cc6600;
-* }
-* .syntax5 {
-* color: #ff0000;
-* }
-* .syntax6 {
-* color: #9966ff;
-* }
-* .syntax7 {
-* background: #ffffcc;
-* color: #ff0066;
-* }
-* .syntax8 {
-* color: #006699;
-* font-weight: bold;
-* }
-* .syntax9 {
-* color: #009966;
-* font-weight: bold;
-* }
-* .syntax10 {
-* color: #0099ff;
-* font-weight: bold;
-* }
-* .syntax11 {
-* color: #66ccff;
-* font-weight: bold;
-* }
-* .syntax12 {
-* color: #02b902;
-* }
-* .syntax13 {
-* color: #ff00cc;
-* }
-* .syntax14 {
-* color: #cc00cc;
-* }
-* .syntax15 {
-* color: #9900cc;
-* }
-* .syntax16 {
-* color: #6600cc;
-* }
-* .syntax17 {
-* color: #0000ff;
-* }
-* .syntax18 {
-* color: #000000;
-* font-weight: bold;
-* }
-* -->
-* </STYLE>
-* <p>
-* Currently LdapPasswordAuthenticationDao authenticates a username/password pair by 
-* 'logging in to' the LDAP server via a JNDI bind() operation.  
-* There is some flexibility in that multiple userContexts can be set; the 
-* LdapPasswordAuthenticationDao will attempt to bind() against each until either a bind() 
-* operation succeeds or all  userContexts have been tried. </p>
-* 
-* <p>
-* LdapPasswordAuthenticationDao offers 3 modes for determining the roles assigned to a user 
-* (these can be used in combination). </p>
-* <ul>
-*     <li>The simplest method is to use the defaultRolename property.  
-*         If set, and no other roles are found for an authenticated user, 
-*         the value of defaultRolename is assigned as the sole role of the user. 
-*     </li>
-*     <li>Roles can be retrieved from the context created by the user login 
-*         (the userContext against which the username/password for the user resulted in a successful bind()).  
-*         The attribute names from which roles will be retrieved in this mode are specified by the 
-*         userRolesAttributes property.
-*     </li>
-*     <li>Roles can be searched for within the LDAP directory.  
-*         This option requires three properties to be set: 
-*         the roleContexts property determines the context(s) which will be searched; 
-*         the roleAttributesSearchFilter property specifies an LDAP search filter 
-*         (with placeholders for the username and/or DN of the user); 
-*         while the roleNameAttributes specifies the attributes which (may) contain role information.
-*     </li>
-* </ul>
-* 
-* <p>
-* If the both the userRolesAttributes method and the roleContexts search method are used, 
-* and if both return results, then the final list of roles will be determined by combining the two results.
-* </p>
-* <p>
-* One final operation is performed before returning the list of GrantedAuthority 
-* objects associated with the user: if the the upperCaseRoleNames property is set to 
-* true the user's role names are capitalized; then the values of the rolePrefix and roleSuffix 
-* are used to wrap any role names.
-* </p>
-* <p>
-* At this point a few examples will probably help clear up the confusion 
-* that the abstract description above may have created.  
-* Unless otherwise noted, all examples will use the following base set of assumptions: 
-* An LDAP server reachable at the url ldap://ldap.mycompany.com:389/ 
-* and a rootContext of dc=mycompany,dc=com.  The following would be you AuthenticationProvider:
-* <PRE>
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">id</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">authenticationProvider</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">class</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">net.sf.acegisecurity.providers.dao.PasswordDaoAuthenticationProvider</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">passwordAuthenticationDao</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">ref</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">local</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">ldapDaoImpl</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-* </PRE>
-* </p>
-* 
-* <p>
-* First example: your users are stored under the rootContext as cn=USERNAME,ou=Users; 
-* user objects have the attribute memberOf which contains the names of any roles they 
-* have been granted.  You would use the following bean configuration:
-* <PRE>
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">id</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">ldapDaoImpl</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">class</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">net.sf.acegisecurity.providers.dao.ldap.LdapPasswordAuthenticationDao</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">url</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>ldap://ldap.mycompany.com:389/<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">rootContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">userContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">alue</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>cn={0},ou=Users,dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">userRolesAttribute</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>memberOf<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-* </PRE>
-* </p>
-* 
-* <p>
-* Second example: users are stored under the rootContext as uid=USERNAME,ou=Users; 
-* user object have no role information.  Groups (aka roles) are stored as objects 
-* under the context ou=Groups and have an attribute memberUid which contains the 
-* full distinguished name of the user.  You would use the following bean configuration:
-* <PRE>
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">id</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">ldapDaoImpl</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">class</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">net.sf.acegisecurity.providers.dao.ldap.LdapPasswordAuthenticationDao</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">url</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>ldap://ldap.mycompany.com:389/<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">rootContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax1">&lt;!--</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">here</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">{0}</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">is</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">the</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">username</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">--&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">userContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>uid={0},ou=Users,dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">roleContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>ou=Groups<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax1">&lt;!--</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">here</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">{0}</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">is</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">the</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">distinguished</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">name</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">(which</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">would</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">be</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">uid=USERNAME,ou=Users,dc=mycompany,cd=com</SPAN>
-*           <SPAN CLASS="syntax1">and</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">{1}</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">is</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">the</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">username.</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">--&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">roleAttributesSearchFilter</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>(memberUid={0})<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">roleNameAttribute</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>memberUid<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-* </PRE>
-* </p>
-* 
-* <p>
-* Third example: under the rootContext your users are stored as uid=USERNAME,ou=Users.
-* You don't care about the roles stored in the LDAP, all you want to know is if the user 
-* can login via LDAP.  You would use the following bean configuration:
-* <PRE>
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">id</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">ldapDaoImpl</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">class</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">net.sf.acegisecurity.providers.dao.ldap.LdapPasswordAuthenticationDao</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">url</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>ldap://ldap.mycompany.com:389/<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">rootContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">userContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">alue</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>cn={0},ou=Users,dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">defaultRolename</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>USER<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-* </PRE>
-* </p>
-* 
-* <p>
-* Forth example (something more complex): under the rootContext your users are stored in to seperate subContexts.
-* Your internal users are under uid=USERNAME,ou=Users; you also have client logins stored 
-* under the context uid=USERNAME,ou=Clients.  For internal users role information is stored 
-* under the context ou=Groups and have an attribute memberUid which contains the 
-* full distinguished name of the user.  For clients, role information is stored as an attribute 
-* memberOf as part of their user object.  You could split the definitions up into two separate 
-* LdapPasswordAuthenticationDao beans, but you could also use:
-* <PRE>
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">id</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">ldapDaoImpl</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">class</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">net.sf.acegisecurity.providers.dao.ldap.LdapPasswordAuthenticationDao</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">url</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>ldap://ldap.mycompany.com:389/<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">rootContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax1">&lt;!--</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">here</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">{0}</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">is</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">the</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">username</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">--&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">userContexts</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*           <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">list</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*             <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>uid={0},ou=Users,dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*             <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>uid={0},ou=Clients,dc=mycompany,dc=com<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*           <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">list</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">userRolesAttribute</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>memberOf<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">roleContext</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>ou=Groups<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax1">&lt;!--</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">here</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">{0}</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">is</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">the</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">distinguished</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">name</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">(which</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">would</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">be</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">uid=USERNAME,ou=Users,dc=mycompany,cd=com</SPAN>
-*           <SPAN CLASS="syntax1">and</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">{1}</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">is</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">the</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">username.</SPAN><SPAN CLASS="syntax1"> </SPAN><SPAN CLASS="syntax1">--&gt;</SPAN>
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">roleAttributesSearchFilter</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>(memberUid={0})<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*         <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17"> </SPAN><SPAN CLASS="syntax17">name</SPAN><SPAN CLASS="syntax17">=</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax13">roleNameAttributes</SPAN><SPAN CLASS="syntax13">&quot;</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>memberUid<SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">value</SPAN><SPAN CLASS="syntax17">&gt;</SPAN><SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">property</SPAN><SPAN CLASS="syntax17">&gt;</SPAN> 
-*     <SPAN CLASS="syntax17">&lt;</SPAN><SPAN CLASS="syntax17">/</SPAN><SPAN CLASS="syntax17">bean</SPAN><SPAN CLASS="syntax17">&gt;</SPAN>
-* </PRE>
-* </p>
-*
-* @author Karel Miarka
-* @author Daniel Miller
-* @author Robert Sanders
-*/
-public class LdapPasswordAuthenticationDao implements PasswordAuthenticationDao {
-  
-   /** InnerClass used to keep context variable together. */
-   private class UserContext {
-       public DirContext dirContext;
-       public String userPrincipal;
-       
-       /**
-        * Get the attribute(s) to match when searching for the user object. This
-        * implementation returns a "distinguishedName" attribute with the value
-        * returned by <code>getUserPrincipal(username)</code>. A subclass may
-        * customize this behavior by overriding <code>getUserPrincipal</code>
-        * and/or <code>getUsernameAttributes</code>.
-        * 
-        * @param username
-        *            DOCUMENT ME!
-        * 
-        * @return DOCUMENT ME!
-        */
-       public Attributes getUsernameAttributes() {
-           Attributes matchAttrs = new BasicAttributes(true); // ignore case
-           matchAttrs.put(new BasicAttribute("distinguishedName", userPrincipal));
-           return matchAttrs;
-       }
-   }
-   
-
-   public static final String BAD_CREDENTIALS_EXCEPTION_MESSAGE = "Invalid username, password or context";
-
-   private static final transient Log log = LogFactory
-           .getLog(LdapPasswordAuthenticationDao.class);
-
-   /** Type of authentication within LDAP; default is simple. */
-   private String authenticationType = "simple";
-
-   /** If set to a non-null value, and a user can be bound to a LDAP Conext, 
-    *  but no role information is found then this role is automatically added. 
-    *  If null (the default) then a BadCredentialsException is thrown
-    *  
-    *  <p>For example; if you have an LDAP directory with no role information 
-    *  stored, you might simply want to give any user who can login a role of "USER".</p>
-    */
-   private String defaultRole = null;
-
-   /** The INITIAL_CONTEXT_FACTORY used to create the JNDI Factory.
-    *  Default is "com.sun.jndi.ldap.LdapCtxFactory"; you <b>should not</b>
-    *  need to set this unless you have unusual needs.
-    **/
-   private String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
-   
-   /** Internal variable, concatenation  */
-   private String providerUrl;
-
-   /** Used to build LDAP Search Filter for finding roles (in the roleContexts) 
-    *  pointing to a user.  Uses MessageFormat like tokens; {0} is the 
-    *  user's DistiguishedName, {1} is the user's username. 
-    *  For more information on syntax see  
-    *  javax.naming.directory.DirContext.search(), or RFC 2254. 
-    *  
-    *  <p>Example: if each group has an attribute 'memberUid' with values being 
-    *  the usernames of the user's in that group, then the value of this property 
-    *  would be <b>(memberUid={1})</b> </p> 
-    **/
-   private String roleAttributesSearchFilter;
-
-   /** Contexts to search for role's (which point to the user id).
-    *  <p>Example, if you have a Groups object containing Groups of users then 
-    *  the expression: <b>ou=Groups,dc=mycompany,dc=com</b> might be used;
-    *  alternatively, if rootContext="dc=mycompany,dc=com" then simply use "ou=Groups" here.
-    **/
-   private String[] roleContexts; 
-   
-   /** Attribute(s) of any role object returned from the roleContexts to use as role-names. 
-    *  <b>Warning: </b> if you do role lookups using the roleContexts and 
-    *  roleAttributesSearchFilter then you need to set roleNameAttributes or ALL attributes 
-    *  will be returned.
-    *  
-    **/
-   private String[] roleNameAttributes;  
-   
-   /** Prefix to be associated with any roles found for a user,
-    *  defaults to an empty string.  
-    *  Older versions of this class used "ROLE_" for this value. */
-   private String rolePrefix = "";
-   
-   /** Suffix to be associated with any roles found for a user,
-    *  defaults to an empty string. */
-   private String roleSuffix = "";
-
-   /** Root context of the LDAP Connection, if any is needed.  
-    *  <p> Example: <b>dc=mycompany,dc=com</b> </p> 
-    *  <p><strong>Note: </strong> It is usually preferable to add this data as part of the 
-    *      userContexts and/or roleContexts attributes. </p> 
-    **/
-   private String rootContext = "";
-   
-   /** If true then all role name values returned from the directory 
-    *  will be converted to uppercase.
-    */
-   private boolean upperCaseRoleNames = false;
-   
-   /**
-    * LDAP URL (without the port) of the LDAP server to connect to; example
-    * <b>ldap://dir.mycompany.com:389/</b>  (port 389 is the standard LDAP port).
-    */
-   private String url;
-   
-   /** One or more LDAP Contexts which contain user account information, use the 
-    *  MessageFormat key {0} to denote location where the user's username should 
-    *  be inserted into the expression to create a DistiguishedName.
-    *  <p>Example: <p>cn={0},ou=Users,dc=mycompnay,dc=com</b> </p>
-    *  <p>Alternatively, if you had set rootContext="dc=mycompany,dc=com" then 
-    *    the first example would be rewritten as <b>cn={0},ou=Users</b>. </p>
-    **/ 
-   private MessageFormat[] userContexts; 
-
-   /** Name(s) of the attribute(s) for a user account object 
-    *  contaning role names assigned to the user.  Leave unset if there are none.
-    *  Consult your LDAP server administrator to determine these value(s).
-    *  
-    **/
-   private String[] userRolesAttributes;
-   
-   /** 
-    * 
-    * @param results Result of searching on of the roleContexts for matches against the current user.
-    * @param roles List of roles the user has already been assigned.
-    * @throws NamingException 
-    */
-   protected void addAnyRolesFound(NamingEnumeration results, Collection roles) throws NamingException {
-       while (results.hasMore()) {
-           SearchResult result = (SearchResult)results.next();
-           Attributes attrs = result.getAttributes();
-           if (attrs == null) {
-               continue;
-           }
-           // Here we loop over the attributes returned in the SearchResult 
-           // TODO replace with Utility method call:
-           NamingEnumeration e = attrs.getAll();
-           while (e.hasMore()) {
-               Attribute a = (Attribute)e.next();
-               for (int i = 0; i < a.size(); i++) {
-                   roles.add( (String)a.get(i) );
-               }
-           }
-       }
-   }
-
-   /**
-    * @return Returns the defaultRole.
-    */
-   public String getDefaultRole() {
-       return defaultRole;
-   }
-
-   /**
-    * Get an array <code>GrantedAuthorities</code> given the list of roles
-    * obtained from the LDAP context. Delegates to
-    * <code>getGrantedAuthority(String ldapRole)</code>. This function may
-    * be overridden in a subclass.
-    * 
-    * @param ldapRoles
-    *            DOCUMENT ME!
-    * 
-    * @return DOCUMENT ME!
-    */
-   protected GrantedAuthority[] getGrantedAuthorities(String[] ldapRoles) {
-       GrantedAuthority[] grantedAuthorities = new GrantedAuthority[ldapRoles.length];
-
-       for (int i = 0; i < ldapRoles.length; i++) {
-           grantedAuthorities[i] = getGrantedAuthority(ldapRoles[i]);
-       }
-
-       return grantedAuthorities;
-   }
-
-   /**
-    * Get a <code>GrantedAuthority</code> given a role obtained from the LDAP
-    * context. If found in the LDAP role, the following characters are
-    * converted to underscore: ',' (comma), '=' (equals), ' ' (space) This
-    * function may be overridden in a subclass.
-    * 
-    * @param ldapRole
-    *            DOCUMENT ME!
-    * 
-    * @return DOCUMENT ME!
-    */
-   protected GrantedAuthority getGrantedAuthority(String ldapRole) {
-       String roleName = rolePrefix + ldapRole.toUpperCase() + roleSuffix;
-       if (upperCaseRoleNames) {
-           roleName = roleName.toUpperCase();
-       }
-       GrantedAuthority ga = new GrantedAuthorityImpl( roleName.replaceAll("[,=\\s]", "_") );
-
-       if (log.isDebugEnabled()) {
-           log.debug("GrantedAuthority: " + ga);
-       }
-
-       return ga;
-   }
-   /*
-   public void testGetGrantedAuthorityString() {
-         LdapPasswordAuthenticationDao uut = new LdapPasswordAuthenticationDao();
-         String[] test = {
-                 "ROLE ABC DEF", "ROLE ABC,DEF", "ROLE ABC=DEF", "ROLE ABC_DEF",
-                 "ROLE,ABC DEF", "ROLE,ABC,DEF", "ROLE,ABC=DEF", "ROLE,ABC_DEF",
-                 "ROLE=ABC DEF", "ROLE=ABC,DEF", "ROLE=ABC=DEF", "ROLE=ABC_DEF",
-                 "ROLE_ABC DEF", "ROLE_ABC,DEF", "ROLE_ABC=DEF", "ROLE_ABC_DEF",
-             };
-         final String expected = "ROLE_ABC_DEF";
- 
-         for (int i = 0; i < test.length; i++) {
-             assertEquals("Unexpected granted authority name.", expected,
-                 uut.getGrantedAuthority(test[i]).getAuthority());
-         }
-     }
-    */
-   
-   /**
-    * @return The InitialContextFactory for creating the root JNDI context; defaults to "com.sun.jndi.ldap.LdapCtxFactory"
-    */
-   public String getInitialContextFactory() {
-       return initialContextFactory;
-   }
-   
-   // ~ Methods
-   // ================================================================
-   
-   /** 
-    * Given a password, construct the Hashtable of JNDI values for a bind attempt.
-    */
-   protected Hashtable getJdniEnvironment(String password) {
-       Hashtable env = new Hashtable(11);
-       env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
-       env.put(Context.PROVIDER_URL, getProviderURL());
-       env.put(Context.SECURITY_AUTHENTICATION, authenticationType);
-       env.put(Context.SECURITY_CREDENTIALS, password);
-       return env;
-   }
-   
-   /** 
-    * @return The full "Provuder" URL for the LDAP source; it should look 
-    *      something like:  ldap://www.mycompany.com:389/
-    */
-   public synchronized String getProviderURL() {
-       if (null == this.providerUrl) {
-           StringBuffer providerUrl = new StringBuffer( this.url );
-           if (!this.url.endsWith("/")) {
-               providerUrl.append("/");
-           }
-           providerUrl.append(this.rootContext);
-           this.providerUrl = providerUrl.toString();
-       }
-       return this.providerUrl;
-   }
-
-   /**
-    * @return Returns the roleUserAttributes.
-    */
-   public String getRoleAttributesSearchFilter() {
-       return roleAttributesSearchFilter;
-   }
-
-   
-   /**
-    * @return Array of MessageFormat String's for Contexts that store role information for users.
-    */
-   public String[] getRoleContexts() {
-       return roleContexts;
-   }
-   
-   /**
-    * @return Returns the roleNameAttributes.
-    */
-   public String[] getRoleNameAttributes() {
-       return roleNameAttributes;
-   }
-   
-   /**
-    * @return Returns the rolePrefix.
-    */
-   public String getRolePrefix() {
-       return rolePrefix;
-   }
-   
-
-   protected Collection getRolesFromRoleSearch(UserContext userContext, String username, String[] roleAttributes) {
-       if ((null == roleContexts) || (roleContexts.length == 0)) {
-           return null;
-       }
-       String[] searchFilterVars = new String[] {userContext.userPrincipal, username};
-       
-       SearchControls controls = new SearchControls();
-       controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-       controls.setReturningAttributes(roleAttributes);
-       
-       List roles = new ArrayList();
-       for (int i = 0; i < roleContexts.length; i++) {
-           try {
-               NamingEnumeration results = userContext.dirContext.search(
-                       roleContexts[i], roleAttributesSearchFilter, searchFilterVars, controls);
-               addAnyRolesFound(results, roles);
-           } catch (NamingException e) {
-               if (log.isInfoEnabled()) { 
-                   log.info("Unable to find user-role match in context = " + roleContexts[i], e);
-               }
-           }
-       }
-       return roles;
-   }
-
-   /**
-    * Looksup any roleAttributes associated with the user's DN within the DirContext.
-    * 
-    * @param userContext
-    *            UserContext Object containing DirContext in which to operate, and the user's DistinguishedName.
-    * @param roleAttributes
-    *            Names of all attributes to search for role name information.
-    * @return Collection of roles granted to the user within the JNDI Context.
-    * @throws NamingException
-    */
-   protected Collection getRolesFromUserContext(UserContext userContext, String[] roleAttributes)
-           throws NamingException {
-       List roles = new ArrayList();
-       if (roleAttributes != null) {
-           if (log.isDebugEnabled()) {
-               StringBuffer rolesString = new StringBuffer();
-   
-               for (int i = 0; i < roleAttributes.length; i++) {
-                   rolesString.append(", ");
-                   rolesString.append(roleAttributes[i]);
-               }
-   
-               log.debug("Searching user context '" + userContext.userPrincipal + "' for roles "
-                       + "attributes: " + rolesString.substring(1));
-           }
-           Attributes attrs = userContext.dirContext.getAttributes(userContext.userPrincipal, roleAttributes);
-           NamingEnumeration roleEnum = attrs.getAll();
-           while (roleEnum.hasMore()) {
-               Attribute roleAttr = (Attribute)roleEnum.next();
-               for (int i = 0; i < roleAttr.size(); i++) {
-                   roles.add( roleAttr.get(i) );
-               }
-           }
-       }
-       return roles;
-   }
-   
-   /**
-    * @return Returns the roleSuffix.
-    */
-   public String getRoleSuffix() {
-       return roleSuffix;
-   }
-
-   /**
-    * @return Returns the rootContext which to connect to; 
-    *  typically it could look something like: dc=mycompany,dc=com.
-    */
-   public String getRootContext() {
-       return rootContext;
-   }
-   
-   /**
-    * @return The LDAP URL to conntect to; example: ldap://ldap.mycompany.com:389/ 
-    */
-   public String getURL() {
-       return url;
-   }
-   
-   /** Attempts to bind to the userContexts; returning on the first successful bind; 
-    *  or failing with a BadCredentialsException.
-    * @param username
-    * @param password
-    * @return UserContext, an innerclass holding the DirContext, and the user's LDAP Principal String.
-    * @throws NamingException
-    * @throws BadCredentialsException
-    */
-   protected UserContext getUserContext(String username, String password) throws NamingException, BadCredentialsException {
-       Hashtable env = getJdniEnvironment(password);
-       UserContext userContext = new UserContext();
-       for (int i = 0; i < userContexts.length; i++) {
-           env.remove(Context.SECURITY_PRINCIPAL);
-           userContext.userPrincipal = userContexts[i].format(new String[]{username});
-           env.put(Context.SECURITY_PRINCIPAL, userContext.userPrincipal);
-           try {
-               userContext.dirContext = new InitialDirContext(env);
-               if (userContext.dirContext != null) {
-                   return userContext;
-               }
-           } catch (AuthenticationException ax) {
-               if (log.isInfoEnabled()) {
-                   log.info("Authentication exception for user.", ax);
-               }
-           }
-       }
-       throw new BadCredentialsException(BAD_CREDENTIALS_EXCEPTION_MESSAGE);
-   }
-   
-
-   /**
-    * @return Returns the userContexts.
-    */
-   public String[] getUserContexts() {
-       String[] formats = new String[userContexts.length];
-       for (int i = 0; i < userContexts.length; i++) {
-           formats[i] = userContexts[i].toPattern();
-       }
-       return formats;
-   }
-
-   /**
-    * @return Returns the userRolesAttributes.
-    */
-   public String[] getUserRolesAttributes() {
-       return userRolesAttributes;
-   }
-
-   /**
-    * @FIXME When using a search (see getRolesFromContext()) I don't think this
-    *        extra check is needed; JNDI should be responible for returning
-    *        only the attributes requested (or maybe I don't understand JNDI
-    *        well enough).
-    * 
-    * @param Name/Id
-    *            of the JNDI Attribute.
-    * 
-    * @return Return true if the given name is a role attribute.
-    */
-   protected boolean isRoleAttribute(String name) {
-       log.info("Checking rolename: " + name);
-       if (name != null) {
-           for (int i = 0; i < userRolesAttributes.length; i++) {
-               if (name.equals(userRolesAttributes[i])) {
-                   return true;
-               }
-           }
-       }
-       return false;
-   }
-   
-   /**
-    * @return Returns the upperCaseRoleNames.
-    */
-   public boolean isUpperCaseRoleNames() {
-       return upperCaseRoleNames;
-   }
-   
-   
-
-   public UserDetails loadUserByUsernameAndPassword(String username,
-           String password) throws DataAccessException,
-           BadCredentialsException {
-       if ((password == null) || (password.length() == 0)) {
-           throw new BadCredentialsException("Empty password");
-       }
-
-       try {
-           if (log.isDebugEnabled()) {
-               log.debug("Connecting to " + getProviderURL() + " as " + username);
-           }
-
-           UserContext userContext = getUserContext(username, password);
-
-           Collection roles = getRolesFromUserContext(userContext, getUserRolesAttributes());
-           Collection roles2 = getRolesFromRoleSearch(userContext, username, getRoleNameAttributes());
-           if (null != roles2) {
-               roles.addAll(roles2);
-           }           
-           
-           userContext.dirContext.close();
-
-           
-           if (roles.isEmpty()) {
-               if (null == defaultRole) {
-                   throw new BadCredentialsException("The user has no granted "
-                       + "authorities or the rolesAttribute is invalid");
-               } else {
-                   roles.add(defaultRole);
-               }
-           }
-
-           String[] ldapRoles = (String[]) roles.toArray(new String[] {});
-           
-           return new User(username, password, true, true, true, true,
-                   getGrantedAuthorities(ldapRoles));
-       } catch (AuthenticationException ex) {
-           throw new BadCredentialsException(
-                   BAD_CREDENTIALS_EXCEPTION_MESSAGE, ex);
-       } catch (CommunicationException ex) {
-           throw new DataAccessResourceFailureException(ex.getRootCause()
-                   .getMessage(), ex);
-       } catch (NamingException ex) {
-           throw new DataAccessResourceFailureException(ex.getMessage(), ex);
-       }
-   }
-   
-   /** If set to a non-null value, and a user can be bound to a LDAP Conext, 
-    *  but no role information is found then this role is automatically added. 
-    *  If null (the default) then a BadCredentialsException is thrown
-    *  
-    *  <p>For example; if you have an LDAP directory with no role information 
-    *  stored, you might simply want to give any user who can login a role of "USER".</p>
-    *  
-    * @param defaultRole The defaultRole to set.
-    */
-   public void setDefaultRole(String defaultRole) {
-       this.defaultRole = defaultRole;
-   }
-
-   /** The INITIAL_CONTEXT_FACTORY used to create the JNDI Factory.
-    *  Default is "com.sun.jndi.ldap.LdapCtxFactory"; you <b>should not</b>
-    *  need to set this unless you have unusual needs.
-    *  
-    * @param initialContextFactory The InitialContextFactory for creating the root JNDI context;
-    *  defaults to "com.sun.jndi.ldap.LdapCtxFactory"
-    */
-   public void setInitialContextFactory(String initialContextFactory) {
-       this.initialContextFactory = initialContextFactory;
-   }
-
-   /** Name(s) of the attribute(s) for a user account object 
-    *  contaning role names assigned to the user.  Leave unset if there are none.
-    *  Consult your LDAP server administrator to determine these value(s).
-    *  
-    * @param roleUserAttributes
-    *            The roleUserAttributes to set.
-    */
-   public void setRoleAttributesSearchFilter(String roleAttributesSearchArgs) {
-       this.roleAttributesSearchFilter = roleAttributesSearchArgs;
-   }
-   
-   /** Shortcut for setRoleContexts( new String[]{roleContext} );  */
-   public void setRoleContext(String roleContext) {
-       setRoleContexts( new String[]{roleContext} );
-   }
-
-   /** Contexts to search for role's (which point to the user id).
-    *  <p>Example, if you have a Groups object containing Groups of users then 
-    *  the expression: <b>ou=Groups,dc=mycompany,dc=com</b> might be used;
-    *  alternatively, if rootContext="dc=mycompany,dc=com" then simply use "ou=Groups" here.
-    *  
-    * @param roleContexts Array of MessageFormat String's for Contexts that store role information for users.
-    */
-   public void setRoleContexts(String[] roleContexts) {
-       this.roleContexts = roleContexts;
-   }
-   
-   /** Used to build LDAP Search Filter for finding roles (in the roleContexts) 
-    *  pointing to a user.  Uses MessageFormat like tokens; {0} is the 
-    *  user's DistiguishedName, {1} is the user's username. 
-    *  For more information on syntax see  
-    *  javax.naming.directory.DirContext.search(), or RFC 2254. 
-    *  
-    *  <p>Example: if each group has an attribute 'memberUid' with values being 
-    *  the usernames of the user's in that group, then the value of this property 
-    *  would be <b>(memberUid={1})</b> </p> 
-    *  
-    * @param roleNameAttributes The roleNameAttributes to set.
-    */
-   public void setRoleNameAttribute(String roleNameAttribute) {
-       setRoleNameAttributes( new String[] {roleNameAttribute} );
-   }
-   
-   /** Attribute(s) of any role object returned from the roleContexts to use as role-names. 
-    *  <b>Warning: </b> if you do role lookups using the roleContexts and 
-    *  roleAttributesSearchFilter then you need to set roleNameAttributes or ALL attributes 
-    *  will be returned.
-    *  
-    * @param roleNameAttributes The roleNameAttributes to set.
-    */
-   public void setRoleNameAttributes(String[] roleNameAttributes) {
-       this.roleNameAttributes = roleNameAttributes;
-   }
-   
-   /** Prefix to be associated with any roles found for a user,
-    *  defaults to an empty string.  
-    *  Older versions of this class used "ROLE_" for this value. 
-    *  
-    * @param rolePrefix The rolePrefix to set.
-    */
-   public void setRolePrefix(String rolePrefix) {
-       this.rolePrefix = rolePrefix;
-   }
-   
-   /** Suffix to be associated with any roles found for a user,
-    *  defaults to an empty string.
-    *  
-    * @param roleSuffix The roleSuffix to set.
-    */
-   public void setRoleSuffix(String roleSuffix) {
-       this.roleSuffix = roleSuffix;
-   }
-   
-   /** Root context of the LDAP Connection, if any is needed.  
-    *  <p> Example: <b>dc=mycompany,dc=com</b> </p> 
-    *  <p><strong>Note: </strong> It is usually preferable to add this data as part of the 
-    *     userContexts and/or roleContexts attributes. </p> 
-    *
-    * @param rootContext The rootContext which to connect to; 
-    *  typically it could look something like: dc=mycompany,dc=com.
-    */
-   public void setRootContext(String rootContext) {
-       this.rootContext = rootContext;
-   }
-   
-   /** If true then all role name values returned from the directory 
-    *  will be converted to uppercase.
-    *  
-    * @param upperCaseRoleNames The upperCaseRoleNames to set.
-    */
-   public void setUpperCaseRoleNames(boolean upperCaseRoleNames) {
-       this.upperCaseRoleNames = upperCaseRoleNames;
-   }
-
-   /**
-    * @param host The LDAP URL to conntect to; example: ldap://ldap.mycompany.com:389/ 
-    */
-   public void setURL(String url) {
-       this.url = url;
-   }
-   
-   /** Shortcut for setUserContexts( new String[]{userContext} );  */
-   public void setUserContext(String userContext) {
-       setUserContexts( new String[]{userContext} );
-   }
-
-   /** One or more LDAP Contexts which contain user account information, use the 
-    *  MessageFormat key {0} to denote location where the user's username should 
-    *  be inserted into the expression to create a DistiguishedName.
-    *  <p>Example: <p>cn={0},ou=Users,dc=mycompnay,dc=com</b> </p>
-    *  <p>Alternatively, if you had set rootContext="dc=mycompany,dc=com" then 
-    *    the first example would be rewritten as <b>cn={0},ou=Users</b>. </p>
-    *    
-    * @param userContexts
-    *            The userContexts to set.
-    */
-   public void setUserContexts(String[] userContexts) {
-       this.userContexts = new MessageFormat[userContexts.length];
-       for (int i = 0; i < userContexts.length; i++) {
-           this.userContexts[i] = new MessageFormat(userContexts[i]);
-       }
-   }
-   
-   /** Shortcut for setUserRolesAttributes(new String[]{userRolesAttribute}); */
-   public void setUserRolesAttribute(String userRolesAttribute) {
-       this.userRolesAttributes = new String[]{userRolesAttribute};
-   }
-
-   /** Attribute(s) of any role object returned from the roleContexts to use as role-names. 
-    *  <b>Warning: </b> if you do role lookups using the roleContexts and 
-    *  roleAttributesSearchFilter then you need to set roleNameAttributes or ALL attributes 
-    *  will be returned.
-    *  
-    * @param userRolesAttributes
-    *            The userRolesAttributes to set.
-    */
-   public void setUserRolesAttributes(String[] userRolesAttributes) {
-       this.userRolesAttributes = userRolesAttributes;
-   }
+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;
+import net.sf.acegisecurity.providers.dao.User;
 
+/** 
+ * A much simplified (vs the 1.6 revision) LdapPasswordAuthenticationDao, 
+ * which should meet all 'basic' needs, leaving advanced options such as 
+ * multiple user and/or role contexts.  This version assumes all users 
+ * are in one context, and roles are assigned via attributes of the user's 
+ * directory object.  Authentication is done by creating a username for 
+ * <br/><br/>
+ * 
+ * <h4>Examples:</h4>
+ * <p>The following examples would be linked into the main Acegi 
+ *    configuration by: <br/>
+ *    <bean id="passwordAuthenticationProvider" 
+ *       class="net.sf.acegisecurity.providers.dao.PasswordDaoAuthenticationProvider">   <br/>
+ *       <property name="passwordAuthenticationDao">                                     <br/>
+ *         <ref bean="passwordAuthenticationDao"/>                                       <br/>
+ *       </property>                                                                     <br/>
+ *    </bean>                                                                            <br/>
+ * </p>
+ * 
+ * <h5 title="as seen in the Unit tests">'Standard' LDAP Settings</h5>
+ * <p>
+ *   <bean id="passwordAuthenticationDao"
+ *       class="net.sf.acegisecurity.providers.dao.ldap.LdapPasswordAuthenticationDao">      <br/>
+ *       <property name="url"><value>ldap://localhost:389/ou=system</value></property>      <br/>
+ *       <property name="usernameFormat"><value>uid={0},ou=users,ou=system</value></property>      <br/>
+ *       <property name="userLookupNameFormat"><value>uid={0},ou=users</value></property>      <br/>
+ *   </bean>      <br/>
+ * </p>
+ * 
+ * <h5>Active Directory Configuration</h5>
+ * <p>
+ * 	I haven't been able to test this directly, 
+ *  but something like the following should do the trick:     <br/>
+ *   <bean id="passwordAuthenticationDao"
+ *       class="net.sf.acegisecurity.providers.dao.ldap.LdapPasswordAuthenticationDao">      <br/>
+ *       <property name="url"><value>ldap://localhost:389/ou=system</value></property>      <br/>
+ *       <property name="usernameFormat"><value>{0}@adDomainName</value></property>      <br/>
+ *   </bean>      <br/>
+ *   (if anyone gets this to work please let me know so I can include it 
+ *   in the documentation).
+ * </p>
+ * 
+ * 
+ * @author Karel Miarka
+ * @author Daniel Miller
+ * @author Robert Sanders
+ */
+public class LdapPasswordAuthenticationDao extends InitialDirContextFactoryBean implements PasswordAuthenticationDao {
+
+	private static final Log logger = LogFactory.getLog(LdapPasswordAuthenticationDao.class);
+
+	public static final String BAD_CREDENTIALS_EXCEPTION_MESSAGE = "Invalid username, password or server configuration (JNDI Context).";
+	
+	/** Pattern used to turn the user's supplied username into the 
+	 *  username format the LDAP server expects.  {0} is the username.
+	 *  
+	 *  <p>
+	 *  Examples: <br/>
+	 *  'Normal' LDAP: "cn={0}" <br/>
+	 *  Active Directory style LDAP: "{0}@AD_Domain"
+	 *  </p>
+	 */
+	private MessageFormat usernameFormat = new MessageFormat("cn={0}");
+	
+	/** Message format used to create the Name within the LDAP Context 
+	 *  from which role information will be retrieved.
+	 *  {0} is the username
+	 *  {1} is the result of usernameFormat.format(new Object[] {username})
+	 *  
+	 *  <p>Example: "uid={0},ou=users"</p>
+	 * 
+	 */
+	private MessageFormat userLookupNameFormat = null;
+
+	/** List of LDAP Attributes which contian role name information. */
+	private String[] roleAttributes = {"memberOf"};
+	
+	/** The role, which if non-null, will be grated the user if the user has no other roles. */
+	private String defaultRole = null;
+	
+	public UserDetails loadUserByUsernameAndPassword(String username, String password) throws DataAccessException, BadCredentialsException {
+		if ((password == null) || (password.length() == 0)) {
+            throw new BadCredentialsException("Empty password");
+        }
+		
+		String ldapUsername = (null == usernameFormat) ? username : usernameFormat.format( new Object[]{username} );
+		if (logger.isDebugEnabled()) {
+			logger.debug("Connecting to " + this.getUrl() + " as " + ldapUsername);
+		}
+		
+	    InitialDirContext dirContext = null;
+		try {
+			dirContext = newInitialDirContext(ldapUsername, password);
+		} catch (AuthenticationException ax) {
+			throw new BadCredentialsException(BAD_CREDENTIALS_EXCEPTION_MESSAGE, ax);
+		}
+		if (null == dirContext) {
+			throw new BadCredentialsException(BAD_CREDENTIALS_EXCEPTION_MESSAGE);
+		}
+		 
+	    String[] roles = null;
+	    if (null != roleAttributes) {
+	    	try {
+	    		String userContextName = (null == userLookupNameFormat) ? "" : 
+	    			userLookupNameFormat.format(new Object[]{username, ldapUsername});
+				roles = getRolesFromContext(dirContext, userContextName);
+			} catch (NamingException e) {
+				throw new DataAccessResourceFailureException("Unable to retrieve role information from LDAP Server.", e);
+			}
+	    }
+	    if ((null == roles) && (null != defaultRole)) {
+	    	roles = new String[] {defaultRole};
+	    }
+	    
+	    return new User(username, password, true, true, true, true, toGrantedAuthority(roles) );
+	}
+	
+	/** Converts from an Array of String rolenames to an array of GrantedAuthority objects.
+	 *  This is a possible extension point for sub-classes to enrich the behavior of how 
+	 *  the GrantedAuthority array is constucted.
+	 *  
+	 * @param rolenames Array of Strings representing the names of the 
+	 * 		roles that the user has been granted according to the LDAP server.
+	 * @return Array of GrantedAuthority objects which will be associated with the User's UserDetails.
+	 */ 
+	protected GrantedAuthority[] toGrantedAuthority(String[] rolenames) {
+		if ((null == rolenames) || (rolenames.length == 0)) {
+			return null;
+		}
+		
+		GrantedAuthority[] grantedAuthorities = new GrantedAuthority[rolenames.length];
+		for (int i = 0; i < rolenames.length; i++) {
+	       grantedAuthorities[i] = toGrantedAuthority(rolenames[i]);
+        }
+
+	   return grantedAuthorities;
+	}
+	
+	/** This is a possible extension point for sub-classes to enrich the behavior of how 
+	 *  the GrantedAuthority object is constucted.
+	 * 
+	 * @param rolename Name of an LDAP role which is granted to the user.
+	 * @return GrantedAuthority object which represents the granted role.
+	 */
+	protected GrantedAuthority toGrantedAuthority(String rolename) {
+		GrantedAuthority ga = new GrantedAuthorityImpl( rolename );
+		return ga;
+	}
+	
+	/** 
+	 * 
+	 * @param ctx The LDAP DirContext retrieved by the user login.
+	 * @return An array of roles granted the user found by searching all attributes named in the roleAttributes field.
+	 * @throws NamingException 
+	 */
+	protected String[] getRolesFromContext(DirContext ctx, String dnOfUser) throws NamingException {
+		if (null == roleAttributes) {
+			return null;
+		}
+		
+	    if (logger.isDebugEnabled()) {
+	        String rolesString = "";
+
+            for (int i = 0; i < roleAttributes.length; i++) {
+                rolesString += (", " + roleAttributes[i]);
+            }
+
+            logger.debug("Searching ldap context for roles using attributes: " + rolesString.substring(1));
+	    }
+	    
+	    ArrayList roles = new ArrayList();
+	    Attributes attrs = null;
+	    if (null == usernameFormat) {
+	    	attrs = ctx.getAttributes("", roleAttributes);
+	    } else {
+	    	attrs = ctx.getAttributes(dnOfUser, roleAttributes);
+	    }
+	    
+	    if (null != attrs) {
+	    	NamingEnumeration attrsEnum = attrs.getAll();
+	    	while ((attrsEnum != null) && (attrsEnum.hasMore())) {
+	    		Attribute attr = (Attribute)attrsEnum.next();
+	    		if (null != attr) {
+		    		ArrayList list = getRolesFromAttribute( attr );
+		    		if (null != list) {
+		    			roles.addAll( list );
+		    		}
+	    		}
+	    	}
+	    }
+	    
+	    if (roles.isEmpty()) {
+	    	return null;
+	    } else {
+	    	return (String[])roles.toArray( new String[roles.size()] );
+	    }
+	}
+	
+	protected ArrayList getRolesFromAttribute(Attribute attr) throws NamingException {
+		NamingEnumeration rolesEnum = attr.getAll();
+		if (null == rolesEnum) {
+			return null;
+		}
+		
+		ArrayList roles = new ArrayList();
+		while (rolesEnum.hasMore()) {
+			String rolename = (String)rolesEnum.next();
+			if (null != rolename) {
+				roles.add( convertLdapRolename(rolename) );
+			}
+		}
+		return roles;
+	}
+	
+	protected String convertLdapRolename(String name) {
+		//System.out.println("Found LDAP UserRole = " + name);
+		return name.toUpperCase();
+	}
+
+	public String getDefaultRole() {
+		return defaultRole;
+	}
+
+	public void setDefaultRole(String defaultRole) {
+		this.defaultRole = defaultRole;
+	}
+
+	public String[] getRoleAttributes() {
+		return roleAttributes;
+	}
+
+	/** List of LDAP Attributes which contian role name information. */
+	public void setRoleAttributes(String[] roleAttributes) {
+		this.roleAttributes = roleAttributes;
+	}
+	
+	/** Utility method to set a single attribute which contains role information.
+	 *  @see setRoleAttributes
+	 */
+	public void setRoleAttribute(String roleAttribute) {
+		setRoleAttributes(new String[]{ roleAttribute });
+	}
+
+	public String getUsernameFormat() {
+		if (null == usernameFormat) {
+			return null;
+		} else {
+			return usernameFormat.toPattern();
+		}
+	}
+	
+	/** Pattern used to turn the user's supplied username into the 
+	 *  username format the LDAP server expects.
+	 *  
+	 *  <p>
+	 *  Examples: <br/>
+	 *  'Normal' LDAP: "cn={0}" <br/>
+	 *  Active Directory style LDAP: "{0}@AD_Domain"
+	 *  </p>
+	 */
+	public void setUsernameFormat(String usernameFormat) {
+		if (null == usernameFormat) {
+			this.usernameFormat = null;
+		} else {
+			this.usernameFormat = new MessageFormat(usernameFormat);
+		}
+	}
+	
+
+	public String getUserLookupNameFormat() {
+		if (null == userLookupNameFormat) {
+			return null;
+		} else {
+			return userLookupNameFormat.toPattern();
+		}
+	}
+
+	public void setUserLookupNameFormat(String userLookupNameFormat) {
+		if (null == userLookupNameFormat) {
+			this.userLookupNameFormat = null;
+		} else {
+			this.userLookupNameFormat = new MessageFormat(userLookupNameFormat);
+		}
+	}
 }