001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/security/drm/SecurityTransaction.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     ---------------------------------------------------------------------------*/
043    package org.deegree.security.drm;
044    
045    import java.util.ArrayList;
046    import java.util.HashSet;
047    import java.util.Iterator;
048    import java.util.List;
049    
050    import org.deegree.security.GeneralSecurityException;
051    import org.deegree.security.UnauthorizedException;
052    import org.deegree.security.drm.model.Group;
053    import org.deegree.security.drm.model.Privilege;
054    import org.deegree.security.drm.model.Right;
055    import org.deegree.security.drm.model.RightSet;
056    import org.deegree.security.drm.model.RightType;
057    import org.deegree.security.drm.model.Role;
058    import org.deegree.security.drm.model.SecurableObject;
059    import org.deegree.security.drm.model.SecuredObject;
060    import org.deegree.security.drm.model.User;
061    
062    /**
063     * 
064     * 
065     * 
066     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
067     * @author last edited by: $Author: apoth $
068     * 
069     * @version $Revision: 9346 $, $Date: 2007-12-27 17:39:07 +0100 (Do, 27 Dez 2007) $
070     */
071    public class SecurityTransaction extends SecurityAccess {
072    
073        private Role adminRole;
074    
075        private long timestamp;
076    
077        /**
078         * @param user
079         * @param registry
080         * @param adminRole
081         */
082        SecurityTransaction( User user, SecurityRegistry registry, Role adminRole ) {
083            super( user, registry );
084            this.adminRole = adminRole;
085            this.timestamp = System.currentTimeMillis();
086        }
087    
088        /**
089         * Returns the conjunction of an array of roles plus a single role.
090         * 
091         * @param roles
092         * @param role
093         * @return the conjunction of an array of roles plus a single role.
094         */
095        public Role[] addRoles( Role[] roles, Role role ) {
096            HashSet<Role> roleSet = new HashSet<Role>( roles.length + 1 );
097            roleSet.add( role );
098            for ( int i = 0; i < roles.length; i++ ) {
099                roleSet.add( roles[i] );
100            }
101            return roleSet.toArray( new Role[roleSet.size()] );
102        }
103    
104        /**
105         * Deletes all data from the underlying <code>Registry</code> and sets the default objects
106         * (SEC_ADMIN user, role and group) and standard rights and privileges.
107         * 
108         * @throws GeneralSecurityException
109         */
110        public void clean()
111                                throws GeneralSecurityException {
112            SecurityAccessManager.getInstance().verify( this );
113            registry.clean( this );
114        }
115    
116        /**
117         * Removes a <code>Group</code> from the <code>Registry</code>.
118         * 
119         * This means:
120         * <ul>
121         * <li>owner role ($G:GROUPNAME) is removed
122         * <li>group is removed
123         * </ul>
124         * 
125         * NOTE: Only performed if the acting user has the 'delete'-right on the group object.
126         * 
127         * @param group
128         * @throws GeneralSecurityException
129         * @throws UnauthorizedException
130         */
131        public void deregisterGroup( Group group )
132                                throws GeneralSecurityException, UnauthorizedException {
133            SecurityAccessManager.getInstance().verify( this );
134            checkForRight( RightType.DELETE, group );
135            try {
136                Role ownerRole = registry.getRoleByName( this, "$G:" + group.getName() );
137                registry.deregisterRole( this, ownerRole );
138            } catch ( UnknownException e ) {
139            }
140            registry.deregisterGroup( this, group );
141        }
142    
143        /**
144         * Removes a <code>Role</code> from the <code>Registry</code>.
145         * 
146         * This means:
147         * <ul>
148         * <li>owner role ($R:ROLENAME) is removed
149         * <li>role is removed
150         * </ul>
151         * 
152         * NOTE: Only performed if acting user has the 'delete'-right on the role object.
153         * 
154         * @param role
155         * @throws GeneralSecurityException
156         * @throws UnauthorizedException
157         */
158        public void deregisterRole( Role role )
159                                throws GeneralSecurityException, UnauthorizedException {
160            SecurityAccessManager.getInstance().verify( this );
161            checkForRight( RightType.DELETE, role );
162            try {
163                Role ownerRole = registry.getRoleByName( this, "$R:" + role.getName() );
164                registry.deregisterRole( this, ownerRole );
165            } catch ( UnknownException e ) {
166            }
167            registry.deregisterRole( this, role );
168        }
169    
170        /**
171         * Removes a <code>SecuredObject</code> from the <code>Registry</code>.
172         * 
173         * This means:
174         * <ul>
175         * <li>owner role ($O:OBJECTNAME) is removed
176         * <li>object is removed
177         * </ul>
178         * 
179         * NOTE: Only performed if acting user has the 'delete'-right on the secured object.
180         * 
181         * @param object
182         * @throws GeneralSecurityException
183         * @throws UnauthorizedException
184         */
185        public void deregisterSecuredObject( SecuredObject object )
186                                throws GeneralSecurityException, UnauthorizedException {
187            SecurityAccessManager.getInstance().verify( this );
188            checkForRight( RightType.DELETE, object );
189            try {
190                Role ownerRole = registry.getRoleByName( this, "$O:" + object.getName() );
191                registry.deregisterRole( this, ownerRole );
192            } catch ( UnknownException e ) {
193            }
194            registry.deregisterSecuredObject( this, object );
195        }
196    
197        /**
198         * Removes a <code>User</code> from the <code>Registry</code>.
199         * 
200         * This means:
201         * <ul>
202         * <li>owner role ($U:USERNAME) is removed
203         * <li>user is removed
204         * </ul>
205         * 
206         * NOTE: Only performed if acting user has the 'delete'-right on the user object.
207         * 
208         * @param user
209         * @throws GeneralSecurityException
210         * @throws UnauthorizedException
211         */
212        public void deregisterUser( User user )
213                                throws GeneralSecurityException, UnauthorizedException {
214            SecurityAccessManager.getInstance().verify( this );
215            checkForRight( RightType.DELETE, user );
216            try {
217                Role ownerRole = registry.getRoleByName( this, "$U:" + user.getName() );
218                registry.deregisterRole( this, ownerRole );
219            } catch ( UnknownException e ) {
220                e.printStackTrace();
221            }
222            registry.deregisterUser( this, user );
223        }
224    
225        /**
226         * 
227         * @return timestamp
228         */
229        public long getTimestamp() {
230            return timestamp;
231        }
232    
233        /**
234         * Registers a new <code>Group</code> to the <code>Registry</code>.
235         * 
236         * This means:
237         * <ul>
238         * <li>a group is created in the registry
239         * <li>a corresponding owner role is created: $G:GROUPNAME
240         * <li>rights for the owner role are set up; creator has delete, update and grant rights on the
241         * group, administrator role gets these right, too
242         * </ul>
243         * 
244         * NOTE: Only performed if acting user has the 'addgroup'-privilege.
245         * 
246         * @param name
247         * @param title
248         * @return
249         * @throws GeneralSecurityException
250         */
251        public Group registerGroup( String name, String title )
252                                throws GeneralSecurityException {
253            SecurityAccessManager.getInstance().verify( this );
254            checkForPrivilege( Privilege.ADDGROUP );
255            if ( name.startsWith( "$" ) ) {
256                throw new GeneralSecurityException( "Groupname '" + name + "' is invalid. The '$'-character is for "
257                                                    + "internal use only." );
258            }
259            Group group = registry.registerGroup( this, name, title );
260            // only add owner role if lock holder is not the administrator
261            if ( this.user.getID() != User.ID_SEC_ADMIN ) {
262                Role ownerRole = registry.registerRole( this, "$G:" + name );
263                registry.setRolesForUser( this, user, addRoles( registry.getRolesForUser( this, user ), ownerRole ) );
264                registry.setRights( this, group, ownerRole, new Right[] { new Right( group, RightType.DELETE ),
265                                                                         new Right( group, RightType.UPDATE ),
266                                                                         new Right( group, RightType.GRANT ) } );
267            }
268            registry.setRights( this, group, adminRole, new Right[] { new Right( group, RightType.DELETE ),
269                                                                     new Right( group, RightType.UPDATE ),
270                                                                     new Right( group, RightType.GRANT ) } );
271            return group;
272        }
273    
274        /**
275         * Registers a new <code>Role</code> to the <code>Registry</code>.
276         * 
277         * This means:
278         * <ul>
279         * <li>a role is created in the registry
280         * <li>a corresponding owner role is created: $R:ROLENAME
281         * <li>rights for the owner role are set up; creator has delete, update and grant rights on the
282         * role, administrator role gets these right, too
283         * </ul>
284         * 
285         * NOTE: Only performed if acting user has the 'addrole'-privilege.
286         * 
287         * @param name
288         * @return
289         * @throws GeneralSecurityException
290         */
291        public Role registerRole( String name )
292                                throws GeneralSecurityException {
293            SecurityAccessManager.getInstance().verify( this );
294            checkForPrivilege( Privilege.ADDROLE );
295            if ( name.startsWith( "$" ) ) {
296                throw new GeneralSecurityException( "Rolename '" + name + "' is invalid. The '$'-character is for "
297                                                    + "internal use only." );
298            }
299    
300            Role role = registry.registerRole( this, name );
301            if ( this.user.getID() != User.ID_SEC_ADMIN ) {
302                Role ownerRole = registry.registerRole( this, "$R:" + name );
303                registry.setRolesForUser( this, user, addRoles( registry.getRolesForUser( this, user ), ownerRole ) );
304                registry.setRights( this, role, ownerRole, new Right[] { new Right( role, RightType.DELETE ),
305                                                                        new Right( role, RightType.UPDATE ),
306                                                                        new Right( role, RightType.GRANT ) } );
307            }
308            registry.setRights( this, role, adminRole, new Right[] { new Right( role, RightType.DELETE ),
309                                                                    new Right( role, RightType.UPDATE ),
310                                                                    new Right( role, RightType.GRANT ) } );
311            return role;
312        }
313    
314        /**
315         * Registers a new <code>SecuredObject</code> to the <code>Registry</code>.
316         * 
317         * This means:
318         * <ul>
319         * <li>a secured object is created in the registry
320         * <li>a corresponding owner role is created: $O:OBJECTNAME
321         * <li>rights for the owner role are set up; creator has delete, update and grant rights on the
322         * object, administrator role gets these right, too
323         * </ul>
324         * 
325         * @param type
326         * @param name
327         * @param title
328         * @return
329         * @throws GeneralSecurityException
330         */
331        public SecuredObject registerSecuredObject( String type, String name, String title )
332                                throws GeneralSecurityException {
333            SecurityAccessManager.getInstance().verify( this );
334            checkForPrivilege( Privilege.ADDOBJECT );
335            if ( name.startsWith( "$" ) ) {
336                throw new GeneralSecurityException( "Objectname '" + name + "' is invalid. The '$'-character is for "
337                                                    + "internal use only." );
338            }
339            SecuredObject object = registry.registerSecuredObject( this, type, name, title );
340            if ( this.user.getID() != User.ID_SEC_ADMIN ) {
341                Role ownerRole = registry.registerRole( this, "$O:" + name );
342                registry.setRolesForUser( this, user, addRoles( registry.getRolesForUser( this, user ), ownerRole ) );
343                registry.setRights( this, object, ownerRole, new Right[] { new Right( object, RightType.DELETE ),
344                                                                          new Right( object, RightType.UPDATE ),
345                                                                          new Right( object, RightType.GRANT ) } );
346            }
347            registry.setRights( this, object, adminRole, new Right[] { new Right( object, RightType.DELETE ),
348                                                                      new Right( object, RightType.UPDATE ),
349                                                                      new Right( object, RightType.GRANT ) } );
350            return object;
351        }
352    
353        /**
354         * Registers a new <code>User</code> to the <code>Registry</code>.
355         * 
356         * This means:
357         * <ul>
358         * <li>a user is created in the registry
359         * <li>a corresponding owner role is created: $U:USERNAME
360         * <li>rights for the owner role are set up; creator has delete, update and grant rights on the
361         * user, administrator role gets these right, too
362         * </ul>
363         * 
364         * NOTE: Only performed if acting user has the 'adduser'-privilege.
365         * 
366         * @param name
367         * @param password
368         *            null means that password checking is disabled
369         * @param lastName
370         * @param firstName
371         * @param mailAddress
372         * @return
373         * @throws GeneralSecurityException
374         */
375        public User registerUser( String name, String password, String lastName, String firstName, String mailAddress )
376                                throws GeneralSecurityException {
377            SecurityAccessManager.getInstance().verify( this );
378            checkForPrivilege( Privilege.ADDUSER );
379            if ( name.startsWith( "$" ) ) {
380                throw new GeneralSecurityException( "Username '" + name + "' is invalid. The '$'-character is for "
381                                                    + "internal use only." );
382            }
383            User user = registry.registerUser( this, name, password, lastName, firstName, mailAddress );
384    
385            // only add owner role if lock holder is not the administrator
386            if ( this.user.getID() != User.ID_SEC_ADMIN ) {
387                Role ownerRole = registry.registerRole( this, "$U:" + name );
388                registry.setRolesForUser( this, user, addRoles( registry.getRolesForUser( this, user ), ownerRole ) );
389                registry.setRights( this, user, ownerRole, new Right[] { new Right( user, RightType.DELETE ),
390                                                                        new Right( user, RightType.UPDATE ),
391                                                                        new Right( user, RightType.GRANT ) } );
392            }
393            registry.setRights( this, user, adminRole, new Right[] { new Right( user, RightType.DELETE ),
394                                                                    new Right( user, RightType.UPDATE ),
395                                                                    new Right( user, RightType.GRANT ) } );
396            return user;
397        }
398    
399        /**
400         * Updates the data of an existing <code>User</code> in the <code>Registry</code>.
401         * 
402         * NOTE: Only performed if acting user has the 'update'-right on the user.
403         * 
404         * @param user
405         * @throws GeneralSecurityException
406         */
407        public void updateUser( User user )
408                                throws GeneralSecurityException {
409            SecurityAccessManager.getInstance().verify( this );
410            checkForRight( RightType.UPDATE, user );
411            registry.updateUser( this, user );
412        }
413    
414        /**
415         * Sets the <code>Group</code> s that a given <code>Group</code> is a DIRECT member of.
416         * 
417         * NOTE: Only performed if the acting user has the 'grant'-right for all the groups that are
418         * requested to be added / removed.
419         * 
420         * @param group
421         * @param newGroups
422         * @throws GeneralSecurityException
423         * @throws UnauthorizedException
424         */
425        public void setGroupsForGroup( Group group, Group[] newGroups )
426                                throws GeneralSecurityException, UnauthorizedException {
427            SecurityAccessManager.getInstance().verify( this );
428            Group[] oldGroups = group.getGroups( this );
429    
430            // build set for old groups
431            HashSet<Group> oldGroupSet = new HashSet<Group>( oldGroups.length );
432            for ( int i = 0; i < oldGroups.length; i++ ) {
433                oldGroupSet.add( oldGroups[i] );
434            }
435            // build set for new groups
436            HashSet<Group> newGroupSet = new HashSet<Group>( oldGroups.length );
437            for ( int i = 0; i < newGroups.length; i++ ) {
438                newGroupSet.add( newGroups[i] );
439            }
440    
441            // check grant right for all groups requested to be removed
442            Iterator it = oldGroupSet.iterator();
443            while ( it.hasNext() ) {
444                Group currGroup = (Group) it.next();
445                if ( !newGroupSet.contains( currGroup ) ) {
446                    checkForRight( RightType.GRANT, group );
447                }
448            }
449    
450            // check grant right for all groups requested to be added
451            it = newGroupSet.iterator();
452            while ( it.hasNext() ) {
453                Group currGroup = (Group) it.next();
454                if ( !oldGroupSet.contains( currGroup ) ) {
455                    checkForRight( RightType.GRANT, group );
456                }
457            }
458            registry.setGroupsForGroup( this, group, newGroups );
459        }
460    
461        /**
462         * Sets the <code>Groups</code> that a given <code>User</code> is a DIRECT member of.
463         * 
464         * NOTE: Only performed if the acting user has the 'grant'-right for all the groups that are
465         * requested to be added / removed.
466         * 
467         * @param user
468         * @param newGroups
469         * @throws GeneralSecurityException
470         * @throws UnauthorizedException
471         */
472        public void setGroupsForUser( User user, Group[] newGroups )
473                                throws GeneralSecurityException, UnauthorizedException {
474            SecurityAccessManager.getInstance().verify( this );
475            Group[] oldGroups = user.getGroups( this );
476    
477            // build set for old groups
478            HashSet<Group> oldGroupSet = new HashSet<Group>( oldGroups.length );
479            for ( int i = 0; i < oldGroups.length; i++ ) {
480                oldGroupSet.add( oldGroups[i] );
481            }
482            // build set for new groups
483            HashSet<Group> newGroupSet = new HashSet<Group>( oldGroups.length );
484            for ( int i = 0; i < newGroups.length; i++ ) {
485                newGroupSet.add( newGroups[i] );
486            }
487    
488            // check grant right for all groups requested to be removed
489            Iterator it = oldGroupSet.iterator();
490            while ( it.hasNext() ) {
491                Group group = (Group) it.next();
492                if ( !newGroupSet.contains( group ) ) {
493                    checkForRight( RightType.GRANT, group );
494                }
495            }
496    
497            // check grant right for all groups requested to be added
498            it = newGroupSet.iterator();
499            while ( it.hasNext() ) {
500                Group group = (Group) it.next();
501                if ( !oldGroupSet.contains( group ) ) {
502                    checkForRight( RightType.GRANT, group );
503                }
504            }
505            registry.setGroupsForUser( this, user, newGroups );
506        }
507    
508        /**
509         * Sets the members (groups) for a group.
510         * 
511         * NOTE: Only performed if the acting user has the 'grant'-right on the group.
512         * 
513         * @param group
514         * @param groups
515         * @throws GeneralSecurityException
516         * @throws UnauthorizedException
517         */
518        public void setGroupsInGroup( Group group, Group[] groups )
519                                throws GeneralSecurityException, UnauthorizedException {
520            SecurityAccessManager.getInstance().verify( this );
521            checkForRight( RightType.GRANT, group );
522            registry.setGroupsInGroup( this, group, groups );
523        }
524    
525        /**
526         * Sets the groups to be associated with the given role.
527         * 
528         * NOTE: Only performed if the acting user has the 'grant'-right on the role.
529         * 
530         * @param role
531         * @param groups
532         * @throws GeneralSecurityException
533         *             if not permitted
534         * @throws UnauthorizedException
535         */
536        public void setGroupsWithRole( Role role, Group[] groups )
537                                throws GeneralSecurityException, UnauthorizedException {
538            SecurityAccessManager.getInstance().verify( this );
539            checkForRight( RightType.GRANT, role );
540            registry.setGroupsWithRole( this, role, groups );
541        }
542    
543        /**
544         * Sets the privileges for a certain role.
545         * 
546         * NOTE: Only performed if the acting user has all the privileges he is trying to grant.
547         * 
548         * FIXME: Shouldn't that be "... to grant / withdraw"?
549         * 
550         * @param role
551         * @param privileges
552         * @throws GeneralSecurityException
553         *             if not permitted
554         */
555        public void setPrivilegesForRole( Role role, Privilege[] privileges )
556                                throws GeneralSecurityException {
557            SecurityAccessManager.getInstance().verify( this );
558            Privilege[] holderPrivileges = user.getPrivileges( this );
559            HashSet<Privilege> holderSet = new HashSet<Privilege>( holderPrivileges.length );
560            for ( int i = 0; i < holderPrivileges.length; i++ ) {
561                holderSet.add( holderPrivileges[i] );
562            }
563            for ( int i = 0; i < privileges.length; i++ ) {
564                if ( !holderSet.contains( privileges[i] ) ) {
565                    throw new GeneralSecurityException( "The requested operation requires the privilege '"
566                                                        + privileges[i].getName() + "'." );
567                }
568            }
569            registry.setPrivilegesForRole( this, role, privileges );
570        }
571    
572        /**
573         * Sets the <code>Rights</code> that a certain role has on a given object.
574         * 
575         * NOTE: Only performed if the acting user has the 'update'-right on the role and the
576         * 'grant'-right on the securable object.
577         * 
578         * @param object
579         * @param role
580         * @param rights
581         * @throws GeneralSecurityException
582         *             if not permitted
583         * @throws UnauthorizedException
584         */
585        public void setRights( SecurableObject object, Role role, Right[] rights )
586                                throws GeneralSecurityException, UnauthorizedException {
587            SecurityAccessManager.getInstance().verify( this );
588            checkForRight( RightType.UPDATE, role );
589            checkForRight( RightType.GRANT, object );
590            registry.setRights( this, object, role, rights );
591        }
592    
593        /**
594         * Sets one certain right that a certain role has on the given objects.
595         * 
596         * NOTE: Only performed if the acting user has the 'update'-right on the role and the
597         * 'grant'-right on the securable objects.
598         * 
599         * @param objects
600         * @param role
601         * @param right
602         * @throws GeneralSecurityException
603         *             if not permitted
604         * @throws UnauthorizedException
605         */
606        public void setRights( SecurableObject[] objects, Role role, Right right )
607                                throws GeneralSecurityException, UnauthorizedException {
608            SecurityAccessManager.getInstance().verify( this );
609            checkForRight( RightType.UPDATE, role );
610            for ( int i = 0; i < objects.length; i++ ) {
611                checkForRight( RightType.GRANT, objects[i] );
612            }
613            registry.setRights( this, objects, role, right );
614        }
615    
616        /**
617         * Adds the specified <code>Rights</code> on the passed object to the passed role. If they are
618         * already present, nothing happens.
619         * 
620         * @param object
621         * @param role
622         * @param additionalRights
623         * @throws GeneralSecurityException
624         * @throws UnauthorizedException
625         */
626        public void addRights( SecurableObject object, Role role, Right[] additionalRights )
627                                throws GeneralSecurityException, UnauthorizedException {
628            SecurityAccessManager.getInstance().verify( this );
629            checkForRight( RightType.UPDATE, role );
630            checkForRight( RightType.GRANT, object );
631            RightSet presentRights = new RightSet( registry.getRights( this, object, role ) );
632            RightSet newRights = presentRights.merge( new RightSet( additionalRights ) );
633            registry.setRights( this, object, role, newRights.toArray( object ) );
634        }
635    
636        /**
637         * Adds the specified <code>Rights</code> on the passed object to the passed role. If they are
638         * already present, nothing happens.
639         * 
640         * @param object
641         * @param role
642         * @param types
643         * @throws UnauthorizedException
644         * @throws GeneralSecurityException
645         */
646        public void addRights( SecurableObject object, Role role, RightType[] types )
647                                throws UnauthorizedException, GeneralSecurityException {
648            Right[] additionalRights = new Right[types.length];
649            for ( int i = 0; i < additionalRights.length; i++ ) {
650                additionalRights[i] = new Right( object, types[i] );
651            }
652            addRights( object, role, additionalRights );
653        }
654    
655        /**
656         * Removes all rights of the specified types that the role may have on the given
657         * <code>SecurableObject</code>.
658         * 
659         * @param object
660         * @param role
661         * @param types
662         * @throws GeneralSecurityException
663         * @throws UnauthorizedException
664         */
665        public void removeRights( SecurableObject object, Role role, RightType[] types )
666                                throws GeneralSecurityException, UnauthorizedException {
667            SecurityAccessManager.getInstance().verify( this );
668            checkForRight( RightType.UPDATE, role );
669            checkForRight( RightType.GRANT, object );
670    
671            Right[] rights = registry.getRights( this, object, role );
672            List<Right> newRightList = new ArrayList<Right>( 20 );
673            for ( int i = 0; i < rights.length; i++ ) {
674                RightType type = rights[i].getType();
675                boolean remove = true;
676                for ( int j = 0; j < types.length; j++ ) {
677                    if ( type.equals( types[j] ) ) {
678                        remove = true;
679                    }
680                }
681                if ( !remove ) {
682                    newRightList.add( rights[i] );
683                }
684            }
685            Right[] newRights = newRightList.toArray( new Right[newRightList.size()] );
686            registry.setRights( this, object, role, newRights );
687        }
688    
689        /**
690         * Sets the members (users) in a group.
691         * 
692         * NOTE: Only performed if the acting user has the 'grant'-right on the group.
693         * 
694         * @param group
695         * @param users
696         * @throws GeneralSecurityException
697         * @throws UnauthorizedException
698         */
699        public void setUsersInGroup( Group group, User[] users )
700                                throws GeneralSecurityException, UnauthorizedException {
701            SecurityAccessManager.getInstance().verify( this );
702            checkForRight( RightType.GRANT, group );
703            registry.setUsersInGroup( this, group, users );
704        }
705    
706        /**
707         * Sets the users to be associated with the given role (DIRECTLY, i.e. not via group
708         * memberships).
709         * 
710         * NOTE: Only performed if the user has the 'grant'-right on the role.
711         * 
712         * @param role
713         * @param users
714         * @throws GeneralSecurityException
715         *             if not permitted
716         * @throws UnauthorizedException
717         */
718        public void setUsersWithRole( Role role, User[] users )
719                                throws GeneralSecurityException, UnauthorizedException {
720            SecurityAccessManager.getInstance().verify( this );
721            checkForRight( RightType.GRANT, role );
722            registry.setUsersWithRole( this, role, users );
723        }
724    
725        /*
726         * (non-Javadoc)
727         * 
728         * @see java.lang.Object#toString()
729         */
730        public String toString() {
731            StringBuffer sb = new StringBuffer();
732            try {
733                User[] users = getAllUsers();
734    
735                sb.append( "\n\nSecurityAccess @ " + System.currentTimeMillis() );
736    
737                sb.append( "\n\n" ).append( users.length ).append( " registered users:\n" );
738                for ( int i = 0; i < users.length; i++ ) {
739                    sb.append( users[i].toString( this ) ).append( "\n" );
740                }
741                Group[] groups = getAllGroups();
742                sb.append( "\n" ).append( groups.length ).append( " registered groups:\n" );
743                for ( int i = 0; i < groups.length; i++ ) {
744                    sb.append( groups[i].toString( this ) ).append( "\n" );
745                }
746                Role[] roles = getAllRoles();
747                sb.append( "\n" ).append( roles.length ).append( " registered roles:\n" );
748                for ( int i = 0; i < roles.length; i++ ) {
749                    sb.append( roles[i].toString( this ) ).append( "\n" );
750                }
751            } catch ( Exception e ) {
752                e.printStackTrace();
753            }
754            return sb.toString();
755        }
756    
757        /**
758         * 
759         */
760        void renew() {
761            this.timestamp = System.currentTimeMillis();
762        }
763    }