View Javadoc

1   /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.acegisecurity.afterinvocation;
16  
17  import org.acegisecurity.AccessDeniedException;
18  import org.acegisecurity.AcegiMessageSource;
19  import org.acegisecurity.Authentication;
20  import org.acegisecurity.ConfigAttribute;
21  import org.acegisecurity.ConfigAttributeDefinition;
22  
23  import org.acegisecurity.acls.AclService;
24  import org.acegisecurity.acls.Permission;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  import org.springframework.context.MessageSource;
30  import org.springframework.context.MessageSourceAware;
31  import org.springframework.context.support.MessageSourceAccessor;
32  
33  import java.util.Iterator;
34  
35  
36  /**
37   * <p>Given a domain object instance returned from a secure object invocation, ensures the principal has
38   * appropriate permission as defined by the {@link AclService}.</p>
39   * <p>The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with a
40   * domain object instance for the current <code>Authentication</code> object.</p>
41   * <p>This after invocation provider will fire if any  {@link ConfigAttribute#getAttribute()} matches the {@link
42   * #processConfigAttribute}. The provider will then lookup the ACLs from the <code>AclService</code> and ensure the
43   * principal is {@link org.acegisecurity.acls.Acl#isGranted(org.acegisecurity.acls.Permission[],
44     org.acegisecurity.acls.sid.Sid[], boolean) Acl.isGranted(Permission[], Sid[], boolean)}
45   * when presenting the {@link #requirePermission} array to that method.</p>
46   * <p>Often users will setup an <code>AclEntryAfterInvocationProvider</code> with a {@link
47   * #processConfigAttribute} of <code>AFTER_ACL_READ</code> and a {@link #requirePermission} of
48   * <code>BasePermission.READ</code>. These are also the defaults.</p>
49   * <p>If the principal does not have sufficient permissions, an <code>AccessDeniedException</code> will be thrown.</p>
50   * <p>If the provided <code>returnObject</code> is <code>null</code>, permission will always be granted and
51   * <code>null</code> will be returned.</p>
52   * <p>All comparisons and prefixes are case sensitive.</p>
53   */
54  public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware {
55      //~ Static fields/initializers =====================================================================================
56  
57      protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);
58  
59      //~ Instance fields ================================================================================================
60  
61      protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
62  
63      //~ Constructors ===================================================================================================
64  
65      public AclEntryAfterInvocationProvider(AclService aclService, Permission[] requirePermission) {
66          super(aclService, "AFTER_ACL_READ", requirePermission);
67      }
68  
69      //~ Methods ========================================================================================================
70  
71      public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
72          Object returnedObject) throws AccessDeniedException {
73          Iterator iter = config.getConfigAttributes();
74  
75          while (iter.hasNext()) {
76              ConfigAttribute attr = (ConfigAttribute) iter.next();
77  
78              if (this.supports(attr)) {
79                  // Need to make an access decision on this invocation
80                  if (returnedObject == null) {
81                      // AclManager interface contract prohibits nulls
82                      // As they have permission to null/nothing, grant access
83                      if (logger.isDebugEnabled()) {
84                          logger.debug("Return object is null, skipping");
85                      }
86  
87                      return null;
88                  }
89  
90                  if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
91                      if (logger.isDebugEnabled()) {
92                          logger.debug("Return object is not applicable for this provider, skipping");
93                      }
94  
95                      return returnedObject;
96                  }
97  
98                  if (hasPermission(authentication, returnedObject)) {
99                      return returnedObject;
100                 } else {
101                     if (logger.isDebugEnabled()) {
102                         logger.debug("Denying access");
103                     }
104 
105                     throw new AccessDeniedException(messages.getMessage(
106                             "BasicAclEntryAfterInvocationProvider.noPermission",
107                             new Object[] {authentication.getName(), returnedObject},
108                             "Authentication {0} has NO permissions to the domain object {1}"));
109                 }
110             }
111         }
112 
113         return returnedObject;
114     }
115 
116     public void setMessageSource(MessageSource messageSource) {
117         this.messages = new MessageSourceAccessor(messageSource);
118     }
119 }