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,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  
 }