001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.providers.ldap.authenticator;
017:
018: import org.acegisecurity.BadCredentialsException;
019:
020: import org.acegisecurity.ldap.InitialDirContextFactory;
021: import org.acegisecurity.ldap.LdapTemplate;
022:
023: import org.acegisecurity.userdetails.ldap.LdapUserDetails;
024: import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028:
029: import java.util.Iterator;
030:
031: /**
032: * An authenticator which binds as a user.
033: *
034: * @author Luke Taylor
035: * @version $Id: BindAuthenticator.java 2348 2007-12-07 16:04:43Z luke_t $
036: *
037: * @see AbstractLdapAuthenticator
038: */
039: public class BindAuthenticator extends AbstractLdapAuthenticator {
040: //~ Static fields/initializers =====================================================================================
041:
042: private static final Log logger = LogFactory
043: .getLog(BindAuthenticator.class);
044:
045: //~ Constructors ===================================================================================================
046:
047: /**
048: * Create an initialized instance to the {@link InitialDirContextFactory} provided.
049: *
050: * @param initialDirContextFactory
051: */
052: public BindAuthenticator(
053: InitialDirContextFactory initialDirContextFactory) {
054: super (initialDirContextFactory);
055: }
056:
057: //~ Methods ========================================================================================================
058:
059: public LdapUserDetails authenticate(String username, String password) {
060: LdapUserDetails user = null;
061:
062: // If DN patterns are configured, try authenticating with them directly
063: Iterator dns = getUserDns(username).iterator();
064:
065: while (dns.hasNext() && (user == null)) {
066: user = bindWithDn((String) dns.next(), username, password);
067: }
068:
069: // Otherwise use the configured locator to find the user
070: // and authenticate with the returned DN.
071: if ((user == null) && (getUserSearch() != null)) {
072: LdapUserDetails userFromSearch = getUserSearch()
073: .searchForUser(username);
074: user = bindWithDn(userFromSearch.getDn(), username,
075: password);
076: }
077:
078: if (user == null) {
079: throw new BadCredentialsException(messages.getMessage(
080: "BindAuthenticator.badCredentials",
081: "Bad credentials"));
082: }
083:
084: return user;
085: }
086:
087: private LdapUserDetails bindWithDn(String userDn, String username,
088: String password) {
089: LdapTemplate template = new LdapTemplate(
090: getInitialDirContextFactory(), userDn, password);
091:
092: try {
093: LdapUserDetailsImpl.Essence user = (LdapUserDetailsImpl.Essence) template
094: .retrieveEntry(userDn, getUserDetailsMapper(),
095: getUserAttributes());
096: user.setUsername(username);
097: user.setPassword(password);
098:
099: return user.createUserDetails();
100: } catch (BadCredentialsException e) {
101: // This will be thrown if an invalid user name is used and the method may
102: // be called multiple times to try different names, so we trap the exception
103: // unless a subclass wishes to implement more specialized behaviour.
104: handleBindException(userDn, username, e.getCause());
105: }
106:
107: return null;
108: }
109:
110: /**
111: * Allows subclasses to inspect the exception thrown by an attempt to bind with a particular DN.
112: * The default implementation just reports the failure to the debug log.
113: */
114: void handleBindException(String userDn, String username,
115: Throwable cause) {
116: if (logger.isDebugEnabled()) {
117: logger.debug("Failed to bind as " + userDn + ": " + cause);
118: }
119: }
120: }
|