001    package org.apache.turbine.services.security.torque;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.util.ArrayList;
023    import java.util.Hashtable;
024    import java.util.Iterator;
025    import java.util.List;
026    
027    import org.apache.commons.configuration.Configuration;
028    import org.apache.commons.lang.StringUtils;
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    import org.apache.torque.TorqueException;
032    import org.apache.torque.om.NumberKey;
033    import org.apache.torque.om.Persistent;
034    import org.apache.torque.util.Criteria;
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.security.BaseSecurityService;
041    import org.apache.turbine.services.security.TurbineSecurity;
042    import org.apache.turbine.services.security.torque.om.TurbineRolePermissionPeer;
043    import org.apache.turbine.services.security.torque.om.TurbineUserGroupRolePeer;
044    import org.apache.turbine.util.security.AccessControlList;
045    import org.apache.turbine.util.security.DataBackendException;
046    import org.apache.turbine.util.security.EntityExistsException;
047    import org.apache.turbine.util.security.GroupSet;
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     * An implementation of SecurityService that uses torque objects.
054     *
055     * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
056     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
057     * @author <a href="mailto:marco@intermeta.de">Marco Kn&uuml;ttel</a>
058     * @version $Id: TorqueSecurityService.java 1096130 2011-04-23 10:37:19Z ludwig $
059     */
060    public class TorqueSecurityService
061        extends BaseSecurityService
062    {
063        /** Logging */
064        private static Log log = LogFactory.getLog(TorqueSecurityService.class);
065    
066        /**
067         * Initializes the TorqueSecurityService, loading the various class objects
068         * representing the security entity peer classes
069         *
070         * @exception InitializationException A problem occured during initialization
071         */
072    
073        public void init()
074            throws InitializationException
075        {
076            Configuration conf = getConfiguration();
077    
078            GroupPeerManager.init(conf);
079            RolePeerManager.init(conf);
080            PermissionPeerManager.init(conf);
081    
082            /* At the end, because it calls setInit(true)! */
083            super.init();
084        }
085    
086    
087        /*-----------------------------------------------------------------------
088          Creation of AccessControlLists
089          -----------------------------------------------------------------------*/
090    
091        /**
092         * Constructs an AccessControlList for a specific user.
093         *
094         * This method creates a snapshot of the state of security information
095         * concerning this user, at the moment of invocation and stores it
096         * into an AccessControlList object.
097         *
098         * @param user the user for whom the AccessControlList are to be retrieved
099         * @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    }