/*
* Copyright 2004, 2005, 2006 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 org.springframework.security.ldap.userdetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.naming.Name;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.ldap.ppolicy.PasswordPolicyData;
import org.springframework.util.Assert;
/**
* 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>
* An instance of this class will be used by the <tt>LdapAuthenticationProvider</tt> to
* construct the final user details object that it returns.
* <p>
* The {@code equals} and {@code hashcode} methods are implemented using the {@code Dn}
* property and do not consider additional state, so it is not possible two store two
* instances with the same DN in the same set, or use them as keys in a map.
*
* @author Luke Taylor
*/
public class LdapUserDetailsImpl implements LdapUserDetails, PasswordPolicyData {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
// ~ Instance fields
// ================================================================================================
private String dn;
private String password;
private String username;
private Collection<GrantedAuthority> authorities = AuthorityUtils.NO_AUTHORITIES;
private boolean accountNonExpired = true;
private boolean accountNonLocked = true;
private boolean credentialsNonExpired = true;
private boolean enabled = true;
// PPolicy data
private int timeBeforeExpiration = Integer.MAX_VALUE;
private int graceLoginsRemaining = Integer.MAX_VALUE;
// ~ Constructors
// ===================================================================================================
protected LdapUserDetailsImpl() {
}
// ~ Methods
// ========================================================================================================
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
public String getDn() {
return dn;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public boolean isAccountNonExpired() {
return accountNonExpired;
}
public boolean isAccountNonLocked() {
return accountNonLocked;
}
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
public boolean isEnabled() {
return enabled;
}
@Override
public void eraseCredentials() {
password = null;
}
public int getTimeBeforeExpiration() {
return timeBeforeExpiration;
}
public int getGraceLoginsRemaining() {
return graceLoginsRemaining;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof LdapUserDetailsImpl) {
return dn.equals(((LdapUserDetailsImpl) obj).dn);
}
return false;
}
@Override
public int hashCode() {
return dn.hashCode();
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString()).append(": ");
sb.append("Dn: ").append(dn).append("; ");
sb.append("Username: ").append(this.username).append("; ");
sb.append("Password: [PROTECTED]; ");
sb.append("Enabled: ").append(this.enabled).append("; ");
sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
sb.append("CredentialsNonExpired: ").append(this.credentialsNonExpired)
.append("; ");
sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");
if (this.getAuthorities() != null && !this.getAuthorities().isEmpty()) {
sb.append("Granted Authorities: ");
boolean first = true;
for (Object authority : this.getAuthorities()) {
if (first) {
first = false;
}
else {
sb.append(", ");
}
sb.append(authority.toString());
}
}
else {
sb.append("Not granted any authorities");
}
return sb.toString();
}
// ~ Inner Classes
// ==================================================================================================
/**
* Variation of essence pattern. Used to create mutable intermediate object
*/
public static class Essence {
protected LdapUserDetailsImpl instance = createTarget();
private List<GrantedAuthority> mutableAuthorities = new ArrayList<GrantedAuthority>();
public Essence() {
}
public Essence(DirContextOperations ctx) {
setDn(ctx.getDn());
}
public Essence(LdapUserDetails copyMe) {
setDn(copyMe.getDn());
setUsername(copyMe.getUsername());
setPassword(copyMe.getPassword());
setEnabled(copyMe.isEnabled());
setAccountNonExpired(copyMe.isAccountNonExpired());
setCredentialsNonExpired(copyMe.isCredentialsNonExpired());
setAccountNonLocked(copyMe.isAccountNonLocked());
setAuthorities(copyMe.getAuthorities());
}
protected LdapUserDetailsImpl createTarget() {
return new LdapUserDetailsImpl();
}
/**
* Adds the authority to the list, unless it is already there, in which case it is
* ignored
*/
public void addAuthority(GrantedAuthority a) {
if (!hasAuthority(a)) {
mutableAuthorities.add(a);
}
}
private boolean hasAuthority(GrantedAuthority a) {
for (GrantedAuthority authority : mutableAuthorities) {
if (authority.equals(a)) {
return true;
}
}
return false;
}
public LdapUserDetails createUserDetails() {
Assert.notNull(instance,
"Essence can only be used to create a single instance");
Assert.notNull(instance.username, "username must not be null");
Assert.notNull(instance.getDn(), "Distinguished name must not be null");
instance.authorities = Collections.unmodifiableList(mutableAuthorities);
LdapUserDetails newInstance = instance;
instance = null;
return newInstance;
}
public Collection<GrantedAuthority> getGrantedAuthorities() {
return mutableAuthorities;
}
public void setAccountNonExpired(boolean accountNonExpired) {
instance.accountNonExpired = accountNonExpired;
}
public void setAccountNonLocked(boolean accountNonLocked) {
instance.accountNonLocked = accountNonLocked;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
mutableAuthorities = new ArrayList<GrantedAuthority>();
mutableAuthorities.addAll(authorities);
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
instance.credentialsNonExpired = credentialsNonExpired;
}
public void setDn(String dn) {
instance.dn = dn;
}
public void setDn(Name dn) {
instance.dn = dn.toString();
}
public void setEnabled(boolean enabled) {
instance.enabled = enabled;
}
public void setPassword(String password) {
instance.password = password;
}
public void setUsername(String username) {
instance.username = username;
}
public void setTimeBeforeExpiration(int timeBeforeExpiration) {
instance.timeBeforeExpiration = timeBeforeExpiration;
}
public void setGraceLoginsRemaining(int graceLoginsRemaining) {
instance.graceLoginsRemaining = graceLoginsRemaining;
}
}
}