/* * 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; } } }