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 }