001 package org.apache.turbine.services.security;
002
003
004 /*
005 * Licensed to the Apache Software Foundation (ASF) under one
006 * or more contributor license agreements. See the NOTICE file
007 * distributed with this work for additional information
008 * regarding copyright ownership. The ASF licenses this file
009 * to you under the Apache License, Version 2.0 (the
010 * "License"); you may not use this file except in compliance
011 * with the License. You may obtain a copy of the License at
012 *
013 * http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing,
016 * software distributed under the License is distributed on an
017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018 * KIND, either express or implied. See the License for the
019 * specific language governing permissions and limitations
020 * under the License.
021 */
022
023
024 import java.util.Map;
025
026 import javax.servlet.ServletConfig;
027
028 import org.apache.commons.configuration.Configuration;
029 import org.apache.commons.lang.StringUtils;
030 import org.apache.commons.logging.Log;
031 import org.apache.commons.logging.LogFactory;
032 import org.apache.fulcrum.crypto.CryptoAlgorithm;
033 import org.apache.fulcrum.crypto.CryptoService;
034 import org.apache.fulcrum.factory.FactoryService;
035 import org.apache.turbine.om.security.Group;
036 import org.apache.turbine.om.security.Permission;
037 import org.apache.turbine.om.security.Role;
038 import org.apache.turbine.om.security.User;
039 import org.apache.turbine.services.InitializationException;
040 import org.apache.turbine.services.ServiceManager;
041 import org.apache.turbine.services.TurbineBaseService;
042 import org.apache.turbine.services.TurbineServices;
043 import org.apache.turbine.util.security.AccessControlList;
044 import org.apache.turbine.util.security.DataBackendException;
045 import org.apache.turbine.util.security.EntityExistsException;
046 import org.apache.turbine.util.security.GroupSet;
047 import org.apache.turbine.util.security.PasswordMismatchException;
048 import org.apache.turbine.util.security.PermissionSet;
049 import org.apache.turbine.util.security.RoleSet;
050 import org.apache.turbine.util.security.UnknownEntityException;
051
052 /**
053 * This is a common subset of SecurityService implementation.
054 *
055 * Provided functionality includes:
056 * <ul>
057 * <li> methods for retrieving User objects, that delegates functionality
058 * to the pluggable implementations of the User interface.
059 * <li> synchronization mechanism for methods reading/modifying the security
060 * information, that guarantees that multiple threads may read the
061 * information concurrently, but threads that modify the information
062 * acquires exclusive access.
063 * <li> implementation of convenience methods for retrieving security entities
064 * that maintain in-memory caching of objects for fast access.
065 * </ul>
066 *
067 * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
068 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
069 * @author <a href="mailto:marco@intermeta.de">Marco Knüttel</a>
070 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
071 * @version $Id: BaseSecurityService.java 1096130 2011-04-23 10:37:19Z ludwig $
072 */
073 public abstract class BaseSecurityService
074 extends TurbineBaseService
075 implements SecurityService
076 {
077 /** The number of threads concurrently reading security information */
078 private int readerCount = 0;
079
080 /** The instance of UserManager the SecurityService uses */
081 private UserManager userManager = null;
082
083 /** The class of User the SecurityService uses */
084 private Class userClass = null;
085
086 /** The class of Group the SecurityService uses */
087 private Class groupClass = null;
088
089 /** The class of Permission the SecurityService uses */
090 private Class permissionClass = null;
091
092 /** The class of Role the SecurityService uses */
093 private Class roleClass = null;
094
095 /** The class of ACL the SecurityService uses */
096 private Class aclClass = null;
097
098 /** A factory to construct ACL Objects */
099 private FactoryService aclFactoryService = null;
100
101 /**
102 * The Group object that represents the <a href="#global">global group</a>.
103 */
104 private static Group globalGroup = null;
105
106 /** Logging */
107 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 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 if (password == null)
147 {
148 return null;
149 }
150 String secure = getConfiguration().getString(
151 SecurityService.SECURE_PASSWORDS_KEY,
152 SecurityService.SECURE_PASSWORDS_DEFAULT).toLowerCase();
153
154 String algorithm = getConfiguration().getString(
155 SecurityService.SECURE_PASSWORDS_ALGORITHM_KEY,
156 SecurityService.SECURE_PASSWORDS_ALGORITHM_DEFAULT);
157
158 CryptoService cs = null;
159 try {
160 ServiceManager serviceManager = TurbineServices.getInstance();
161 cs = (CryptoService)serviceManager.getService(CryptoService.ROLE);
162 }
163 catch (Exception e){
164 throw new RuntimeException("Could not access Crypto Service",e);
165 }
166
167 if (cs != null && (secure.equals("true") || secure.equals("yes")))
168 {
169 try
170 {
171 CryptoAlgorithm ca = cs.getCryptoAlgorithm(algorithm);
172
173 ca.setSeed(salt);
174
175 String result = ca.encrypt(password);
176
177 return result;
178 }
179 catch (Exception e)
180 {
181 log.error("Unable to encrypt password: ", e);
182
183 return null;
184 }
185 }
186 else
187 {
188 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 String result = encryptPassword(checkpw, encpw);
205
206 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 Configuration conf = getConfiguration();
220
221 String userManagerClassName = conf.getString(
222 SecurityService.USER_MANAGER_KEY,
223 SecurityService.USER_MANAGER_DEFAULT);
224
225 String userClassName = conf.getString(
226 SecurityService.USER_CLASS_KEY,
227 SecurityService.USER_CLASS_DEFAULT);
228
229 String groupClassName = conf.getString(
230 SecurityService.GROUP_CLASS_KEY,
231 SecurityService.GROUP_CLASS_DEFAULT);
232
233 String permissionClassName = conf.getString(
234 SecurityService.PERMISSION_CLASS_KEY,
235 SecurityService.PERMISSION_CLASS_DEFAULT);
236
237 String roleClassName = conf.getString(
238 SecurityService.ROLE_CLASS_KEY,
239 SecurityService.ROLE_CLASS_DEFAULT);
240
241 String aclClassName = conf.getString(
242 SecurityService.ACL_CLASS_KEY,
243 SecurityService.ACL_CLASS_DEFAULT);
244
245 try
246 {
247 userClass = Class.forName(userClassName);
248 groupClass = Class.forName(groupClassName);
249 permissionClass = Class.forName(permissionClassName);
250 roleClass = Class.forName(roleClassName);
251 aclClass = Class.forName(aclClassName);
252 }
253 catch (Exception e)
254 {
255 if (userClass == null)
256 {
257 throw new InitializationException(
258 "Failed to create a Class object for User implementation", e);
259 }
260 if (groupClass == null)
261 {
262 throw new InitializationException(
263 "Failed to create a Class object for Group implementation", e);
264 }
265 if (permissionClass == null)
266 {
267 throw new InitializationException(
268 "Failed to create a Class object for Permission implementation", e);
269 }
270 if (roleClass == null)
271 {
272 throw new InitializationException(
273 "Failed to create a Class object for Role implementation", e);
274 }
275 if (aclClass == null)
276 {
277 throw new InitializationException(
278 "Failed to create a Class object for ACL implementation", e);
279 }
280 }
281
282 try
283 {
284 UserManager userManager =
285 (UserManager) Class.forName(userManagerClassName).newInstance();
286
287 userManager.init(conf);
288
289 setUserManager(userManager);
290 }
291 catch (Exception e)
292 {
293 throw new InitializationException("Failed to instantiate UserManager", e);
294 }
295
296 try
297 {
298 aclFactoryService = (FactoryService)TurbineServices.getInstance().getService(FactoryService.ROLE);
299 }
300 catch (Exception e)
301 {
302 throw new InitializationException(
303 "BaseSecurityService.init: Failed to get the Factory Service object", e);
304 }
305
306 setInit(true);
307 }
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 if (userClass == null)
321 {
322 throw new UnknownEntityException(
323 "Failed to create a Class object for User implementation");
324 }
325 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 user = (User) getUserClass().newInstance();
344 }
345 catch (Exception e)
346 {
347 throw new UnknownEntityException(
348 "Failed instantiate an User implementation object", e);
349 }
350 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 User user = getUserInstance();
369 user.setName(userName);
370 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 if (groupClass == null)
385 {
386 throw new UnknownEntityException(
387 "Failed to create a Class object for Group implementation");
388 }
389 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 group = (Group) getGroupClass().newInstance();
408 }
409 catch (Exception e)
410 {
411 throw new UnknownEntityException("Failed to instantiate a Group implementation object", e);
412 }
413 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 Group group = getGroupInstance();
432 group.setName(groupName);
433 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 if (permissionClass == null)
448 {
449 throw new UnknownEntityException(
450 "Failed to create a Class object for Permission implementation");
451 }
452 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 permission = (Permission) getPermissionClass().newInstance();
471 }
472 catch (Exception e)
473 {
474 throw new UnknownEntityException("Failed to instantiate a Permission implementation object", e);
475 }
476 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 Permission perm = getPermissionInstance();
494 perm.setName(permName);
495 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 if (roleClass == null)
510 {
511 throw new UnknownEntityException(
512 "Failed to create a Class object for Role implementation");
513 }
514 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 role = (Role) getRoleClass().newInstance();
534 }
535 catch (Exception e)
536 {
537 throw new UnknownEntityException("Failed to instantiate a Role implementation object", e);
538 }
539 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 Role role = getRoleInstance();
558 role.setName(roleName);
559 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 if (aclClass == null)
574 {
575 throw new UnknownEntityException(
576 "Failed to create a Class object for ACL implementation");
577 }
578 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 Object[] objects = {roles, permissions};
597 String[] signatures = {Map.class.getName(), Map.class.getName()};
598 AccessControlList accessControlList;
599
600 try
601 {
602 accessControlList =
603 (AccessControlList) aclFactoryService.getInstance(aclClass.getName(),
604 objects,
605 signatures);
606 }
607 catch (Exception e)
608 {
609 throw new UnknownEntityException(
610 "Failed to instantiate an ACL implementation object", e);
611 }
612
613 return accessControlList;
614 }
615
616 /**
617 * Returns the configured UserManager.
618 *
619 * @return An UserManager object
620 */
621 public UserManager getUserManager()
622 {
623 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 this.userManager = userManager;
634 }
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 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 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 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 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 User user = getUserInstance();
715 user.setName("");
716 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 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 getUserManager().store(user);
747 }
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 userManager.saveOnSessionUnbind(user);
765 }
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 getUserManager().createAccount(user, password);
781 }
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 revokeAll(user);
796
797 getUserManager().removeAccount(user);
798 }
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 getUserManager().changePassword(user, oldPassword, newPassword);
817 }
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 getUserManager().forcePassword(user, password);
837 }
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 readerCount++;
848 }
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 readerCount--;
859 this.notify();
860 }
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 while (readerCount > 0)
872 {
873 try
874 {
875 this.wait();
876 }
877 catch (InterruptedException e)
878 {
879 }
880 }
881 }
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 }
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 if (globalGroup == null)
904 {
905 synchronized (BaseSecurityService.class)
906 {
907 if (globalGroup == null)
908 {
909 try
910 {
911 globalGroup = getAllGroups()
912 .getGroupByName(Group.GLOBAL_GROUP_NAME);
913 }
914 catch (DataBackendException e)
915 {
916 log.error("Failed to retrieve global group object: ", e);
917 }
918 }
919 }
920 }
921 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 Group group = getAllGroups().getGroupByName(name);
937 if (group == null)
938 {
939 throw new UnknownEntityException(
940 "The specified group does not exist");
941 }
942 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 Group group = getAllGroups().getGroupById(id);
959 if (group == null)
960 {
961 throw new UnknownEntityException(
962 "The specified group does not exist");
963 }
964 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 Role role = getAllRoles().getRoleByName(name);
980 if (role == null)
981 {
982 throw new UnknownEntityException(
983 "The specified role does not exist");
984 }
985 role.setPermissions(getPermissions(role));
986 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 Role role = getAllRoles().getRoleById(id);
1003 if (role == null)
1004 {
1005 throw new UnknownEntityException(
1006 "The specified role does not exist");
1007 }
1008 role.setPermissions(getPermissions(role));
1009 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 Permission permission = getAllPermissions().getPermissionByName(name);
1025 if (permission == null)
1026 {
1027 throw new UnknownEntityException(
1028 "The specified permission does not exist");
1029 }
1030 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 Permission permission = getAllPermissions().getPermissionById(id);
1048 if (permission == null)
1049 {
1050 throw new UnknownEntityException(
1051 "The specified permission does not exist");
1052 }
1053 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 }