1 package org.apache.turbine.services.security;
2
3
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 */
22
23
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.apache.commons.configuration.Configuration;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.fulcrum.factory.FactoryService;
31 import org.apache.fulcrum.security.acl.AccessControlList;
32 import org.apache.fulcrum.security.model.turbine.TurbineUserManager;
33 import org.apache.fulcrum.security.model.turbine.entity.TurbineUser;
34 import org.apache.fulcrum.security.util.DataBackendException;
35 import org.apache.fulcrum.security.util.EntityExistsException;
36 import org.apache.fulcrum.security.util.PasswordMismatchException;
37 import org.apache.fulcrum.security.util.UnknownEntityException;
38 import org.apache.fulcrum.security.util.UserSet;
39 import org.apache.turbine.om.security.TurbineUserDelegate;
40 import org.apache.turbine.om.security.User;
41 import org.apache.turbine.services.InitializationException;
42 import org.apache.turbine.services.ServiceManager;
43 import org.apache.turbine.services.TurbineServices;
44 import org.apache.turbine.util.ObjectUtils;
45
46 /**
47 * Default user manager.
48 *
49 * The user manager wraps Fulcrum security user objects into
50 * Turbine-specific ones.
51 *
52 *
53 * <ol><li>either in a method with the same name (and very similar signature)
54 * <li>or mapped to method names as listed below:
55 *
56 * <ul>
57 * <li>method(s) in this manager -> Fulcrum manager method(s)
58 * <li>{@link #createAccount(User, String)}createAccount -> addUser(User, String)
59 * <li>{@link #removeAccount(User)} -> removeUser(User)
60 * <li>{@link #store(User)} -> saveUser(User)
61 * <li>{@link #retrieve(String)} and {@link #retrieve(String, String)} -> getUser(String), getUser(String, String)
62 * <li>{@link #retrieveList(Object)} ->getAllUsers()
63 * <li>{@link #accountExists(String)}, {@link #accountExists(User)} -> checkExists(String), checkExists(User)
64 *
65 * In this way all public methods of Fulcrum {@link TurbineUserManager} interface are used by reference of the Fulcrum delegate {@link #umDelegate}
66 * and wrapped by this manager.
67 *
68 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
69 * @version $Id: PassiveUserManager.java 1096130 2011-04-23 10:37:19Z ludwig $
70 */
71 public class DefaultUserManager implements UserManager
72 {
73 /** Fulcrum user manager instance to delegate to */
74 private TurbineUserManager umDelegate = null;
75
76 private FactoryService factoryService = null;
77
78 /** The user class, which the UserManager uses as wrapper for Fulcrum {@link TurbineUser} */
79 private String userWrapperClass;
80
81
82 /** Logging */
83 private static Log log = LogFactory.getLog(DefaultUserManager.class);
84
85 /**
86 * Wrap a Fulcrum user object into a Turbine user object
87 *
88 * @param user the user object to delegate to
89 *
90 * @return the wrapped object
91 */
92 protected <U extends User> U wrap(TurbineUser user)
93 {
94 // U u = (U)new DefaultUserImpl(user);
95 @SuppressWarnings("unchecked")
96 U u = (U) getUserWrapper(user);
97 return u;
98 }
99
100 /**
101 * Exception could be ignored, as it is tested before in {@link #init(Configuration)}.
102 *
103 * @param user the user object to wrap
104 * @return instance extending {@link User}
105 */
106 @SuppressWarnings("unchecked")
107 public <U extends User> U getUserWrapper(TurbineUser user)
108 {
109 try
110 {
111 Object params[] = new Object[] { user };
112 String signature[] = new String[] { TurbineUser.class.getName() };
113 return (U) factoryService.getInstance(getUserWrapperClass(), params, signature);
114 }
115 catch (Exception e)
116 {
117 log.error("after init/late instantiation exception", e);
118 return null; // (U)new DefaultUserImpl(user);
119 }
120 }
121
122 /**
123 * Get the wrapper class for user objects
124 *
125 * @return the wrapper class name
126 */
127 public String getUserWrapperClass()
128 {
129 return userWrapperClass;
130 }
131
132 /**
133 * Set the wrapper class for user objects
134 *
135 * @param userWrapperClass2 the wrapper class name
136 */
137 public void setUserWrapperClass(String userWrapperClass2)
138 {
139 userWrapperClass = userWrapperClass2;
140 }
141
142 /**
143 * Initializes the UserManager
144 *
145 * @param conf A Configuration object to init this Manager
146 */
147 @Override
148 public void init(Configuration conf) throws InitializationException
149 {
150 ServiceManager manager = TurbineServices.getInstance();
151 this.umDelegate = (TurbineUserManager)manager.getService(TurbineUserManager.ROLE);
152
153 String userWrapperClass = conf.getString(
154 SecurityService.USER_WRAPPER_KEY,
155 SecurityService.USER_WRAPPER_DEFAULT);
156
157 // String userClass = conf.getString(
158 // SecurityService.USER_KEY,
159 // SecurityService.USER_DEFAULT);
160
161 try
162 {
163 factoryService = (FactoryService)manager.getService(FactoryService.ROLE);
164
165 // check instantiation
166
167 // should provide default constructor
168 TurbineUser turbineUser = umDelegate.getUserInstance();
169 //(TurbineUser) factoryService.getInstance(userClass);
170 Object params[] = new Object[] { turbineUser };
171 String signature[] = new String[] { TurbineUser.class.getName() };
172
173 // Just check if exceptions would occur
174 factoryService.getInstance(userWrapperClass, params, signature);
175
176 this.setUserWrapperClass(userWrapperClass);
177 }
178 catch (Exception e)
179 {
180 throw new InitializationException("Failed to instantiate user wrapper class", e);
181 }
182
183 }
184
185
186 /**
187 * Check whether a specified user's account exists.
188 *
189 * The login name is used for looking up the account.
190 *
191 * @param user The user to be checked.
192 * @return true if the specified account exists
193 * @throws DataBackendException if there was an error accessing the data backend.
194 */
195 @Override
196 public boolean accountExists(User user)
197 throws DataBackendException
198 {
199 if (user == null) {
200 return false;
201 }
202 return umDelegate.checkExists(user.getUserDelegate());
203 }
204
205 /**
206 * Check whether a specified user's account exists.
207 *
208 * The login name is used for looking up the account.
209 *
210 * @param userName The name of the user to be checked.
211 * @return true if the specified account exists
212 * @throws DataBackendException if there was an error accessing the data backend.
213 */
214 @Override
215 public boolean accountExists(String userName)
216 throws DataBackendException
217 {
218 return umDelegate.checkExists(userName);
219 }
220
221 /**
222 * Retrieve a user from persistent storage using username as the
223 * key.
224 *
225 * @param username the name of the user.
226 * @return an User object.
227 * @throws UnknownEntityException if the user's record does not
228 * exist in the database.
229 * @throws DataBackendException if there is a problem accessing the
230 * storage.
231 */
232 @Override
233 public <U extends User> U retrieve(String username)
234 throws UnknownEntityException, DataBackendException
235 {
236 TurbineUser u = umDelegate.getUser(username);
237 return wrap(u);
238 }
239
240 /**
241 * Retrieve a set of users that meet the specified criteria.
242 *
243 * As the keys for the criteria, you should use the constants that
244 * are defined in {@link User} interface, plus the names
245 * of the custom attributes you added to your user representation
246 * in the data storage. Use verbatim names of the attributes -
247 * without table name prefix in case of DB implementation.
248 *
249 * @param criteria The criteria of selection.
250 * @return a List of users meeting the criteria.
251 * @throws DataBackendException if there is a problem accessing the
252 * storage.
253 */
254 @Override
255 public List<? extends User> retrieveList(Object criteria)
256 throws DataBackendException
257 {
258 UserSet<org.apache.fulcrum.security.entity.User> uset = umDelegate.getAllUsers();
259 List<User> userList = new ArrayList<User>();
260
261 for (org.apache.fulcrum.security.entity.User u : uset)
262 {
263 TurbineUser tu = (TurbineUser)u;
264 userList.add(wrap(tu));
265 }
266
267 return userList;
268 }
269
270 /**
271 * Retrieve a user from persistent storage using username as the
272 * key, and authenticate the user. The implementation may chose
273 * to authenticate to the server as the user whose data is being
274 * retrieved.
275 *
276 * @param username the name of the user.
277 * @param password the user supplied password.
278 * @return an User object.
279 * @throws PasswordMismatchException if the supplied password was
280 * incorrect.
281 * @throws UnknownEntityException if the user's record does not
282 * exist in the database.
283 * @throws DataBackendException if there is a problem accessing the
284 * storage.
285 */
286 @Override
287 public <U extends User> U retrieve(String username, String password)
288 throws PasswordMismatchException, UnknownEntityException,
289 DataBackendException
290 {
291 TurbineUser u = umDelegate.getUser(username, password);
292 return wrap(u);
293 }
294
295 /**
296 * Save an User object to persistent storage. User's record is
297 * required to exist in the storage.
298 *
299 * @param user an User object to store.
300 * @throws UnknownEntityException if the user's record does not
301 * exist in the database.
302 * @throws DataBackendException if there is a problem accessing the
303 * storage.
304 */
305 @Override
306 public void store(User user)
307 throws UnknownEntityException, DataBackendException
308 {
309 if (user == null) {
310 throw new UnknownEntityException("user is null");
311 }
312 try
313 {
314 user.setObjectdata(ObjectUtils.serializeMap(user.getPermStorage()));
315 }
316 catch (Exception e)
317 {
318 throw new DataBackendException("Could not serialize permanent storage", e);
319 }
320
321 umDelegate.saveUser(((TurbineUserDelegate)user).getUserDelegate());
322 }
323
324 /**
325 * Saves User data when the session is unbound. The user account is required
326 * to exist in the storage.
327 *
328 * LastLogin, AccessCounter, persistent pull tools, and any data stored
329 * in the permData hashtable that is not mapped to a column will be saved.
330 *
331 * @throws UnknownEntityException if the user's account does not
332 * exist in the database.
333 * @throws DataBackendException if there is a problem accessing the
334 * storage.
335 */
336 @Override
337 public void saveOnSessionUnbind(User user)
338 throws UnknownEntityException, DataBackendException
339 {
340 store(user);
341 }
342
343 /**
344 * Authenticate an User with the specified password. If authentication
345 * is successful the method returns nothing. If there are any problems,
346 * exception was thrown.
347 *
348 * @param user an User object to authenticate.
349 * @param password the user supplied password.
350 * @throws PasswordMismatchException if the supplied password was
351 * incorrect.
352 * @throws UnknownEntityException if the user's record does not
353 * exist in the database.
354 * @throws DataBackendException if there is a problem accessing the
355 * storage.
356 */
357 @Override
358 public void authenticate(User user, String password)
359 throws PasswordMismatchException, UnknownEntityException,
360 DataBackendException
361 {
362 umDelegate.authenticate(user, password);
363 }
364
365 /**
366 * Creates new user account with specified attributes.
367 *
368 * @param user the object describing account to be created.
369 * @param initialPassword The password to use for the object creation
370 *
371 * @throws DataBackendException if there was an error accessing the data backend.
372 * @throws EntityExistsException if the user account already exists.
373 */
374 @Override
375 public void createAccount(User user, String initialPassword)
376 throws UnknownEntityException, EntityExistsException, DataBackendException
377 {
378 if (user == null) {
379 throw new UnknownEntityException("user is null");
380 }
381 umDelegate.addUser(user.getUserDelegate(), initialPassword);
382 }
383
384 /**
385 * Removes an user account from the system.
386 *
387 * @param user the object describing the account to be removed.
388 * @throws DataBackendException if there was an error accessing the data backend.
389 * @throws UnknownEntityException if the user account is not present.
390 */
391 @Override
392 public void removeAccount(User user)
393 throws UnknownEntityException, DataBackendException
394 {
395 if (user == null) {
396 throw new UnknownEntityException("user is null");
397 }
398 umDelegate.removeUser(user.getUserDelegate());
399 }
400
401 /**
402 * Change the password for an User.
403 *
404 * @param user an User to change password for.
405 * @param oldPassword the current password supplied by the user.
406 * @param newPassword the current password requested by the user.
407 * @throws PasswordMismatchException if the supplied password was
408 * incorrect.
409 * @throws UnknownEntityException if the user's record does not
410 * exist in the database.
411 * @throws DataBackendException if there is a problem accessing the
412 * storage.
413 */
414 @Override
415 public void changePassword(User user, String oldPassword,
416 String newPassword)
417 throws PasswordMismatchException, UnknownEntityException,
418 DataBackendException
419 {
420 if (user == null) {
421 throw new UnknownEntityException("user is null");
422 }
423 umDelegate.changePassword(
424 ((TurbineUserDelegate)user).getUserDelegate(),
425 oldPassword, newPassword);
426 }
427
428 /**
429 * Forcibly sets new password for an User.
430 *
431 * This is supposed by the administrator to change the forgotten or
432 * compromised passwords. Certain implementations of this feature
433 * would require administrative level access to the authenticating
434 * server / program.
435 *
436 * @param user an User to change password for.
437 * @param password the new password.
438 * @throws UnknownEntityException if the user's record does not
439 * exist in the database.
440 * @throws DataBackendException if there is a problem accessing the
441 * storage.
442 */
443 @Override
444 public void forcePassword(User user, String password)
445 throws UnknownEntityException, DataBackendException
446 {
447 if (user == null) {
448 throw new UnknownEntityException("user is null");
449 }
450 umDelegate.forcePassword(user.getUserDelegate(), password);
451 }
452
453 /**
454 * Constructs an User object to represent an anonymous user of the
455 * application.
456 *
457 * @return An anonymous Turbine User.
458 * @throws UnknownEntityException
459 * if the anonymous User object couldn't be constructed.
460 */
461 @Override
462 public <U extends User> U getAnonymousUser() throws UnknownEntityException
463 {
464 TurbineUser u = umDelegate.getAnonymousUser();
465 return wrap(u);
466 }
467
468 /**
469 * Checks whether a passed user object matches the anonymous user pattern
470 * according to the configured user manager
471 *
472 * @param u a user object
473 *
474 * @return True if this is an anonymous user
475 *
476 */
477 @Override
478 public boolean isAnonymousUser(User u)
479 {
480 return umDelegate.isAnonymousUser(u);
481 }
482
483 /**
484 * Construct a blank User object.
485 *
486 * This method calls getUserClass, and then creates a new object using the
487 * default constructor.
488 *
489 * @return an object implementing User interface.
490 * @throws DataBackendException
491 * if the object could not be instantiated.
492 */
493 @Override
494 public <U extends User> U getUserInstance() throws DataBackendException
495 {
496 TurbineUser u = umDelegate.getUserInstance();
497 return wrap(u);
498 }
499
500 /**
501 * Construct a blank User object.
502 *
503 * This method calls getUserClass, and then creates a new object using the
504 * default constructor.
505 *
506 * @param userName
507 * The name of the user.
508 *
509 * @return an object implementing User interface.
510 * @throws DataBackendException
511 * if the object could not be instantiated.
512 */
513 @Override
514 public <U extends User> U getUserInstance(String userName) throws DataBackendException
515 {
516 TurbineUser u = umDelegate.getUserInstance(userName);
517 return wrap(u);
518 }
519
520 /**
521 * Return a Class object representing the system's chosen implementation of
522 * of ACL interface.
523 *
524 * @return systems's chosen implementation of ACL interface.
525 * @throws UnknownEntityException
526 * if the implementation of ACL interface could not be
527 * determined, or does not exist.
528 */
529 @Override
530 public <A extends AccessControlList> A getACL(User user) throws UnknownEntityException
531 {
532 if (user == null) {
533 throw new UnknownEntityException("user is null");
534 }
535 return umDelegate.getACL(user.getUserDelegate());
536 }
537 }