View Javadoc

1   /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.acegisecurity.providers.ldap.authenticator;
17  
18  import org.acegisecurity.AcegiMessageSource;
19  
20  import org.acegisecurity.ldap.InitialDirContextFactory;
21  import org.acegisecurity.ldap.LdapEntryMapper;
22  import org.acegisecurity.ldap.LdapUserSearch;
23  
24  import org.acegisecurity.providers.ldap.LdapAuthenticator;
25  
26  import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
27  
28  import org.springframework.beans.factory.InitializingBean;
29  
30  import org.springframework.context.MessageSource;
31  import org.springframework.context.MessageSourceAware;
32  import org.springframework.context.support.MessageSourceAccessor;
33  
34  import org.springframework.util.Assert;
35  
36  import java.text.MessageFormat;
37  
38  import java.util.ArrayList;
39  import java.util.List;
40  
41  
42  /**
43   * Base class for the authenticator implementations.
44   *
45   * @author Luke Taylor
46   * @version $Id: AbstractLdapAuthenticator.java 1585 2006-07-20 13:15:55Z carlossg $
47   */
48  public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, InitializingBean, MessageSourceAware {
49      //~ Instance fields ================================================================================================
50  
51      private InitialDirContextFactory initialDirContextFactory;
52      private LdapUserDetailsMapper userDetailsMapper = new LdapUserDetailsMapper();
53  
54      /** Optional search object which can be used to locate a user when a simple DN match isn't sufficient */
55      private LdapUserSearch userSearch;
56      protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
57  
58      /**
59       * The suffix to be added to the DN patterns, worked out internally from the root DN of the configured
60       * InitialDirContextFactory.
61       */
62      private String dnSuffix = "";
63  
64      /** The attributes which will be retrieved from the directory. Null means all attributes */
65      private String[] userAttributes = null;
66  
67      //private String[] userDnPattern = null;
68      /** Stores the patterns which are used as potential DN matches */
69      private MessageFormat[] userDnFormat = null;
70  
71      //~ Constructors ===================================================================================================
72  
73      /**
74       * Create an initialized instance to the {@link InitialDirContextFactory} provided.
75       * 
76       * @param initialDirContextFactory
77       */
78      public AbstractLdapAuthenticator(InitialDirContextFactory initialDirContextFactory) {
79          this.setInitialDirContextFactory(initialDirContextFactory);
80      }
81  
82      // ~ Methods
83      // ========================================================================================================
84  
85      public void afterPropertiesSet() throws Exception {
86          Assert.isTrue((userDnFormat != null) || (userSearch != null),
87                  "Either an LdapUserSearch or DN pattern (or both) must be supplied.");
88      }
89  
90      /**
91       * Set the {@link InitialDirContextFactory} and initialize this instance from its data.
92       * 
93       * @param initialDirContextFactory
94       */
95      private void setInitialDirContextFactory(InitialDirContextFactory initialDirContextFactory) {
96          Assert.notNull(initialDirContextFactory, "initialDirContextFactory must not be null.");
97          this.initialDirContextFactory = initialDirContextFactory;
98  
99          String rootDn = initialDirContextFactory.getRootDn();
100 
101         if (rootDn.length() > 0) {
102             dnSuffix = "," + rootDn;
103         }
104     }
105 
106     protected InitialDirContextFactory getInitialDirContextFactory() {
107         return initialDirContextFactory;
108     }
109 
110     public String[] getUserAttributes() {
111         return userAttributes;
112     }
113 
114     protected LdapEntryMapper getUserDetailsMapper() {
115         return userDetailsMapper;
116     }
117 
118     /**
119      * Builds list of possible DNs for the user, worked out from the <tt>userDnPatterns</tt> property. The
120      * returned value includes the root DN of the provider URL used to configure the
121      * <tt>InitialDirContextfactory</tt>.
122      *
123      * @param username the user's login name
124      *
125      * @return the list of possible DN matches, empty if <tt>userDnPatterns</tt> wasn't set.
126      */
127     protected List getUserDns(String username) {
128         if (userDnFormat == null) {
129             return new ArrayList(0);
130         }
131 
132         List userDns = new ArrayList(userDnFormat.length);
133         String[] args = new String[] {username};
134 
135         synchronized (userDnFormat) {
136             for (int i = 0; i < userDnFormat.length; i++) {
137                 userDns.add(userDnFormat[i].format(args) + dnSuffix);
138             }
139         }
140 
141         return userDns;
142     }
143 
144     protected LdapUserSearch getUserSearch() {
145         return userSearch;
146     }
147 
148     public void setMessageSource(MessageSource messageSource) {
149         Assert.notNull("Message source must not be null");
150         this.messages = new MessageSourceAccessor(messageSource);
151     }
152 
153     /**
154      * Sets the user attributes which will be retrieved from the directory.
155      *
156      * @param userAttributes
157      */
158     public void setUserAttributes(String[] userAttributes) {
159         Assert.notNull(userAttributes, "The userAttributes property cannot be set to null");
160         this.userAttributes = userAttributes;
161     }
162 
163     public void setUserDetailsMapper(LdapUserDetailsMapper userDetailsMapper) {
164         Assert.notNull("userDetailsMapper must not be null");
165         this.userDetailsMapper = userDetailsMapper;
166     }
167 
168     /**
169      * Sets the pattern which will be used to supply a DN for the user. The pattern should be the name relative
170      * to the root DN. The pattern argument {0} will contain the username. An example would be "cn={0},ou=people".
171      *
172      * @param dnPattern the array of patterns which will be tried when obtaining a username
173      * to a DN.
174      */
175     public void setUserDnPatterns(String[] dnPattern) {
176         Assert.notNull(dnPattern, "The array of DN patterns cannot be set to null");
177 //        this.userDnPattern = dnPattern;
178         userDnFormat = new MessageFormat[dnPattern.length];
179 
180         for (int i = 0; i < dnPattern.length; i++) {
181             userDnFormat[i] = new MessageFormat(dnPattern[i]);
182         }
183     }
184 
185     public void setUserSearch(LdapUserSearch userSearch) {
186         Assert.notNull(userSearch, "The userSearch cannot be set to null");
187         this.userSearch = userSearch;
188     }
189 }