Removed old LDAP stuff.

This commit is contained in:
Luke Taylor 2006-05-07 17:40:51 +00:00
parent ab05cb95ff
commit fd1ed6bcdd
9 changed files with 0 additions and 1716 deletions

View File

@ -1,222 +0,0 @@
package org.acegisecurity.providers.dao.ldap;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Convient base class and/or bean which can be used to create DirContext objects.
* Many user's will only need to set to Url property.
*
* <p>
* Eample: <br/>
* <bean id="initialDirContextFactoryBean"
* class="org.acegisecurity.providers.dao.ldap.InitialDirContextFactoryBean"> <br/>
* <property name="url"><value>ldap://myserver.com:389/</value></property> <br/>
* <property name="managerUser"><value>cn=UserWithSearchPermissions,dc=mycompany,dc=com</value></property> <br/>
* <property name="managerPassword"><value>PasswordForUser</value></property> <br/>
* </bean> <br/>
* </p>
*
*
* @see http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html
*
* @author robert.sanders
*
*/
public class InitialDirContextFactoryBean {
/**
* LDAP URL (with or without the port) of the LDAP server to connect to.
* <p>Example: <br/>
* <b>ldap://dir.mycompany.com:389/dc=mycompany,dc=com</b> <br/>
* <small>(port 389 is the standard LDAP port). </small>
* </p>
*/
private String url;
/** If your LDAP server does not allow anonymous searches then
* you will need to provide a username with which to login with;
* this is that username.
*/
private String managerUser;
/** If your LDAP server does not allow anonymous searches then
* you will need to provide a username with which to login with;
* this is the password of that user.
*/
private String managerPassword;
/** Type of authentication within LDAP; default is simple. */
private String authenticationType = "simple";
/** 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";
/** Allows extra environment variables to be added at config time. */
private Map extraEnvVars = null;
/** Use the LDAP Connection pool (in SUN JVMs)?; if true, then the
* LDAP environment property "com.sun.jndi.ldap.connect.pool" is added
* to any other JNDI properties.
* @see http://java.sun.com/products/jndi/tutorial/ldap/connect/pool.html
* @see http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html
*/
private boolean connectionPoolEnabled = true;
public InitialDirContext newInitialDirContext(String username, String password) throws AuthenticationException, DataAccessResourceFailureException {
Hashtable env = getEnvironment();
if (null != username) {
env.put(Context.SECURITY_PRINCIPAL, username);
}
if (null != password) {
env.put(Context.SECURITY_CREDENTIALS, password);
}
try {
return new InitialDirContext(env);
} catch (AuthenticationException ax) {
throw ax; // just pass it right on.
} catch (NamingException nx) {
// any other JNDI exception:
throw new DataAccessResourceFailureException("Unable to connect to LDAP Server; check managerUser and managerPassword.", nx);
}
}
/** Returns a new InitialDirContext using the provided managerUser and managerPassword (if provided) as credentials.
* @throws AuthenticationException */
public InitialDirContext newInitialDirContext() throws DataAccessResourceFailureException, AuthenticationException {
return newInitialDirContext(managerUser, managerPassword);
}
/**
* @return The Hashtable describing the base DirContext that will be created; minus the username/password if any.
*/
protected Hashtable getEnvironment() {
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_AUTHENTICATION, authenticationType);
if (connectionPoolEnabled) {
env.put("com.sun.jndi.ldap.connect.pool", "true");
}
if ((extraEnvVars != null) && (extraEnvVars.size() > 0)) {
env.putAll(extraEnvVars);
}
return env;
}
/**
* @return Returns the authenticationType.
*/
public String getAuthenticationType() {
return authenticationType;
}
/**
* @param authenticationType The authenticationType to set.
*/
public void setAuthenticationType(String authenticationType) {
this.authenticationType = authenticationType;
}
/**
* @return Returns the initialContextFactory.
*/
public String getInitialContextFactory() {
return initialContextFactory;
}
/**
* @param initialContextFactory The initialContextFactory to set.
*/
public void setInitialContextFactory(String initialContextFactory) {
this.initialContextFactory = initialContextFactory;
}
/**
* @return Password (if any) of the user named by the managerUser property.
*/
public String getManagerPassword() {
return managerPassword;
}
/**
* @param managerPassword Password (if any) of the user named by the managerUser property.
*/
public void setManagerPassword(String managerPassword) {
this.managerPassword = managerPassword;
}
/**
* @return Name of the user (typically a fully qualified DN) which
* will be used to authenticate with the LDAP server when initiating LDAP connections.
*/
public String getManagerUser() {
return managerUser;
}
/**
* For OpenLDAP this might be "cn=Manager,dc=mycompany,dc=com";
* because this user typically <b>only</b> needs to be able to search/read
* the contexts against which LDAP operations occur, you may wish
* to create an account with read-only settings for this purpose.
* <p>
* If this property is not set, then the default behavor is
* to connect to the LDAP server anonymously.
* </p>
*
*
* @param managerUser Name of the user (typically a fully qualified DN) which
* will be used to authenticate with the LDAP server when initiating LDAP connections.
*/
public void setManagerUser(String managerUser) {
this.managerUser = managerUser;
}
/**
* @return The URL of the LDAP host to connect to, including port (if non-default),
* and the base DN from which other operations will be relative to.
*/
public String getUrl() {
return url;
}
/**
* LDAP URL (with or without the port) of the LDAP server to connect to.
* <p>Example: <br/>
* <b>ldap://dir.mycompany.com:389/dc=mycompany,dc=com</b> <br/>
* <small>(port 389 is the standard LDAP port) </small> so the example above could also be: <br/>
* <b>ldap://dir.mycompany.com/dc=mycompany,dc=com</b> <br/>
* </p>
*
*
* @param url The URL of the LDAP host to connect to, including port (if non-default),
* and the base DN from which other operations will be relative to.
*/
public void setUrl(String url) {
this.url = url;
}
/**
* @return Allows extra environment variables to be added at config time.
*/
public Map getExtraEnvVars() {
return extraEnvVars;
}
/**
* @param extraEnvVars Allows extra environment variables to be added at config time.
*/
public void setExtraEnvVars(Map extraEnvVars) {
this.extraEnvVars = extraEnvVars;
}
}

View File

@ -1,309 +0,0 @@
package org.acegisecurity.providers.dao.ldap;
import java.text.MessageFormat;
import java.util.ArrayList;
import javax.naming.AuthenticationException;
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 org.acegisecurity.BadCredentialsException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UserDetails;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* 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="org.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="org.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="org.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);
}
}
}

View File

@ -1,77 +0,0 @@
/* Copyright 2004 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.acegisecurity.providers.dao.ldap;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.userdetails.UserDetails;
import org.springframework.dao.DataAccessException;
/**
* Defines an interface for DAO implementations capable of locating and also
* validating a password.
*
* <p>
* Used with the {@link PasswordDaoAuthenticationProvider}.
* </p>
*
* <p>
* The interface requires only one read-only method, which simplifies support
* of new data access strategies.
* </p>
*
* @deprecated instead subclass {@link org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider}
* @author Karel Miarka
*/
public interface PasswordAuthenticationDao {
//~ Methods ================================================================
/**
* Locates the user based on the username and password. In the actual
* implementation, the search may possibly be case sensitive, or case
* insensitive depending on how the implementaion instance is configured.
* In this case, the <code>UserDetails</code> object that comes back may
* have a username that is of a different case than what was actually
* requested.
*
* <p>
* The implementation is responsible for password validation. It must throw
* <code>BadCredentialsException</code> (or subclass of that exception if
* desired) if the provided password is invalid.
* </p>
*
* <p>
* The implementation is responsible for filling the username and password
* parameters into the implementation of <code>UserDetails</code>.
* </p>
*
* @param username the username presented to the {@link
* PasswordDaoAuthenticationProvider}
* @param password the password presented to the {@link
* PasswordDaoAuthenticationProvider}
*
* @return a fully populated user record
*
* @throws DataAccessException if user could not be found for a
* repository-specific reason
* @throws BadCredentialsException if the user could not be found, invalid
* password provided or the user has no
* <code>GrantedAuthority</code>s
*/
public UserDetails loadUserByUsernameAndPassword(String username,
String password) throws DataAccessException, BadCredentialsException;
}

View File

@ -1,246 +0,0 @@
/* 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 org.acegisecurity.providers.dao.ldap;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationServiceException;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.DisabledException;
import org.acegisecurity.LockedException;
import org.acegisecurity.providers.AuthenticationProvider;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.DaoAuthenticationProvider;
import org.acegisecurity.providers.dao.UserCache;
import org.acegisecurity.providers.dao.cache.NullUserCache;
import org.acegisecurity.userdetails.UserDetails;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.util.Assert;
/**
* An {@link AuthenticationProvider} implementation that retrieves user details
* from a {@link PasswordAuthenticationDao}.
*
* <p>
* This <code>AuthenticationProvider</code> is capable of validating {@link
* UsernamePasswordAuthenticationToken} requests containing the correct
* username, password and when the user is not disabled.
* </p>
*
* <p>
* Unlike {@link DaoAuthenticationProvider}, the responsibility for password
* validation is delegated to <code>PasswordAuthenticationDao</code>.
* </p>
*
* <p>
* Upon successful validation, a
* <code>UsernamePasswordAuthenticationToken</code> will be created and
* returned to the caller. The token will include as its principal either a
* <code>String</code> representation of the username, or the {@link
* UserDetails} that was returned from the authentication repository. Using
* <code>String</code> is appropriate if a container adapter is being used, as
* it expects <code>String</code> representations of the username. Using
* <code>UserDetails</code> is appropriate if you require access to additional
* properties of the authenticated user, such as email addresses,
* human-friendly names etc. As container adapters are not recommended to be
* used, and <code>UserDetails</code> implementations provide additional
* flexibility, by default a <code>UserDetails</code> is returned. To override
* this default, set the {@link #setForcePrincipalAsString} to
* <code>true</code>.
* </p>
*
* <p>
* Caching is handled via the <code>UserDetails</code> object being placed in
* the {@link UserCache}. This ensures that subsequent requests with the same
* username and password can be validated without needing to query the {@link
* PasswordAuthenticationDao}. It should be noted that if a user appears to
* present an incorrect password, the {@link PasswordAuthenticationDao} will
* be queried to confirm the most up-to-date password was used for comparison.
* </p>
*
* <p>
* If an application context is detected (which is automatically the case when
* the bean is started within a Spring container), application events will be
* published to the context. See {@link
* org.acegisecurity.event.authentication.AbstractAuthenticationEvent} for
* further information.
* </p>
*
* @deprecated instead subclass {@link org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider}
* @author Karel Miarka
*/
public class PasswordDaoAuthenticationProvider implements AuthenticationProvider,
InitializingBean {
//~ Instance fields ========================================================
private PasswordAuthenticationDao authenticationDao;
private UserCache userCache = new NullUserCache();
private boolean forcePrincipalAsString = false;
//~ Methods ================================================================
public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
this.forcePrincipalAsString = forcePrincipalAsString;
}
public boolean isForcePrincipalAsString() {
return forcePrincipalAsString;
}
public void setPasswordAuthenticationDao(
PasswordAuthenticationDao authenticationDao) {
this.authenticationDao = authenticationDao;
}
public PasswordAuthenticationDao getPasswordAuthenticationDao() {
return authenticationDao;
}
public void setUserCache(UserCache userCache) {
this.userCache = userCache;
}
public UserCache getUserCache() {
return userCache;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.authenticationDao,
"A Password authentication DAO must be set");
Assert.notNull(this.userCache, "A user cache must be set");
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Determine username
String username = authentication.getPrincipal().toString();
if (authentication.getPrincipal() instanceof UserDetails) {
username = ((UserDetails) authentication.getPrincipal())
.getUsername();
}
String password = authentication.getCredentials().toString();
boolean cacheWasUsed = true;
UserDetails user = this.userCache.getUserFromCache(username);
// Check if the provided password is the same as the password in cache
if ((user != null) && !password.equals(user.getPassword())) {
user = null;
this.userCache.removeUserFromCache(username);
}
if (user == null) {
cacheWasUsed = false;
user = getUserFromBackend(username, password);
}
if (!user.isEnabled()) {
throw new DisabledException("User is disabled");
}
if (!user.isAccountNonExpired()) {
throw new AccountExpiredException("User account has expired");
}
if (!user.isAccountNonLocked()) {
throw new LockedException("User account is locked");
}
if (!user.isCredentialsNonExpired()) {
throw new CredentialsExpiredException(
"User credentials have expired");
}
if (!cacheWasUsed) {
// Put into cache
this.userCache.putUserInCache(user);
}
Object principalToReturn = user;
if (forcePrincipalAsString) {
principalToReturn = user.getUsername();
}
return createSuccessAuthentication(principalToReturn, authentication,
user);
}
public boolean supports(Class authentication) {
if (UsernamePasswordAuthenticationToken.class.isAssignableFrom(
authentication)) {
return true;
} else {
return false;
}
}
/**
* Creates a successful {@link Authentication} object.
*
* <P>
* Protected so subclasses can override. This might be required if multiple
* credentials need to be placed into a custom <code>Authentication</code>
* object, such as a password as well as a ZIP code.
* </p>
*
* <P>
* Subclasses will usually store the original credentials the user supplied
* (not salted or encoded passwords) in the returned
* <code>Authentication</code> object.
* </p>
*
* @param principal that should be the principal in the returned object
* (defined by the {@link #isForcePrincipalAsString()} method)
* @param authentication that was presented to the
* <code>PasswordDaoAuthenticationProvider</code> for validation
* @param user that was loaded by the
* <code>PasswordAuthenticationDao</code>
*
* @return the successful authentication token
*/
protected Authentication createSuccessAuthentication(Object principal,
Authentication authentication, UserDetails user) {
// Ensure we return the original credentials the user supplied,
// so subsequent attempts are successful even with encoded passwords.
// Also ensure we return the original getDetails(), so that future
// authentication events after cache expiry contain the details
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
authentication.getCredentials(), user.getAuthorities());
result.setDetails((authentication.getDetails() != null)
? authentication.getDetails() : null);
return result;
}
private UserDetails getUserFromBackend(String username, String password) {
try {
return this.authenticationDao.loadUserByUsernameAndPassword(username,
password);
} catch (DataAccessException repositoryProblem) {
throw new AuthenticationServiceException(repositoryProblem
.getMessage(), repositoryProblem);
}
}
}

View File

@ -1,170 +0,0 @@
package org.acegisecurity.providers.dao.ldap.revised;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* @see http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html
*
* @author robert.sanders
*
*/
public class InitialDirContextFactory {
/**
* LDAP URL (without the port) of the LDAP server to connect to; example
* <b>ldap://dir.mycompany.com:389/dc=mycompany,dc=com</b> (port 389 is the standard LDAP port).
*/
private String URL;
/** If your LDAP server does not allow anonymous searches then
* you will need to provide a username with which to login with;
* this is that username.
*/
private String managerUser;
/** If your LDAP server does not allow anonymous searches then
* you will need to provide a username with which to login with;
* this is the password of that user.
*/
private String managerPassword;
/** Type of authentication within LDAP; default is simple. */
private String authenticationType = "simple";
/** 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";
/** Allows extra environment variables to be added at config time. */
private Map extraEnvVars = null;
/** Use the LDAP Connection pool (in SUN JVMs)?; if true, then the
* LDAP environment property "com.sun.jndi.ldap.connect.pool" is added
* to any other JNDI properties.
* @see http://java.sun.com/products/jndi/tutorial/ldap/connect/pool.html
* @see http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html
*/
private boolean connectionPoolEnabled = true;
public InitialDirContext newInitialDirContext() throws DataAccessResourceFailureException {
Hashtable env = getEnvironment();
if (managerUser != null) {
env.put(Context.SECURITY_PRINCIPAL, managerUser);
env.put(Context.SECURITY_CREDENTIALS, managerPassword);
}
try {
return new InitialDirContext(env);
} catch (NamingException nx) {
throw new DataAccessResourceFailureException("Unable to connect to LDAP Server; check managerUser and managerPassword.", nx);
}
}
/**
* @return The Hashtable describing the base DirContext that will be created; minus the username/password if any.
*/
protected Hashtable getEnvironment() {
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
env.put(Context.PROVIDER_URL, URL);
env.put(Context.SECURITY_AUTHENTICATION, authenticationType);
if (connectionPoolEnabled) {
env.put("com.sun.jndi.ldap.connect.pool", "true");
}
if ((extraEnvVars != null) && (extraEnvVars.size() > 0)) {
env.putAll(extraEnvVars);
}
return env;
}
/**
* @return Returns the authenticationType.
*/
public String getAuthenticationType() {
return authenticationType;
}
/**
* @param authenticationType The authenticationType to set.
*/
public void setAuthenticationType(String authenticationType) {
this.authenticationType = authenticationType;
}
/**
* @return Returns the initialContextFactory.
*/
public String getInitialContextFactory() {
return initialContextFactory;
}
/**
* @param initialContextFactory The initialContextFactory to set.
*/
public void setInitialContextFactory(String initialContextFactory) {
this.initialContextFactory = initialContextFactory;
}
/**
* @return Returns the managerPassword.
*/
public String getManagerPassword() {
return managerPassword;
}
/**
* @param managerPassword The managerPassword to set.
*/
public void setManagerPassword(String managerPassword) {
this.managerPassword = managerPassword;
}
/**
* @return Returns the managerUser.
*/
public String getManagerUser() {
return managerUser;
}
/**
* @param managerUser The managerUser to set.
*/
public void setManagerUser(String managerUser) {
this.managerUser = managerUser;
}
/**
* @return Returns the uRL.
*/
public String getURL() {
return URL;
}
/**
* @param url The uRL to set.
*/
public void setURL(String url) {
URL = url;
}
/**
* @return Allows extra environment variables to be added at config time.
*/
public Map getExtraEnvVars() {
return extraEnvVars;
}
/**
* @param extraEnvVars Allows extra environment variables to be added at config time.
*/
public void setExtraEnvVars(Map extraEnvVars) {
this.extraEnvVars = extraEnvVars;
}
}

View File

@ -1,216 +0,0 @@
/**
*
*/
package org.acegisecurity.providers.dao.ldap.revised;
import java.util.ArrayList;
import java.util.Hashtable;
import javax.naming.Context;
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.acegisecurity.BadCredentialsException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.providers.dao.ldap.PasswordAuthenticationDao;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UserDetails;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
/**
* 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 InitialDirContextFactory initialDirContextFactory;
/** Array of LdapSearchBean which will be used to search the context.
*/
private UserSearchBean[] userSearchBeans;
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 = initialDirContextFactory.newInitialDirContext();
UserSearchResults userSearchResults = null;
try {
for (int i = 0; (i < userSearchBeans.length) && (null == userSearchResults); i++) {
try {
userSearchResults = userSearchBeans[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 = initialDirContextFactory.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("", null, roleAttrs);
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;
}
/**
* @return Returns the userSearchBeans.
*/
public UserSearchBean[] getUserSearchBeans() {
return userSearchBeans;
}
/**
* @param userSearchBeans The userSearchBeans to set.
*/
public void setUserSearchBeans(UserSearchBean[] userSearchBeans) {
this.userSearchBeans = userSearchBeans;
}
/** Convience method to set only one userSearchBean.
* <b>NOTE:</b> this method resets the entire userSearchBeans array,
* and can therefore not be used to append entries to the array.
*
* @param userSearchBean
*/
public void setUserSearchBean(UserSearchBean userSearchBean) {
this.userSearchBeans = new UserSearchBean[]{userSearchBean};
}
/**
* @return Returns the ldapSupport.
*/
public InitialDirContextFactory getInitialDirContextFactory() {
return initialDirContextFactory;
}
/**
* @param ldapSupport The ldapSupport to set.
*/
public void setInitialDirContextFactory(InitialDirContextFactory initialDirContextFactory) {
this.initialDirContextFactory = initialDirContextFactory;
}
}

View File

@ -1,171 +0,0 @@
/**
*
*/
package org.acegisecurity.providers.dao.ldap.revised;
import javax.naming.directory.SearchControls;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Used to specify properties which are used to
* construct JNDI SearchControls instances.
*
* @see javax.naming.directory.SearchControls
*
*/
public class SearchControlsFactory {
private static final transient Log logger = LogFactory.getLog(SearchControlsFactory.class);
/** Name, which when combined with the rootContext of the DirContext
* being searched will resolve to the DN that the search should be performed in.
*/
private String searchContextName;
/** Names of the attributes to return from the search;
* default is null in which case ALL attributes will be returned.
*/
private String[] returnAttrNames;
/**
* One of the 3 possible scope values as specified in SearchControles. <br/>
* <ul>
* <li>SearchControls.OBJECT_SCOPE = Search the attributes associated with the object specified by searchContextName.
* <li>SearchControls.ONELEVEL_SCOPE = Search the objects contained within the searchContextName.
* <li>SearchControls.SUBTREE_SCOPE = Recursivly search the objects contained within the searchContextName and any child context's it may contain.
* </ul>
*
*/
private int searchScope = SearchControls.ONELEVEL_SCOPE;
/** Number of milliseconds to wait before a timeout error is triggered. */
private int timeout = 10000;
/** Maximum number of objects to return. Defauts to zero == no limit. */
private int countLimit = 0;
/** If set to true then links will be followed,
* if left at the default of false then links will be returned (not followed).
*/
private boolean followLinks = false;
/** If set to true (the default) then objects can be returned from the LDAP server. */
private boolean returnObjects = true;
/** Given the settings for this LdapSearchCriteria,
* use it to create a new instance of SearchControls with matching settings.
*
* @return A new instance of SearchControls.
*/
public SearchControls newSearchControls() {
SearchControls controls =
new SearchControls(searchScope, countLimit, timeout, returnAttrNames, returnObjects, followLinks);
return controls;
}
/**
* @return Returns the countLimit.
*/
public int getCountLimit() {
return countLimit;
}
/**
* @param countLimit The countLimit to set.
*/
public void setCountLimit(int countLimit) {
this.countLimit = countLimit;
}
/**
* @return Returns the followLinks.
*/
public boolean isFollowLinks() {
return followLinks;
}
/**
* @param followLinks The followLinks to set.
*/
public void setFollowLinks(boolean followLinks) {
this.followLinks = followLinks;
}
/**
* @return Returns the returnAttrNames.
*/
public String[] getReturnAttrNames() {
return returnAttrNames;
}
/**
* @param returnAttrNames The returnAttrNames to set.
*/
public void setReturnAttrNames(String[] returnAttrNames) {
this.returnAttrNames = returnAttrNames;
}
/**
* @return Returns the searchContextName.
*/
public String getSearchContextName() {
return searchContextName;
}
/**
* @param searchContextName The searchContextName to set.
*/
public void setSearchContextName(String searchContextName) {
this.searchContextName = searchContextName;
}
/**
* @return Returns the searchScope.
*/
public int getSearchScope() {
return searchScope;
}
/**
* @param searchScope The searchScope to set.
*/
public void setSearchScope(int searchScope) {
this.searchScope = searchScope;
}
/** Set the searchScope using a string, should be one of:
* OBJECT_SCOPE, ONELEVEL_SCOPE, or SUBTREE_SCOPE (you probably want ONELEVEL_SCOPE).
*
* @param scope
*/
public void setSearchScope(String scope) {
if ("OBJECT_SCOPE".equals(scope)) {
setSearchScope( SearchControls.OBJECT_SCOPE );
} else if ("ONELEVEL_SCOPE".equals(scope)) {
setSearchScope( SearchControls.ONELEVEL_SCOPE );
} else if ("SUBTREE_SCOPE".equals(scope)) {
setSearchScope( SearchControls.SUBTREE_SCOPE );
} else {
logger.warn("Scope '" + scope + "' not recognized, setting to ONELEVEL_SCOPE");
setSearchScope( SearchControls.ONELEVEL_SCOPE );
}
}
/**
* @return Returns the timeout.
*/
public int getTimeout() {
return timeout;
}
/**
* @param timeout The timeout to set.
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}

View File

@ -1,208 +0,0 @@
/**
*
*/
package org.acegisecurity.providers.dao.ldap.revised;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.springframework.beans.factory.InitializingBean;
/**
* @author robert.sanders
*
*/
public class UserSearchBean implements InitializingBean {
/** Context relative to the rootContext to which the directory is connected. */
private String subContext;
/** If true then searches the entire subtree as idenified by context,
* if false (the default) then only search the level identified by the context.
*/
private boolean searchSubtree = false;
/** The name and any associate information of the
* ldap attribute used to match the username.
* Expected in the form "uid={0}", or "uid={0}@company.com"
* where {0} is the username that the user attempted to login with.
*/
private String usernameFilter;
/** LDAP Search Filter (@see 'RFC 2255'). NOTE: you can
* use <b>either</b> searchFilter <b>or</b> filters, but <b>not</b>
* both in a given LdapSearchBean.
*/
private String searchFilter = "objectClass=*";
/** The attribute used when attempting to log the
* user in to the LDAP server, if not set it defaults
* to the attribute identified by usernameAttr.
* For some LDAP systems this may need to be something like "sAMAccountName" (MS ActiveDirectory).
*/
private String loginAttr;
/** The time (in milliseconds) which to wait before the search fails;
* the default is zero, meaning forever.
*/
private int searchTimeLimit = 0;
/** Attributes of the User's LDAP Object that contain role name information. */
private String[] roleAttributes;
/** Internal state - initialized at startup by combining the base searchFilter with the usernameFilter. */
private String searchFilterInternal;
/** Internal state - initialized at startup based on the values of the JavaBean properties. */
private SearchControls searchControls;
/** Return the JNDI SearchResult containing the user's information, or null if no SearchResult is found.
*
* @param ctx The context in which the search will be based (note that subContext property refines this).
* @param username The username to search for.
* @return The JNDI SearchResult containing the user's information, or null if no SearchResult is found.
* @throws NamingException Passes on the Exception if a JNDI Exception occurs.
*/
public UserSearchResults searchForUser(DirContext ctx, String username) throws NamingException {
//System.out.println("searchFilterInternal [" + searchFilterInternal + "]");
NamingEnumeration enm = ctx.search(subContext, searchFilterInternal, new String[]{username}, searchControls);
if (!enm.hasMore()) {
return null; // user not found.
}
SearchResult searchResult = (SearchResult)enm.next();
UserSearchResults userSearchResults = new UserSearchResults(searchResult);
userSearchResults.setUserSearchBean(this);
String userDN = searchResult.getName();
if (searchResult.isRelative()) {
userDN = userDN + "," + subContext + "," + ctx.getNameInNamespace();
}
userSearchResults.setLdapName( userDN );
String loginName;
if (null != loginAttr) {
loginName = (String)userSearchResults.getAttributes().get(loginAttr).get();
} else {
loginName = userDN;
}
userSearchResults.setUserLoginName(loginName);
return userSearchResults;
}
public void afterPropertiesSet() throws Exception {
searchControls = new SearchControls();
if (searchSubtree) {
searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
} else {
searchControls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
}
searchControls.setTimeLimit( searchTimeLimit );
String baseFilter = (null != searchFilter) ? searchFilter : "";
searchFilterInternal = "(&(" + baseFilter + ")(" + usernameFilter + "))";
}
/**
* @return Returns the loginAttr.
*/
public String getLoginAttr() {
return loginAttr;
}
/**
* @param loginAttr The loginAttr to set.
*/
public void setLoginAttr(String loginAttr) {
this.loginAttr = loginAttr;
}
/**
* @return Returns the roleAttributes.
*/
public String[] getRoleAttributes() {
return roleAttributes;
}
/**
* @param roleAttributes The roleAttributes to set.
*/
public void setRoleAttributes(String[] roleAttributes) {
this.roleAttributes = roleAttributes;
}
/**
* @return Returns the searchFilter.
*/
public String getSearchFilter() {
return searchFilter;
}
/**
* @param searchFilter The searchFilter to set.
*/
public void setSearchFilter(String searchFilter) {
this.searchFilter = searchFilter;
}
/**
* @return Returns the searchSubtree.
*/
public boolean isSearchSubtree() {
return searchSubtree;
}
/**
* @param searchSubtree The searchSubtree to set.
*/
public void setSearchSubtree(boolean searchSubtree) {
this.searchSubtree = searchSubtree;
}
/**
* @return Returns the searchTimeLimit.
*/
public int getSearchTimeLimit() {
return searchTimeLimit;
}
/**
* @param searchTimeLimit The searchTimeLimit to set.
*/
public void setSearchTimeLimit(int searchTimeLimit) {
this.searchTimeLimit = searchTimeLimit;
}
/**
* @return Returns the subContext.
*/
public String getSubContext() {
return subContext;
}
/**
* @param subContext The subContext to set.
*/
public void setSubContext(String subContext) {
this.subContext = subContext;
}
/**
* @return Returns the usernameFilter.
*/
public String getUsernameFilter() {
return usernameFilter;
}
/**
* @param usernameFilter The usernameFilter to set.
*/
public void setUsernameFilter(String usernameFilter) {
this.usernameFilter = usernameFilter;
}
}

View File

@ -1,97 +0,0 @@
/**
*
*/
package org.acegisecurity.providers.dao.ldap.revised;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchResult;
/**
* Encapsulates the information returned by a successful UserSearchBean
*
*/
public class UserSearchResults {
private Attributes attributes;
/** The full DN of the user. */
private String ldapName;
/** The name that should be used to log the user into the LDAP server (to test authentication). */
private String userLoginName;
/** Internal state: the UserSearchBean which yeilded the results. */
private UserSearchBean userSearchBean;
public UserSearchResults() {
super();
}
public UserSearchResults(SearchResult searchResult) {
super();
setAttributes( searchResult.getAttributes() );
}
public UserSearchResults(SearchResult searchResult, UserSearchBean userSearchBean) {
super();
this.userSearchBean = userSearchBean;
setAttributes( searchResult.getAttributes() );
}
/**
* @return Returns the attributes.
*/
public Attributes getAttributes() {
return attributes;
}
/**
* @param attributes The attributes to set.
*/
public void setAttributes(Attributes attributes) {
this.attributes = attributes;
}
/**
* @return Returns the name.
*/
public String getLdapName() {
return ldapName;
}
/**
* @param name The name to set.
*/
public void setLdapName(String name) {
this.ldapName = name;
}
/**
* @return Returns the userLoginName.
*/
public String getUserLoginName() {
return userLoginName;
}
/**
* @param userLoginName The userLoginName to set.
*/
public void setUserLoginName(String userLoginName) {
this.userLoginName = userLoginName;
}
/**
* @return Returns the userSearchBean.
*/
public UserSearchBean getUserSearchBean() {
return userSearchBean;
}
/**
* @param userSearchBean The userSearchBean to set.
*/
public void setUserSearchBean(UserSearchBean userSearchBean) {
this.userSearchBean = userSearchBean;
}
}