Introduce LDAPUserDetails.

This commit is contained in:
Luke Taylor 2006-05-15 19:34:57 +00:00
parent fd1ed6bcdd
commit db042046e9
3 changed files with 295 additions and 0 deletions

View File

@ -0,0 +1,30 @@
package org.acegisecurity.userdetails.ldap;
import org.acegisecurity.userdetails.UserDetails;
import javax.naming.directory.Attributes;
import javax.naming.ldap.Control;
/**
* @author Luke Taylor
* @version $Id$
*/
public interface LdapUserDetails extends UserDetails {
/**
* @return the DN of the entry for this user's account.
*/
String getDn();
/**
* @return the attributes for the user's entry in the directory (or a subset of them,
* depending on what was retrieved).
*/
Attributes getAttributes();
/**
* Returns any LDAP response controls (as part of a user authentication process, for example).
*
* @return an array of LDAP Control instances, never null
*/
Control[] getControls();
}

View File

@ -0,0 +1,183 @@
package org.acegisecurity.userdetails.ldap;
import org.acegisecurity.GrantedAuthority;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.ldap.Control;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
/**
* A UserDetails implementation which is used internally by the Ldap services.
*
* It also contains the user's distinguished name and a set of attributes that
* have been retrieved from the Ldap server.
* <p>
* An instance may be created as the result of a search, or when user information
* is retrieved during authentication.
* </p>
* <p>
* An instance of this class will be used by the <tt>LdapAuthenticationProvider</tt>
* to construct the final user details object that it returns.
* </p>
*
* @author Luke Taylor
* @version $Id$
*/
public class LdapUserDetailsImpl implements LdapUserDetails {
private static final GrantedAuthority[] NO_AUTHORITIES = new GrantedAuthority[0];
private static final Control[] NO_CONTROLS = new Control[0];
//~ Instance fields ========================================================
private String dn;
private Attributes attributes = new BasicAttributes();
private String username;
private String password;
private boolean enabled = true;
private boolean accountNonExpired = true;
private boolean credentialsNonExpired = true;
private boolean accountNonLocked = true;
private GrantedAuthority[] authorities = NO_AUTHORITIES;
private Control[] controls = NO_CONTROLS;
//~ Constructors ===========================================================
protected LdapUserDetailsImpl() {
}
//~ Methods ================================================================
public String getDn() {
return dn;
}
public Attributes getAttributes() {
return attributes;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public boolean isEnabled() {
return enabled;
}
public boolean isAccountNonExpired() {
return accountNonExpired;
}
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
public boolean isAccountNonLocked() {
return accountNonLocked;
}
public GrantedAuthority[] getAuthorities() {
return authorities;
}
public Control[] getControls() {
return controls;
}
//~ Inner classes ==========================================================
/** Variation of essence pattern. Used to create mutable intermediate object */
public static class Essence {
LdapUserDetailsImpl instance = new LdapUserDetailsImpl();
List mutableAuthorities = new ArrayList();
public Essence() {
}
public Essence(LdapUserDetails copyMe) {
instance.dn = copyMe.getDn();
instance.attributes = copyMe.getAttributes();
instance.username = copyMe.getUsername();
instance.password = copyMe.getPassword();
instance.enabled = copyMe.isEnabled();
instance.accountNonExpired = copyMe.isAccountNonExpired();
instance.credentialsNonExpired = copyMe.isCredentialsNonExpired();
instance.accountNonLocked = copyMe.isAccountNonLocked();
instance.controls = copyMe.getControls();
mutableAuthorities = Arrays.asList(copyMe.getAuthorities());
}
public Essence setDn(String dn) {
instance.dn = dn;
return this;
}
public Essence setAttributes(Attributes attributes) {
instance.attributes = attributes;
return this;
}
public Essence setUsername(String username) {
instance.username = username;
return this;
}
public Essence setPassword(String password) {
instance.password = password;
return this;
}
public Essence setEnabled(boolean enabled) {
instance.enabled = enabled;
return this;
}
public Essence setAccountNonExpired(boolean accountNonExpired) {
instance.accountNonExpired = accountNonExpired;
return this;
}
public Essence setCredentialsNonExpired(boolean credentialsNonExpired) {
instance.credentialsNonExpired = credentialsNonExpired;
return this;
}
public Essence setAccountNonLocked(boolean accountNonLocked) {
instance.accountNonLocked = accountNonLocked;
return this;
}
public Essence setAuthorities(GrantedAuthority[] authorities) {
mutableAuthorities = Arrays.asList(authorities);
return this;
}
public Essence addAuthority(GrantedAuthority a) {
mutableAuthorities.add(a);
return this;
}
public GrantedAuthority[] getGrantedAuthorities() {
return (GrantedAuthority[])mutableAuthorities.toArray(new GrantedAuthority[0]);
}
public LdapUserDetails createUserDetails() {
//TODO: Validation of properties
instance.authorities = getGrantedAuthorities();
return instance;
}
}
}

View File

@ -0,0 +1,82 @@
package org.acegisecurity.userdetails.ldap;
import org.acegisecurity.ldap.LdapEntryMapper;
import org.acegisecurity.GrantedAuthorityImpl;
import org.springframework.util.Assert;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
/**
* @author Luke Taylor
* @version $Id$
*/
public class LdapUserDetailsMapper implements LdapEntryMapper {
private final Log logger = LogFactory.getLog(LdapUserDetailsMapper.class);
private String passwordAttributeName = "userPassword";
private String[] roleAttributes = null;
private String rolePrefix = "ROLE_";
private boolean convertToUpperCase = true;
public void setPasswordAttributeName(String passwordAttributeName) {
this.passwordAttributeName = passwordAttributeName;
}
public void setRoleAttributes(String[] roleAttributes) {
Assert.notNull(roleAttributes, "roleAttributes array cannot be null");
this.roleAttributes = roleAttributes;
}
public Object mapAttributes(String dn, Attributes attributes) throws NamingException {
LdapUserDetailsImpl.Essence essence = new LdapUserDetailsImpl.Essence();
essence.setDn(dn);
essence.setAttributes(attributes);
Attribute passwordAttribute = attributes.get(passwordAttributeName);
if(passwordAttribute != null) {
Object retrievedPassword = passwordAttribute.get();
if (!(retrievedPassword instanceof String)) {
// Assume it's binary
retrievedPassword = new String((byte[])retrievedPassword);
}
essence.setPassword((String)retrievedPassword);
}
// Map the roles
for(int i=0; roleAttributes != null && i < roleAttributes.length; i++) {
Attribute roleAttribute = attributes.get(roleAttributes[i]);
NamingEnumeration attributeRoles = roleAttribute.getAll();
while(attributeRoles.hasMore()) {
Object role = attributeRoles.next();
// We only handle Strings for the time being
if(role instanceof String) {
if(convertToUpperCase) {
role = ((String)role).toUpperCase();
}
essence.addAuthority(new GrantedAuthorityImpl(rolePrefix + role));
} else {
logger.warn("Non-String value found for role attribute " + roleAttribute.getID());
}
}
}
return essence.createUserDetails();
}
}