View Javadoc

1   package org.apache.turbine.services.security.torque;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Hashtable;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import org.apache.commons.configuration.Configuration;
28  import org.apache.commons.lang.StringUtils;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.torque.TorqueException;
32  import org.apache.torque.om.NumberKey;
33  import org.apache.torque.om.Persistent;
34  import org.apache.torque.util.Criteria;
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.security.BaseSecurityService;
41  import org.apache.turbine.services.security.TurbineSecurity;
42  import org.apache.turbine.services.security.torque.om.TurbineRolePermissionPeer;
43  import org.apache.turbine.services.security.torque.om.TurbineUserGroupRolePeer;
44  import org.apache.turbine.util.security.AccessControlList;
45  import org.apache.turbine.util.security.DataBackendException;
46  import org.apache.turbine.util.security.EntityExistsException;
47  import org.apache.turbine.util.security.GroupSet;
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   * An implementation of SecurityService that uses torque objects.
54   *
55   * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
56   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
57   * @author <a href="mailto:marco@intermeta.de">Marco Kn&uuml;ttel</a>
58   * @version $Id: TorqueSecurityService.java 1096130 2011-04-23 10:37:19Z ludwig $
59   */
60  public class TorqueSecurityService
61      extends BaseSecurityService
62  {
63      /** Logging */
64      private static Log log = LogFactory.getLog(TorqueSecurityService.class);
65  
66      /**
67       * Initializes the TorqueSecurityService, loading the various class objects
68       * representing the security entity peer classes
69       *
70       * @exception InitializationException A problem occured during initialization
71       */
72  
73      public void init()
74          throws InitializationException
75      {
76          Configuration conf = getConfiguration();
77  
78          GroupPeerManager.init(conf);
79          RolePeerManager.init(conf);
80          PermissionPeerManager.init(conf);
81  
82          /* At the end, because it calls setInit(true)! */
83          super.init();
84      }
85  
86  
87      /*-----------------------------------------------------------------------
88        Creation of AccessControlLists
89        -----------------------------------------------------------------------*/
90  
91      /**
92       * Constructs an AccessControlList for a specific user.
93       *
94       * This method creates a snapshot of the state of security information
95       * concerning this user, at the moment of invocation and stores it
96       * into an AccessControlList object.
97       *
98       * @param user the user for whom the AccessControlList are to be retrieved
99       * @return A new AccessControlList object.
100      * @throws DataBackendException if there was an error accessing the data
101      *         backend.
102      * @throws UnknownEntityException if user account is not present.
103      */
104     public AccessControlList getACL(User user)
105         throws DataBackendException, UnknownEntityException
106     {
107         if (!TurbineSecurity.accountExists(user))
108         {
109             throw new UnknownEntityException("The account '"
110                                              + user.getName() + "' does not exist");
111         }
112         try
113         {
114             Hashtable roles = new Hashtable();
115             Hashtable permissions = new Hashtable();
116             // notify the state modifiers (writers) that we want to create
117             // the snapshot.
118             lockShared();
119 
120             // construct the snapshot:
121 
122             // foreach group in the system
123             for (Iterator groupsIterator = getAllGroups().iterator();
124                  groupsIterator.hasNext();)
125             {
126                 Group group = (Group) groupsIterator.next();
127                 // get roles of user in the group
128                 RoleSet groupRoles = RolePeerManager.retrieveSet(user, group);
129                 // put the Set into roles(group)
130                 roles.put(group, groupRoles);
131                 // collect all permissions in this group
132                 PermissionSet groupPermissions = new PermissionSet();
133                 // foreach role in Set
134                 for (Iterator rolesIterator = groupRoles.iterator();
135                      rolesIterator.hasNext();)
136                 {
137                     Role role = (Role) rolesIterator.next();
138                     // get permissions of the role
139                     PermissionSet rolePermissions =
140                         PermissionPeerManager.retrieveSet(role);
141                     groupPermissions.add(rolePermissions);
142                 }
143                 // put the Set into permissions(group)
144                 permissions.put(group, groupPermissions);
145             }
146             return getAclInstance(roles, permissions);
147         }
148         catch (Exception e)
149         {
150             throw new DataBackendException("Failed to build ACL for user '" +
151                                            user.getName() + "'" , e);
152         }
153         finally
154         {
155             // notify the state modifiers that we are done creating the snapshot.
156             unlockShared();
157         }
158     }
159 
160     /*-----------------------------------------------------------------------
161       Security management
162       -----------------------------------------------------------------------*/
163 
164     /**
165      * Grant an User a Role in a Group.
166      *
167      * @param user the user.
168      * @param group the group.
169      * @param role the role.
170      * @throws DataBackendException if there was an error accessing the data
171      *         backend.
172      * @throws UnknownEntityException if user account, group or role is not
173      *         present.
174      */
175     public synchronized void grant(User user, Group group, Role role)
176         throws DataBackendException, UnknownEntityException
177     {
178         boolean userExists = false;
179         boolean groupExists = false;
180         boolean roleExists = false;
181         try
182         {
183             lockExclusive();
184             userExists = TurbineSecurity.accountExists(user);
185             groupExists = checkExists(group);
186             roleExists = checkExists(role);
187             if (userExists && groupExists && roleExists)
188             {
189                 Criteria criteria = new Criteria();
190                 criteria.add(TurbineUserGroupRolePeer.USER_ID,
191                              ((Persistent) user).getPrimaryKey());
192                 criteria.add(TurbineUserGroupRolePeer.GROUP_ID,
193                              ((Persistent) group).getPrimaryKey());
194                 criteria.add(TurbineUserGroupRolePeer.ROLE_ID,
195                              ((Persistent) role).getPrimaryKey());
196                 TurbineUserGroupRolePeer.doInsert(criteria);
197                 return;
198             }
199         }
200         catch (Exception e)
201         {
202             throw new DataBackendException("grant(User,Group,Role) failed", e);
203         }
204         finally
205         {
206             unlockExclusive();
207         }
208         if (!userExists)
209         {
210             throw new UnknownEntityException("Unknown user '"
211                                              + user.getName() + "'");
212         }
213         if (!groupExists)
214         {
215             throw new UnknownEntityException("Unknown group '"
216                                              + group.getName() + "'");
217         }
218         if (!roleExists)
219         {
220             throw new UnknownEntityException("Unknown role '"
221                                              + role.getName() + "'");
222         }
223     }
224 
225     /**
226      * Revoke a Role in a Group from an User.
227      *
228      * @param user the user.
229      * @param group the group.
230      * @param role the role.
231      * @throws DataBackendException if there was an error accessing the data
232      *         backend.
233      * @throws UnknownEntityException if user account, group or role is not
234      *         present.
235      */
236     public synchronized void revoke(User user, Group group, Role role)
237         throws DataBackendException, UnknownEntityException
238     {
239         boolean userExists = false;
240         boolean groupExists = false;
241         boolean roleExists = false;
242         try
243         {
244             lockExclusive();
245             userExists = TurbineSecurity.accountExists(user);
246             groupExists = checkExists(group);
247             roleExists = checkExists(role);
248             if (userExists && groupExists && roleExists)
249             {
250                 Criteria criteria = new Criteria();
251                 criteria.add(TurbineUserGroupRolePeer.USER_ID,
252                              ((Persistent) user).getPrimaryKey());
253                 criteria.add(TurbineUserGroupRolePeer.GROUP_ID,
254                              ((Persistent) group).getPrimaryKey());
255                 criteria.add(TurbineUserGroupRolePeer.ROLE_ID,
256                              ((Persistent) role).getPrimaryKey());
257                 TurbineUserGroupRolePeer.doDelete(criteria);
258                 return;
259             }
260         }
261         catch (Exception e)
262         {
263             throw new DataBackendException("revoke(User,Role,Group) failed", e);
264         }
265         finally
266         {
267             unlockExclusive();
268         }
269         if (!userExists)
270         {
271             throw new UnknownEntityException("Unknown user '"
272                                              + user.getName() + "'");
273         }
274         if (!groupExists)
275         {
276             throw new UnknownEntityException("Unknown group '"
277                                              + group.getName() + "'");
278         }
279         if (!roleExists)
280         {
281             throw new UnknownEntityException("Unknown role '"
282                                              + role.getName() + "'");
283         }
284     }
285 
286     /**
287      * Revokes all roles from an User.
288      *
289      * This method is used when deleting an account.
290      *
291      * @param user the User.
292      * @throws DataBackendException if there was an error accessing the data
293      *         backend.
294      * @throws UnknownEntityException if the account is not present.
295      */
296     public synchronized void revokeAll(User user)
297         throws DataBackendException, UnknownEntityException
298     {
299         boolean userExists = false;
300         try
301         {
302             lockExclusive();
303             userExists = TurbineSecurity.accountExists(user);
304             if (userExists)
305             {
306                 // The following would not work, due to an annoying misfeature
307                 // of Village. Village allows only a single row to be deleted at
308                 // a time. I wish that it was possible to disable this
309                 // behaviour!
310 
311                 // Criteria criteria = new Criteria();
312                 // criteria.add(UserGroupRolePeer.USER_ID,
313                 //           ((Persistent) user).getPrimaryKey());
314                 // UserGroupRolePeer.doDelete(criteria);
315                 int id = ((NumberKey) ((Persistent) user)
316                           .getPrimaryKey()).intValue();
317                 TurbineUserGroupRolePeer.deleteAll(
318                     TurbineUserGroupRolePeer.TABLE_NAME,
319                     TurbineUserGroupRolePeer.USER_ID, id);
320                 return;
321             }
322         }
323         catch (Exception e)
324         {
325             throw new DataBackendException("revokeAll(User) failed", e);
326         }
327         finally
328         {
329             unlockExclusive();
330         }
331         throw new UnknownEntityException("Unknown user '"
332                                          + user.getName() + "'");
333     }
334 
335     /**
336      * Grants a Role a Permission
337      *
338      * @param role the Role.
339      * @param permission the Permission.
340      * @throws DataBackendException if there was an error accessing the data
341      *         backend.
342      * @throws UnknownEntityException if role or permission is not present.
343      */
344     public synchronized void grant(Role role, Permission permission)
345         throws DataBackendException, UnknownEntityException
346     {
347         boolean roleExists = false;
348         boolean permissionExists = false;
349         try
350         {
351             lockExclusive();
352             roleExists = checkExists(role);
353             permissionExists = checkExists(permission);
354             if (roleExists && permissionExists)
355             {
356                 Criteria criteria = new Criteria();
357                 criteria.add(TurbineRolePermissionPeer.ROLE_ID,
358                              ((Persistent) role).getPrimaryKey());
359                 criteria.add(TurbineRolePermissionPeer.PERMISSION_ID,
360                              ((Persistent) permission).getPrimaryKey());
361                 TurbineRolePermissionPeer.doInsert(criteria);
362                 return;
363             }
364         }
365         catch (Exception e)
366         {
367             throw new DataBackendException("grant(Role,Permission) failed", e);
368         }
369         finally
370         {
371             unlockExclusive();
372         }
373         if (!roleExists)
374         {
375             throw new UnknownEntityException("Unknown role '"
376                                              + role.getName() + "'");
377         }
378         if (!permissionExists)
379         {
380             throw new UnknownEntityException("Unknown permission '"
381                                              + permission.getName() + "'");
382         }
383     }
384 
385     /**
386      * Revokes a Permission from a Role.
387      *
388      * @param role the Role.
389      * @param permission the Permission.
390      * @throws DataBackendException if there was an error accessing the data
391      *         backend.
392      * @throws UnknownEntityException if role or permission is not present.
393      */
394     public synchronized void revoke(Role role, Permission permission)
395         throws DataBackendException, UnknownEntityException
396     {
397         boolean roleExists = false;
398         boolean permissionExists = false;
399         try
400         {
401             lockExclusive();
402             roleExists = checkExists(role);
403             permissionExists = checkExists(permission);
404             if (roleExists && permissionExists)
405             {
406                 Criteria criteria = new Criteria();
407                 criteria.add(TurbineRolePermissionPeer.ROLE_ID,
408                              ((Persistent) role).getPrimaryKey());
409                 criteria.add(TurbineRolePermissionPeer.PERMISSION_ID,
410                              ((Persistent) permission).getPrimaryKey());
411                 TurbineRolePermissionPeer.doDelete(criteria);
412                 return;
413             }
414         }
415         catch (Exception e)
416         {
417             throw new DataBackendException("revoke(Role,Permission) failed", e);
418         }
419         finally
420         {
421             unlockExclusive();
422         }
423         if (!roleExists)
424         {
425             throw new UnknownEntityException("Unknown role '"
426                                              + role.getName() + "'");
427         }
428         if (!permissionExists)
429         {
430             throw new UnknownEntityException("Unknown permission '"
431                                              + permission.getName() + "'");
432         }
433     }
434 
435     /**
436      * Revokes all permissions from a Role.
437      *
438      * This method is user when deleting a Role.
439      *
440      * @param role the Role
441      * @throws DataBackendException if there was an error accessing the data
442      *         backend.
443      * @throws UnknownEntityException if the Role is not present.
444      */
445     public synchronized void revokeAll(Role role)
446         throws DataBackendException, UnknownEntityException
447     {
448         boolean roleExists = false;
449         try
450         {
451             lockExclusive();
452             roleExists = checkExists(role);
453             if (roleExists)
454             {
455                 // The following would not work, due to an annoying misfeature
456                 // of Village. see revokeAll( user )
457 
458                 // Criteria criteria = new Criteria();
459                 // criteria.add(RolePermissionPeer.ROLE_ID,
460                 //         role.getPrimaryKey());
461                 // RolePermissionPeer.doDelete(criteria);
462 
463                 int id = ((NumberKey) ((Persistent) role)
464                           .getPrimaryKey()).intValue();
465                 TurbineRolePermissionPeer.deleteAll(
466                     TurbineRolePermissionPeer.TABLE_NAME,
467                     TurbineRolePermissionPeer.ROLE_ID, id);
468                 return;
469             }
470         }
471         catch (Exception e)
472         {
473             throw new DataBackendException("revokeAll(Role) failed", e);
474         }
475         finally
476         {
477             unlockExclusive();
478         }
479         throw new UnknownEntityException("Unknown role '"
480                                          + role.getName() + "'");
481     }
482 
483     /*-----------------------------------------------------------------------
484       Group/Role/Permission management
485       -----------------------------------------------------------------------*/
486 
487     /**
488      * Retrieve a set of Groups that meet the specified Criteria.
489      *
490      * @param criteria A Criteria of Group selection.
491      * @return a set of Groups that meet the specified Criteria.
492      * @throws DataBackendException if there was an error accessing the data
493      *         backend.
494      */
495     public GroupSet getGroups(Object criteria)
496         throws DataBackendException
497     {
498         if (criteria instanceof Criteria)
499         {
500             Criteria torqueCriteria = new Criteria();
501             Criteria c = (Criteria)criteria;
502             Iterator keys = c.keySet().iterator();
503             while (keys.hasNext())
504             {
505                 String key = (String) keys.next();
506                 torqueCriteria.put(GroupPeerManager.getColumnName(key),
507                         c.get(key));
508             }
509             List groups = new ArrayList(0);
510             try
511             {
512                 groups = GroupPeerManager.doSelect(torqueCriteria);
513             }
514             catch (TorqueException e)
515             {
516                 throw new DataBackendException("getGroups(Object) failed", e);
517             }
518 
519             return new GroupSet(groups);
520         }
521         else
522         {
523             throw new DataBackendException(
524                     "getGroups(Object) failed with invalid criteria");
525         }
526     }
527 
528     /**
529      * Retrieve a set of Roles that meet the specified Criteria.
530      *
531      * @param criteria A Criteria of Roles selection.
532      * @return a set of Roles that meet the specified Criteria.
533      * @throws DataBackendException if there was an error accessing the data
534      *         backend.
535      */
536     public RoleSet getRoles(Object criteria)
537         throws DataBackendException
538     {
539         if (criteria instanceof Criteria)
540         {
541             Criteria torqueCriteria = new Criteria();
542             Criteria c = (Criteria)criteria;
543             Iterator keys = c.keySet().iterator();
544             while (keys.hasNext())
545             {
546                 String key = (String) keys.next();
547                 torqueCriteria.put(RolePeerManager.getColumnName(key),
548                         c.get(key));
549             }
550             List roles = new ArrayList(0);
551             try
552             {
553                 roles = RolePeerManager.doSelect(torqueCriteria);
554             }
555             catch (TorqueException e)
556             {
557                 throw new DataBackendException("getRoles(Criteria) failed", e);
558             }
559             return new RoleSet(roles);
560         }
561         else
562         {
563             throw new DataBackendException(
564                     "getRoles(Object) failed with invalid criteria");
565         }
566     }
567 
568     /**
569      * Retrieve a set of Permissions that meet the specified Criteria.
570      *
571      * @param criteria A Criteria of Permissions selection.
572      * @return a set of Permissions that meet the specified Criteria.
573      * @throws DataBackendException if there was an error accessing the data
574      *         backend.
575      */
576     public PermissionSet getPermissions(Object criteria)
577         throws DataBackendException
578     {
579         if (criteria instanceof Criteria)
580         {
581             Criteria torqueCriteria = new Criteria();
582             Criteria c = (Criteria)criteria;
583             Iterator keys = c.keySet().iterator();
584             while (keys.hasNext())
585             {
586                 String key = (String) keys.next();
587                 torqueCriteria.put(PermissionPeerManager.getColumnName(key),
588                         c.get(key));
589             }
590             List permissions = new ArrayList(0);
591             try
592             {
593                 permissions = PermissionPeerManager.doSelect(torqueCriteria);
594             }
595             catch (TorqueException e)
596             {
597                 throw new DataBackendException(
598                     "getPermissions(Object) failed", e);
599             }
600             
601             return new PermissionSet(permissions);
602         }
603         else
604         {
605             throw new DataBackendException(
606                     "getPermissions(Object) failed with invalid criteria");
607         }
608     }
609 
610     /**
611      * Retrieves all permissions associated with a role.
612      *
613      * @param role the role name, for which the permissions are to be retrieved.
614      * @return A Permission set for the Role.
615      * @throws DataBackendException if there was an error accessing the data
616      *         backend.
617      * @throws UnknownEntityException if the role is not present.
618      */
619     public PermissionSet getPermissions(Role role)
620         throws DataBackendException, UnknownEntityException
621     {
622         boolean roleExists = false;
623         try
624         {
625             lockShared();
626             roleExists = checkExists(role);
627             if (roleExists)
628             {
629                 return PermissionPeerManager.retrieveSet(role);
630             }
631         }
632         catch (Exception e)
633         {
634             throw new DataBackendException("getPermissions(Role) failed", e);
635         }
636         finally
637         {
638             unlockShared();
639         }
640         throw new UnknownEntityException("Unknown role '"
641                                          + role.getName() + "'");
642     }
643 
644     /**
645      * Stores Group's attributes. The Groups is required to exist in the system.
646      *
647      * @param group The Group to be stored.
648      * @throws DataBackendException if there was an error accessing the data
649      *         backend.
650      * @throws UnknownEntityException if the group does not exist.
651      */
652     public void saveGroup(Group group)
653         throws DataBackendException, UnknownEntityException
654     {
655         boolean groupExists = false;
656         try
657         {
658             groupExists = checkExists(group);
659             if (groupExists)
660             {
661                 Criteria criteria = GroupPeerManager.buildCriteria(group);
662                 GroupPeerManager.doUpdate(criteria);
663                 return;
664             }
665         }
666         catch (Exception e)
667         {
668             throw new DataBackendException("saveGroup(Group) failed", e);
669         }
670         throw new UnknownEntityException("Unknown group '" + group + "'");
671     }
672 
673     /**
674      * Stores Role's attributes. The Roles is required to exist in the system.
675      *
676      * @param role The Role to be stored.
677      * @throws DataBackendException if there was an error accessing the data
678      *         backend.
679      * @throws UnknownEntityException if the role does not exist.
680      */
681     public void saveRole(Role role)
682         throws DataBackendException, UnknownEntityException
683     {
684         boolean roleExists = false;
685         try
686         {
687             roleExists = checkExists(role);
688             if (roleExists)
689             {
690                 Criteria criteria = RolePeerManager.buildCriteria(role);
691                 RolePeerManager.doUpdate(criteria);
692                 return;
693             }
694         }
695         catch (Exception e)
696         {
697             throw new DataBackendException("saveRole(Role) failed", e);
698         }
699         throw new UnknownEntityException("Unknown role '" + role + "'");
700     }
701 
702     /**
703      * Stores Permission's attributes. The Permissions is required to exist in
704      * the system.
705      *
706      * @param permission The Permission to be stored.
707      * @throws DataBackendException if there was an error accessing the data
708      *         backend.
709      * @throws UnknownEntityException if the permission does not exist.
710      */
711     public void savePermission(Permission permission)
712         throws DataBackendException, UnknownEntityException
713     {
714         boolean permissionExists = false;
715         try
716         {
717             permissionExists = checkExists(permission);
718             if (permissionExists)
719             {
720                 Criteria criteria = PermissionPeerManager.buildCriteria(permission);
721                 PermissionPeerManager.doUpdate(criteria);
722                 return;
723             }
724         }
725         catch (Exception e)
726         {
727             throw new DataBackendException(
728                 "savePermission(Permission) failed", e);
729         }
730         throw new UnknownEntityException("Unknown permission '"
731                                          + permission + "'");
732     }
733 
734     /**
735      * Creates a new group with specified attributes.
736      *
737      * @param group the object describing the group to be created.
738      * @return a new Group object that has id set up properly.
739      * @throws DataBackendException if there was an error accessing the data
740      *         backend.
741      * @throws EntityExistsException if the group already exists.
742      */
743     public synchronized Group addGroup(Group group)
744         throws DataBackendException,
745                EntityExistsException
746     {
747         boolean groupExists = false;
748 
749         if (StringUtils.isEmpty(group.getName()))
750         {
751             throw new DataBackendException("Could not create "
752                                            + "a group with empty name!");
753         }
754 
755         try
756         {
757             lockExclusive();
758             groupExists = checkExists(group);
759             if (!groupExists)
760             {
761                 // add a row to the table
762                 Criteria criteria = GroupPeerManager.buildCriteria(group);
763                 GroupPeerManager.doInsert(criteria);
764                 // try to get the object back using the name as key.
765                 criteria = new Criteria();
766                 criteria.add(GroupPeerManager.getNameColumn(),
767                              group.getName());
768                 List results = GroupPeerManager.doSelect(criteria);
769                 if (results.size() != 1)
770                 {
771                     throw new DataBackendException(
772                         "Internal error - query returned "
773                         + results.size() + " rows");
774                 }
775                 Group newGroup = (Group) results.get(0);
776                 // add the group to system-wide cache
777                 getAllGroups().add(newGroup);
778                 // return the object with correct id
779                 return newGroup;
780             }
781         }
782         catch (Exception e)
783         {
784             throw new DataBackendException("addGroup(Group) failed", e);
785         }
786         finally
787         {
788             unlockExclusive();
789         }
790         // the only way we could get here without return/throw tirggered
791         // is that the groupExists was true.
792         throw new EntityExistsException("Group '" + group + "' already exists");
793     }
794 
795     /**
796      * Creates a new role with specified attributes.
797      *
798      * @param role the object describing the role to be created.
799      * @return a new Role object that has id set up properly.
800      * @throws DataBackendException if there was an error accessing the data
801      *         backend.
802      * @throws EntityExistsException if the role already exists.
803      */
804     public synchronized Role addRole(Role role)
805         throws DataBackendException, EntityExistsException
806     {
807         boolean roleExists = false;
808 
809         if (StringUtils.isEmpty(role.getName()))
810         {
811             throw new DataBackendException("Could not create "
812                                            + "a role with empty name!");
813         }
814 
815         try
816         {
817             lockExclusive();
818             roleExists = checkExists(role);
819             if (!roleExists)
820             {
821                 // add a row to the table
822                 Criteria criteria = RolePeerManager.buildCriteria(role);
823                 RolePeerManager.doInsert(criteria);
824                 // try to get the object back using the name as key.
825                 criteria = new Criteria();
826                 criteria.add(RolePeerManager.getNameColumn(), role.getName());
827                 List results = RolePeerManager.doSelect(criteria);
828                 if (results.size() != 1)
829                 {
830                     throw new DataBackendException(
831                         "Internal error - query returned "
832                         + results.size() + " rows");
833                 }
834                 Role newRole = (Role) results.get(0);
835                 // add the role to system-wide cache
836                 getAllRoles().add(newRole);
837                 // return the object with correct id
838                 return newRole;
839             }
840         }
841         catch (Exception e)
842         {
843             throw new DataBackendException("addRole(Role) failed", e);
844         }
845         finally
846         {
847             unlockExclusive();
848         }
849         // the only way we could get here without return/throw tirggered
850         // is that the roleExists was true.
851         throw new EntityExistsException("Role '" + role + "' already exists");
852     }
853 
854     /**
855      * Creates a new permission with specified attributes.
856      *
857      * @param permission the object describing the permission to be created.
858      * @return a new Permission object that has id set up properly.
859      * @throws DataBackendException if there was an error accessing the data
860      *         backend.
861      * @throws EntityExistsException if the permission already exists.
862      */
863     public synchronized Permission addPermission(Permission permission)
864         throws DataBackendException, EntityExistsException
865     {
866         boolean permissionExists = false;
867 
868         if (StringUtils.isEmpty(permission.getName()))
869         {
870             throw new DataBackendException("Could not create "
871                                            + "a permission with empty name!");
872         }
873 
874         try
875         {
876             lockExclusive();
877             permissionExists = checkExists(permission);
878             if (!permissionExists)
879             {
880                 // add a row to the table
881                 Criteria criteria = PermissionPeerManager.buildCriteria(permission);
882                 PermissionPeerManager.doInsert(criteria);
883                 // try to get the object back using the name as key.
884                 criteria = new Criteria();
885                 criteria.add(PermissionPeerManager.getNameColumn(),
886                              permission.getName());
887                 List results = PermissionPeerManager.doSelect(criteria);
888                 if (results.size() != 1)
889                 {
890                     throw new DataBackendException(
891                         "Internal error - query returned "
892                         + results.size() + " rows");
893                 }
894                 Permission newPermission = (Permission) results.get(0);
895                 // add the permission to system-wide cache
896                 getAllPermissions().add(newPermission);
897                 // return the object with correct id
898                 return newPermission;
899             }
900         }
901         catch (Exception e)
902         {
903             throw new DataBackendException(
904                 "addPermission(Permission) failed", e);
905         }
906         finally
907         {
908             unlockExclusive();
909         }
910         // the only way we could get here without return/throw tirggered
911         // is that the permissionExists was true.
912         throw new EntityExistsException("Permission '" + permission
913                                         + "' already exists");
914     }
915 
916     /**
917      * Removes a Group from the system.
918      *
919      * @param group The object describing the group to be removed.
920      * @throws DataBackendException if there was an error accessing the data
921      *         backend.
922      * @throws UnknownEntityException if the group does not exist.
923      */
924     public synchronized void removeGroup(Group group)
925         throws DataBackendException, UnknownEntityException
926     {
927         boolean groupExists = false;
928         try
929         {
930             lockExclusive();
931             groupExists = checkExists(group);
932             if (groupExists)
933             {
934                 Criteria criteria = GroupPeerManager.buildCriteria(group);
935                 GroupPeerManager.doDelete(criteria);
936                 getAllGroups().remove(group);
937                 return;
938             }
939         }
940         catch (Exception e)
941         {
942             log.error("Failed to delete a Group");
943             log.error(e);
944             throw new DataBackendException("removeGroup(Group) failed", e);
945         }
946         finally
947         {
948             unlockExclusive();
949         }
950         throw new UnknownEntityException("Unknown group '" + group + "'");
951     }
952 
953     /**
954      * Removes a Role from the system.
955      *
956      * @param role The object describing the role to be removed.
957      * @throws DataBackendException if there was an error accessing the data
958      *         backend.
959      * @throws UnknownEntityException if the role does not exist.
960      */
961     public synchronized void removeRole(Role role)
962         throws DataBackendException, UnknownEntityException
963     {
964         boolean roleExists = false;
965         try
966         {
967             lockExclusive();
968             roleExists = checkExists(role);
969             if (roleExists)
970             {
971                 // revoke all permissions from the role to be deleted
972                 revokeAll(role);
973                 Criteria criteria = RolePeerManager.buildCriteria(role);
974                 RolePeerManager.doDelete(criteria);
975                 getAllRoles().remove(role);
976                 return;
977             }
978         }
979         catch (Exception e)
980         {
981             throw new DataBackendException("removeRole(Role)", e);
982         }
983         finally
984         {
985             unlockExclusive();
986         }
987         throw new UnknownEntityException("Unknown role '" + role + "'");
988     }
989 
990     /**
991      * Removes a Permission from the system.
992      *
993      * @param permission The object describing the permission to be removed.
994      * @throws DataBackendException if there was an error accessing the data
995      *         backend.
996      * @throws UnknownEntityException if the permission does not exist.
997      */
998     public synchronized void removePermission(Permission permission)
999         throws DataBackendException, UnknownEntityException
1000     {
1001         boolean permissionExists = false;
1002         try
1003         {
1004             lockExclusive();
1005             permissionExists = checkExists(permission);
1006             if (permissionExists)
1007             {
1008                 Criteria criteria = PermissionPeerManager.buildCriteria(permission);
1009                 PermissionPeerManager.doDelete(criteria);
1010                 getAllPermissions().remove(permission);
1011                 return;
1012             }
1013         }
1014         catch (Exception e)
1015         {
1016             throw new DataBackendException("removePermission(Permission)", e);
1017         }
1018         finally
1019         {
1020             unlockExclusive();
1021         }
1022         throw new UnknownEntityException("Unknown permission '"
1023                                          + permission + "'");
1024     }
1025 
1026     /**
1027      * Renames an existing Group.
1028      *
1029      * @param group The object describing the group to be renamed.
1030      * @param name the new name for the group.
1031      * @throws DataBackendException if there was an error accessing the data
1032      *         backend.
1033      * @throws UnknownEntityException if the group does not exist.
1034      */
1035     public synchronized void renameGroup(Group group, String name)
1036         throws DataBackendException, UnknownEntityException
1037     {
1038         boolean groupExists = false;
1039         try
1040         {
1041             lockExclusive();
1042             groupExists = checkExists(group);
1043             if (groupExists)
1044             {
1045                 group.setName(name);
1046                 Criteria criteria = GroupPeerManager.buildCriteria(group);
1047                 GroupPeerManager.doUpdate(criteria);
1048                 return;
1049             }
1050         }
1051         catch (Exception e)
1052         {
1053             throw new DataBackendException("renameGroup(Group,String)", e);
1054         }
1055         finally
1056         {
1057             unlockExclusive();
1058         }
1059         throw new UnknownEntityException("Unknown group '" + group + "'");
1060     }
1061 
1062     /**
1063      * Renames an existing Role.
1064      *
1065      * @param role The object describing the role to be renamed.
1066      * @param name the new name for the role.
1067      * @throws DataBackendException if there was an error accessing the data
1068      *         backend.
1069      * @throws UnknownEntityException if the role does not exist.
1070      */
1071     public synchronized void renameRole(Role role, String name)
1072         throws DataBackendException, UnknownEntityException
1073     {
1074         boolean roleExists = false;
1075         try
1076         {
1077             lockExclusive();
1078             roleExists = checkExists(role);
1079             if (roleExists)
1080             {
1081                 role.setName(name);
1082                 Criteria criteria = RolePeerManager.buildCriteria(role);
1083                 RolePeerManager.doUpdate(criteria);
1084                 return;
1085             }
1086         }
1087         catch (Exception e)
1088         {
1089             throw new DataBackendException("renameRole(Role,String)", e);
1090         }
1091         finally
1092         {
1093             unlockExclusive();
1094         }
1095         throw new UnknownEntityException("Unknown role '" + role + "'");
1096     }
1097 
1098     /**
1099      * Renames an existing Permission.
1100      *
1101      * @param permission The object describing the permission to be renamed.
1102      * @param name the new name for the permission.
1103      * @throws DataBackendException if there was an error accessing the data
1104      *         backend.
1105      * @throws UnknownEntityException if the permission does not exist.
1106      */
1107     public synchronized void renamePermission(Permission permission,
1108                                               String name)
1109         throws DataBackendException, UnknownEntityException
1110     {
1111         boolean permissionExists = false;
1112         try
1113         {
1114             lockExclusive();
1115             permissionExists = checkExists(permission);
1116             if (permissionExists)
1117             {
1118                 permission.setName(name);
1119                 Criteria criteria = PermissionPeerManager.buildCriteria(permission);
1120                 PermissionPeerManager.doUpdate(criteria);
1121                 return;
1122             }
1123         }
1124         catch (Exception e)
1125         {
1126             throw new DataBackendException(
1127                 "renamePermission(Permission,name)", e);
1128         }
1129         finally
1130         {
1131             unlockExclusive();
1132         }
1133         throw new UnknownEntityException("Unknown permission '"
1134                                          + permission + "'");
1135     }
1136 
1137     /* Service specific implementation methods */
1138 
1139     /**
1140      * Determines if the <code>Group</code> exists in the security system.
1141      *
1142      * @param group a <code>Group</code> value
1143      * @return true if the group exists in the system, false otherwise
1144      * @throws DataBackendException when more than one Group with
1145      *         the same name exists.
1146      * @throws Exception A generic exception.
1147      */
1148     protected boolean checkExists(Group group)
1149         throws DataBackendException, Exception
1150     {
1151         return GroupPeerManager.checkExists(group);
1152     }
1153 
1154     /**
1155      * Determines if the <code>Role</code> exists in the security system.
1156      *
1157      * @param role a <code>Role</code> value
1158      * @return true if the role exists in the system, false otherwise
1159      * @throws DataBackendException when more than one Role with
1160      *         the same name exists.
1161      * @throws Exception A generic exception.
1162      */
1163     protected boolean checkExists(Role role)
1164         throws DataBackendException, Exception
1165     {
1166         return RolePeerManager.checkExists(role);
1167     }
1168 
1169     /**
1170      * Determines if the <code>Permission</code> exists in the security system.
1171      *
1172      * @param permission a <code>Permission</code> value
1173      * @return true if the permission exists in the system, false otherwise
1174      * @throws DataBackendException when more than one Permission with
1175      *         the same name exists.
1176      * @throws Exception A generic exception.
1177      */
1178     protected boolean checkExists(Permission permission)
1179         throws DataBackendException, Exception
1180     {
1181         return PermissionPeerManager.checkExists(permission);
1182     }
1183 
1184 
1185     /**
1186      * Retrieves all groups defined in the system.
1187      *
1188      * @return the names of all groups defined in the system.
1189      * @throws DataBackendException if there was an error accessing the
1190      *         data backend.
1191      */
1192     public GroupSet getAllGroups() throws DataBackendException
1193     {
1194         return getGroups(new Criteria());
1195     }
1196 
1197 
1198     /**
1199      * Retrieves all permissions defined in the system.
1200      *
1201      * @return the names of all roles defined in the system.
1202      * @throws DataBackendException if there was an error accessing the
1203      *         data backend.
1204      */
1205     public PermissionSet getAllPermissions() throws DataBackendException
1206     {
1207         return getPermissions(new Criteria());
1208     }
1209 
1210 
1211     /**
1212      * Retrieves all roles defined in the system.
1213      *
1214      * @return the names of all roles defined in the system.
1215      * @throws DataBackendException if there was an error accessing the
1216      *         data backend.
1217      */
1218     public RoleSet getAllRoles() throws DataBackendException
1219     {
1220         return getRoles(new Criteria());
1221     }
1222 
1223 
1224     /**
1225      * Retrieve a set of users that meet the specified criteria.
1226      *
1227      * As the keys for the criteria, you should use the constants that
1228      * are defined in {@link User} interface, plus the names
1229      * of the custom attributes you added to your user representation
1230      * in the data storage. Use verbatim names of the attributes -
1231      * without table name prefix in case of Torque implementation.
1232      *
1233      * @param criteria The criteria of selection.
1234      * @return a List of users meeting the criteria.
1235      * @throws DataBackendException if there is a problem accessing the
1236      *         storage.
1237      */
1238     public List getUserList(Object criteria) throws DataBackendException
1239     {
1240         return getUserManager().retrieveList(criteria);
1241     }
1242 
1243 }