View Javadoc

1   /* Copyright 2004, 2005 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  import org.acegisecurity.GrantedAuthority;
20  import org.acegisecurity.GrantedAuthorityImpl;
21  import org.acegisecurity.context.SecurityContextHolder;
22  
23  import org.springframework.util.StringUtils;
24  
25  import org.springframework.web.util.ExpressionEvaluationUtils;
26  
27  import java.util.Arrays;
28  import java.util.Collection;
29  import java.util.Collections;
30  import java.util.HashSet;
31  import java.util.Iterator;
32  import java.util.Set;
33  
34  import javax.servlet.jsp.JspException;
35  import javax.servlet.jsp.tagext.Tag;
36  import javax.servlet.jsp.tagext.TagSupport;
37  
38  
39  /***
40   * An implementation of {@link javax.servlet.jsp.tagext.Tag} that allows it's
41   * body through if some authorizations are granted to the request's principal.
42   *
43   * @author Francois Beausoleil
44   * @version $Id: AuthorizeTag.java,v 1.13 2005/11/17 00:56:29 benalex Exp $
45   */
46  public class AuthorizeTag extends TagSupport {
47      //~ Instance fields ========================================================
48  
49      private String ifAllGranted = "";
50      private String ifAnyGranted = "";
51      private String ifNotGranted = "";
52  
53      //~ Methods ================================================================
54  
55      public void setIfAllGranted(String ifAllGranted) throws JspException {
56          this.ifAllGranted = ifAllGranted;
57      }
58  
59      public String getIfAllGranted() {
60          return ifAllGranted;
61      }
62  
63      public void setIfAnyGranted(String ifAnyGranted) throws JspException {
64          this.ifAnyGranted = ifAnyGranted;
65      }
66  
67      public String getIfAnyGranted() {
68          return ifAnyGranted;
69      }
70  
71      public void setIfNotGranted(String ifNotGranted) throws JspException {
72          this.ifNotGranted = ifNotGranted;
73      }
74  
75      public String getIfNotGranted() {
76          return ifNotGranted;
77      }
78  
79      public int doStartTag() throws JspException {
80          if (((null == ifAllGranted) || "".equals(ifAllGranted))
81              && ((null == ifAnyGranted) || "".equals(ifAnyGranted))
82              && ((null == ifNotGranted) || "".equals(ifNotGranted))) {
83              return Tag.SKIP_BODY;
84          }
85  
86          final Collection granted = getPrincipalAuthorities();
87  
88          final String evaledIfNotGranted = ExpressionEvaluationUtils
89              .evaluateString("ifNotGranted", ifNotGranted, pageContext);
90  
91          if ((null != evaledIfNotGranted) && !"".equals(evaledIfNotGranted)) {
92              Set grantedCopy = retainAll(granted,
93                      parseAuthoritiesString(evaledIfNotGranted));
94  
95              if (!grantedCopy.isEmpty()) {
96                  return Tag.SKIP_BODY;
97              }
98          }
99  
100         final String evaledIfAllGranted = ExpressionEvaluationUtils
101             .evaluateString("ifAllGranted", ifAllGranted, pageContext);
102 
103         if ((null != evaledIfAllGranted) && !"".equals(evaledIfAllGranted)) {
104             if (!granted.containsAll(parseAuthoritiesString(evaledIfAllGranted))) {
105                 return Tag.SKIP_BODY;
106             }
107         }
108 
109         final String evaledIfAnyGranted = ExpressionEvaluationUtils
110             .evaluateString("ifAnyGranted", ifAnyGranted, pageContext);
111 
112         if ((null != evaledIfAnyGranted) && !"".equals(evaledIfAnyGranted)) {
113             Set grantedCopy = retainAll(granted,
114                     parseAuthoritiesString(evaledIfAnyGranted));
115 
116             if (grantedCopy.isEmpty()) {
117                 return Tag.SKIP_BODY;
118             }
119         }
120 
121         return Tag.EVAL_BODY_INCLUDE;
122     }
123 
124     private Collection getPrincipalAuthorities() {
125         Authentication currentUser = SecurityContextHolder.getContext()
126                                                           .getAuthentication();
127 
128         if (null == currentUser) {
129             return Collections.EMPTY_LIST;
130         }
131 
132         if ((null == currentUser.getAuthorities())
133             || (currentUser.getAuthorities().length < 1)) {
134             return Collections.EMPTY_LIST;
135         }
136 
137         Collection granted = Arrays.asList(currentUser.getAuthorities());
138 
139         return granted;
140     }
141 
142     private Set authoritiesToRoles(Collection c) {
143         Set target = new HashSet();
144 
145         for (Iterator iterator = c.iterator(); iterator.hasNext();) {
146             GrantedAuthority authority = (GrantedAuthority) iterator.next();
147 
148             if (null == authority.getAuthority()) {
149                 throw new IllegalArgumentException(
150                     "Cannot process GrantedAuthority objects which return null from getAuthority() - attempting to process "
151                     + authority.toString());
152             }
153 
154             target.add(authority.getAuthority());
155         }
156 
157         return target;
158     }
159 
160     private Set parseAuthoritiesString(String authorizationsString) {
161         final Set requiredAuthorities = new HashSet();
162         final String[] authorities = StringUtils
163             .commaDelimitedListToStringArray(authorizationsString);
164 
165         for (int i = 0; i < authorities.length; i++) {
166             String authority = authorities[i];
167 
168          // Remove the role's whitespace characters without depending on JDK 1.4+ 
169          // Includes space, tab, new line, carriage return and form feed. 
170          String role = StringUtils.replace(authority, " ", ""); 
171          role = StringUtils.replace(role, "\t", ""); 
172          role = StringUtils.replace(role, "\r", ""); 
173          role = StringUtils.replace(role, "\n", ""); 
174          role = StringUtils.replace(role, "\f", ""); 
175 
176          requiredAuthorities.add(new GrantedAuthorityImpl(role));
177         }
178 
179         return requiredAuthorities;
180     }
181 
182     /***
183      * Find the common authorities between the current authentication's {@link
184      * GrantedAuthority} and the ones that have been specified in the tag's
185      * ifAny, ifNot or ifAllGranted attributes.
186      * 
187      * <p>
188      * We need to manually iterate over both collections, because the granted
189      * authorities might not implement {@link Object#equals(Object)} and
190      * {@link Object#hashCode()} in the same way as {@link
191      * GrantedAuthorityImpl}, thereby invalidating {@link
192      * Collection#retainAll(java.util.Collection)} results.
193      * </p>
194      * 
195      * <p>
196      * <strong>CAVEAT</strong>:  This method <strong>will not</strong> work if
197      * the granted authorities returns a <code>null</code> string as the
198      * return value of {@link
199      * org.acegisecurity.GrantedAuthority#getAuthority()}.
200      * </p>
201      * 
202      * <p>
203      * Reported by rawdave, on Fri Feb 04, 2005 2:11 pm in the Acegi Security
204      * System for Spring forums.
205      * </p>
206      *
207      * @param granted The authorities granted by the authentication. May be any
208      *        implementation of {@link GrantedAuthority} that does
209      *        <strong>not</strong> return <code>null</code> from {@link
210      *        org.acegisecurity.GrantedAuthority#getAuthority()}.
211      * @param required A {@link Set} of {@link GrantedAuthorityImpl}s that have
212      *        been built using ifAny, ifAll or ifNotGranted.
213      *
214      * @return A set containing only the common authorities between
215      *         <var>granted</var> and <var>required</var>.
216      *
217      * @see <a
218      *      href="http://forum.springframework.org/viewtopic.php?t=3367">authz:authorize
219      *      ifNotGranted not behaving as expected</a>
220      */
221     private Set retainAll(final Collection granted, final Set required) {
222         Set grantedRoles = authoritiesToRoles(granted);
223         Set requiredRoles = authoritiesToRoles(required);
224         grantedRoles.retainAll(requiredRoles);
225 
226         return rolesToAuthorities(grantedRoles, granted);
227     }
228 
229     private Set rolesToAuthorities(Set grantedRoles, Collection granted) {
230         Set target = new HashSet();
231 
232         for (Iterator iterator = grantedRoles.iterator(); iterator.hasNext();) {
233             String role = (String) iterator.next();
234 
235             for (Iterator grantedIterator = granted.iterator();
236                 grantedIterator.hasNext();) {
237                 GrantedAuthority authority = (GrantedAuthority) grantedIterator
238                     .next();
239 
240                 if (authority.getAuthority().equals(role)) {
241                     target.add(authority);
242 
243                     break;
244                 }
245             }
246         }
247 
248         return target;
249     }
250 }