##### Coverage Report - org.apache.turbine.services.security.ldap.LDAPUserManager

Classes in this File | Line Coverage | Branch Coverage | Complexity
LDAPUserManager |
0% | 0/113
0% | 0/12
| 3.0588235294117645;3,059

1 |  |
     package org.apache.turbine.services.security.ldap;
2 |  |
3 |  |
     /*
4 |  |
      * Licensed to the Apache Software Foundation (ASF) under one
5 |  |
      * or more contributor license agreements.  See the NOTICE file
6 |  |
      * distributed with this work for additional information
7 |  |
      * regarding copyright ownership.  The ASF licenses this file
8 |  |
      * to you under the Apache License, Version 2.0 (the
9 |  |
      * "License"); you may not use this file except in compliance
10 |  |
      * with the License.  You may obtain a copy of the License at
11 |  |
      *
12 |  |
      *   http://www.apache.org/licenses/LICENSE-2.0
13 |  |
      *
14 |  |
      * Unless required by applicable law or agreed to in writing,
15 |  |
      * software distributed under the License is distributed on an
16 |  |
      * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 |  |
      * KIND, either express or implied.  See the License for the
18 |  |
      * specific language governing permissions and limitations
19 |  |
      * under the License.
20 |  |
      */
21 |  |
22 |  |
     import java.util.List;
23 |  |
     import java.util.Hashtable;
24 |  |
     import java.util.Vector;
25 |  |
26 |  |
     import javax.naming.AuthenticationException;
27 |  |
     import javax.naming.Context;
28 |  |
     import javax.naming.NamingEnumeration;
29 |  |
     import javax.naming.NamingException;
30 |  |
     import javax.naming.directory.Attributes;
31 |  |
     import javax.naming.directory.DirContext;
32 |  |
     import javax.naming.directory.SearchControls;
33 |  |
     import javax.naming.directory.SearchResult;
34 |  |
35 |  |
     import org.apache.commons.configuration.Configuration;
36 |  |
37 |  |
     import org.apache.turbine.om.security.User;
38 |  |
     import org.apache.turbine.services.security.TurbineSecurity;
39 |  |
     import org.apache.turbine.services.security.UserManager;
40 |  |
     import org.apache.turbine.util.security.DataBackendException;
41 |  |
     import org.apache.turbine.util.security.EntityExistsException;
42 |  |
     import org.apache.turbine.util.security.PasswordMismatchException;
43 |  |
     import org.apache.turbine.util.security.UnknownEntityException;
44 |  |
45 |  |
     /**
46 |  |
      * A UserManager performs {@link org.apache.turbine.om.security.User}
47 |  |
      * object related tasks on behalf of the
48 |  |
      * {@link org.apache.turbine.services.security.SecurityService}.
49 |  |
      *
50 |  |
      * This implementation uses ldap for retrieving user data. It
51 |  |
      * expects that the User interface implementation will be castable to
52 |  |
      * {@link org.apache.turbine.om.BaseObject}.
53 |  |
      *
54 |  |
      * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
55 |  |
      * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
56 |  |
      * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
57 |  |
      * @author <a href="mailto:cberry@gluecode.com">Craig D. Berry</a>
58 |  |
      * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
59 |  |
      * @author <a href="mailto:tadewunmi@gluecode.com">Tracy M. Adewunmi</a>
60 |  |
      * @author <a href="mailto:lflournoy@gluecode.com">Leonard J. Flournoy</a>
61 |  |
      * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
62 |  |
      * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
63 |  |
      * @author <a href="mailto:hhernandez@itweb.com.mx">Humberto Hernandez</a>
64 |  |
      * @version $Id: LDAPUserManager.java 1096130 2011-04-23 10:37:19Z ludwig $
65 |  |
      */
66 | 0 |
     public class LDAPUserManager implements UserManager
67 |  |
     {
68 |  |
         /**
69 |  |
          * Initializes the UserManager
70 |  |
          *
71 |  |
          * @param conf A Configuration object to init this Manager
72 |  |
          */
73 |  |
         public void init(Configuration conf)
74 |  |
         {
75 |  |
             // GNDN
76 | 0 |
         }
77 |  |
78 |  |
         /**
79 |  |
          * Check wether a specified user's account exists.
80 |  |
          *
81 |  |
          * The login name is used for looking up the account.
82 |  |
          *
83 |  |
          * @param user The user to be checked.
84 |  |
          * @return true if the specified account exists
85 |  |
          * @throws DataBackendException Error accessing the data backend.
86 |  |
          */
87 |  |
         public boolean accountExists(User user) throws DataBackendException
88 |  |
         {
89 | 0 |
             return accountExists(user.getName());
90 |  |
         }
91 |  |
92 |  |
         /**
93 |  |
          *
94 |  |
          * Check wether a specified user's account exists.
95 |  |
          * The login name is used for looking up the account.
96 |  |
          *
97 |  |
          * @param username The name of the user to be checked.
98 |  |
          * @return true if the specified account exists
99 |  |
          * @throws DataBackendException Error accessing the data backend.
100 |  |
          */
101 |  |
         public boolean accountExists(String username)
102 |  |
                 throws DataBackendException
103 |  |
         {
104 |  |
             try
105 |  |
             {
106 | 0 |
                 User ldapUser = retrieve(username);
107 |  |
             }
108 | 0 |
             catch (UnknownEntityException ex)
109 |  |
             {
110 | 0 |
                 return false;
111 | 0 |
             }
112 |  |
113 | 0 |
             return true;
114 |  |
         }
115 |  |
116 |  |
         /**
117 |  |
          * Retrieve a user from persistent storage using username as the
118 |  |
          * key.
119 |  |
          *
120 |  |
          * @param username the name of the user.
121 |  |
          * @return an User object.
122 |  |
          * @exception UnknownEntityException if the user's account does not
123 |  |
          *            exist in the database.
124 |  |
          * @exception DataBackendException Error accessing the data backend.
125 |  |
          */
126 |  |
         public User retrieve(String username)
127 |  |
                 throws UnknownEntityException, DataBackendException
128 |  |
         {
129 |  |
             try
130 |  |
             {
131 | 0 |
                 DirContext ctx = bindAsAdmin();
132 |  |
133 |  |
                 /*
134 |  |
                  * Define the search.
135 |  |
                  */
136 | 0 |
                 String userBaseSearch = LDAPSecurityConstants.getBaseSearch();
137 | 0 |
                 String filter = LDAPSecurityConstants.getNameAttribute();
138 |  |
139 | 0 |
                 filter = "(" + filter + "=" + username + ")";
140 |  |
141 |  |
                 /*
142 |  |
                  * Create the default search controls.
143 |  |
                  */
144 | 0 |
                 SearchControls ctls = new SearchControls();
145 |  |
146 | 0 |
                 NamingEnumeration answer =
147 |  |
                         ctx.search(userBaseSearch, filter, ctls);
148 |  |
149 | 0 |
                 if (answer.hasMore())
150 |  |
                 {
151 | 0 |
                     SearchResult sr = (SearchResult) answer.next();
152 | 0 |
                     Attributes attribs = sr.getAttributes();
153 | 0 |
                     LDAPUser ldapUser = createLDAPUser();
154 |  |
155 | 0 |
                     ldapUser.setLDAPAttributes(attribs);
156 | 0 |
                     ldapUser.setTemp("turbine.user", ldapUser);
157 |  |
158 | 0 |
                     return ldapUser;
159 |  |
                 }
160 |  |
                 else
161 |  |
                 {
162 | 0 |
                     throw new UnknownEntityException("The given user: "
163 |  |
                             + username + "\n does not exist.");
164 |  |
                 }
165 |  |
             }
166 | 0 |
             catch (NamingException ex)
167 |  |
             {
168 | 0 |
                 throw new DataBackendException(
169 |  |
                         "The LDAP server specified is unavailable", ex);
170 |  |
             }
171 |  |
         }
172 |  |
173 |  |
         /**
174 |  |
          * This is currently not implemented to behave as expected.  It
175 |  |
          * ignores the Criteria argument and returns all the users.
176 |  |
          *
177 |  |
          * Retrieve a set of users that meet the specified criteria.
178 |  |
          *
179 |  |
          * As the keys for the criteria, you should use the constants that
180 |  |
          * are defined in {@link User} interface, plus the the names
181 |  |
          * of the custom attributes you added to your user representation
182 |  |
          * in the data storage. Use verbatim names of the attributes -
183 |  |
          * without table name prefix in case of DB implementation.
184 |  |
          *
185 |  |
          * @param criteria The criteria of selection.
186 |  |
          * @return a List of users meeting the criteria.
187 |  |
          * @throws DataBackendException Error accessing the data backend.
188 |  |
          * @deprecated Use <a href="#retrieveList">retrieveList</a> instead.
189 |  |
          */
190 |  |
         public User[] retrieve(Object criteria)
191 |  |
                 throws DataBackendException
192 |  |
         {
193 | 0 |
             return (User []) retrieveList(criteria).toArray(new User[0]);
194 |  |
         }
195 |  |
196 |  |
         /**
197 |  |
          * Retrieve a list of users that meet the specified criteria.
198 |  |
          *
199 |  |
          * As the keys for the criteria, you should use the constants that
200 |  |
          * are defined in {@link User} interface, plus the names
201 |  |
          * of the custom attributes you added to your user representation
202 |  |
          * in the data storage. Use verbatim names of the attributes -
203 |  |
          * without table name prefix in case of Torque implementation.
204 |  |
          *
205 |  |
          * @param criteria The criteria of selection.
206 |  |
          * @return a List of users meeting the criteria.
207 |  |
          * @throws DataBackendException if there is a problem accessing the
208 |  |
          *         storage.
209 |  |
          */
210 |  |
         public List retrieveList(Object criteria)
211 |  |
                 throws DataBackendException
212 |  |
         {
213 | 0 |
             List users = new Vector(0);
214 |  |
215 |  |
             try
216 |  |
             {
217 | 0 |
                 DirContext ctx = bindAsAdmin();
218 |  |
219 | 0 |
                 String userBaseSearch = LDAPSecurityConstants.getBaseSearch();
220 | 0 |
                 String filter = LDAPSecurityConstants.getNameAttribute();
221 |  |
222 | 0 |
                 filter = "(" + filter + "=*)";
223 |  |
224 |  |
                 /*
225 |  |
                  * Create the default search controls.
226 |  |
                  */
227 | 0 |
                 SearchControls ctls = new SearchControls();
228 |  |
229 | 0 |
                 NamingEnumeration answer =
230 |  |
                         ctx.search(userBaseSearch, filter, ctls);
231 |  |
232 | 0 |
                 while (answer.hasMore())
233 |  |
                 {
234 | 0 |
                     SearchResult sr = (SearchResult) answer.next();
235 | 0 |
                     Attributes attribs = sr.getAttributes();
236 | 0 |
                     LDAPUser ldapUser = createLDAPUser();
237 |  |
238 | 0 |
                     ldapUser.setLDAPAttributes(attribs);
239 | 0 |
                     ldapUser.setTemp("turbine.user", ldapUser);
240 | 0 |
                     users.add(ldapUser);
241 | 0 |
                 }
242 |  |
             }
243 | 0 |
             catch (NamingException ex)
244 |  |
             {
245 | 0 |
                 throw new DataBackendException(
246 |  |
                         "The LDAP server specified is unavailable", ex);
247 | 0 |
             }
248 | 0 |
             return users;
249 |  |
         }
250 |  |
251 |  |
         /**
252 |  |
          * Retrieve a user from persistent storage using username as the
253 |  |
          * key, and authenticate the user. The implementation may chose
254 |  |
          * to authenticate to the server as the user whose data is being
255 |  |
          * retrieved.
256 |  |
          *
257 |  |
          * @param username the name of the user.
258 |  |
          * @param password the user supplied password.
259 |  |
          * @return an User object.
260 |  |
          * @exception PasswordMismatchException if the supplied password was
261 |  |
          *            incorrect.
262 |  |
          * @exception UnknownEntityException if the user's account does not
263 |  |
          *            exist in the database.
264 |  |
          * @exception DataBackendException Error accessing the data backend.
265 |  |
          */
266 |  |
         public User retrieve(String username, String password)
267 |  |
                 throws PasswordMismatchException,
268 |  |
                 UnknownEntityException, DataBackendException
269 |  |
         {
270 | 0 |
             User user = retrieve(username);
271 |  |
272 | 0 |
             authenticate(user, password);
273 | 0 |
             return user;
274 |  |
         }
275 |  |
276 |  |
         /**
277 |  |
          * Save a User object to persistent storage. User's account is
278 |  |
          * required to exist in the storage.
279 |  |
          *
280 |  |
          * @param user an User object to store.
281 |  |
          * @throws UnknownEntityException if the user's account does not
282 |  |
          *            exist in the database.
283 |  |
          * @throws DataBackendException if there is an LDAP error
284 |  |
          *
285 |  |
          */
286 |  |
         public void store(User user)
287 |  |
                 throws UnknownEntityException, DataBackendException
288 |  |
         {
289 | 0 |
             if (!accountExists(user))
290 |  |
             {
291 | 0 |
                 throw new UnknownEntityException("The account '"
292 |  |
                         + user.getName() + "' does not exist");
293 |  |
             }
294 |  |
295 |  |
             try
296 |  |
             {
297 | 0 |
                 LDAPUser ldapUser = (LDAPUser) user;
298 | 0 |
                 Attributes attrs = ldapUser.getLDAPAttributes();
299 | 0 |
                 String name = ldapUser.getDN();
300 |  |
301 | 0 |
                 DirContext ctx = bindAsAdmin();
302 |  |
303 | 0 |
                 ctx.modifyAttributes(name, DirContext.REPLACE_ATTRIBUTE, attrs);
304 |  |
             }
305 | 0 |
             catch (NamingException ex)
306 |  |
             {
307 | 0 |
                 throw new DataBackendException("NamingException caught", ex);
308 | 0 |
             }
309 | 0 |
         }
310 |  |
311 |  |
         /**
312 |  |
          * This method is not yet implemented.
313 |  |
          * Saves User data when the session is unbound. The user account is required
314 |  |
          * to exist in the storage.
315 |  |
          *
316 |  |
          * LastLogin, AccessCounter, persistent pull tools, and any data stored
317 |  |
          * in the permData hashtable that is not mapped to a column will be saved.
318 |  |
          *
319 |  |
          * @exception UnknownEntityException if the user's account does not
320 |  |
          *            exist in the database.
321 |  |
          * @exception DataBackendException if there is a problem accessing the
322 |  |
          *            storage.
323 |  |
          */
324 |  |
         public void saveOnSessionUnbind(User user)
325 |  |
                 throws UnknownEntityException, DataBackendException
326 |  |
         {
327 | 0 |
             if (!accountExists(user))
328 |  |
             {
329 | 0 |
                 throw new UnknownEntityException("The account '" +
330 |  |
                         user.getName() + "' does not exist");
331 |  |
             }
332 | 0 |
         }
333 |  |
334 |  |
         /**
335 |  |
          * Authenticate a User with the specified password. If authentication
336 |  |
          * is successful the method returns nothing. If there are any problems,
337 |  |
          * exception was thrown.
338 |  |
          *
339 |  |
          * @param user a User object to authenticate.
340 |  |
          * @param password the user supplied password.
341 |  |
          * @exception PasswordMismatchException if the supplied password was
342 |  |
          *            incorrect.
343 |  |
          * @exception UnknownEntityException if the user's account does not
344 |  |
          *            exist in the database.
345 |  |
          * @exception DataBackendException Error accessing the data backend.
346 |  |
          */
347 |  |
         public void authenticate(User user, String password)
348 |  |
                 throws PasswordMismatchException,
349 |  |
                 UnknownEntityException,
350 |  |
                 DataBackendException
351 |  |
         {
352 | 0 |
             LDAPUser ldapUser = (LDAPUser) user;
353 |  |
354 |  |
             try
355 |  |
             {
356 | 0 |
                 bind(ldapUser.getDN(), password);
357 |  |
             }
358 | 0 |
             catch (AuthenticationException ex)
359 |  |
             {
360 | 0 |
                 throw new PasswordMismatchException(
361 |  |
                         "The given password for: "
362 |  |
                         + ldapUser.getDN() + " is invalid\n");
363 |  |
             }
364 | 0 |
             catch (NamingException ex)
365 |  |
             {
366 | 0 |
                 throw new DataBackendException(
367 |  |
                         "NamingException caught:", ex);
368 | 0 |
             }
369 | 0 |
         }
370 |  |
371 |  |
         /**
372 |  |
          * This method is not yet implemented
373 |  |
          * Change the password for an User.
374 |  |
          *
375 |  |
          * @param user an User to change password for.
376 |  |
          * @param newPass the new password.
377 |  |
          * @param oldPass the old password.
378 |  |
          * @exception PasswordMismatchException if the supplied password was
379 |  |
          *            incorrect.
380 |  |
          * @exception UnknownEntityException if the user's account does not
381 |  |
          *            exist in the database.
382 |  |
          * @exception DataBackendException Error accessing the data backend.
383 |  |
          */
384 |  |
         public void changePassword(User user, String oldPass, String newPass)
385 |  |
                 throws PasswordMismatchException,
386 |  |
                 UnknownEntityException, DataBackendException
387 |  |
         {
388 | 0 |
             throw new DataBackendException(
389 |  |
                     "The method changePassword has no implementation.");
390 |  |
         }
391 |  |
392 |  |
         /**
393 |  |
          * This method is not yet implemented
394 |  |
          * Forcibly sets new password for an User.
395 |  |
          *
396 |  |
          * This is supposed to be used by the administrator to change the forgotten
397 |  |
          * or compromised passwords. Certain implementatations of this feature
398 |  |
          * would require adminstrative level access to the authenticating
399 |  |
          * server / program.
400 |  |
          *
401 |  |
          * @param user an User to change password for.
402 |  |
          * @param password the new password.
403 |  |
          * @exception UnknownEntityException if the user's record does not
404 |  |
          *            exist in the database.
405 |  |
          * @exception DataBackendException Error accessing the data backend.
406 |  |
          */
407 |  |
         public void forcePassword(User user, String password)
408 |  |
                 throws UnknownEntityException, DataBackendException
409 |  |
         {
410 | 0 |
             throw new DataBackendException(
411 |  |
                     "The method forcePassword has no implementation.");
412 |  |
         }
413 |  |
414 |  |
         /**
415 |  |
          * Creates new user account with specified attributes.
416 |  |
          *
417 |  |
          * @param user the object describing account to be created.
418 |  |
          * @param initialPassword Not used yet.
419 |  |
          * @throws DataBackendException Error accessing the data backend.
420 |  |
          * @throws EntityExistsException if the user account already exists.
421 |  |
          */
422 |  |
         public void createAccount(User user, String initialPassword)
423 |  |
                 throws EntityExistsException, DataBackendException
424 |  |
         {
425 | 0 |
             if (accountExists(user))
426 |  |
             {
427 | 0 |
                 throw new EntityExistsException("The account '"
428 |  |
                         + user.getName() + "' already exist");
429 |  |
             }
430 |  |
431 |  |
             try
432 |  |
             {
433 | 0 |
                 LDAPUser ldapUser = (LDAPUser) user;
434 | 0 |
                 Attributes attrs = ldapUser.getLDAPAttributes();
435 | 0 |
                 String name = ldapUser.getDN();
436 |  |
437 | 0 |
                 DirContext ctx = bindAsAdmin();
438 |  |
439 | 0 |
                 ctx.bind(name, null, attrs);
440 |  |
             }
441 | 0 |
             catch (NamingException ex)
442 |  |
             {
443 | 0 |
                 throw new DataBackendException("NamingException caught", ex);
444 | 0 |
             }
445 | 0 |
         }
446 |  |
447 |  |
         /**
448 |  |
          * Removes an user account from the system.
449 |  |
          *
450 |  |
          * @param user the object describing the account to be removed.
451 |  |
          * @throws DataBackendException Error accessing the data backend.
452 |  |
          * @throws UnknownEntityException if the user account is not present.
453 |  |
          */
454 |  |
         public void removeAccount(User user)
455 |  |
                 throws UnknownEntityException, DataBackendException
456 |  |
         {
457 | 0 |
             if (!accountExists(user))
458 |  |
             {
459 | 0 |
                 throw new UnknownEntityException("The account '"
460 |  |
                         + user.getName() + "' does not exist");
461 |  |
             }
462 |  |
463 |  |
             try
464 |  |
             {
465 | 0 |
                 LDAPUser ldapUser = (LDAPUser) user;
466 | 0 |
                 String name = ldapUser.getDN();
467 |  |
468 | 0 |
                 DirContext ctx = bindAsAdmin();
469 |  |
470 | 0 |
                 ctx.unbind(name);
471 |  |
             }
472 | 0 |
             catch (NamingException ex)
473 |  |
             {
474 | 0 |
                 throw new DataBackendException("NamingException caught", ex);
475 | 0 |
             }
476 | 0 |
         }
477 |  |
478 |  |
         /**
479 |  |
          * Bind as the admin user.
480 |  |
          *
481 |  |
          * @throws NamingException when an error occurs with the named server.
482 |  |
          * @return a new DirContext.
483 |  |
          */
484 |  |
         public static DirContext bindAsAdmin()
485 |  |
                 throws NamingException
486 |  |
         {
487 | 0 |
             String adminUser = LDAPSecurityConstants.getAdminUsername();
488 | 0 |
             String adminPassword = LDAPSecurityConstants.getAdminPassword();
489 |  |
490 | 0 |
             return bind(adminUser, adminPassword);
491 |  |
         }
492 |  |
493 |  |
         /**
494 |  |
          * Creates an initial context.
495 |  |
          *
496 |  |
          * @param username admin username supplied in TRP.
497 |  |
          * @param password admin password supplied in TRP
498 |  |
          * @throws NamingException when an error occurs with the named server.
499 |  |
          * @return a new DirContext.
500 |  |
          */
501 |  |
         public static DirContext bind(String username, String password)
502 |  |
                 throws NamingException
503 |  |
         {
504 | 0 |
             String host = LDAPSecurityConstants.getLDAPHost();
505 | 0 |
             String port = LDAPSecurityConstants.getLDAPPort();
506 | 0 |
             String providerURL = "ldap://" + host + ":" + port;
507 | 0 |
             String ldapProvider = LDAPSecurityConstants.getLDAPProvider();
508 | 0 |
             String authentication = LDAPSecurityConstants.getLDAPAuthentication();
509 |  |
510 |  |
             /*
511 |  |
              * creating an initial context using Sun's client
512 |  |
              * LDAP Provider.
513 |  |
              */
514 | 0 |
             Hashtable env = new Hashtable();
515 |  |
516 | 0 |
             env.put(Context.INITIAL_CONTEXT_FACTORY, ldapProvider);
517 | 0 |
             env.put(Context.PROVIDER_URL, providerURL);
518 | 0 |
             env.put(Context.SECURITY_AUTHENTICATION, authentication);
519 | 0 |
             env.put(Context.SECURITY_PRINCIPAL, username);
520 | 0 |
             env.put(Context.SECURITY_CREDENTIALS, password);
521 |  |
522 | 0 |
             DirContext ctx = new javax.naming.directory.InitialDirContext(env);
523 |  |
524 | 0 |
             return ctx;
525 |  |
         }
526 |  |
527 |  |
         /**
528 |  |
          * Create a new instance of the LDAP User according to the value
529 |  |
          * configured in TurbineResources.properties.
530 |  |
          * @return a new instance of the LDAP User.
531 |  |
          * @throws DataBackendException if there is an error creating the
532 |  |
          */
533 |  |
         private LDAPUser createLDAPUser()
534 |  |
                 throws DataBackendException
535 |  |
         {
536 |  |
             try
537 |  |
             {
538 | 0 |
                 return (LDAPUser) TurbineSecurity.getUserInstance();
539 |  |
             }
540 | 0 |
             catch (ClassCastException ex)
541 |  |
             {
542 | 0 |
                 throw new DataBackendException("ClassCastException:", ex);
543 |  |
             }
544 | 0 |
             catch (UnknownEntityException ex)
545 |  |
             {
546 | 0 |
                 throw new DataBackendException("UnknownEntityException:", ex);
547 |  |
             }
548 |  |
         }
549 |  |
550 |  |
     }