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