Coverage Report - org.acegisecurity.taglibs.authz.AclTag
 
Classes in this File Line Coverage Branch Coverage Complexity
AclTag
87% 
95% 
4.429
 
 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  
 
 16  
 package org.acegisecurity.taglibs.authz;
 17  
 
 18  
 import org.acegisecurity.Authentication;
 19  
 
 20  
 import org.acegisecurity.acl.AclEntry;
 21  
 import org.acegisecurity.acl.AclManager;
 22  
 import org.acegisecurity.acl.basic.BasicAclEntry;
 23  
 
 24  
 import org.acegisecurity.context.SecurityContextHolder;
 25  
 
 26  
 import org.apache.commons.logging.Log;
 27  
 import org.apache.commons.logging.LogFactory;
 28  
 
 29  
 import org.springframework.beans.factory.BeanFactoryUtils;
 30  
 
 31  
 import org.springframework.context.ApplicationContext;
 32  
 
 33  
 import org.springframework.web.context.support.WebApplicationContextUtils;
 34  
 import org.springframework.web.util.ExpressionEvaluationUtils;
 35  
 
 36  
 import java.util.HashSet;
 37  
 import java.util.Set;
 38  
 import java.util.StringTokenizer;
 39  
 
 40  
 import javax.servlet.ServletContext;
 41  
 import javax.servlet.jsp.JspException;
 42  
 import javax.servlet.jsp.PageContext;
 43  
 import javax.servlet.jsp.tagext.Tag;
 44  
 import javax.servlet.jsp.tagext.TagSupport;
 45  
 
 46  
 
 47  
 /**
 48  
  * An implementation of {@link javax.servlet.jsp.tagext.Tag} that allows its body through if some authorizations
 49  
  * are granted to the request's principal.<P>Only works with permissions that are subclasses of {@link
 50  
  * org.acegisecurity.acl.basic.BasicAclEntry}.</p>
 51  
  *  <p>One or more comma separate integer permissions are specified via the <code>hasPermission</code> attribute.
 52  
  * The tag will include its body if <b>any</b> of the integer permissions have been granted to the current
 53  
  * <code>Authentication</code> (obtained from the <code>SecurityContextHolder</code>).</p>
 54  
  *  <p>For this class to operate it must be able to access the application context via the
 55  
  * <code>WebApplicationContextUtils</code> and locate an {@link AclManager}. Application contexts have no need to have
 56  
  * more than one <code>AclManager</code> (as a provider-based implementation can be used so that it locates a provider
 57  
  * that is authoritative for the given domain object instance), so the first <code>AclManager</code> located will be
 58  
  * used.</p>
 59  
  *
 60  
  * @author Ben Alex
 61  
  * @version $Id: AclTag.java 1496 2006-05-23 13:38:33Z benalex $
 62  
  */
 63  18
 public class AclTag extends TagSupport {
 64  
     //~ Static fields/initializers =====================================================================================
 65  
 
 66  4
     protected static final Log logger = LogFactory.getLog(AclTag.class);
 67  
 
 68  
     //~ Instance fields ================================================================================================
 69  
 
 70  
     private Object domainObject;
 71  18
     private String hasPermission = "";
 72  
 
 73  
     //~ Methods ========================================================================================================
 74  
 
 75  
     public int doStartTag() throws JspException {
 76  9
         if ((null == hasPermission) || "".equals(hasPermission)) {
 77  1
             return Tag.SKIP_BODY;
 78  
         }
 79  
 
 80  8
         final String evaledPermissionsString = ExpressionEvaluationUtils.evaluateString("hasPermission", hasPermission,
 81  
                 pageContext);
 82  
 
 83  8
         Integer[] requiredIntegers = null;
 84  
 
 85  
         try {
 86  8
             requiredIntegers = parseIntegersString(evaledPermissionsString);
 87  1
         } catch (NumberFormatException nfe) {
 88  1
             throw new JspException(nfe);
 89  7
         }
 90  
 
 91  7
         Object resolvedDomainObject = null;
 92  
 
 93  7
         if (domainObject instanceof String) {
 94  5
             resolvedDomainObject = ExpressionEvaluationUtils.evaluate("domainObject", (String) domainObject,
 95  
                     Object.class, pageContext);
 96  
         } else {
 97  2
             resolvedDomainObject = domainObject;
 98  
         }
 99  
 
 100  7
         if (resolvedDomainObject == null) {
 101  1
             if (logger.isDebugEnabled()) {
 102  0
                 logger.debug("domainObject resolved to null, so including tag body");
 103  
             }
 104  
 
 105  
             // Of course they have access to a null object!
 106  1
             return Tag.EVAL_BODY_INCLUDE;
 107  
         }
 108  
 
 109  6
         if (SecurityContextHolder.getContext().getAuthentication() == null) {
 110  1
             if (logger.isDebugEnabled()) {
 111  0
                 logger.debug(
 112  
                     "SecurityContextHolder did not return a non-null Authentication object, so skipping tag body");
 113  
             }
 114  
 
 115  1
             return Tag.SKIP_BODY;
 116  
         }
 117  
 
 118  5
         Authentication auth = SecurityContextHolder.getContext().getAuthentication();
 119  
 
 120  5
         ApplicationContext context = getContext(pageContext);
 121  5
         String[] beans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, AclManager.class, false, false);
 122  
 
 123  5
         if (beans.length == 0) {
 124  0
             throw new JspException("No AclManager would found the application context: " + context.toString());
 125  
         }
 126  
 
 127  5
         AclManager aclManager = (AclManager) context.getBean(beans[0]);
 128  
 
 129  
         // Obtain aclEntrys applying to the current Authentication object
 130  5
         AclEntry[] acls = aclManager.getAcls(resolvedDomainObject, auth);
 131  
 
 132  5
         if (logger.isDebugEnabled()) {
 133  0
             logger.debug("Authentication: '" + auth + "' has: " + ((acls == null) ? 0 : acls.length)
 134  
                 + " AclEntrys for domain object: '" + resolvedDomainObject + "' from AclManager: '"
 135  
                 + aclManager.toString() + "'");
 136  
         }
 137  
 
 138  5
         if ((acls == null) || (acls.length == 0)) {
 139  2
             return Tag.SKIP_BODY;
 140  
         }
 141  
 
 142  9
         for (int i = 0; i < acls.length; i++) {
 143  
             // Locate processable AclEntrys
 144  8
             if (acls[i] instanceof BasicAclEntry) {
 145  5
                 BasicAclEntry processableAcl = (BasicAclEntry) acls[i];
 146  
 
 147  
                 // See if principal has any of the required permissions
 148  9
                 for (int y = 0; y < requiredIntegers.length; y++) {
 149  6
                     if (processableAcl.isPermitted(requiredIntegers[y].intValue())) {
 150  2
                         if (logger.isDebugEnabled()) {
 151  0
                             logger.debug("Including tag body as found permission: " + requiredIntegers[y]
 152  
                                 + " due to AclEntry: '" + processableAcl + "'");
 153  
                         }
 154  
 
 155  2
                         return Tag.EVAL_BODY_INCLUDE;
 156  
                     }
 157  
                 }
 158  
             }
 159  
         }
 160  
 
 161  1
         if (logger.isDebugEnabled()) {
 162  0
             logger.debug("No permission, so skipping tag body");
 163  
         }
 164  
 
 165  1
         return Tag.SKIP_BODY;
 166  
     }
 167  
 
 168  
     /**
 169  
      * Allows test cases to override where application context obtained from.
 170  
      *
 171  
      * @param pageContext so the <code>ServletContext</code> can be accessed as required by Spring's
 172  
      *        <code>WebApplicationContextUtils</code>
 173  
      *
 174  
      * @return the Spring application context (never <code>null</code>)
 175  
      */
 176  
     protected ApplicationContext getContext(PageContext pageContext) {
 177  0
         ServletContext servletContext = pageContext.getServletContext();
 178  
 
 179  0
         return WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
 180  
     }
 181  
 
 182  
     public Object getDomainObject() {
 183  1
         return domainObject;
 184  
     }
 185  
 
 186  
     public String getHasPermission() {
 187  1
         return hasPermission;
 188  
     }
 189  
 
 190  
     private Integer[] parseIntegersString(String integersString)
 191  
         throws NumberFormatException {
 192  8
         final Set integers = new HashSet();
 193  
         final StringTokenizer tokenizer;
 194  8
         tokenizer = new StringTokenizer(integersString, ",", false);
 195  
 
 196  19
         while (tokenizer.hasMoreTokens()) {
 197  12
             String integer = tokenizer.nextToken();
 198  12
             integers.add(new Integer(integer));
 199  11
         }
 200  
 
 201  7
         return (Integer[]) integers.toArray(new Integer[] {});
 202  
     }
 203  
 
 204  
     public void setDomainObject(Object domainObject) {
 205  8
         this.domainObject = domainObject;
 206  8
     }
 207  
 
 208  
     public void setHasPermission(String hasPermission) {
 209  9
         this.hasPermission = hasPermission;
 210  9
     }
 211  
 }