Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
BaseSecurityService |
|
| 2.391304347826087;2,391 |
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.Map; | |
25 | ||
26 | import javax.servlet.ServletConfig; | |
27 | ||
28 | import org.apache.commons.configuration.Configuration; | |
29 | import org.apache.commons.lang.StringUtils; | |
30 | import org.apache.commons.logging.Log; | |
31 | import org.apache.commons.logging.LogFactory; | |
32 | import org.apache.fulcrum.crypto.CryptoAlgorithm; | |
33 | import org.apache.fulcrum.crypto.CryptoService; | |
34 | import org.apache.fulcrum.factory.FactoryService; | |
35 | import org.apache.turbine.om.security.Group; | |
36 | import org.apache.turbine.om.security.Permission; | |
37 | import org.apache.turbine.om.security.Role; | |
38 | import org.apache.turbine.om.security.User; | |
39 | import org.apache.turbine.services.InitializationException; | |
40 | import org.apache.turbine.services.ServiceManager; | |
41 | import org.apache.turbine.services.TurbineBaseService; | |
42 | import org.apache.turbine.services.TurbineServices; | |
43 | import org.apache.turbine.util.security.AccessControlList; | |
44 | import org.apache.turbine.util.security.DataBackendException; | |
45 | import org.apache.turbine.util.security.EntityExistsException; | |
46 | import org.apache.turbine.util.security.GroupSet; | |
47 | import org.apache.turbine.util.security.PasswordMismatchException; | |
48 | import org.apache.turbine.util.security.PermissionSet; | |
49 | import org.apache.turbine.util.security.RoleSet; | |
50 | import org.apache.turbine.util.security.UnknownEntityException; | |
51 | ||
52 | /** | |
53 | * This is a common subset of SecurityService implementation. | |
54 | * | |
55 | * Provided functionality includes: | |
56 | * <ul> | |
57 | * <li> methods for retrieving User objects, that delegates functionality | |
58 | * to the pluggable implementations of the User interface. | |
59 | * <li> synchronization mechanism for methods reading/modifying the security | |
60 | * information, that guarantees that multiple threads may read the | |
61 | * information concurrently, but threads that modify the information | |
62 | * acquires exclusive access. | |
63 | * <li> implementation of convenience methods for retrieving security entities | |
64 | * that maintain in-memory caching of objects for fast access. | |
65 | * </ul> | |
66 | * | |
67 | * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a> | |
68 | * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> | |
69 | * @author <a href="mailto:marco@intermeta.de">Marco Knüttel</a> | |
70 | * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> | |
71 | * @version $Id: BaseSecurityService.java 1096130 2011-04-23 10:37:19Z ludwig $ | |
72 | */ | |
73 | 20 | public abstract class BaseSecurityService |
74 | extends TurbineBaseService | |
75 | implements SecurityService | |
76 | { | |
77 | /** The number of threads concurrently reading security information */ | |
78 | 20 | private int readerCount = 0; |
79 | ||
80 | /** The instance of UserManager the SecurityService uses */ | |
81 | 20 | private UserManager userManager = null; |
82 | ||
83 | /** The class of User the SecurityService uses */ | |
84 | 20 | private Class userClass = null; |
85 | ||
86 | /** The class of Group the SecurityService uses */ | |
87 | 20 | private Class groupClass = null; |
88 | ||
89 | /** The class of Permission the SecurityService uses */ | |
90 | 20 | private Class permissionClass = null; |
91 | ||
92 | /** The class of Role the SecurityService uses */ | |
93 | 20 | private Class roleClass = null; |
94 | ||
95 | /** The class of ACL the SecurityService uses */ | |
96 | 20 | private Class aclClass = null; |
97 | ||
98 | /** A factory to construct ACL Objects */ | |
99 | 20 | private FactoryService aclFactoryService = null; |
100 | ||
101 | /** | |
102 | * The Group object that represents the <a href="#global">global group</a>. | |
103 | */ | |
104 | 20 | private static Group globalGroup = null; |
105 | ||
106 | /** Logging */ | |
107 | 20 | private static Log log = LogFactory.getLog(BaseSecurityService.class); |
108 | ||
109 | /** | |
110 | * This method provides client-side encryption of passwords. | |
111 | * | |
112 | * If <code>secure.passwords</code> are enabled in TurbineResources, | |
113 | * the password will be encrypted, if not, it will be returned unchanged. | |
114 | * The <code>secure.passwords.algorithm</code> property can be used | |
115 | * to chose which digest algorithm should be used for performing the | |
116 | * encryption. <code>SHA</code> is used by default. | |
117 | * | |
118 | * @param password the password to process | |
119 | * @return processed password | |
120 | */ | |
121 | public String encryptPassword(String password) | |
122 | { | |
123 | 0 | return encryptPassword(password, null); |
124 | } | |
125 | ||
126 | /** | |
127 | * This method provides client-side encryption of passwords. | |
128 | * | |
129 | * If <code>secure.passwords</code> are enabled in TurbineResources, | |
130 | * the password will be encrypted, if not, it will be returned unchanged. | |
131 | * The <code>secure.passwords.algorithm</code> property can be used | |
132 | * to chose which digest algorithm should be used for performing the | |
133 | * encryption. <code>SHA</code> is used by default. | |
134 | * | |
135 | * The used algorithms must be prepared to accept null as a | |
136 | * valid parameter for salt. All algorithms in the Fulcrum Cryptoservice | |
137 | * accept this. | |
138 | * | |
139 | * @param password the password to process | |
140 | * @param salt algorithms that needs a salt can provide one here | |
141 | * @return processed password | |
142 | */ | |
143 | ||
144 | public String encryptPassword(String password, String salt) | |
145 | { | |
146 | 0 | if (password == null) |
147 | { | |
148 | 0 | return null; |
149 | } | |
150 | 0 | String secure = getConfiguration().getString( |
151 | SecurityService.SECURE_PASSWORDS_KEY, | |
152 | SecurityService.SECURE_PASSWORDS_DEFAULT).toLowerCase(); | |
153 | ||
154 | 0 | String algorithm = getConfiguration().getString( |
155 | SecurityService.SECURE_PASSWORDS_ALGORITHM_KEY, | |
156 | SecurityService.SECURE_PASSWORDS_ALGORITHM_DEFAULT); | |
157 | ||
158 | 0 | CryptoService cs = null; |
159 | try { | |
160 | 0 | ServiceManager serviceManager = TurbineServices.getInstance(); |
161 | 0 | cs = (CryptoService)serviceManager.getService(CryptoService.ROLE); |
162 | } | |
163 | 0 | catch (Exception e){ |
164 | 0 | throw new RuntimeException("Could not access Crypto Service",e); |
165 | 0 | } |
166 | ||
167 | 0 | if (cs != null && (secure.equals("true") || secure.equals("yes"))) |
168 | { | |
169 | try | |
170 | { | |
171 | 0 | CryptoAlgorithm ca = cs.getCryptoAlgorithm(algorithm); |
172 | ||
173 | 0 | ca.setSeed(salt); |
174 | ||
175 | 0 | String result = ca.encrypt(password); |
176 | ||
177 | 0 | return result; |
178 | } | |
179 | 0 | catch (Exception e) |
180 | { | |
181 | 0 | log.error("Unable to encrypt password: ", e); |
182 | ||
183 | 0 | return null; |
184 | } | |
185 | } | |
186 | else | |
187 | { | |
188 | 0 | return password; |
189 | } | |
190 | } | |
191 | ||
192 | /** | |
193 | * Checks if a supplied password matches the encrypted password | |
194 | * | |
195 | * @param checkpw The clear text password supplied by the user | |
196 | * @param encpw The current, encrypted password | |
197 | * | |
198 | * @return true if the password matches, else false | |
199 | * | |
200 | */ | |
201 | ||
202 | public boolean checkPassword(String checkpw, String encpw) | |
203 | { | |
204 | 0 | String result = encryptPassword(checkpw, encpw); |
205 | ||
206 | 0 | return (result == null) ? false : result.equals(encpw); |
207 | } | |
208 | ||
209 | /** | |
210 | * Initializes the SecurityService, locating the apropriate UserManager | |
211 | * This is a zero parameter variant which queries the Turbine Servlet | |
212 | * for its config. | |
213 | * | |
214 | * @throws InitializationException Something went wrong in the init stage | |
215 | */ | |
216 | public void init() | |
217 | throws InitializationException | |
218 | { | |
219 | 24 | Configuration conf = getConfiguration(); |
220 | ||
221 | 24 | String userManagerClassName = conf.getString( |
222 | SecurityService.USER_MANAGER_KEY, | |
223 | SecurityService.USER_MANAGER_DEFAULT); | |
224 | ||
225 | 24 | String userClassName = conf.getString( |
226 | SecurityService.USER_CLASS_KEY, | |
227 | SecurityService.USER_CLASS_DEFAULT); | |
228 | ||
229 | 24 | String groupClassName = conf.getString( |
230 | SecurityService.GROUP_CLASS_KEY, | |
231 | SecurityService.GROUP_CLASS_DEFAULT); | |
232 | ||
233 | 24 | String permissionClassName = conf.getString( |
234 | SecurityService.PERMISSION_CLASS_KEY, | |
235 | SecurityService.PERMISSION_CLASS_DEFAULT); | |
236 | ||
237 | 24 | String roleClassName = conf.getString( |
238 | SecurityService.ROLE_CLASS_KEY, | |
239 | SecurityService.ROLE_CLASS_DEFAULT); | |
240 | ||
241 | 24 | String aclClassName = conf.getString( |
242 | SecurityService.ACL_CLASS_KEY, | |
243 | SecurityService.ACL_CLASS_DEFAULT); | |
244 | ||
245 | try | |
246 | { | |
247 | 24 | userClass = Class.forName(userClassName); |
248 | 24 | groupClass = Class.forName(groupClassName); |
249 | 24 | permissionClass = Class.forName(permissionClassName); |
250 | 24 | roleClass = Class.forName(roleClassName); |
251 | 24 | aclClass = Class.forName(aclClassName); |
252 | } | |
253 | 0 | catch (Exception e) |
254 | { | |
255 | 0 | if (userClass == null) |
256 | { | |
257 | 0 | throw new InitializationException( |
258 | "Failed to create a Class object for User implementation", e); | |
259 | } | |
260 | 0 | if (groupClass == null) |
261 | { | |
262 | 0 | throw new InitializationException( |
263 | "Failed to create a Class object for Group implementation", e); | |
264 | } | |
265 | 0 | if (permissionClass == null) |
266 | { | |
267 | 0 | throw new InitializationException( |
268 | "Failed to create a Class object for Permission implementation", e); | |
269 | } | |
270 | 0 | if (roleClass == null) |
271 | { | |
272 | 0 | throw new InitializationException( |
273 | "Failed to create a Class object for Role implementation", e); | |
274 | } | |
275 | 0 | if (aclClass == null) |
276 | { | |
277 | 0 | throw new InitializationException( |
278 | "Failed to create a Class object for ACL implementation", e); | |
279 | } | |
280 | 24 | } |
281 | ||
282 | try | |
283 | { | |
284 | 24 | UserManager userManager = |
285 | (UserManager) Class.forName(userManagerClassName).newInstance(); | |
286 | ||
287 | 24 | userManager.init(conf); |
288 | ||
289 | 24 | setUserManager(userManager); |
290 | } | |
291 | 0 | catch (Exception e) |
292 | { | |
293 | 0 | throw new InitializationException("Failed to instantiate UserManager", e); |
294 | 24 | } |
295 | ||
296 | try | |
297 | { | |
298 | 24 | aclFactoryService = (FactoryService)TurbineServices.getInstance().getService(FactoryService.ROLE); |
299 | } | |
300 | 0 | catch (Exception e) |
301 | { | |
302 | 0 | throw new InitializationException( |
303 | "BaseSecurityService.init: Failed to get the Factory Service object", e); | |
304 | 24 | } |
305 | ||
306 | 24 | setInit(true); |
307 | 24 | } |
308 | ||
309 | /** | |
310 | * Return a Class object representing the system's chosen implementation of | |
311 | * of User interface. | |
312 | * | |
313 | * @return systems's chosen implementation of User interface. | |
314 | * @throws UnknownEntityException if the implementation of User interface | |
315 | * could not be determined, or does not exist. | |
316 | */ | |
317 | public Class getUserClass() | |
318 | throws UnknownEntityException | |
319 | { | |
320 | 4 | if (userClass == null) |
321 | { | |
322 | 0 | throw new UnknownEntityException( |
323 | "Failed to create a Class object for User implementation"); | |
324 | } | |
325 | 4 | return userClass; |
326 | } | |
327 | ||
328 | /** | |
329 | * Construct a blank User object. | |
330 | * | |
331 | * This method calls getUserClass, and then creates a new object using | |
332 | * the default constructor. | |
333 | * | |
334 | * @return an object implementing User interface. | |
335 | * @throws UnknownEntityException if the object could not be instantiated. | |
336 | */ | |
337 | public User getUserInstance() | |
338 | throws UnknownEntityException | |
339 | { | |
340 | User user; | |
341 | try | |
342 | { | |
343 | 4 | user = (User) getUserClass().newInstance(); |
344 | } | |
345 | 0 | catch (Exception e) |
346 | { | |
347 | 0 | throw new UnknownEntityException( |
348 | "Failed instantiate an User implementation object", e); | |
349 | 4 | } |
350 | 4 | return user; |
351 | } | |
352 | ||
353 | /** | |
354 | * Construct a blank User object. | |
355 | * | |
356 | * This method calls getUserClass, and then creates a new object using | |
357 | * the default constructor. | |
358 | * | |
359 | * @param userName The name of the user. | |
360 | * | |
361 | * @return an object implementing User interface. | |
362 | * | |
363 | * @throws UnknownEntityException if the object could not be instantiated. | |
364 | */ | |
365 | public User getUserInstance(String userName) | |
366 | throws UnknownEntityException | |
367 | { | |
368 | 0 | User user = getUserInstance(); |
369 | 0 | user.setName(userName); |
370 | 0 | return user; |
371 | } | |
372 | ||
373 | /** | |
374 | * Return a Class object representing the system's chosen implementation of | |
375 | * of Group interface. | |
376 | * | |
377 | * @return systems's chosen implementation of Group interface. | |
378 | * @throws UnknownEntityException if the implementation of Group interface | |
379 | * could not be determined, or does not exist. | |
380 | */ | |
381 | public Class getGroupClass() | |
382 | throws UnknownEntityException | |
383 | { | |
384 | 0 | if (groupClass == null) |
385 | { | |
386 | 0 | throw new UnknownEntityException( |
387 | "Failed to create a Class object for Group implementation"); | |
388 | } | |
389 | 0 | return groupClass; |
390 | } | |
391 | ||
392 | /** | |
393 | * Construct a blank Group object. | |
394 | * | |
395 | * This method calls getGroupClass, and then creates a new object using | |
396 | * the default constructor. | |
397 | * | |
398 | * @return an object implementing Group interface. | |
399 | * @throws UnknownEntityException if the object could not be instantiated. | |
400 | */ | |
401 | public Group getGroupInstance() | |
402 | throws UnknownEntityException | |
403 | { | |
404 | Group group; | |
405 | try | |
406 | { | |
407 | 0 | group = (Group) getGroupClass().newInstance(); |
408 | } | |
409 | 0 | catch (Exception e) |
410 | { | |
411 | 0 | throw new UnknownEntityException("Failed to instantiate a Group implementation object", e); |
412 | 0 | } |
413 | 0 | return group; |
414 | } | |
415 | ||
416 | /** | |
417 | * Construct a blank Group object. | |
418 | * | |
419 | * This method calls getGroupClass, and then creates a new object using | |
420 | * the default constructor. | |
421 | * | |
422 | * @param groupName The name of the Group | |
423 | * | |
424 | * @return an object implementing Group interface. | |
425 | * | |
426 | * @throws UnknownEntityException if the object could not be instantiated. | |
427 | */ | |
428 | public Group getGroupInstance(String groupName) | |
429 | throws UnknownEntityException | |
430 | { | |
431 | 0 | Group group = getGroupInstance(); |
432 | 0 | group.setName(groupName); |
433 | 0 | return group; |
434 | } | |
435 | ||
436 | /** | |
437 | * Return a Class object representing the system's chosen implementation of | |
438 | * of Permission interface. | |
439 | * | |
440 | * @return systems's chosen implementation of Permission interface. | |
441 | * @throws UnknownEntityException if the implementation of Permission interface | |
442 | * could not be determined, or does not exist. | |
443 | */ | |
444 | public Class getPermissionClass() | |
445 | throws UnknownEntityException | |
446 | { | |
447 | 0 | if (permissionClass == null) |
448 | { | |
449 | 0 | throw new UnknownEntityException( |
450 | "Failed to create a Class object for Permission implementation"); | |
451 | } | |
452 | 0 | return permissionClass; |
453 | } | |
454 | ||
455 | /** | |
456 | * Construct a blank Permission object. | |
457 | * | |
458 | * This method calls getPermissionClass, and then creates a new object using | |
459 | * the default constructor. | |
460 | * | |
461 | * @return an object implementing Permission interface. | |
462 | * @throws UnknownEntityException if the object could not be instantiated. | |
463 | */ | |
464 | public Permission getPermissionInstance() | |
465 | throws UnknownEntityException | |
466 | { | |
467 | Permission permission; | |
468 | try | |
469 | { | |
470 | 0 | permission = (Permission) getPermissionClass().newInstance(); |
471 | } | |
472 | 0 | catch (Exception e) |
473 | { | |
474 | 0 | throw new UnknownEntityException("Failed to instantiate a Permission implementation object", e); |
475 | 0 | } |
476 | 0 | return permission; |
477 | } | |
478 | ||
479 | /** | |
480 | * Construct a blank Permission object. | |
481 | * | |
482 | * This method calls getPermissionClass, and then creates a new object using | |
483 | * the default constructor. | |
484 | * | |
485 | * @param permName The name of the permission. | |
486 | * | |
487 | * @return an object implementing Permission interface. | |
488 | * @throws UnknownEntityException if the object could not be instantiated. | |
489 | */ | |
490 | public Permission getPermissionInstance(String permName) | |
491 | throws UnknownEntityException | |
492 | { | |
493 | 0 | Permission perm = getPermissionInstance(); |
494 | 0 | perm.setName(permName); |
495 | 0 | return perm; |
496 | } | |
497 | ||
498 | /** | |
499 | * Return a Class object representing the system's chosen implementation of | |
500 | * of Role interface. | |
501 | * | |
502 | * @return systems's chosen implementation of Role interface. | |
503 | * @throws UnknownEntityException if the implementation of Role interface | |
504 | * could not be determined, or does not exist. | |
505 | */ | |
506 | public Class getRoleClass() | |
507 | throws UnknownEntityException | |
508 | { | |
509 | 0 | if (roleClass == null) |
510 | { | |
511 | 0 | throw new UnknownEntityException( |
512 | "Failed to create a Class object for Role implementation"); | |
513 | } | |
514 | 0 | return roleClass; |
515 | } | |
516 | ||
517 | /** | |
518 | * Construct a blank Role object. | |
519 | * | |
520 | * This method calls getRoleClass, and then creates a new object using | |
521 | * the default constructor. | |
522 | * | |
523 | * @return an object implementing Role interface. | |
524 | * @throws UnknownEntityException if the object could not be instantiated. | |
525 | */ | |
526 | public Role getRoleInstance() | |
527 | throws UnknownEntityException | |
528 | { | |
529 | Role role; | |
530 | ||
531 | try | |
532 | { | |
533 | 0 | role = (Role) getRoleClass().newInstance(); |
534 | } | |
535 | 0 | catch (Exception e) |
536 | { | |
537 | 0 | throw new UnknownEntityException("Failed to instantiate a Role implementation object", e); |
538 | 0 | } |
539 | 0 | return role; |
540 | } | |
541 | ||
542 | /** | |
543 | * Construct a blank Role object. | |
544 | * | |
545 | * This method calls getRoleClass, and then creates a new object using | |
546 | * the default constructor. | |
547 | * | |
548 | * @param roleName The name of the role. | |
549 | * | |
550 | * @return an object implementing Role interface. | |
551 | * | |
552 | * @throws UnknownEntityException if the object could not be instantiated. | |
553 | */ | |
554 | public Role getRoleInstance(String roleName) | |
555 | throws UnknownEntityException | |
556 | { | |
557 | 0 | Role role = getRoleInstance(); |
558 | 0 | role.setName(roleName); |
559 | 0 | return role; |
560 | } | |
561 | ||
562 | /** | |
563 | * Return a Class object representing the system's chosen implementation of | |
564 | * of ACL interface. | |
565 | * | |
566 | * @return systems's chosen implementation of ACL interface. | |
567 | * @throws UnknownEntityException if the implementation of ACL interface | |
568 | * could not be determined, or does not exist. | |
569 | */ | |
570 | public Class getAclClass() | |
571 | throws UnknownEntityException | |
572 | { | |
573 | 2 | if (aclClass == null) |
574 | { | |
575 | 0 | throw new UnknownEntityException( |
576 | "Failed to create a Class object for ACL implementation"); | |
577 | } | |
578 | 2 | return aclClass; |
579 | } | |
580 | ||
581 | /** | |
582 | * Construct a new ACL object. | |
583 | * | |
584 | * This constructs a new ACL object from the configured class and | |
585 | * initializes it with the supplied roles and permissions. | |
586 | * | |
587 | * @param roles The roles that this ACL should contain | |
588 | * @param permissions The permissions for this ACL | |
589 | * | |
590 | * @return an object implementing ACL interface. | |
591 | * @throws UnknownEntityException if the object could not be instantiated. | |
592 | */ | |
593 | public AccessControlList getAclInstance(Map roles, Map permissions) | |
594 | throws UnknownEntityException | |
595 | { | |
596 | 4 | Object[] objects = {roles, permissions}; |
597 | 4 | String[] signatures = {Map.class.getName(), Map.class.getName()}; |
598 | AccessControlList accessControlList; | |
599 | ||
600 | try | |
601 | { | |
602 | 4 | accessControlList = |
603 | (AccessControlList) aclFactoryService.getInstance(aclClass.getName(), | |
604 | objects, | |
605 | signatures); | |
606 | } | |
607 | 0 | catch (Exception e) |
608 | { | |
609 | 0 | throw new UnknownEntityException( |
610 | "Failed to instantiate an ACL implementation object", e); | |
611 | 4 | } |
612 | ||
613 | 4 | return accessControlList; |
614 | } | |
615 | ||
616 | /** | |
617 | * Returns the configured UserManager. | |
618 | * | |
619 | * @return An UserManager object | |
620 | */ | |
621 | public UserManager getUserManager() | |
622 | { | |
623 | 2 | return userManager; |
624 | } | |
625 | ||
626 | /** | |
627 | * Configure a new user Manager. | |
628 | * | |
629 | * @param userManager An UserManager object | |
630 | */ | |
631 | public void setUserManager(UserManager userManager) | |
632 | { | |
633 | 24 | this.userManager = userManager; |
634 | 24 | } |
635 | ||
636 | /** | |
637 | * Check whether a specified user's account exists. | |
638 | * | |
639 | * The login name is used for looking up the account. | |
640 | * | |
641 | * @param user The user to be checked. | |
642 | * @return true if the specified account exists | |
643 | * @throws DataBackendException if there was an error accessing the data | |
644 | * backend. | |
645 | */ | |
646 | public boolean accountExists(User user) | |
647 | throws DataBackendException | |
648 | { | |
649 | 0 | return getUserManager().accountExists(user); |
650 | } | |
651 | ||
652 | /** | |
653 | * Check whether a specified user's account exists. | |
654 | * | |
655 | * The login name is used for looking up the account. | |
656 | * | |
657 | * @param userName The name of the user to be checked. | |
658 | * @return true if the specified account exists | |
659 | * @throws DataBackendException if there was an error accessing the data | |
660 | * backend. | |
661 | */ | |
662 | public boolean accountExists(String userName) | |
663 | throws DataBackendException | |
664 | { | |
665 | 0 | return getUserManager().accountExists(userName); |
666 | } | |
667 | ||
668 | /** | |
669 | * Authenticates an user, and constructs an User object to represent | |
670 | * him/her. | |
671 | * | |
672 | * @param username The user name. | |
673 | * @param password The user password. | |
674 | * @return An authenticated Turbine User. | |
675 | * @throws PasswordMismatchException if the supplied password was incorrect. | |
676 | * @throws UnknownEntityException if the user's account does not | |
677 | * exist in the database. | |
678 | * @throws DataBackendException if there is a problem accessing the storage. | |
679 | */ | |
680 | public User getAuthenticatedUser(String username, String password) | |
681 | throws DataBackendException, UnknownEntityException, | |
682 | PasswordMismatchException | |
683 | { | |
684 | 2 | return getUserManager().retrieve(username, password); |
685 | } | |
686 | ||
687 | /** | |
688 | * Constructs an User object to represent a registered user of the | |
689 | * application. | |
690 | * | |
691 | * @param username The user name. | |
692 | * @return A Turbine User. | |
693 | * @throws UnknownEntityException if the user's account does not exist | |
694 | * @throws DataBackendException if there is a problem accessing the storage. | |
695 | */ | |
696 | public User getUser(String username) | |
697 | throws DataBackendException, UnknownEntityException | |
698 | { | |
699 | 0 | return getUserManager().retrieve(username); |
700 | } | |
701 | ||
702 | ||
703 | /** | |
704 | * Constructs an User object to represent an anonymous user of the | |
705 | * application. | |
706 | * | |
707 | * @return An anonymous Turbine User. | |
708 | * @throws UnknownEntityException if the implementation of User interface | |
709 | * could not be determined, or does not exist. | |
710 | */ | |
711 | public User getAnonymousUser() | |
712 | throws UnknownEntityException | |
713 | { | |
714 | 4 | User user = getUserInstance(); |
715 | 4 | user.setName(""); |
716 | 4 | return user; |
717 | } | |
718 | ||
719 | /** | |
720 | * Checks whether a passed user object matches the anonymous user pattern | |
721 | * according to the configured user manager | |
722 | * | |
723 | * @param user An user object | |
724 | * | |
725 | * @return True if this is an anonymous user | |
726 | * | |
727 | */ | |
728 | public boolean isAnonymousUser(User user) | |
729 | { | |
730 | // Either just null, the name is null or the name is the empty string | |
731 | 20 | return (user == null) || StringUtils.isEmpty(user.getName()); |
732 | } | |
733 | ||
734 | /** | |
735 | * Saves User's data in the permanent storage. The user account is required | |
736 | * to exist in the storage. | |
737 | * | |
738 | * @param user the User object to save | |
739 | * @throws UnknownEntityException if the user's account does not | |
740 | * exist in the database. | |
741 | * @throws DataBackendException if there is a problem accessing the storage. | |
742 | */ | |
743 | public void saveUser(User user) | |
744 | throws UnknownEntityException, DataBackendException | |
745 | { | |
746 | 0 | getUserManager().store(user); |
747 | 0 | } |
748 | ||
749 | /** | |
750 | * Saves User data when the session is unbound. The user account is required | |
751 | * to exist in the storage. | |
752 | * | |
753 | * LastLogin, AccessCounter, persistent pull tools, and any data stored | |
754 | * in the permData hashtable that is not mapped to a column will be saved. | |
755 | * | |
756 | * @exception UnknownEntityException if the user's account does not | |
757 | * exist in the database. | |
758 | * @exception DataBackendException if there is a problem accessing the | |
759 | * storage. | |
760 | */ | |
761 | public void saveOnSessionUnbind(User user) | |
762 | throws UnknownEntityException, DataBackendException | |
763 | { | |
764 | 0 | userManager.saveOnSessionUnbind(user); |
765 | 0 | } |
766 | ||
767 | /** | |
768 | * Creates new user account with specified attributes. | |
769 | * | |
770 | * @param user the object describing account to be created. | |
771 | * @param password The password to use for the account. | |
772 | * | |
773 | * @throws DataBackendException if there was an error accessing the | |
774 | * data backend. | |
775 | * @throws EntityExistsException if the user account already exists. | |
776 | */ | |
777 | public void addUser(User user, String password) | |
778 | throws DataBackendException, EntityExistsException | |
779 | { | |
780 | 0 | getUserManager().createAccount(user, password); |
781 | 0 | } |
782 | ||
783 | /** | |
784 | * Removes an user account from the system. | |
785 | * | |
786 | * @param user the object describing the account to be removed. | |
787 | * @throws DataBackendException if there was an error accessing the data | |
788 | * backend. | |
789 | * @throws UnknownEntityException if the user account is not present. | |
790 | */ | |
791 | public void removeUser(User user) | |
792 | throws DataBackendException, UnknownEntityException | |
793 | { | |
794 | // revoke all roles form the user | |
795 | 0 | revokeAll(user); |
796 | ||
797 | 0 | getUserManager().removeAccount(user); |
798 | 0 | } |
799 | ||
800 | /** | |
801 | * Change the password for an User. | |
802 | * | |
803 | * @param user an User to change password for. | |
804 | * @param oldPassword the current password supplied by the user. | |
805 | * @param newPassword the current password requested by the user. | |
806 | * @throws PasswordMismatchException if the supplied password was incorrect. | |
807 | * @throws UnknownEntityException if the user's record does not | |
808 | * exist in the database. | |
809 | * @throws DataBackendException if there is a problem accessing the storage. | |
810 | */ | |
811 | public void changePassword(User user, String oldPassword, | |
812 | String newPassword) | |
813 | throws PasswordMismatchException, UnknownEntityException, | |
814 | DataBackendException | |
815 | { | |
816 | 0 | getUserManager().changePassword(user, oldPassword, newPassword); |
817 | 0 | } |
818 | ||
819 | /** | |
820 | * Forcibly sets new password for an User. | |
821 | * | |
822 | * This is supposed by the administrator to change the forgotten or | |
823 | * compromised passwords. Certain implementatations of this feature | |
824 | * would require administrative level access to the authenticating | |
825 | * server / program. | |
826 | * | |
827 | * @param user an User to change password for. | |
828 | * @param password the new password. | |
829 | * @throws UnknownEntityException if the user's record does not | |
830 | * exist in the database. | |
831 | * @throws DataBackendException if there is a problem accessing the storage. | |
832 | */ | |
833 | public void forcePassword(User user, String password) | |
834 | throws UnknownEntityException, DataBackendException | |
835 | { | |
836 | 0 | getUserManager().forcePassword(user, password); |
837 | 0 | } |
838 | ||
839 | /** | |
840 | * Acquire a shared lock on the security information repository. | |
841 | * | |
842 | * Methods that read security information need to invoke this | |
843 | * method at the beginning of their body. | |
844 | */ | |
845 | protected synchronized void lockShared() | |
846 | { | |
847 | 0 | readerCount++; |
848 | 0 | } |
849 | ||
850 | /** | |
851 | * Release a shared lock on the security information repository. | |
852 | * | |
853 | * Methods that read security information need to invoke this | |
854 | * method at the end of their body. | |
855 | */ | |
856 | protected synchronized void unlockShared() | |
857 | { | |
858 | 0 | readerCount--; |
859 | 0 | this.notify(); |
860 | 0 | } |
861 | ||
862 | /** | |
863 | * Acquire an exclusive lock on the security information repository. | |
864 | * | |
865 | * Methods that modify security information need to invoke this | |
866 | * method at the beginning of their body. Note! Those methods must | |
867 | * be <code>synchronized</code> themselves! | |
868 | */ | |
869 | protected void lockExclusive() | |
870 | { | |
871 | 0 | while (readerCount > 0) |
872 | { | |
873 | try | |
874 | { | |
875 | 0 | this.wait(); |
876 | } | |
877 | 0 | catch (InterruptedException e) |
878 | { | |
879 | 0 | } |
880 | } | |
881 | 0 | } |
882 | ||
883 | /** | |
884 | * Release an exclusive lock on the security information repository. | |
885 | * | |
886 | * This method is provided only for completeness. It does not really | |
887 | * do anything. Note! Methods that modify security information | |
888 | * must be <code>synchronized</code>! | |
889 | */ | |
890 | protected void unlockExclusive() | |
891 | { | |
892 | // do nothing | |
893 | 0 | } |
894 | ||
895 | /** | |
896 | * Provides a reference to the Group object that represents the | |
897 | * <a href="#global">global group</a>. | |
898 | * | |
899 | * @return a Group object that represents the global group. | |
900 | */ | |
901 | public Group getGlobalGroup() | |
902 | { | |
903 | 0 | if (globalGroup == null) |
904 | { | |
905 | 0 | synchronized (BaseSecurityService.class) |
906 | { | |
907 | 0 | if (globalGroup == null) |
908 | { | |
909 | try | |
910 | { | |
911 | 0 | globalGroup = getAllGroups() |
912 | .getGroupByName(Group.GLOBAL_GROUP_NAME); | |
913 | } | |
914 | 0 | catch (DataBackendException e) |
915 | { | |
916 | 0 | log.error("Failed to retrieve global group object: ", e); |
917 | 0 | } |
918 | } | |
919 | 0 | } |
920 | } | |
921 | 0 | return globalGroup; |
922 | } | |
923 | ||
924 | /** | |
925 | * Retrieve a Group object with specified name. | |
926 | * | |
927 | * @param name the name of the Group. | |
928 | * @return an object representing the Group with specified name. | |
929 | * @throws DataBackendException if there was an error accessing the | |
930 | * data backend. | |
931 | * @throws UnknownEntityException if the group does not exist. | |
932 | */ | |
933 | public Group getGroupByName(String name) | |
934 | throws DataBackendException, UnknownEntityException | |
935 | { | |
936 | 0 | Group group = getAllGroups().getGroupByName(name); |
937 | 0 | if (group == null) |
938 | { | |
939 | 0 | throw new UnknownEntityException( |
940 | "The specified group does not exist"); | |
941 | } | |
942 | 0 | return group; |
943 | } | |
944 | ||
945 | /** | |
946 | * Retrieve a Group object with specified Id. | |
947 | * | |
948 | * @param id the id of the Group. | |
949 | * @return an object representing the Group with specified name. | |
950 | * @throws UnknownEntityException if the permission does not | |
951 | * exist in the database. | |
952 | * @throws DataBackendException if there is a problem accessing the | |
953 | * storage. | |
954 | */ | |
955 | public Group getGroupById(int id) | |
956 | throws DataBackendException, UnknownEntityException | |
957 | { | |
958 | 0 | Group group = getAllGroups().getGroupById(id); |
959 | 0 | if (group == null) |
960 | { | |
961 | 0 | throw new UnknownEntityException( |
962 | "The specified group does not exist"); | |
963 | } | |
964 | 0 | return group; |
965 | } | |
966 | ||
967 | /** | |
968 | * Retrieve a Role object with specified name. | |
969 | * | |
970 | * @param name the name of the Role. | |
971 | * @return an object representing the Role with specified name. | |
972 | * @throws DataBackendException if there was an error accessing the | |
973 | * data backend. | |
974 | * @throws UnknownEntityException if the role does not exist. | |
975 | */ | |
976 | public Role getRoleByName(String name) | |
977 | throws DataBackendException, UnknownEntityException | |
978 | { | |
979 | 0 | Role role = getAllRoles().getRoleByName(name); |
980 | 0 | if (role == null) |
981 | { | |
982 | 0 | throw new UnknownEntityException( |
983 | "The specified role does not exist"); | |
984 | } | |
985 | 0 | role.setPermissions(getPermissions(role)); |
986 | 0 | return role; |
987 | } | |
988 | ||
989 | /** | |
990 | * Retrieve a Role object with specified Id. | |
991 | * @param id the id of the Role. | |
992 | * @return an object representing the Role with specified name. | |
993 | * @throws UnknownEntityException if the permission does not | |
994 | * exist in the database. | |
995 | * @throws DataBackendException if there is a problem accessing the | |
996 | * storage. | |
997 | */ | |
998 | public Role getRoleById(int id) | |
999 | throws DataBackendException, | |
1000 | UnknownEntityException | |
1001 | { | |
1002 | 0 | Role role = getAllRoles().getRoleById(id); |
1003 | 0 | if (role == null) |
1004 | { | |
1005 | 0 | throw new UnknownEntityException( |
1006 | "The specified role does not exist"); | |
1007 | } | |
1008 | 0 | role.setPermissions(getPermissions(role)); |
1009 | 0 | return role; |
1010 | } | |
1011 | ||
1012 | /** | |
1013 | * Retrieve a Permission object with specified name. | |
1014 | * | |
1015 | * @param name the name of the Permission. | |
1016 | * @return an object representing the Permission with specified name. | |
1017 | * @throws DataBackendException if there was an error accessing the | |
1018 | * data backend. | |
1019 | * @throws UnknownEntityException if the permission does not exist. | |
1020 | */ | |
1021 | public Permission getPermissionByName(String name) | |
1022 | throws DataBackendException, UnknownEntityException | |
1023 | { | |
1024 | 0 | Permission permission = getAllPermissions().getPermissionByName(name); |
1025 | 0 | if (permission == null) |
1026 | { | |
1027 | 0 | throw new UnknownEntityException( |
1028 | "The specified permission does not exist"); | |
1029 | } | |
1030 | 0 | return permission; |
1031 | } | |
1032 | ||
1033 | /** | |
1034 | * Retrieve a Permission object with specified Id. | |
1035 | * | |
1036 | * @param id the id of the Permission. | |
1037 | * @return an object representing the Permission with specified name. | |
1038 | * @throws UnknownEntityException if the permission does not | |
1039 | * exist in the database. | |
1040 | * @throws DataBackendException if there is a problem accessing the | |
1041 | * storage. | |
1042 | */ | |
1043 | public Permission getPermissionById(int id) | |
1044 | throws DataBackendException, | |
1045 | UnknownEntityException | |
1046 | { | |
1047 | 0 | Permission permission = getAllPermissions().getPermissionById(id); |
1048 | 0 | if (permission == null) |
1049 | { | |
1050 | 0 | throw new UnknownEntityException( |
1051 | "The specified permission does not exist"); | |
1052 | } | |
1053 | 0 | return permission; |
1054 | } | |
1055 | ||
1056 | /** | |
1057 | * Retrieves all groups defined in the system. | |
1058 | * | |
1059 | * @return the names of all groups defined in the system. | |
1060 | * @throws DataBackendException if there was an error accessing the | |
1061 | * data backend. | |
1062 | */ | |
1063 | public abstract GroupSet getAllGroups() | |
1064 | throws DataBackendException; | |
1065 | ||
1066 | /** | |
1067 | * Retrieves all roles defined in the system. | |
1068 | * | |
1069 | * @return the names of all roles defined in the system. | |
1070 | * @throws DataBackendException if there was an error accessing the | |
1071 | * data backend. | |
1072 | */ | |
1073 | public abstract RoleSet getAllRoles() | |
1074 | throws DataBackendException; | |
1075 | ||
1076 | /** | |
1077 | * Retrieves all permissions defined in the system. | |
1078 | * | |
1079 | * @return the names of all roles defined in the system. | |
1080 | * @throws DataBackendException if there was an error accessing the | |
1081 | * data backend. | |
1082 | */ | |
1083 | public abstract PermissionSet getAllPermissions() | |
1084 | throws DataBackendException; | |
1085 | } |