##### Coverage Report - org.apache.turbine.services.security.torque.TorqueUserManager

Classes in this File | Line Coverage | Branch Coverage | Complexity
TorqueUserManager |
0% | 0/100
0% | 0/40
| 4.2;4,2

1 |  |
     package org.apache.turbine.services.security.torque;
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.Iterator;
23 |  |
     import java.util.List;
24 |  |
25 |  |
     import org.apache.commons.configuration.Configuration;
26 |  |
     import org.apache.commons.lang.StringUtils;
27 |  |
     import org.apache.torque.om.Persistent;
28 |  |
     import org.apache.torque.util.Criteria;
29 |  |
     import org.apache.turbine.om.security.User;
30 |  |
     import org.apache.turbine.services.InitializationException;
31 |  |
     import org.apache.turbine.services.security.TurbineSecurity;
32 |  |
     import org.apache.turbine.services.security.UserManager;
33 |  |
     import org.apache.turbine.util.security.DataBackendException;
34 |  |
     import org.apache.turbine.util.security.EntityExistsException;
35 |  |
     import org.apache.turbine.util.security.PasswordMismatchException;
36 |  |
     import org.apache.turbine.util.security.UnknownEntityException;
37 |  |
38 |  |
     /**
39 |  |
      * An UserManager performs {@link org.apache.turbine.om.security.User}
40 |  |
      * objects related tasks on behalf of the
41 |  |
      * {@link org.apache.turbine.services.security.BaseSecurityService}.
42 |  |
      *
43 |  |
      * This implementation uses a relational database for storing user data. It
44 |  |
      * expects that the User interface implementation will be castable to
45 |  |
      * {@link org.apache.torque.om.BaseObject}.
46 |  |
      *
47 |  |
      * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
48 |  |
      * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
49 |  |
      * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
50 |  |
      * @author <a href="mailto:cberry@gluecode.com">Craig D. Berry</a>
51 |  |
      * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
52 |  |
      * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
53 |  |
      * @version $Id: TorqueUserManager.java 1096130 2011-04-23 10:37:19Z ludwig $
54 |  |
      */
55 | 0 |
     public class TorqueUserManager
56 |  |
         implements UserManager
57 |  |
     {
58 |  |
         /**
59 |  |
          * Initializes the UserManager
60 |  |
          *
61 |  |
          * @param conf A Configuration object to init this Manager
62 |  |
          *
63 |  |
          * @throws InitializationException When something went wrong.
64 |  |
          */
65 |  |
         public void init(Configuration conf)
66 |  |
             throws InitializationException
67 |  |
         {
68 | 0 |
             UserPeerManager.init(conf);
69 | 0 |
         }
70 |  |
71 |  |
         /**
72 |  |
          * Check whether a specified user's account exists.
73 |  |
          *
74 |  |
          * The login name is used for looking up the account.
75 |  |
          *
76 |  |
          * @param user The user to be checked.
77 |  |
          * @return true if the specified account exists
78 |  |
          * @throws DataBackendException if there was an error accessing
79 |  |
          *         the data backend.
80 |  |
          */
81 |  |
         public boolean accountExists(User user)
82 |  |
             throws DataBackendException
83 |  |
         {
84 | 0 |
             return accountExists(user.getName());
85 |  |
         }
86 |  |
87 |  |
         /**
88 |  |
          * Check whether a specified user's account exists.
89 |  |
          *
90 |  |
          * The login name is used for looking up the account.
91 |  |
          *
92 |  |
          * @param userName The name of the user to be checked.
93 |  |
          * @return true if the specified account exists
94 |  |
          * @throws DataBackendException if there was an error accessing
95 |  |
          *         the data backend.
96 |  |
          */
97 |  |
         public boolean accountExists(String userName)
98 |  |
             throws DataBackendException
99 |  |
         {
100 | 0 |
             Criteria criteria = new Criteria();
101 | 0 |
             criteria.add(UserPeerManager.getNameColumn(), userName);
102 |  |
             List users;
103 |  |
             try
104 |  |
             {
105 | 0 |
                 users = UserPeerManager.doSelect(criteria);
106 |  |
             }
107 | 0 |
             catch (Exception e)
108 |  |
             {
109 | 0 |
                 throw new DataBackendException(
110 |  |
                     "Failed to check account's presence", e);
111 | 0 |
             }
112 | 0 |
             if (users.size() > 1)
113 |  |
             {
114 | 0 |
                 throw new DataBackendException(
115 |  |
                     "Multiple Users with same username '" + userName + "'");
116 |  |
             }
117 | 0 |
             return (users.size() == 1);
118 |  |
         }
119 |  |
120 |  |
         /**
121 |  |
          * Retrieve a user from persistent storage using username as the
122 |  |
          * key.
123 |  |
          *
124 |  |
          * @param userName the name of the user.
125 |  |
          * @return an User object.
126 |  |
          * @exception UnknownEntityException if the user's account does not
127 |  |
          *            exist in the database.
128 |  |
          * @exception DataBackendException if there is a problem accessing the
129 |  |
          *            storage.
130 |  |
          */
131 |  |
         public User retrieve(String userName)
132 |  |
             throws UnknownEntityException, DataBackendException
133 |  |
         {
134 | 0 |
             Criteria criteria = new Criteria();
135 | 0 |
             criteria.add(UserPeerManager.getNameColumn(), userName);
136 |  |
137 | 0 |
             List users = retrieveList(criteria);
138 |  |
139 | 0 |
             if (users.size() > 1)
140 |  |
             {
141 | 0 |
                 throw new DataBackendException(
142 |  |
                     "Multiple Users with same username '" + userName + "'");
143 |  |
             }
144 | 0 |
             if (users.size() == 1)
145 |  |
             {
146 | 0 |
                 return (User) users.get(0);
147 |  |
             }
148 | 0 |
             throw new UnknownEntityException("Unknown user '" + userName + "'");
149 |  |
         }
150 |  |
151 |  |
         /**
152 |  |
          * Retrieve a user from persistent storage using the primary key
153 |  |
          *
154 |  |
          * @param key The primary key object
155 |  |
          * @return an User object.
156 |  |
          * @throws UnknownEntityException if the user's record does not
157 |  |
          *         exist in the database.
158 |  |
          * @throws DataBackendException if there is a problem accessing the
159 |  |
          *         storage.
160 |  |
          */
161 |  |
         public User retrieveById(Object key)
162 |  |
                 throws UnknownEntityException, DataBackendException
163 |  |
         {
164 | 0 |
             Criteria criteria = new Criteria();
165 | 0 |
             criteria.add(UserPeerManager.getIdColumn(), key);
166 |  |
167 | 0 |
             List users = retrieveList(criteria);
168 |  |
169 | 0 |
             if (users.size() > 1)
170 |  |
             {
171 | 0 |
                 throw new DataBackendException(
172 |  |
                     "Multiple Users with same unique Key '" + String.valueOf(key) + "'");
173 |  |
             }
174 | 0 |
             if (users.size() == 1)
175 |  |
             {
176 | 0 |
                 return (User) users.get(0);
177 |  |
             }
178 | 0 |
             throw new UnknownEntityException("Unknown user with key '" + String.valueOf(key) + "'");
179 |  |
         }
180 |  |
181 |  |
         /**
182 |  |
          * @deprecated Use <a href="#retrieveList">retrieveList</a> instead.
183 |  |
          *
184 |  |
          * @param criteria The criteria of selection.
185 |  |
          * @return a List of users meeting the criteria.
186 |  |
          * @throws DataBackendException if there is a problem accessing the
187 |  |
          *         storage.
188 |  |
          */
189 |  |
         public User[] retrieve(Object criteria)
190 |  |
             throws DataBackendException
191 |  |
         {
192 | 0 |
             return (User [])retrieveList(criteria).toArray(new User[0]);
193 |  |
         }
194 |  |
195 |  |
         /**
196 |  |
          * Retrieve a list of users that meet the specified criteria.
197 |  |
          *
198 |  |
          * As the keys for the criteria, you should use the constants that
199 |  |
          * are defined in {@link User} interface, plus the names
200 |  |
          * of the custom attributes you added to your user representation
201 |  |
          * in the data storage. Use verbatim names of the attributes -
202 |  |
          * without table name prefix in case of Torque implementation.
203 |  |
          *
204 |  |
          * @param criteria The criteria of selection.
205 |  |
          * @return a List of users meeting the criteria.
206 |  |
          * @throws DataBackendException if there is a problem accessing the
207 |  |
          *         storage.
208 |  |
          */
209 |  |
         public List retrieveList(Object criteria)
210 |  |
             throws DataBackendException
211 |  |
         {
212 | 0 |
             if (criteria instanceof Criteria)
213 |  |
             {
214 | 0 |
                 Criteria c = (Criteria)criteria;
215 | 0 |
                 for (Iterator keys = c.keySet().iterator(); keys.hasNext(); )
216 |  |
                 {
217 | 0 |
                     String key = (String) keys.next();
218 |  |
219 |  |
                     // set the table name for all attached criterion
220 | 0 |
                     Criteria.Criterion[] criterion =
221 |  |
                         c.getCriterion(key).getAttachedCriterion();
222 |  |
223 | 0 |
                     for (int i = 0; i < criterion.length; i++)
224 |  |
                     {
225 | 0 |
                         if (StringUtils.isEmpty(criterion[i].getTable()))
226 |  |
                         {
227 | 0 |
                             criterion[i].setTable(UserPeerManager.getTableName());
228 |  |
                         }
229 |  |
                     }
230 | 0 |
                 }
231 | 0 |
                 List users = null;
232 |  |
                 try
233 |  |
                 {
234 | 0 |
                     users = UserPeerManager.doSelect(c);
235 |  |
                 }
236 | 0 |
                 catch (Exception e)
237 |  |
                 {
238 | 0 |
                     throw new DataBackendException("Failed to retrieve users", e);
239 | 0 |
                 }
240 | 0 |
                 return users;
241 |  |
             }
242 |  |
             else
243 |  |
             {
244 | 0 |
                 throw new DataBackendException("Failed to retrieve users with invalid criteria");
245 |  |
             }
246 |  |
         }
247 |  |
248 |  |
         /**
249 |  |
          * Retrieve a user from persistent storage using username as the
250 |  |
          * key, and authenticate the user. The implementation may chose
251 |  |
          * to authenticate to the server as the user whose data is being
252 |  |
          * retrieved.
253 |  |
          *
254 |  |
          * @param userName the name of the user.
255 |  |
          * @param password the user supplied password.
256 |  |
          * @return an User object.
257 |  |
          * @exception PasswordMismatchException if the supplied password was
258 |  |
          *            incorrect.
259 |  |
          * @exception UnknownEntityException if the user's account does not
260 |  |
          *            exist in the database.
261 |  |
          * @exception DataBackendException if there is a problem accessing the
262 |  |
          *            storage.
263 |  |
          */
264 |  |
         public User retrieve(String userName, String password)
265 |  |
             throws PasswordMismatchException, UnknownEntityException,
266 |  |
                    DataBackendException
267 |  |
         {
268 | 0 |
             User user = retrieve(userName);
269 | 0 |
             authenticate(user, password);
270 | 0 |
             return user;
271 |  |
         }
272 |  |
273 |  |
         /**
274 |  |
          * Save an User object to persistent storage. User's account is
275 |  |
          * required to exist in the storage.
276 |  |
          *
277 |  |
          * @param user an User object to store.
278 |  |
          * @exception UnknownEntityException if the user's account does not
279 |  |
          *            exist in the database.
280 |  |
          * @exception DataBackendException if there is a problem accessing the
281 |  |
          *            storage.
282 |  |
          */
283 |  |
         public void store(User user)
284 |  |
             throws UnknownEntityException, DataBackendException
285 |  |
         {
286 | 0 |
             if (!accountExists(user))
287 |  |
             {
288 | 0 |
                 throw new UnknownEntityException("The account '" +
289 |  |
                                                  user.getName() + "' does not exist");
290 |  |
             }
291 |  |
292 |  |
             try
293 |  |
             {
294 |  |
                 // this is to mimic the old behavior of the method, the user
295 |  |
                 // should be new that is passed to this method.  It would be
296 |  |
                 // better if this was checked, but the original code did not
297 |  |
                 // care about the user's state, so we set it to be appropriate
298 | 0 |
                 ((Persistent) user).setNew(false);
299 | 0 |
                 ((Persistent) user).setModified(true);
300 | 0 |
                 ((Persistent) user).save();
301 |  |
             }
302 | 0 |
             catch (Exception e)
303 |  |
             {
304 | 0 |
                 throw new DataBackendException("Failed to save user object", e);
305 | 0 |
             }
306 | 0 |
         }
307 |  |
308 |  |
         /**
309 |  |
          * Saves User data when the session is unbound. The user account is required
310 |  |
          * to exist in the storage.
311 |  |
          *
312 |  |
          * LastLogin, AccessCounter, persistent pull tools, and any data stored
313 |  |
          * in the permData hashtable that is not mapped to a column will be saved.
314 |  |
          *
315 |  |
          * @exception UnknownEntityException if the user's account does not
316 |  |
          *            exist in the database.
317 |  |
          * @exception DataBackendException if there is a problem accessing the
318 |  |
          *            storage.
319 |  |
          */
320 |  |
         public void saveOnSessionUnbind(User user)
321 |  |
             throws UnknownEntityException, DataBackendException
322 |  |
         {
323 | 0 |
             if (!user.hasLoggedIn())
324 |  |
             {
325 | 0 |
                 return;
326 |  |
             }
327 | 0 |
             store(user);
328 | 0 |
         }
329 |  |
330 |  |
331 |  |
         /**
332 |  |
          * Authenticate an User with the specified password. If authentication
333 |  |
          * is successful the method returns nothing. If there are any problems,
334 |  |
          * exception was thrown.
335 |  |
          *
336 |  |
          * @param user an User object to authenticate.
337 |  |
          * @param password the user supplied password.
338 |  |
          * @exception PasswordMismatchException if the supplied password was
339 |  |
          *            incorrect.
340 |  |
          * @exception UnknownEntityException if the user's account does not
341 |  |
          *            exist in the database.
342 |  |
          * @exception DataBackendException if there is a problem accessing the
343 |  |
          *            storage.
344 |  |
          */
345 |  |
         public void authenticate(User user, String password)
346 |  |
             throws PasswordMismatchException, UnknownEntityException,
347 |  |
                    DataBackendException
348 |  |
         {
349 | 0 |
             if (!accountExists(user))
350 |  |
             {
351 | 0 |
                 throw new UnknownEntityException("The account '" +
352 |  |
                                                  user.getName() + "' does not exist");
353 |  |
             }
354 |  |
355 |  |
             // log.debug("Supplied Pass: " + password);
356 |  |
             // log.debug("User Pass: " + user.getPassword());
357 |  |
358 |  |
             /*
359 |  |
              * Unix crypt needs the existing, encrypted password text as
360 |  |
              * salt for checking the supplied password. So we supply it
361 |  |
              * into the checkPassword routine
362 |  |
              */
363 |  |
364 | 0 |
             if (!TurbineSecurity.checkPassword(password, user.getPassword()))
365 |  |
             {
366 | 0 |
                 throw new PasswordMismatchException("The passwords do not match");
367 |  |
             }
368 | 0 |
         }
369 |  |
370 |  |
         /**
371 |  |
          * Change the password for an User. The user must have supplied the
372 |  |
          * old password to allow the change.
373 |  |
          *
374 |  |
          * @param user an User to change password for.
375 |  |
          * @param oldPassword The old password to verify
376 |  |
          * @param newPassword The new password to set
377 |  |
          * @exception PasswordMismatchException if the supplied password was
378 |  |
          *            incorrect.
379 |  |
          * @exception UnknownEntityException if the user's account does not
380 |  |
          *            exist in the database.
381 |  |
          * @exception DataBackendException if there is a problem accessing the
382 |  |
          *            storage.
383 |  |
          */
384 |  |
         public void changePassword(User user, String oldPassword,
385 |  |
                                    String newPassword)
386 |  |
             throws PasswordMismatchException, UnknownEntityException,
387 |  |
                    DataBackendException
388 |  |
         {
389 | 0 |
             if (!accountExists(user))
390 |  |
             {
391 | 0 |
                 throw new UnknownEntityException("The account '" +
392 |  |
                                                  user.getName() + "' does not exist");
393 |  |
             }
394 |  |
395 | 0 |
             if (!TurbineSecurity.checkPassword(oldPassword, user.getPassword()))
396 |  |
             {
397 | 0 |
                 throw new PasswordMismatchException(
398 |  |
                     "The supplied old password for '" + user.getName() +
399 |  |
                     "' was incorrect");
400 |  |
             }
401 | 0 |
             user.setPassword(TurbineSecurity.encryptPassword(newPassword));
402 |  |
             // save the changes in the database imediately, to prevent the password
403 |  |
             // being 'reverted' to the old value if the user data is lost somehow
404 |  |
             // before it is saved at session's expiry.
405 | 0 |
             store(user);
406 | 0 |
         }
407 |  |
408 |  |
         /**
409 |  |
          * Forcibly sets new password for an User.
410 |  |
          *
411 |  |
          * This is supposed by the administrator to change the forgotten or
412 |  |
          * compromised passwords. Certain implementatations of this feature
413 |  |
          * would require administrative level access to the authenticating
414 |  |
          * server / program.
415 |  |
          *
416 |  |
          * @param user an User to change password for.
417 |  |
          * @param password the new password.
418 |  |
          * @exception UnknownEntityException if the user's record does not
419 |  |
          *            exist in the database.
420 |  |
          * @exception DataBackendException if there is a problem accessing the
421 |  |
          *            storage.
422 |  |
          */
423 |  |
         public void forcePassword(User user, String password)
424 |  |
             throws UnknownEntityException, DataBackendException
425 |  |
         {
426 | 0 |
             if (!accountExists(user))
427 |  |
             {
428 | 0 |
                 throw new UnknownEntityException("The account '" +
429 |  |
                                                  user.getName() + "' does not exist");
430 |  |
             }
431 | 0 |
             user.setPassword(TurbineSecurity.encryptPassword(password));
432 |  |
             // save the changes in the database immediately, to prevent the
433 |  |
             // password being 'reverted' to the old value if the user data
434 |  |
             // is lost somehow before it is saved at session's expiry.
435 | 0 |
             store(user);
436 | 0 |
         }
437 |  |
438 |  |
         /**
439 |  |
          * Creates new user account with specified attributes.
440 |  |
          *
441 |  |
          * @param user The object describing account to be created.
442 |  |
          * @param initialPassword the password for the new account
443 |  |
          * @throws DataBackendException if there was an error accessing
444 |  |
          the data backend.
445 |  |
          * @throws EntityExistsException if the user account already exists.
446 |  |
          */
447 |  |
         public void createAccount(User user, String initialPassword)
448 |  |
             throws EntityExistsException, DataBackendException
449 |  |
         {
450 | 0 |
             if(StringUtils.isEmpty(user.getName()))
451 |  |
             {
452 | 0 |
                 throw new DataBackendException("Could not create "
453 |  |
                                                + "an user with empty name!");
454 |  |
             }
455 |  |
456 | 0 |
             if (accountExists(user))
457 |  |
             {
458 | 0 |
                 throw new EntityExistsException("The account '" +
459 |  |
                                                 user.getName() + "' already exists");
460 |  |
             }
461 | 0 |
             user.setPassword(TurbineSecurity.encryptPassword(initialPassword));
462 |  |
463 |  |
             try
464 |  |
             {
465 |  |
                 // this is to mimic the old behavior of the method, the user
466 |  |
                 // should be new that is passed to this method.  It would be
467 |  |
                 // better if this was checked, but the original code did not
468 |  |
                 // care about the user's state, so we set it to be appropriate
469 | 0 |
                 ((Persistent) user).setNew(true);
470 | 0 |
                 ((Persistent) user).setModified(true);
471 | 0 |
                 ((Persistent) user).save();
472 |  |
             }
473 | 0 |
             catch (Exception e)
474 |  |
             {
475 | 0 |
                 throw new DataBackendException("Failed to create account '" +
476 |  |
                                                user.getName() + "'", e);
477 | 0 |
             }
478 | 0 |
         }
479 |  |
480 |  |
         /**
481 |  |
          * Removes an user account from the system.
482 |  |
          *
483 |  |
          * @param user the object describing the account to be removed.
484 |  |
          * @throws DataBackendException if there was an error accessing
485 |  |
          the data backend.
486 |  |
          * @throws UnknownEntityException if the user account is not present.
487 |  |
          */
488 |  |
         public void removeAccount(User user)
489 |  |
             throws UnknownEntityException, DataBackendException
490 |  |
         {
491 | 0 |
             if (!accountExists(user))
492 |  |
             {
493 | 0 |
                 throw new UnknownEntityException("The account '" +
494 |  |
                                                  user.getName() + "' does not exist");
495 |  |
             }
496 | 0 |
             Criteria criteria = new Criteria();
497 | 0 |
             criteria.add(UserPeerManager.getNameColumn(), user.getName());
498 |  |
             try
499 |  |
             {
500 | 0 |
                 UserPeerManager.doDelete(criteria);
501 |  |
             }
502 | 0 |
             catch (Exception e)
503 |  |
             {
504 | 0 |
                 throw new DataBackendException("Failed to remove account '" +
505 |  |
                                                user.getName() + "'", e);
506 | 0 |
             }
507 | 0 |
         }
508 |  |
     }