View Javadoc

1   /*
2   jGuard is a security framework based on top of jaas (java authentication and authorization security).
3   it is written for web applications, to resolve simply, access control problems.
4   
5   http://sourceforge.net/projects/jguard/
6   
7   Copyright (C) 2004  Charles GAY
8   
9   This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13  
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  Lesser General Public License for more details.
18  
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  
23  
24  jGuard project home page:
25  http://sourceforge.net/projects/jguard/
26  
27  */
28  package net.sf.jguard.ext.authorization.manager;
29  
30  import net.sf.jguard.core.authorization.manager.AuthorizationManager;
31  import java.security.Permission;
32  import java.security.PermissionCollection;
33  import java.security.Permissions;
34  import java.security.Principal;
35  import java.security.ProtectionDomain;
36  import java.util.Arrays;
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.Enumeration;
40  import java.util.HashMap;
41  import java.util.HashSet;
42  import java.util.Iterator;
43  import java.util.List;
44  import java.util.Map;
45  import java.util.Random;
46  import java.util.Set;
47  import java.util.Stack;
48  import java.util.TreeSet;
49  
50  import java.util.logging.Level;
51  import net.sf.jguard.core.authorization.permissions.Domain;
52  import net.sf.jguard.core.authorization.permissions.JGNegativePermissionCollection;
53  import net.sf.jguard.core.authorization.permissions.JGPermissionCollection;
54  import net.sf.jguard.core.authorization.permissions.JGPositivePermissionCollection;
55  import net.sf.jguard.core.authorization.permissions.NoSuchPermissionException;
56  import net.sf.jguard.core.authorization.permissions.PermissionUtils;
57  import net.sf.jguard.core.authorization.policy.ProtectionDomainUtils;
58  import net.sf.jguard.core.principals.RolePrincipal;
59  import net.sf.jguard.core.principals.UserPrincipal;
60  import net.sf.jguard.ext.SecurityConstants;
61  import net.sf.jguard.core.authorization.AuthorizationException;
62  import net.sf.jguard.core.principals.PrincipalUtils;
63  import org.slf4j.Logger;
64  import org.slf4j.LoggerFactory;
65  
66  /**
67   * Abstract class inherited by all the AuthorizationManager implementations.
68   * @author <a href="mailto:diabolo512@users.sourceforge.net">Charles Gay</a>
69   * @author <a href="mailto:tandilero@users.sourceforge.net">Maximiliano Batelli</a>
70   *
71   */
72  public abstract class AbstractAuthorizationManager implements  AuthorizationManager {
73  	/** Logger for this class */
74  	private static final Logger logger = LoggerFactory.getLogger(AbstractAuthorizationManager.class.getName());
75  
76     
77  
78      protected String applicationName = null;
79      protected  Map principals;
80      protected  Set principalsSet;
81      protected  Map domains;
82      //we add also this Set of domains to certify Domain unicity
83      protected  static Set domainsSet;
84      protected  JGPermissionCollection urlp;
85      //store all the permissions of all the domains
86      protected Map permissions ;
87      protected Set permissionsSet;
88      //store the permissions set associated with the domain ids
89      protected Map domainsPermissions;
90      //  store the hierarcy while assembly the principals to after link
91      protected Map hierarchyMap;
92      protected Map options;
93      private boolean negativePermissions;
94      
95      //permissions always granted set dynamically at startup
96      protected Permissions alwaysGrantedPermissions = null;
97      
98      /**
99       * initialize AuthorizationManager implementation.
100      * @param options
101      */
102     public AbstractAuthorizationManager(Map options){
103         super();
104         principals = new HashMap();
105         principalsSet = new TreeSet();
106         domains = new HashMap();
107         domainsSet = new TreeSet();
108         permissions = new HashMap();
109         permissionsSet = new HashSet();
110         domainsPermissions = new HashMap();
111         hierarchyMap = new HashMap();
112         urlp = null;
113         alwaysGrantedPermissions = new Permissions();
114     	String negativePermission = (String)options.get(SecurityConstants.NEGATIVE_PERMISSIONS);
115     	if(negativePermission!= null && negativePermission.equalsIgnoreCase("true")){
116     		this.urlp = new JGNegativePermissionCollection();
117     		this.negativePermissions = true;
118     	}else{
119     		this.urlp = new JGPositivePermissionCollection();
120     		this.negativePermissions = false;
121     	}
122     }
123 
124     /**
125      * define the application's name, and propagate it into Principals.
126      * this mechanism is done because application's name can only be known when the
127      * first request is here (bad j2ee design....).
128      * @param applicationName
129      */
130     public void setApplicationName(String applicationName){
131 
132         this.applicationName = applicationName;
133         Iterator itPrincipalsSet = principalsSet.iterator();
134         while(itPrincipalsSet.hasNext()){
135             RolePrincipal principalTemp = (RolePrincipal)itPrincipalsSet.next();
136             principalTemp.setApplicationName(applicationName);
137         }
138         Iterator itPrincipalsMap = principals.values().iterator();
139         while(itPrincipalsMap.hasNext()){
140             RolePrincipal principal = (RolePrincipal)itPrincipalsMap.next();
141             principal.setApplicationName(applicationName);
142         }
143 
144     }
145     /**
146      * with a collection of domain names, provide the corresponding set of URLDomains.
147      * @param domainNames collection of domains.
148      * @return URLPermission's Set
149      */
150     public Set getDomains(Collection domainNames) {
151         Set doms = new HashSet();
152         Iterator itDomNames = domainNames.iterator();
153 
154         while(itDomNames.hasNext()){
155             JGPermissionCollection dom = (JGPermissionCollection)domains.get(itDomNames.next());
156             doms.add(dom);
157         }
158 
159         return doms;
160     }
161     /**
162      * with a collection of URLPermissions names, provide the corresponding
163      * set of URLPermissions.
164      * @param permissionNames collection of permission names to grab.
165      * @return URLPermission's Set
166      */
167     public Set getPermissions(Collection permissionNames) {
168         Set perms = new HashSet();
169         Iterator itPermNames = permissionNames.iterator();
170 
171         while(itPermNames.hasNext()){
172             Permission perm;
173             String permissionName = (String)itPermNames.next();
174 			try {
175 				perm = urlp.getPermission(permissionName);
176             perms.add(perm);
177 			} catch (NoSuchPermissionException e) {
178 				logger.debug(" permission "+permissionName+" not found in JGPermissionCollection ");
179 			}
180         }
181 
182         return perms;
183     }
184     
185 
186     /**
187      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#refresh()
188      */
189     public abstract void refresh();
190       
191     
192     
193     /**
194      * compare declared Principals in the application, with principals set of the user.
195      * for the principals of the user, we retrieve corresponding permissions declared in the application,
196      * and we regroup them in a PermissionCollection.
197      * @param principals
198      * @return PermissionCollection
199      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#getPermissionCollection(java.util.Set)
200      * @see net.sf.jguard.core.authorization.manager.PermissionProvider
201      */
202     public PermissionCollection getPermissions(ProtectionDomain protectionDomain) {
203        Set ppals = new HashSet(Arrays.asList(protectionDomain.getPrincipals()));
204         UserPrincipal userPrincipal = ProtectionDomainUtils.getUserPrincipal(protectionDomain);
205     	RolePrincipal tempUserPrincipal;
206     	RolePrincipal tempDefinedPrincipal;
207 
208     	Iterator definedPrincipalsIt;
209 
210         JGPermissionCollection urlpUser = null;
211     	if(!negativePermissions){
212     		urlpUser = new JGPositivePermissionCollection();
213     	}else{
214     		urlpUser = new JGNegativePermissionCollection();
215     	}
216         
217         Iterator userPrincipalsIt = ppals.iterator();
218         
219     	//add all RolePrincipal permissions to JGPermissionCollection
220     	while(userPrincipalsIt.hasNext()){
221     		Principal ppal = (Principal)userPrincipalsIt.next();
222     		if (!(ppal instanceof RolePrincipal)) {
223     			//we skip principal which are not RolePrincipal
224     			//only jGuardPrincipals own permissions
225     			continue;
226     		}else{
227     			tempUserPrincipal = (RolePrincipal) ppal;
228     		}
229     		
230     		//we don't add the RolePrincipal if its definition is false
231     		if(!PermissionUtils.evaluatePrincipal(tempUserPrincipal, userPrincipal)) {
232     			continue;
233     		}
234 
235     		if (logger.isDebugEnabled()) {
236     			logger.debug("getPermissionCollection() -  user's principal name="+ tempUserPrincipal.getLocalName());
237     			logger.debug("getPermissionCollection() -  user's principal applicationName="
238     					+ tempUserPrincipal.getApplicationName());
239     		}
240     		definedPrincipalsIt = principalsSet.iterator();
241     		//we search the corresponding defined Principal
242     		while(definedPrincipalsIt.hasNext()){
243     			tempDefinedPrincipal = (RolePrincipal)definedPrincipalsIt.next();
244     			if (logger.isDebugEnabled()) {
245     				logger.debug("getPermissionCollection() -  system's principal name="
246     						+ tempDefinedPrincipal.getLocalName());
247     				logger.debug("getPermissionCollection() -  system's principal applicationName="
248     						+ applicationName);
249     			}
250     			
251     			//if RolePrincipal owned by the user(Authentication side) matches 
252     			//with the RolePrincipal owned by the application(Authorization side),
253     			//we add all the related permissions in the PermissionCollection of the user
254     			if(tempDefinedPrincipal.equals(tempUserPrincipal)){
255     				if (logger.isDebugEnabled()) {
256     					logger.debug("getPermissionCollection() -  principal name="
257     							+ tempUserPrincipal.getLocalName()
258     							+ " is declared in this application ");
259     				}
260                     urlpUser.addAll(tempDefinedPrincipal.getAllPermissions());
261                     Set tempset = tempDefinedPrincipal.getAllPermissions();
262 
263     				if (logger.isDebugEnabled()) {
264     					logger.debug("getPermissionCollection() -  permissions granted are :"
265     							+ tempset.toString());
266     				}
267 
268     				break;
269     			}
270     		}
271     	}
272         
273         //we add the permissions bound to the protectionDomain assigned statically by the classloader
274         if(protectionDomain.getPermissions()!=null){
275             urlpUser.addAll(protectionDomain.getPermissions());
276         }
277 
278         if(logger.isDebugEnabled()){
279         	logger.debug(" user has got "+urlpUser.size()+" permissions: \n"+urlpUser);
280         }
281         
282         //resolve regexp in permissions
283         JGPermissionCollection resolvedPermissions = (JGPermissionCollection)PermissionUtils.evaluatePermissionCollection(protectionDomain,(PermissionCollection)urlpUser);
284         //we remove unresolved permissions
285         //and replace them with the resolved one
286         //we do that to preserve the JGpermissionCollection subclass
287         //positive or negative
288         urlpUser.clear();
289         urlpUser.addAll(resolvedPermissions);
290         
291         //TODO CGA add Dynamic Separation Of Duty (DSOD) feature specified in RBAC
292         //(Role based Access Control)
293         //we will implement it as a Permissions subclass
294         //it will check permissions against DSO constraint in a static way
295         //in conjunction with the class WorkflowCheckerFactory
296         
297         Permissions result = PermissionUtils.mergePermissionCollections(urlpUser,alwaysGrantedPermissions);
298     	return result;
299     }
300 
301     /**
302      * clone a RolePrincipal/Role and set its name with the name of the Principal to clone plus
303      * a random number.
304      * @param roleName RolePrincipal name to clone
305      * @return cloned RolePrincipal with a different name : original JguardPrincipal name + Random integer betweeen 0 and 99999
306      * @throws AuthorizationException
307      */
308     public Principal clonePrincipal(String roleName) throws AuthorizationException{
309         Random rnd = new Random();
310         String cloneName = roleName+rnd.nextInt(99999);
311 
312         return clonePrincipal(roleName, cloneName);
313     }
314 
315     /**
316      * clone a RolePrincipal/Role.
317      * @param roleName RolePrincipal name to clone
318      * @param cloneName RolePrincipal cloned name
319      * @return cloned RolePrincipal with a different name : original JguardPrincipal name + Random integer betweeen 0 and 99999
320      * @throws AuthorizationException
321      */
322     public Principal clonePrincipal(String roleName,String cloneName) throws AuthorizationException {
323     	cloneName = RolePrincipal.getName(cloneName, applicationName);
324     	Principal role = (Principal)principals.get(roleName);
325     	Principal clone = null;
326     	if(role instanceof RolePrincipal) {
327             clone = (RolePrincipal)((RolePrincipal)role).clone();
328             ((RolePrincipal)clone).setName(cloneName);
329     	}
330     	else
331     		clone = PrincipalUtils.getPrincipal(role.getClass().getName(), cloneName);
332 
333         //persist the newly created clone
334         createPrincipal(clone);
335 
336     return clone;
337     }
338 
339 
340     /**
341      * return Set of domains.
342      * @return domains Set
343      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#listDomains()
344      */
345     public Set listDomains() throws AuthorizationException {
346         return domainsSet;
347     }
348     /**
349      * read an URLPermission.
350      * @param permissionName
351      * @throws AuthorizationException
352      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#readPermission(java.lang.String)
353      */
354     public Permission readPermission(String permissionName) throws AuthorizationException {
355         try {
356         return urlp.getPermission(permissionName);
357 		} catch (NoSuchPermissionException e) {
358 			throw new AuthorizationException(" permission "+permissionName+" not found ");
359 		}
360     }
361     /**
362      * return an Domain with its associated URLPermission set.
363      * @param domainName
364      * @return Domain
365      * @throws AuthorizationException
366      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#readDomain(java.lang.String)
367      */
368     public JGPermissionCollection readDomain(String domainName) throws AuthorizationException{
369     	JGPermissionCollection domainFound = (JGPermissionCollection)domains.get(domainName);
370     	if(domainFound==null){
371     		throw new AuthorizationException(" domain with name="+domainName+" is not found");
372     	}
373         return domainFound;
374     }
375     /**
376      * return the corresponding application role.
377      * @return role
378      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#readPrincipal(java.lang.String)
379      * @throws AuthorizationException
380      */
381     public Principal readPrincipal(String roleName) throws AuthorizationException {
382     	Principal principalFound = (Principal)principals.get(roleName);
383     	if(principalFound==null){
384     		throw new AuthorizationException(" principal with name="+roleName+" is not found");
385     	}
386         return principalFound;
387     }
388 
389     /**
390      * <p>Update the permissions from jGuardPrincipals that contains this domain.</p>
391      * <p><b>Note:</b> This method is need because, first, there are no warranty that the reference
392      * of domain in the RolePrincipal object are the same from domainsSet and map and, second, the
393      * getPermissions method from RolePrincipal don't load the permissions from domains objects
394      * (it use a internal set of permissions).</p>
395      * @param domain the domain that will be updated in the principals
396      */
397     protected void updatePrincipals(Domain domain) {
398         for (Iterator principalsIt = principalsSet.iterator(); principalsIt.hasNext(); ) {
399             RolePrincipal principal = (RolePrincipal) principalsIt.next();
400 
401             //2005-06-01 vinipitta:
402             //if the principal contains the domain we remove the domain from it and replace by the
403             //current(updated) version of the domain. This forces the principal to update the
404             //permission list
405             if (principal.getDomains().contains(domain)) {
406                 principal.removeDomain(domain);
407                 //if we use the principal.getDomains().add method instead then this will not work!
408                 principal.addDomain(domain);
409                 domainsSet.remove(domain);
410                 domainsSet.add(domain);
411                 domains.remove(domain.getName());
412                 domains.put(domain.getName(),domain);
413             }
414         }
415     }
416 
417     /**
418      * <p>Update the permissions from jGuardPrincipals <b>and</b> the associated domain.</p>
419      * <p><b>Note:</b> This method is need because, first, there are no warranty that the reference
420      * of domain in the RolePrincipal object are the same from domainsSet and map and, second, the
421      * getPermissions method from RolePrincipal don't load the permissions from domains objects
422      * (it use a internal set of permissions).</p>
423      * @param permission whose domain will be updated in the principals
424      */
425     protected void updatePrincipals(Permission permission) {
426         for (Iterator principalsIt = principalsSet.iterator(); principalsIt.hasNext(); ) {
427             RolePrincipal principal = (RolePrincipal) principalsIt.next();
428             Domain domain = getDomain(permission);
429             //2005-06-01 vinipitta:
430             //if the principal contains the domain we remove the domain from it and replace by the
431             //current(updated) version of the domain. This forces the principal to update the
432             //permission list
433             if (principal.getDomains().contains(domain)) {
434                 principal.removeDomain(domain);
435                 //if we use the principal.getDomains().add method instead then this will not work!
436                 principal.addDomain(domain);
437                 domainsSet.remove(domain);
438                 domainsSet.add(domain);
439                 domains.remove(domain.getName());
440                 domains.put(domain.getName(),domain);
441               //we  handle the use case when the principal is ited directly
442               //to a permission and not indirectly through a domain
443             }else if(principal.getOrphanedPermissions().contains(permission)){
444                principal.getOrphanedPermissions().remove(permission);
445                principal.getOrphanedPermissions().add(permission);
446                principal.getPermissions().remove(permission);
447                principal.getPermissions().add(permission);
448 
449             }
450         }
451     }
452 
453     /**
454      * update the principals with this updated domain.
455      * it implies a suppress and an addition.
456      * @param newDomain
457      * @param oldDomainName
458      */
459     protected void updatePrincipals(JGPermissionCollection newDomain, String oldDomainName) {
460         JGPermissionCollection domain = new Domain(oldDomainName);
461 
462         for (Iterator principalsIt = principalsSet.iterator(); principalsIt.hasNext(); ) {
463             RolePrincipal principal = (RolePrincipal) principalsIt.next();
464 
465             //2005-06-01 vinipitta:
466             //if the principal contains the domain we remove the domain from it and replace by the
467             //current(updated) version of the domain. This forces the principal to update the
468             //permission list
469             if (principal.getDomains().contains(domain)) {
470                 principal.removeDomain(domain);
471                 //if we use the principal.getDomains().add method instead then this will not work!
472                 principal.addDomain(newDomain);
473             }
474         }
475     }
476 
477 
478     /**
479      * Remove the domain from all principals that have relationship with this domain.
480      * @param domainName the name of the domain that will be removed
481      */
482     protected void removeDomainFromPrincipals(String domainName) {
483         JGPermissionCollection domain = new Domain(domainName);
484 
485         for (Iterator principalsIt = principalsSet.iterator(); principalsIt.hasNext(); ) {
486             RolePrincipal principal = (RolePrincipal) principalsIt.next();
487             if (principal.getDomains().contains(domain)) {
488                 principal.removeDomain(domain);
489                 domains.remove(domain);
490                 domainsSet.remove(domain);
491             }
492         }
493     }
494 
495     /**
496      * Remove the permission from all principals that have relationship with this permission like a
497      * orphaned permission (directly), or through a domain (indirectly).
498      * @param permissionName the name of the permission that will be removed
499      */
500     protected void removePermissionFromPrincipals(String permissionName) {
501         Permission permission = (Permission) permissions.get(permissionName);
502 
503         for (Iterator principalsIt = principalsSet.iterator(); principalsIt.hasNext(); ) {
504             RolePrincipal principal = (RolePrincipal) principalsIt.next();
505             if (principal.getOrphanedPermissions().contains(permission)) {
506                 principal.getOrphanedPermissions().remove(permission);
507                 principal.getPermissions().remove(permission);
508                 logger.debug("removePermissionFromPrincipals: " + permission);
509             }else if(principal.getPermissionsFromDomains().contains(permission)){
510                 principal.getPermissionsFromDomains().remove(permission);
511                 principal.getPermissions().remove(permission);
512                 logger.debug("removePermissionFromPrincipals: " + permission);
513             }
514         }
515     }
516 
517 	/**
518 	 * return the domain which contains the permission.
519 	 * @param permission
520 	 * @return domain which owns the permission or null if no domain contains
521 	 * this permisison
522 	 */
523 	protected  Domain getDomain(Permission permission){
524 	    Iterator iterator = domainsSet.iterator();
525 	    while(iterator.hasNext()){
526 	    	Domain temp = (Domain)iterator.next();
527 	    	if(temp.containsPermission(permission)){
528 	    		return temp;
529 	    	}
530 	    }
531 	    //no domains contains this permission
532 		return null;
533 	}
534 
535 	/**
536 	 * add the permission to the corresponding role.
537 	 * if the permission is not persisted, we persist it and create
538 	 * a corresponding Domain with the same name.
539 	 * @param roleName role updated
540 	 * @param perm permission to add
541 	 * @throws AuthorizationException
542 	 */
543 	public void addToPrincipal(String roleName, Permission perm) throws AuthorizationException {
544 		RolePrincipal role = (RolePrincipal) principals.get(roleName);
545 		if(role == null){
546 			throw new SecurityException(" Principal/role "+roleName+" does not exists ");
547 		}
548 		//if permission does not exists, we add it
549 		// and create a corresponding domain with the same name
550 		if(!permissionsSet.contains(perm)){
551 			permissionsSet.add(perm);
552 			permissions.put(perm.getName(),perm);
553 			createDomain(perm.getName());
554 			createPermission(perm,perm.getName());
555 		}
556 		role.addPermission(perm);
557 	}
558 
559 	/**
560 	 * add the domain to the role, and
561 	 * persist the domain if it does not exists?
562 	 * @param roleName
563 	 * @param domain
564 	 * @throws AuthorizationException
565 	 */
566 	public void addToPrincipal(String roleName,Domain domain) throws AuthorizationException{
567 		RolePrincipal role = (RolePrincipal) principals.get(roleName);
568 		if(role == null){
569 			throw new SecurityException(" Principal/role "+roleName+" does not exists ");
570 		}
571 
572 		if(domainsSet.contains(domain)){
573 			domainsSet.add(domain);
574 			domains.put(domain.getName(),domain);
575 			createDomain(domain.getName());
576 		}
577 
578 		role.addDomain(domain);
579 	}
580 
581 	/**
582      * This commands establishes a new immediate inheritance relationship
583      * between the existing principals/principals roleAsc and the roleDesc.
584      * The command is valid if and only if the role roleAsc is not an immediate
585      * ascendant of roleDesc, and descendant does
586      * not properly inherit roleAsc principal/role (in order to avoid cycle creation).
587      *
588      * @param principalAscName  the principal/role <strong>local</strong> name that will inherite.
589      * @param principalDescName the principal/role <strong>local</strong> name that will be inherited.
590      * @throws AuthorizationException if the inheritance already exists or create a cycle.
591      */
592     public void addInheritance(String principalAscName, String principalDescName) throws AuthorizationException {
593 
594     	//getting the principals
595         Principal principalAsc = (Principal) principals.get(principalAscName);
596         Principal principalDesc = (Principal) principals.get(principalDescName);
597 
598         if (principalAscName.equals(principalDescName)){
599             logger.error("ascendant and descendant cannot be the same principal ");
600             throw new AuthorizationException("ascendant and descendant cannot be the same principal ");
601         }
602 
603         if (principalAsc == null) {
604             logger.error("Role " + principalAscName + " not found!");
605             throw new AuthorizationException("Role " + principalAscName + " not found!");
606         }
607 
608         if (principalDesc == null) {
609             logger.error("Role " + principalDescName + " not found!");
610             throw new AuthorizationException("Role " + principalDescName + " not found!");
611         }
612 
613     	if(!RolePrincipal.class.isAssignableFrom(principalAsc.getClass())
614     		||!RolePrincipal.class.isAssignableFrom(principalDesc.getClass())){
615     		throw new AuthorizationException(" role inheritance is only supported by RolePrincipal \n roleAsc class="+principalAsc.getClass().getName()+" \n roleDesc class="+principalDesc.getClass().getName());
616     	}
617 
618         //check if the roleAsc is immediate ascendant of roleDesc
619         for (Iterator it = ((RolePrincipal)principalAsc).getDescendants().iterator(); it.hasNext(); ) {
620             if (principalDesc.equals(it.next())) {
621                 logger.error("Role " + principalAscName + " is immediate ascendant of role " + principalDescName + "!");
622                 throw new AuthorizationException("Role " + principalAscName + " is immediate ascendant of role " + principalDescName + "!");
623             }
624         }
625 
626         //check if roleDesc inherit roleAsc
627         //use a stack instead of a recursive method
628         Stack rolesToCheck = new Stack();
629         //used to check first all principals from one level before check the next level
630         Stack rolesFromNextLevel = new Stack();
631         rolesToCheck.addAll(((RolePrincipal)principalDesc).getDescendants());
632 
633         while (!rolesToCheck.isEmpty()) {
634             RolePrincipal role = (RolePrincipal) rolesToCheck.pop();
635             if (principalAsc.equals(role)) {
636                 logger.error("Role " + principalAscName + " cannot inherit role "
637                         + principalDescName + " because " + principalDescName + " inherit "
638                         + principalAscName);
639                 throw new AuthorizationException("Role " + principalAscName + " cannot inherit role "
640                         + principalDescName + " because " + principalDescName + " inherit "
641                         + principalAscName);
642             }
643 
644             rolesFromNextLevel.addAll(role.getDescendants());
645 
646             //is time to go to next level
647             if (rolesToCheck.isEmpty()) {
648                 rolesToCheck.addAll(rolesFromNextLevel);
649 
650                 //clear the second level stack
651                 rolesFromNextLevel.clear();
652             }
653         }
654 
655         //update in-memory role
656         ((RolePrincipal)principalAsc).getDescendants().add(principalDesc);
657 
658         //update xml
659         updatePrincipal((RolePrincipal)principalAsc);
660     }
661 
662     /**
663      * @param roleAscName  the role that inherit.
664      * @param roleDescName the role that is inherited.
665      * @throws AuthorizationException if the inheritance already exists or create a cycle.
666      */
667     public void deleteInheritance(String roleAscName, String roleDescName) throws AuthorizationException {
668         RolePrincipal roleAsc = (RolePrincipal) principals.get(roleAscName);
669         roleAsc.getDescendants().remove(principals.get(roleDescName));
670         updatePrincipal(roleAsc);
671     }
672 
673     /**
674      * replace the inital principal with the new one.
675      * @param principal RolePrincipal updated
676      * @throws AuthorizationException
677      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#updatePrincipal(net.sf.jguard.core.principals.RolePrincipal)
678      */
679     public void updatePrincipal(Principal principal) throws AuthorizationException {
680         deletePrincipal(principal);
681         createPrincipal(principal);
682         logger.debug(" updated principal="+principal);
683     }
684 
685     /**
686 	 * assembly the hierarchy of jGuardPrincipals.
687 	 */
688 	protected void assemblyHierarchy() {
689 		//now that every principal is mapped, assembly the hierarchy.
690 		for (Iterator it = hierarchyMap.keySet().iterator(); it.hasNext(); ) {
691 		    String ascendantName = (String) it.next();
692 		    RolePrincipal ascendant = (RolePrincipal) principals.get(ascendantName);
693 
694 		    for (Iterator it2 = ((List) hierarchyMap.get(ascendantName)).iterator(); it2.hasNext(); ) {
695 		    	RolePrincipal descendant = (RolePrincipal) it2.next();
696 		        ascendant.getDescendants().add(descendant);
697 		        logger.debug("Role " + ascendantName + " inherits from role " + descendant.getLocalName());
698 		    }
699 		}
700 	}
701     /**
702      *
703      * @param principal
704      */
705     protected void deleteReferenceInHierarchy(RolePrincipal principal){
706           String principalName = principal.getLocalName();
707 
708           //clean the hierarchy
709           for (Iterator it = hierarchyMap.keySet().iterator(); it.hasNext(); ) {
710         	  String ascendantName = (String) it.next();
711         	  if(principalName.equals(ascendantName)){
712         		  //we remove in memory the deleted principal
713         		  hierarchyMap.remove(ascendantName);
714         	  }else{
715         		  List descendants = (List) hierarchyMap.get(ascendantName);
716         		  descendants.remove(principal);
717         	  }
718           }
719 
720           //clean descendants references in the principal Map
721           Collection values = principals.values();
722           Iterator itValues = values.iterator();
723           while(itValues.hasNext()){
724         	  RolePrincipal ppalTemp = (RolePrincipal)itValues.next();
725         	  ppalTemp.getDescendants().remove(principal);
726           }
727 
728           //clean descendants references in the principal Set
729           Iterator itPrincipalsSet = principalsSet.iterator();
730           while(itPrincipalsSet.hasNext()){
731                RolePrincipal ppalTemp = (RolePrincipal)itPrincipalsSet.next();
732                ppalTemp.getDescendants().remove(principal);
733           }
734 
735     }
736 
737     /**
738      * return the principal's Set.
739      * @return principal's Set
740      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#listPrincipals()
741      */
742     public Set listPrincipals()  {
743        return principalsSet;
744     }
745     /**
746      * return all the permissions.
747      * @return URLPermission container
748      * @see net.sf.jguard.ext.authorization.manager.AuthorizationManager#listPermissions()
749      */
750     public JGPermissionCollection listPermissions() {
751         return new JGPositivePermissionCollection(permissionsSet);
752     }
753 
754 
755 	/**
756 	 * import data from the provided AbstractAuthorizationManager into
757 	 * our AuthorizationManager.
758 	 * @param authManager
759 	 * @throws AuthorizationException
760 	 */
761 	public void importAuthorizationManager(AuthorizationManager authManager)throws AuthorizationException{
762 		if(authManager.isEmpty()){
763 			logger.warn(" authManager to import is empty ");
764 			return;
765 		}
766 		//import domains set and associated permissions
767                  Set domains = authManager.getDomainsSet();
768                  Iterator itDomains = domains.iterator();
769                  while(itDomains.hasNext()){
770                          Domain domain = (Domain)itDomains.next();
771                          createDomain(domain.getName());
772                          Iterator itPermissions = domain.getPermissions().iterator();
773                          while(itPermissions.hasNext()){
774                          Permission perm = (Permission)itPermissions.next();
775                          createPermission(perm,domain.getName());
776                      }
777                  }
778 
779 
780                  //import principal set
781                  Set Principals = authManager.getPrincipalsSet();
782                  Iterator itPrincipals = Principals.iterator();
783                  while(itPrincipals.hasNext()){
784                          Principal principal = (Principal)itPrincipals.next();
785                      createPrincipal(principal);
786                  }
787 
788 
789                  //import principal inheritance
790                  Iterator itPrincipals2 = Principals.iterator();
791                  while(itPrincipals2.hasNext()){
792                          Principal principal = (Principal)itPrincipals2.next();
793                          if(principal instanceof RolePrincipal){
794                                  RolePrincipal ppal = (RolePrincipal)principal;
795                          Set descendants = ppal.getDescendants();
796                          Iterator itDescendants = descendants.iterator();
797                          while(itDescendants.hasNext()){
798                                  RolePrincipal descPrincipal = (RolePrincipal)itDescendants.next();
799                                  addInheritance(getLocalName(principal),getLocalName(descPrincipal));
800                          }
801                      }
802                  }
803 
804 
805 	}
806 
807       
808 	public final Set getDomainsSet() {
809 		return Collections.unmodifiableSet(domainsSet);
810 	}
811 
812 	public final Map getDomains() {
813 		return Collections.unmodifiableMap(domains);
814 	}
815 
816 	public final Map getDomainsPermissions() {
817 		return Collections.unmodifiableMap(domainsPermissions);
818 	}
819 
820 	public final Map getHierarchyMap() {
821 		return Collections.unmodifiableMap(hierarchyMap);
822 	}
823 
824 	public final Map getPermissions() {
825 		return Collections.unmodifiableMap(permissions);
826 	}
827 
828 
829 	public final Set getPermissionsSet() {
830 		return Collections.unmodifiableSet(permissionsSet);
831 	}
832 
833 	public final Map getPrincipals() {
834 		return Collections.unmodifiableMap(principals);
835 	}
836 
837 
838 	public final Set getPrincipalsSet() {
839 		return Collections.unmodifiableSet(principalsSet);
840 	}
841 	 protected static String getLocalName(Principal principal) {
842 			
843 			String name = null;
844 			if (principal instanceof RolePrincipal) {
845 				RolePrincipal rolePrincipal = (RolePrincipal) principal;
846 				name = rolePrincipal.getLocalName();
847 			}else{
848 				name = principal.getName();
849 			}
850 			return name;
851 		}
852         /**
853 	 * add some permissions always granted by this Policy, like permission used to
854 	 * <i>logoff</i> in webapp, or permissions used to reached the <i>AccessDenied</i> page.
855 	 * @param permissions permissions always granted by this Policy
856 	 */
857 	final public void addAlwaysGrantedPermissions(Permissions permissions){
858 		Enumeration perms= permissions.elements();
859 		while(perms.hasMoreElements()){
860 			alwaysGrantedPermissions.add((Permission)perms.nextElement());
861 		}
862 	}
863         
864        /**
865         * return an <strong>unmodifiable</strong> Map of options.
866         */
867        final public Map getOptions(){
868            return Collections.unmodifiableMap(options);
869        }
870        
871        public String getApplicationName(){
872            return applicationName;
873        }
874 }
875