KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > repo > security > permissions > impl > PermissionServiceImpl


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.repo.security.permissions.impl;
18
19 import java.io.Serializable JavaDoc;
20 import java.util.HashSet JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Set JavaDoc;
23
24 import net.sf.acegisecurity.Authentication;
25 import net.sf.acegisecurity.GrantedAuthority;
26 import net.sf.acegisecurity.providers.dao.User;
27
28 import org.alfresco.repo.cache.SimpleCache;
29 import org.alfresco.repo.security.authentication.AuthenticationComponent;
30 import org.alfresco.repo.security.permissions.DynamicAuthority;
31 import org.alfresco.repo.security.permissions.NodePermissionEntry;
32 import org.alfresco.repo.security.permissions.PermissionEntry;
33 import org.alfresco.repo.security.permissions.PermissionReference;
34 import org.alfresco.repo.security.permissions.PermissionServiceSPI;
35 import org.alfresco.service.cmr.dictionary.DictionaryService;
36 import org.alfresco.service.cmr.repository.ChildAssociationRef;
37 import org.alfresco.service.cmr.repository.NodeRef;
38 import org.alfresco.service.cmr.repository.NodeService;
39 import org.alfresco.service.cmr.security.AccessPermission;
40 import org.alfresco.service.cmr.security.AccessStatus;
41 import org.alfresco.service.cmr.security.AuthorityService;
42 import org.alfresco.service.cmr.security.AuthorityType;
43 import org.alfresco.service.cmr.security.PermissionService;
44 import org.alfresco.service.namespace.QName;
45 import org.alfresco.util.EqualsHelper;
46 import org.apache.commons.logging.Log;
47 import org.apache.commons.logging.LogFactory;
48 import org.springframework.beans.factory.InitializingBean;
49
50 /**
51  * The Alfresco implementation of a permissions service against our APIs for the
52  * permissions model and permissions persistence.
53  *
54  * @author andyh
55  */

56 public class PermissionServiceImpl implements PermissionServiceSPI, InitializingBean
57 {
58     
59     static SimplePermissionReference OLD_ALL_PERMISSIONS_REFERENCE = new SimplePermissionReference(
60             QName.createQName("", PermissionService.ALL_PERMISSIONS),
61             PermissionService.ALL_PERMISSIONS);
62     
63     private static Log log = LogFactory.getLog(PermissionServiceImpl.class);
64     
65     /** a transactionally-safe cache to be injected */
66     private SimpleCache<Serializable JavaDoc, AccessStatus> accessCache;
67     
68     /*
69      * Access to the model
70      */

71     private ModelDAO modelDAO;
72
73     /*
74      * Access to permissions
75      */

76     private PermissionsDAO permissionsDAO;
77
78     /*
79      * Access to the node service
80      */

81     private NodeService nodeService;
82
83     /*
84      * Access to the data dictionary
85      */

86     private DictionaryService dictionaryService;
87
88     /*
89      * Access to the authentication component
90      */

91     private AuthenticationComponent authenticationComponent;
92
93     /*
94      * Access to the authority component
95      */

96     private AuthorityService authorityService;
97     
98     /*
99      * Dynamic authorities providers
100      */

101     private List JavaDoc<DynamicAuthority> dynamicAuthorities;
102
103     /*
104      * Standard spring construction.
105      */

106     public PermissionServiceImpl()
107     {
108         super();
109     }
110
111     //
112
// Inversion of control
113
//
114

115     public void setDictionaryService(DictionaryService dictionaryService)
116     {
117         this.dictionaryService = dictionaryService;
118     }
119
120     public void setModelDAO(ModelDAO modelDAO)
121     {
122         this.modelDAO = modelDAO;
123     }
124
125     public void setNodeService(NodeService nodeService)
126     {
127         this.nodeService = nodeService;
128     }
129
130     public void setPermissionsDAO(PermissionsDAO permissionsDAO)
131     {
132         this.permissionsDAO = permissionsDAO;
133     }
134
135     public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
136     {
137         this.authenticationComponent = authenticationComponent;
138     }
139     
140     public void setAuthorityService(AuthorityService authorityService)
141     {
142         this.authorityService = authorityService;
143     }
144
145     public void setDynamicAuthorities(List JavaDoc<DynamicAuthority> dynamicAuthorities)
146     {
147         this.dynamicAuthorities = dynamicAuthorities;
148     }
149
150     /**
151      * Set the permissions access cache.
152      *
153      * @param accessCache a transactionally safe cache
154      */

155     public void setAccessCache(SimpleCache<Serializable JavaDoc, AccessStatus> accessCache)
156     {
157         this.accessCache = accessCache;
158     }
159
160     public void afterPropertiesSet() throws Exception JavaDoc
161     {
162         if (dictionaryService == null)
163         {
164             throw new IllegalArgumentException JavaDoc("Property 'dictionaryService' has not been set");
165         }
166         if (modelDAO == null)
167         {
168             throw new IllegalArgumentException JavaDoc("Property 'modelDAO' has not been set");
169         }
170         if (nodeService == null)
171         {
172             throw new IllegalArgumentException JavaDoc("Property 'nodeService' has not been set");
173         }
174         if (permissionsDAO == null)
175         {
176             throw new IllegalArgumentException JavaDoc("Property 'permissionsDAO' has not been set");
177         }
178         if (authenticationComponent == null)
179         {
180             throw new IllegalArgumentException JavaDoc("Property 'authenticationComponent' has not been set");
181         }
182         if(authorityService == null)
183         {
184             throw new IllegalArgumentException JavaDoc("Property 'authorityService' has not been set");
185         }
186         if (accessCache == null)
187         {
188             throw new IllegalArgumentException JavaDoc("Property 'accessCache' has not been set");
189         }
190     }
191
192     //
193
// Permissions Service
194
//
195

196     public String JavaDoc getOwnerAuthority()
197     {
198         return OWNER_AUTHORITY;
199     }
200
201     public String JavaDoc getAllAuthorities()
202     {
203         return ALL_AUTHORITIES;
204     }
205
206     public String JavaDoc getAllPermission()
207     {
208         return ALL_PERMISSIONS;
209     }
210
211     public Set JavaDoc<AccessPermission> getPermissions(NodeRef nodeRef)
212     {
213         return getAllPermissionsImpl(nodeRef, true, true);
214     }
215
216     public Set JavaDoc<AccessPermission> getAllSetPermissions(NodeRef nodeRef)
217     {
218         HashSet JavaDoc<AccessPermission> accessPermissions = new HashSet JavaDoc<AccessPermission>();
219         NodePermissionEntry nodePremissionEntry = getSetPermissions(nodeRef);
220         for (PermissionEntry pe : nodePremissionEntry.getPermissionEntries())
221         {
222             accessPermissions.add(new AccessPermissionImpl(getPermission(pe.getPermissionReference()), pe
223                     .getAccessStatus(), pe.getAuthority()));
224         }
225         return accessPermissions;
226     }
227
228     private Set JavaDoc<AccessPermission> getAllPermissionsImpl(NodeRef nodeRef, boolean includeTrue, boolean includeFalse)
229     {
230         String JavaDoc userName = authenticationComponent.getCurrentUserName();
231         HashSet JavaDoc<AccessPermission> accessPermissions = new HashSet JavaDoc<AccessPermission>();
232         for (PermissionReference pr : getSettablePermissionReferences(nodeRef))
233         {
234             if (hasPermission(nodeRef, pr) == AccessStatus.ALLOWED)
235             {
236                 accessPermissions.add(new AccessPermissionImpl(getPermission(pr), AccessStatus.ALLOWED, userName));
237             }
238             else
239             {
240                 if (includeFalse)
241                 {
242                     accessPermissions.add(new AccessPermissionImpl(getPermission(pr), AccessStatus.DENIED, userName));
243                 }
244             }
245         }
246         return accessPermissions;
247     }
248
249     private class AccessPermissionImpl implements AccessPermission
250     {
251         private String JavaDoc permission;
252
253         private AccessStatus accessStatus;
254
255         private String JavaDoc authority;
256
257         private AuthorityType authorityType;
258
259         AccessPermissionImpl(String JavaDoc permission, AccessStatus accessStatus, String JavaDoc authority)
260         {
261             this.permission = permission;
262             this.accessStatus = accessStatus;
263             this.authority = authority;
264             this.authorityType = AuthorityType.getAuthorityType(authority);
265         }
266
267         public String JavaDoc getPermission()
268         {
269             return permission;
270         }
271
272         public AccessStatus getAccessStatus()
273         {
274             return accessStatus;
275         }
276
277         public String JavaDoc getAuthority()
278         {
279             return authority;
280         }
281
282         public AuthorityType getAuthorityType()
283         {
284             return authorityType;
285         }
286
287         @Override JavaDoc
288         public boolean equals(Object JavaDoc o)
289         {
290             if (this == o)
291             {
292                 return true;
293             }
294             if (!(o instanceof AccessPermissionImpl))
295             {
296                 return false;
297             }
298             AccessPermissionImpl other = (AccessPermissionImpl) o;
299             return this.getPermission().equals(other.getPermission())
300                     && (this.getAccessStatus() == other.getAccessStatus() && (this.getAccessStatus().equals(other
301                             .getAccessStatus())));
302         }
303
304         @Override JavaDoc
305         public int hashCode()
306         {
307             return ((authority.hashCode() * 37) + permission.hashCode()) * 37 + accessStatus.hashCode();
308         }
309     }
310
311     public Set JavaDoc<String JavaDoc> getSettablePermissions(NodeRef nodeRef)
312     {
313         Set JavaDoc<PermissionReference> settable = getSettablePermissionReferences(nodeRef);
314         Set JavaDoc<String JavaDoc> strings = new HashSet JavaDoc<String JavaDoc>(settable.size());
315         for (PermissionReference pr : settable)
316         {
317             strings.add(getPermission(pr));
318         }
319         return strings;
320     }
321
322     public Set JavaDoc<String JavaDoc> getSettablePermissions(QName type)
323     {
324         Set JavaDoc<PermissionReference> settable = getSettablePermissionReferences(type);
325         Set JavaDoc<String JavaDoc> strings = new HashSet JavaDoc<String JavaDoc>(settable.size());
326         for (PermissionReference pr : settable)
327         {
328             strings.add(getPermission(pr));
329         }
330         return strings;
331     }
332
333     public NodePermissionEntry getSetPermissions(NodeRef nodeRef)
334     {
335         return permissionsDAO.getPermissions(nodeRef);
336     }
337
338     public AccessStatus hasPermission(NodeRef nodeRef, PermissionReference perm)
339     {
340         // If the node ref is null there is no sensible test to do - and there
341
// must be no permissions
342
// - so we allow it
343
if (nodeRef == null)
344         {
345             return AccessStatus.ALLOWED;
346         }
347
348         // If the permission is null we deny
349
if (perm == null)
350         {
351             return AccessStatus.DENIED;
352         }
353         
354         // Allow permissions for nodes that do not exist
355
if (!nodeService.exists(nodeRef))
356         {
357             return AccessStatus.ALLOWED;
358         }
359         
360         // Get the current authentications
361
// Use the smart authentication cache to improve permissions performance
362
Authentication auth = authenticationComponent.getCurrentAuthentication();
363         Set JavaDoc<String JavaDoc> authorisations = getAuthorisations(auth, nodeRef);
364         Serializable JavaDoc key = generateKey(
365                 authorisations,
366                 nodeRef,
367                 perm);
368         AccessStatus status = accessCache.get(key);
369         if (status != null)
370         {
371             return status;
372         }
373         
374         // If the node does not support the given permission there is no point
375
// doing the test
376
Set JavaDoc<PermissionReference> available = modelDAO.getAllPermissions(nodeRef);
377         available.add(getAllPermissionReference());
378         available.add(OLD_ALL_PERMISSIONS_REFERENCE);
379         
380         if (!(available.contains(perm)))
381         {
382             accessCache.put(key, AccessStatus.DENIED);
383             return AccessStatus.DENIED;
384         }
385
386         //
387
// TODO: Dynamic permissions via evaluators
388
//
389

390         /*
391          * Does the current authentication have the supplied permission on the
392          * given node.
393          */

394
395         QName typeQname = nodeService.getType(nodeRef);
396         Set JavaDoc<QName> aspectQNames = nodeService.getAspects(nodeRef);
397
398         if (perm.equals(OLD_ALL_PERMISSIONS_REFERENCE))
399         {
400             perm = getAllPermissionReference();
401         }
402         NodeTest nt = new NodeTest(perm, typeQname, aspectQNames);
403         boolean result = nt.evaluate(authorisations, nodeRef);
404         if (log.isDebugEnabled())
405         {
406             log.debug("Permission <"
407                     + perm + "> is " + (result ? "allowed" : "denied") + " for "
408                     + authenticationComponent.getCurrentUserName() + " on node " + nodeService.getPath(nodeRef));
409         }
410         
411         status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED;
412         accessCache.put(key, status);
413         return status;
414     }
415     
416     /**
417      * Key for a cache object is built from all the known Authorities (which can change
418      * dynamically so they must all be used) the NodeRef ID and the permission reference itself.
419      * This gives a unique key for each permission test.
420      */

421     static Serializable JavaDoc generateKey(Set JavaDoc<String JavaDoc> auths, NodeRef ref, PermissionReference perm)
422     {
423         HashSet JavaDoc<Serializable JavaDoc> key = new HashSet JavaDoc<Serializable JavaDoc>(auths);
424         key.add(ref.getId());
425         key.add(perm.toString());
426         return key;
427     }
428
429     /**
430      * Get the authorisations for the currently authenticated user
431      *
432      * @param auth
433      * @return
434      */

435     private Set JavaDoc<String JavaDoc> getAuthorisations(Authentication auth, NodeRef nodeRef)
436     {
437         HashSet JavaDoc<String JavaDoc> auths = new HashSet JavaDoc<String JavaDoc>();
438         // No authenticated user then no permissions
439
if (auth == null)
440         {
441             return auths;
442         }
443         // TODO: Refactor and use the authentication service for this.
444
User user = (User) auth.getPrincipal();
445         auths.add(user.getUsername());
446         for (GrantedAuthority authority : auth.getAuthorities())
447         {
448             auths.add(authority.getAuthority());
449         }
450         if (dynamicAuthorities != null)
451         {
452             for (DynamicAuthority da : dynamicAuthorities)
453             {
454                 if (da.hasAuthority(nodeRef, user.getUsername()))
455                 {
456                     auths.add(da.getAuthority());
457                 }
458             }
459         }
460         auths.addAll(authorityService.getAuthorities());
461         return auths;
462     }
463
464     public NodePermissionEntry explainPermission(NodeRef nodeRef, PermissionReference perm)
465     {
466         // TODO Auto-generated method stub
467
return null;
468     }
469
470     public void deletePermissions(NodeRef nodeRef)
471     {
472         permissionsDAO.deletePermissions(nodeRef);
473         accessCache.clear();
474     }
475
476     public void deletePermissions(NodePermissionEntry nodePermissionEntry)
477     {
478         permissionsDAO.deletePermissions(nodePermissionEntry);
479         accessCache.clear();
480     }
481
482     public void deletePermission(PermissionEntry permissionEntry)
483     {
484         permissionsDAO.deletePermissions(permissionEntry);
485         accessCache.clear();
486     }
487
488     public void deletePermission(NodeRef nodeRef, String JavaDoc authority, PermissionReference perm, boolean allow)
489     {
490         permissionsDAO.deletePermissions(nodeRef, authority, perm, allow);
491         accessCache.clear();
492     }
493
494     public void clearPermission(NodeRef nodeRef, String JavaDoc authority)
495     {
496         permissionsDAO.clearPermission(nodeRef, authority);
497         accessCache.clear();
498     }
499
500     public void setPermission(NodeRef nodeRef, String JavaDoc authority, PermissionReference perm, boolean allow)
501     {
502         permissionsDAO.setPermission(nodeRef, authority, perm, allow);
503         accessCache.clear();
504     }
505
506     public void setPermission(PermissionEntry permissionEntry)
507     {
508         permissionsDAO.setPermission(permissionEntry);
509         accessCache.clear();
510     }
511
512     public void setPermission(NodePermissionEntry nodePermissionEntry)
513     {
514         permissionsDAO.setPermission(nodePermissionEntry);
515         accessCache.clear();
516     }
517
518     public void setInheritParentPermissions(NodeRef nodeRef, boolean inheritParentPermissions)
519     {
520         permissionsDAO.setInheritParentPermissions(nodeRef, inheritParentPermissions);
521         accessCache.clear();
522     }
523     
524     /**
525      * @see org.alfresco.service.cmr.security.PermissionService#getInheritParentPermissions(org.alfresco.service.cmr.repository.NodeRef)
526      */

527     public boolean getInheritParentPermissions(NodeRef nodeRef)
528     {
529         return permissionsDAO.getInheritParentPermissions(nodeRef);
530     }
531
532     
533     public PermissionReference getPermissionReference(QName qname, String JavaDoc permissionName)
534     {
535         return modelDAO.getPermissionReference(qname, permissionName);
536     }
537
538     public PermissionReference getAllPermissionReference()
539     {
540         return getPermissionReference(ALL_PERMISSIONS);
541     }
542     
543     public String JavaDoc getPermission(PermissionReference permissionReference)
544     {
545         if (modelDAO.isUnique(permissionReference))
546         {
547             return permissionReference.getName();
548         }
549         else
550         {
551             return permissionReference.toString();
552         }
553     }
554
555     public PermissionReference getPermissionReference(String JavaDoc permissionName)
556     {
557         return modelDAO.getPermissionReference(null, permissionName);
558     }
559
560     public Set JavaDoc<PermissionReference> getSettablePermissionReferences(QName type)
561     {
562         return modelDAO.getExposedPermissions(type);
563     }
564
565     public Set JavaDoc<PermissionReference> getSettablePermissionReferences(NodeRef nodeRef)
566     {
567         return modelDAO.getExposedPermissions(nodeRef);
568     }
569
570     public void deletePermission(NodeRef nodeRef, String JavaDoc authority, String JavaDoc perm, boolean allow)
571     {
572         deletePermission(nodeRef, authority, getPermissionReference(perm), allow);
573     }
574
575     public AccessStatus hasPermission(NodeRef nodeRef, String JavaDoc perm)
576     {
577         return hasPermission(nodeRef, getPermissionReference(perm));
578     }
579
580     public void setPermission(NodeRef nodeRef, String JavaDoc authority, String JavaDoc perm, boolean allow)
581     {
582         setPermission(nodeRef, authority, getPermissionReference(perm), allow);
583     }
584
585     public void deletePermissions(String JavaDoc recipient)
586     {
587         permissionsDAO.deleteAllPermissionsForAuthority(recipient);
588         accessCache.clear();
589     }
590     
591     //
592
// SUPPORT CLASSES
593
//
594

595     /**
596      * Support class to test the permission on a node.
597      *
598      * @author Andy Hind
599      */

600     private class NodeTest
601     {
602         /*
603          * The required permission.
604          */

605         PermissionReference required;
606
607         /*
608          * Granters of the permission
609          */

610         Set JavaDoc<PermissionReference> granters;
611
612         /*
613          * The additional permissions required at the node level.
614          */

615         Set JavaDoc<PermissionReference> nodeRequirements = new HashSet JavaDoc<PermissionReference>();
616
617         /*
618          * The additional permissions required on the parent.
619          */

620         Set JavaDoc<PermissionReference> parentRequirements = new HashSet JavaDoc<PermissionReference>();
621
622         /*
623          * The permissions required on all children .
624          */

625         Set JavaDoc<PermissionReference> childrenRequirements = new HashSet JavaDoc<PermissionReference>();
626
627         /*
628          * The type name of the node.
629          */

630         QName typeQName;
631
632         /*
633          * The aspects set on the node.
634          */

635         Set JavaDoc<QName> aspectQNames;
636
637         /*
638          * Constructor just gets the additional requirements
639          */

640         NodeTest(PermissionReference required, QName typeQName, Set JavaDoc<QName> aspectQNames)
641         {
642             this.required = required;
643             this.typeQName = typeQName;
644             this.aspectQNames = aspectQNames;
645
646             // Set the required node permissions
647
nodeRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames,
648                     RequiredPermission.On.NODE);
649
650             parentRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames,
651                     RequiredPermission.On.PARENT);
652
653             childrenRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames,
654                     RequiredPermission.On.CHILDREN);
655
656             // Find all the permissions that grant the allowed permission
657
// All permissions are treated specially.
658
granters = modelDAO.getGrantingPermissions(required);
659             granters.add(getAllPermissionReference());
660             granters.add(OLD_ALL_PERMISSIONS_REFERENCE);
661         }
662
663         /**
664          * External hook point
665          *
666          * @param authorisations
667          * @param nodeRef
668          * @return
669          */

670         boolean evaluate(Set JavaDoc<String JavaDoc> authorisations, NodeRef nodeRef)
671         {
672             Set JavaDoc<Pair<String JavaDoc, PermissionReference>> denied = new HashSet JavaDoc<Pair<String JavaDoc, PermissionReference>>();
673             return evaluate(authorisations, nodeRef, denied, null);
674         }
675
676         /**
677          * Internal hook point for recursion
678          *
679          * @param authorisations
680          * @param nodeRef
681          * @param denied
682          * @param recursiveIn
683          * @return
684          */

685         boolean evaluate(Set JavaDoc<String JavaDoc> authorisations, NodeRef nodeRef, Set JavaDoc<Pair<String JavaDoc, PermissionReference>> denied,
686                 MutableBoolean recursiveIn)
687         {
688             // Do we defer our required test to a parent (yes if not null)
689
MutableBoolean recursiveOut = null;
690
691             Set JavaDoc<Pair<String JavaDoc, PermissionReference>> locallyDenied = new HashSet JavaDoc<Pair<String JavaDoc, PermissionReference>>();
692             locallyDenied.addAll(denied);
693             locallyDenied.addAll(getDenied(nodeRef));
694
695             // Start out true and "and" all other results
696
boolean success = true;
697
698             // Check the required permissions but not for sets they rely on
699
// their underlying permissions
700
if (required.equals(getPermissionReference(ALL_PERMISSIONS)) || modelDAO.checkPermission(required))
701             {
702                 if (parentRequirements.contains(required))
703                 {
704                     if (checkGlobalPermissions(authorisations) || checkRequired(authorisations, nodeRef, locallyDenied))
705                     {
706                         // No need to do the recursive test as it has been found
707
recursiveOut = null;
708                         if (recursiveIn != null)
709                         {
710                             recursiveIn.setValue(true);
711                         }
712                     }
713                     else
714                     {
715                         // Much cheaper to do this as we go then check all the
716
// stack values for each parent
717
recursiveOut = new MutableBoolean(false);
718                     }
719                 }
720                 else
721                 {
722                     // We have to do the test as no parent will help us out
723
success &= hasSinglePermission(authorisations, nodeRef);
724                 }
725                 if (!success)
726                 {
727                     return false;
728                 }
729             }
730
731             // Check the other permissions required on the node
732
for (PermissionReference pr : nodeRequirements)
733             {
734                 // Build a new test
735
NodeTest nt = new NodeTest(pr, typeQName, aspectQNames);
736                 success &= nt.evaluate(authorisations, nodeRef, locallyDenied, null);
737                 if (!success)
738                 {
739                     return false;
740                 }
741             }
742
743             // Check the permission required of the parent
744

745             if (success)
746             {
747                 ChildAssociationRef car = nodeService.getPrimaryParent(nodeRef);
748                 if (car.getParentRef() != null)
749                 {
750
751                     NodePermissionEntry nodePermissions = permissionsDAO.getPermissions(car.getChildRef());
752                     if ((nodePermissions == null) || (nodePermissions.inheritPermissions()))
753                     {
754
755                         locallyDenied.addAll(getDenied(car.getParentRef()));
756                         for (PermissionReference pr : parentRequirements)
757                         {
758                             if (pr.equals(required))
759                             {
760                                 // Recursive permission
761
success &= this.evaluate(authorisations, car.getParentRef(), locallyDenied,
762                                         recursiveOut);
763                                 if ((recursiveOut != null) && recursiveOut.getValue())
764                                 {
765                                     if (recursiveIn != null)
766                                     {
767                                         recursiveIn.setValue(true);
768                                     }
769                                 }
770                             }
771                             else
772                             {
773                                 NodeTest nt = new NodeTest(pr, typeQName, aspectQNames);
774                                 success &= nt.evaluate(authorisations, car.getParentRef(), locallyDenied, null);
775                             }
776
777                             if (!success)
778                             {
779                                 return false;
780                             }
781                         }
782                     }
783                 }
784             }
785
786             if ((recursiveOut != null) && (!recursiveOut.getValue()))
787             {
788                 // The required authentication was not resolved in recursion
789
return false;
790             }
791
792             // Check permissions required of children
793
if (childrenRequirements.size() > 0)
794             {
795                 List JavaDoc<ChildAssociationRef> childAssocRefs = nodeService.getChildAssocs(nodeRef);
796                 for (PermissionReference pr : childrenRequirements)
797                 {
798                     for (ChildAssociationRef child : childAssocRefs)
799                     {
800                         success &= (hasPermission(child.getChildRef(), pr) == AccessStatus.ALLOWED);
801                         if (!success)
802                         {
803                             return false;
804                         }
805                     }
806                 }
807             }
808
809             return success;
810         }
811
812         public boolean hasSinglePermission(Set JavaDoc<String JavaDoc> authorisations, NodeRef nodeRef)
813         {
814             // Check global permission
815

816             if (checkGlobalPermissions(authorisations))
817             {
818                 return true;
819             }
820
821             Set JavaDoc<Pair<String JavaDoc, PermissionReference>> denied = new HashSet JavaDoc<Pair<String JavaDoc, PermissionReference>>();
822
823             // Keep track of permission that are denied
824

825             // Permissions are only evaluated up the primary parent chain
826
// TODO: Do not ignore non primary permissions
827
ChildAssociationRef car = nodeService.getPrimaryParent(nodeRef);
828             // Work up the parent chain evaluating permissions.
829
while (car != null)
830             {
831                 // Add any denied permission to the denied list - these can not
832
// then
833
// be used to given authentication.
834
// A -> B -> C
835
// If B denies all permissions to any - allowing all permissions
836
// to
837
// andy at node A has no effect
838

839                 denied.addAll(getDenied(car.getChildRef()));
840
841                 // If the current node allows the permission we are done
842
// The test includes any parent or ancestor requirements
843
if (checkRequired(authorisations, car.getChildRef(), denied))
844                 {
845                     return true;
846                 }
847
848                 // Build the next element of the evaluation chain
849
if (car.getParentRef() != null)
850                 {
851                     NodePermissionEntry nodePermissions = permissionsDAO.getPermissions(car.getChildRef());
852                     if ((nodePermissions == null) || (nodePermissions.inheritPermissions()))
853                     {
854                         car = nodeService.getPrimaryParent(car.getParentRef());
855                     }
856                     else
857                     {
858                         car = null;
859                     }
860                 }
861                 else
862                 {
863                     car = null;
864                 }
865
866             }
867
868             // TODO: Support meta data permissions on the root node?
869

870             return false;
871
872         }
873
874         /**
875          * Check if we have a global permission
876          *
877          * @param authorisations
878          * @return
879          */

880         private boolean checkGlobalPermissions(Set JavaDoc<String JavaDoc> authorisations)
881         {
882             for (PermissionEntry pe : modelDAO.getGlobalPermissionEntries())
883             {
884                 if (isGranted(pe, authorisations, null))
885                 {
886                     return true;
887                 }
888             }
889             return false;
890         }
891
892         /**
893          * Get the list of permissions denied for this node.
894          *
895          * @param nodeRef
896          * @return
897          */

898         Set JavaDoc<Pair<String JavaDoc, PermissionReference>> getDenied(NodeRef nodeRef)
899         {
900             Set JavaDoc<Pair<String JavaDoc, PermissionReference>> deniedSet = new HashSet JavaDoc<Pair<String JavaDoc, PermissionReference>>();
901
902             // Loop over all denied permissions
903
NodePermissionEntry nodeEntry = permissionsDAO.getPermissions(nodeRef);
904             if (nodeEntry != null)
905             {
906                 for (PermissionEntry pe : nodeEntry.getPermissionEntries())
907                 {
908                     if (pe.isDenied())
909                     {
910                         // All the sets that grant this permission must be
911
// denied
912
// Note that granters includes the orginal permission
913
Set JavaDoc<PermissionReference> granters = modelDAO
914                                 .getGrantingPermissions(pe.getPermissionReference());
915                         for (PermissionReference granter : granters)
916                         {
917                             deniedSet.add(new Pair<String JavaDoc, PermissionReference>(pe.getAuthority(), granter));
918                         }
919
920                         // All the things granted by this permission must be
921
// denied
922
Set JavaDoc<PermissionReference> grantees = modelDAO.getGranteePermissions(pe.getPermissionReference());
923                         for (PermissionReference grantee : grantees)
924                         {
925                             deniedSet.add(new Pair<String JavaDoc, PermissionReference>(pe.getAuthority(), grantee));
926                         }
927
928                         // All permission excludes all permissions available for
929
// the node.
930
if (pe.getPermissionReference().equals(getAllPermissionReference()) || pe.getPermissionReference().equals(OLD_ALL_PERMISSIONS_REFERENCE))
931                         {
932                             for (PermissionReference deny : modelDAO.getAllPermissions(nodeRef))
933                             {
934                                 deniedSet.add(new Pair<String JavaDoc, PermissionReference>(pe.getAuthority(), deny));
935                             }
936                         }
937                     }
938                 }
939             }
940             return deniedSet;
941         }
942
943         /**
944          * Check that a given authentication is available on a node
945          *
946          * @param authorisations
947          * @param nodeRef
948          * @param denied
949          * @return
950          */

951         boolean checkRequired(Set JavaDoc<String JavaDoc> authorisations, NodeRef nodeRef, Set JavaDoc<Pair<String JavaDoc, PermissionReference>> denied)
952         {
953             NodePermissionEntry nodeEntry = permissionsDAO.getPermissions(nodeRef);
954
955             // No permissions set - short cut to deny
956
if (nodeEntry == null)
957             {
958                 return false;
959             }
960
961             // Check if each permission allows - the first wins.
962
// We could have other voting style mechanisms here
963
for (PermissionEntry pe : nodeEntry.getPermissionEntries())
964             {
965                 if (isGranted(pe, authorisations, denied))
966                 {
967                     return true;
968                 }
969             }
970             return false;
971         }
972
973         /**
974          * Is a permission granted
975          *
976          * @param pe -
977          * the permissions entry to consider
978          * @param granters -
979          * the set of granters
980          * @param authorisations -
981          * the set of authorities
982          * @param denied -
983          * the set of denied permissions/authority pais
984          * @return
985          */

986         private boolean isGranted(PermissionEntry pe, Set JavaDoc<String JavaDoc> authorisations,
987                 Set JavaDoc<Pair<String JavaDoc, PermissionReference>> denied)
988         {
989             // If the permission entry denies then we just deny
990
if (pe.isDenied())
991             {
992                 return false;
993             }
994
995             // The permission is allowed but we deny it as it is in the denied
996
// set
997
if (denied != null)
998             {
999                 Pair<String JavaDoc, PermissionReference> specific = new Pair<String JavaDoc, PermissionReference>(pe.getAuthority(),
1000                        required);
1001                if (denied.contains(specific))
1002                {
1003                    return false;
1004                }
1005            }
1006
1007            // If the permission has a match in both the authorities and
1008
// granters list it is allowed
1009
// It applies to the current user and it is granted
1010
if (authorisations.contains(pe.getAuthority()) && granters.contains(pe.getPermissionReference()))
1011            {
1012                {
1013                    return true;
1014                }
1015            }
1016
1017            // Default deny
1018
return false;
1019        }
1020     
1021    }
1022
1023    /**
1024     * Helper class to store a pair of objects which may be null
1025     *
1026     * @author Andy Hind
1027     */

1028    private static class Pair<A, B>
1029    {
1030        A a;
1031
1032        B b;
1033
1034        Pair(A a, B b)
1035        {
1036            this.a = a;
1037            this.b = b;
1038        }
1039
1040        A getA()
1041        {
1042            return a;
1043        }
1044
1045        B getB()
1046        {
1047            return b;
1048        }
1049
1050        @Override JavaDoc
1051        public boolean equals(Object JavaDoc o)
1052        {
1053            if (this == o)
1054            {
1055                return true;
1056            }
1057            if (!(this instanceof Pair))
1058            {
1059                return false;
1060            }
1061            Pair other = (Pair) o;
1062            return EqualsHelper.nullSafeEquals(this.getA(), other.getA())
1063                    && EqualsHelper.nullSafeEquals(this.getB(), other.getB());
1064        }
1065
1066        @Override JavaDoc
1067        public int hashCode()
1068        {
1069            return (((a == null) ? 0 : a.hashCode()) * 37) + ((b == null) ? 0 : b.hashCode());
1070        }
1071
1072    }
1073
1074    private static class MutableBoolean
1075    {
1076        private boolean value;
1077
1078        MutableBoolean(boolean value)
1079        {
1080            this.value = value;
1081        }
1082
1083        void setValue(boolean value)
1084        {
1085            this.value = value;
1086        }
1087
1088        boolean getValue()
1089        {
1090            return value;
1091        }
1092    }
1093}
1094
Popular Tags