11 changed files with 458 additions and 346 deletions
@ -0,0 +1,336 @@
@@ -0,0 +1,336 @@
|
||||
/* |
||||
* Copyright 2004-2010 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.taglibs.authz; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashSet; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.ServletContext; |
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.ServletRequest; |
||||
import javax.servlet.ServletResponse; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
|
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.core.GenericTypeResolver; |
||||
import org.springframework.expression.Expression; |
||||
import org.springframework.expression.ParseException; |
||||
import org.springframework.security.access.expression.ExpressionUtils; |
||||
import org.springframework.security.access.expression.SecurityExpressionHandler; |
||||
import org.springframework.security.core.Authentication; |
||||
import org.springframework.security.core.GrantedAuthority; |
||||
import org.springframework.security.core.authority.AuthorityUtils; |
||||
import org.springframework.security.core.context.SecurityContextHolder; |
||||
import org.springframework.security.web.FilterInvocation; |
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.context.support.WebApplicationContextUtils; |
||||
|
||||
/** |
||||
* A base class for an <authorize> tag that is independent of the tag rendering technology (JSP, Facelets). |
||||
* It treats tag attributes as simple strings rather than strings that may contain expressions with the |
||||
* exception of the "access" attribute, which is always expected to contain a Spring EL expression. |
||||
* |
||||
* Subclasses are expected to extract tag attribute values from the specific rendering technology, evaluate |
||||
* them as expressions if necessary, and set the String-based attributes of this class. |
||||
* |
||||
* @author Francois Beausoleil |
||||
* @author Luke Taylor |
||||
* @author Rossen Stoyanchev |
||||
* |
||||
* @since 3.1.0 |
||||
*/ |
||||
public abstract class AbstractAuthorizeTag { |
||||
|
||||
private String access; |
||||
private String url; |
||||
private String method; |
||||
private String ifAllGranted; |
||||
private String ifAnyGranted; |
||||
private String ifNotGranted; |
||||
|
||||
/** |
||||
* This method allows subclasses to provide a way to access the ServletRequest according to the rendering |
||||
* technology. |
||||
*/ |
||||
protected abstract ServletRequest getRequest(); |
||||
|
||||
/** |
||||
* This method allows subclasses to provide a way to access the ServletResponse according to the rendering |
||||
* technology. |
||||
*/ |
||||
protected abstract ServletResponse getResponse(); |
||||
|
||||
/** |
||||
* This method allows subclasses to provide a way to access the ServletContext according to the rendering |
||||
* technology. |
||||
*/ |
||||
protected abstract ServletContext getServletContext(); |
||||
|
||||
/** |
||||
* Make an authorization decision by considering all <authorize> tag attributes. The following are valid |
||||
* combinations of attributes: |
||||
* <ul> |
||||
* <li>access</li> |
||||
* <li>url, method</li> |
||||
* <li>ifAllGranted, ifAnyGranted, ifNotGranted</li> |
||||
* </ul> |
||||
* The above combinations are mutually exclusive and evaluated in the given order. |
||||
* |
||||
* @return the result of the authorization decision |
||||
* |
||||
* @throws IOException |
||||
*/ |
||||
public boolean authorize() throws IOException { |
||||
boolean isAuthorized = false; |
||||
|
||||
if (StringUtils.hasText(getAccess())) { |
||||
isAuthorized = authorizeUsingAccessExpression(); |
||||
|
||||
} else if (StringUtils.hasText(getUrl())) { |
||||
isAuthorized = authorizeUsingUrlCheck(); |
||||
|
||||
} else { |
||||
isAuthorized = authorizeUsingGrantedAuthorities(); |
||||
|
||||
} |
||||
|
||||
return isAuthorized; |
||||
} |
||||
|
||||
/** |
||||
* Make an authorization decision by considering ifAllGranted, ifAnyGranted, and ifNotGranted. All 3 or any |
||||
* combination can be provided. All provided attributes must evaluate to true. |
||||
* |
||||
* @return the result of the authorization decision |
||||
*/ |
||||
public boolean authorizeUsingGrantedAuthorities() { |
||||
boolean hasTextAllGranted = StringUtils.hasText(getIfAllGranted()); |
||||
boolean hasTextAnyGranted = StringUtils.hasText(getIfAnyGranted()); |
||||
boolean hasTextNotGranted = StringUtils.hasText(getIfNotGranted()); |
||||
|
||||
if ((!hasTextAllGranted) && (!hasTextAnyGranted) && (!hasTextNotGranted)) { |
||||
return false; |
||||
} |
||||
|
||||
final Collection<GrantedAuthority> granted = getPrincipalAuthorities(); |
||||
|
||||
if (hasTextAllGranted) { |
||||
if (!granted.containsAll(toAuthorities(getIfAllGranted()))) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if (hasTextAnyGranted) { |
||||
Set<GrantedAuthority> grantedCopy = retainAll(granted, toAuthorities(getIfAnyGranted())); |
||||
if (grantedCopy.isEmpty()) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if (hasTextNotGranted) { |
||||
Set<GrantedAuthority> grantedCopy = retainAll(granted, toAuthorities(getIfNotGranted())); |
||||
if (!grantedCopy.isEmpty()) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Make an authorization decision based on a Spring EL expression. See the "Expression-Based Access Control" chapter |
||||
* in Spring Security for details on what expressions can be used. |
||||
* |
||||
* @return the result of the authorization decision |
||||
* |
||||
* @throws IOException |
||||
*/ |
||||
public boolean authorizeUsingAccessExpression() throws IOException { |
||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication(); |
||||
if (currentUser == null) { |
||||
return false; |
||||
} |
||||
|
||||
SecurityExpressionHandler<FilterInvocation> handler = getExpressionHandler(); |
||||
|
||||
Expression accessExpression; |
||||
try { |
||||
accessExpression = handler.getExpressionParser().parseExpression(getAccess()); |
||||
|
||||
} catch (ParseException e) { |
||||
IOException ioException = new IOException(); |
||||
ioException.initCause(e); |
||||
throw ioException; |
||||
} |
||||
|
||||
FilterInvocation f = new FilterInvocation(getRequest(), getResponse(), new FilterChain() { |
||||
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
}); |
||||
|
||||
return ExpressionUtils.evaluateAsBoolean(accessExpression, handler.createEvaluationContext(currentUser, f)); |
||||
} |
||||
|
||||
/** |
||||
* Make an authorization decision based on the URL and HTTP method attributes. True is returned if the user is |
||||
* allowed to access the given URL as defined. |
||||
* |
||||
* @return the result of the authorization decision |
||||
* |
||||
* @throws IOException |
||||
*/ |
||||
public boolean authorizeUsingUrlCheck() throws IOException { |
||||
String contextPath = ((HttpServletRequest) getRequest()).getContextPath(); |
||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication(); |
||||
return getPrivilegeEvaluator().isAllowed(contextPath, getUrl(), getMethod(), currentUser); |
||||
} |
||||
|
||||
public String getAccess() { |
||||
return access; |
||||
} |
||||
|
||||
public void setAccess(String access) { |
||||
this.access = access; |
||||
} |
||||
|
||||
public String getUrl() { |
||||
return url; |
||||
} |
||||
|
||||
public void setUrl(String url) { |
||||
this.url = url; |
||||
} |
||||
|
||||
public String getMethod() { |
||||
return method; |
||||
} |
||||
|
||||
public void setMethod(String method) { |
||||
this.method = (method != null) ? method.toUpperCase() : null; |
||||
} |
||||
|
||||
public String getIfAllGranted() { |
||||
return ifAllGranted; |
||||
} |
||||
|
||||
public void setIfAllGranted(String ifAllGranted) { |
||||
this.ifAllGranted = ifAllGranted; |
||||
} |
||||
|
||||
public String getIfAnyGranted() { |
||||
return ifAnyGranted; |
||||
} |
||||
|
||||
public void setIfAnyGranted(String ifAnyGranted) { |
||||
this.ifAnyGranted = ifAnyGranted; |
||||
} |
||||
|
||||
public String getIfNotGranted() { |
||||
return ifNotGranted; |
||||
} |
||||
|
||||
public void setIfNotGranted(String ifNotGranted) { |
||||
this.ifNotGranted = ifNotGranted; |
||||
} |
||||
|
||||
/*------------- Private helper methods -----------------*/ |
||||
|
||||
private Collection<GrantedAuthority> getPrincipalAuthorities() { |
||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication(); |
||||
if (null == currentUser) { |
||||
return Collections.emptyList(); |
||||
} |
||||
return currentUser.getAuthorities(); |
||||
} |
||||
|
||||
private Set<GrantedAuthority> toAuthorities(String authorizations) { |
||||
final Set<GrantedAuthority> requiredAuthorities = new HashSet<GrantedAuthority>(); |
||||
requiredAuthorities.addAll(AuthorityUtils.commaSeparatedStringToAuthorityList(authorizations)); |
||||
return requiredAuthorities; |
||||
} |
||||
|
||||
private Set<GrantedAuthority> retainAll(final Collection<GrantedAuthority> granted, |
||||
final Set<GrantedAuthority> required) { |
||||
Set<String> grantedRoles = authoritiesToRoles(granted); |
||||
Set<String> requiredRoles = authoritiesToRoles(required); |
||||
grantedRoles.retainAll(requiredRoles); |
||||
|
||||
return rolesToAuthorities(grantedRoles, granted); |
||||
} |
||||
|
||||
private Set<String> authoritiesToRoles(Collection<GrantedAuthority> c) { |
||||
Set<String> target = new HashSet<String>(); |
||||
for (GrantedAuthority authority : c) { |
||||
if (null == authority.getAuthority()) { |
||||
throw new IllegalArgumentException( |
||||
"Cannot process GrantedAuthority objects which return null from getAuthority() - attempting to process " |
||||
+ authority.toString()); |
||||
} |
||||
target.add(authority.getAuthority()); |
||||
} |
||||
return target; |
||||
} |
||||
|
||||
private Set<GrantedAuthority> rolesToAuthorities(Set<String> grantedRoles, Collection<GrantedAuthority> granted) { |
||||
Set<GrantedAuthority> target = new HashSet<GrantedAuthority>(); |
||||
for (String role : grantedRoles) { |
||||
for (GrantedAuthority authority : granted) { |
||||
if (authority.getAuthority().equals(role)) { |
||||
target.add(authority); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
return target; |
||||
} |
||||
|
||||
private SecurityExpressionHandler<FilterInvocation> getExpressionHandler() throws IOException { |
||||
ApplicationContext appContext = WebApplicationContextUtils |
||||
.getRequiredWebApplicationContext(getServletContext()); |
||||
Map<String, SecurityExpressionHandler> handlers = appContext |
||||
.getBeansOfType(SecurityExpressionHandler.class); |
||||
|
||||
for (SecurityExpressionHandler h : handlers.values()) { |
||||
if (FilterInvocation.class.equals(GenericTypeResolver.resolveTypeArgument(h.getClass(), |
||||
SecurityExpressionHandler.class))) { |
||||
return h; |
||||
} |
||||
} |
||||
|
||||
throw new IOException("No visible WebSecurityExpressionHandler instance could be found in the application " |
||||
+ "context. There must be at least one in order to support expressions in JSP 'authorize' tags."); |
||||
} |
||||
|
||||
private WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() throws IOException { |
||||
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); |
||||
Map<String, WebInvocationPrivilegeEvaluator> wipes = ctx.getBeansOfType(WebInvocationPrivilegeEvaluator.class); |
||||
|
||||
if (wipes.size() == 0) { |
||||
throw new IOException( |
||||
"No visible WebInvocationPrivilegeEvaluator instance could be found in the application " |
||||
+ "context. There must be at least one in order to support the use of URL access checks in 'authorize' tags."); |
||||
} |
||||
|
||||
return (WebInvocationPrivilegeEvaluator) wipes.values().toArray()[0]; |
||||
} |
||||
} |
||||
@ -1,141 +0,0 @@
@@ -1,141 +0,0 @@
|
||||
package org.springframework.security.taglibs.authz; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.*; |
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.ServletContext; |
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.ServletRequest; |
||||
import javax.servlet.ServletResponse; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.jsp.JspException; |
||||
import javax.servlet.jsp.PageContext; |
||||
|
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.core.GenericTypeResolver; |
||||
import org.springframework.expression.Expression; |
||||
import org.springframework.expression.ParseException; |
||||
import org.springframework.security.access.expression.ExpressionUtils; |
||||
import org.springframework.security.access.expression.SecurityExpressionHandler; |
||||
import org.springframework.security.core.Authentication; |
||||
import org.springframework.security.core.context.SecurityContextHolder; |
||||
import org.springframework.security.web.FilterInvocation; |
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; |
||||
import org.springframework.web.context.support.WebApplicationContextUtils; |
||||
|
||||
/** |
||||
* Access control tag which evaluates its body based either on |
||||
* <ul> |
||||
* <li>an access expression (the "access" attribute), or</li> |
||||
* <li>by evaluating the current user's right to access a particular URL (set using the "url" attribute).</li> |
||||
* </ul> |
||||
* @author Luke Taylor |
||||
* @since 3.0 |
||||
*/ |
||||
public class AuthorizeTag extends LegacyAuthorizeTag { |
||||
private String access; |
||||
private String url; |
||||
private String method; |
||||
private String var; |
||||
|
||||
// If access expression evaluates to "true" return
|
||||
public int doStartTag() throws JspException { |
||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication(); |
||||
|
||||
if (currentUser == null) { |
||||
return SKIP_BODY; |
||||
} |
||||
|
||||
int result; |
||||
|
||||
if (access != null && access.length() > 0) { |
||||
result = authorizeUsingAccessExpression(currentUser); |
||||
} else if (url != null && url.length() > 0) { |
||||
result = authorizeUsingUrlCheck(currentUser); |
||||
} else { |
||||
result = super.doStartTag(); |
||||
} |
||||
|
||||
if (var != null) { |
||||
pageContext.setAttribute(var, Boolean.valueOf(result == EVAL_BODY_INCLUDE), PageContext.PAGE_SCOPE); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
private int authorizeUsingAccessExpression(Authentication currentUser) throws JspException { |
||||
SecurityExpressionHandler<FilterInvocation> handler = getExpressionHandler(); |
||||
|
||||
Expression accessExpression; |
||||
try { |
||||
accessExpression = handler.getExpressionParser().parseExpression(access); |
||||
|
||||
} catch (ParseException e) { |
||||
throw new JspException(e); |
||||
} |
||||
|
||||
FilterInvocation f = new FilterInvocation(pageContext.getRequest(), pageContext.getResponse(), DUMMY_CHAIN); |
||||
|
||||
if (ExpressionUtils.evaluateAsBoolean(accessExpression, handler.createEvaluationContext(currentUser, f))) { |
||||
return EVAL_BODY_INCLUDE; |
||||
} |
||||
|
||||
return SKIP_BODY; |
||||
} |
||||
|
||||
private int authorizeUsingUrlCheck(Authentication currentUser) throws JspException { |
||||
return getPrivilegeEvaluator().isAllowed(((HttpServletRequest)pageContext.getRequest()).getContextPath(), |
||||
url, method, currentUser) ? EVAL_BODY_INCLUDE : SKIP_BODY; |
||||
} |
||||
|
||||
public void setAccess(String access) { |
||||
this.access = access; |
||||
} |
||||
|
||||
public void setUrl(String url) { |
||||
this.url = url; |
||||
} |
||||
|
||||
public void setMethod(String method) { |
||||
this.method = method; |
||||
} |
||||
|
||||
public void setVar(String var) { |
||||
this.var = var; |
||||
} |
||||
|
||||
SecurityExpressionHandler<FilterInvocation> getExpressionHandler() throws JspException { |
||||
ServletContext servletContext = pageContext.getServletContext(); |
||||
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); |
||||
Map<String, SecurityExpressionHandler> expressionHdlrs = ctx.getBeansOfType(SecurityExpressionHandler.class); |
||||
|
||||
|
||||
for (SecurityExpressionHandler h : expressionHdlrs.values()) { |
||||
if (FilterInvocation.class.equals(GenericTypeResolver.resolveTypeArgument(h.getClass(), SecurityExpressionHandler.class))) { |
||||
return h; |
||||
} |
||||
} |
||||
|
||||
throw new JspException("No visible SecurityExpressionHandler<FilterInvocation> instance could be found in the " + |
||||
"application context. There must be at least one in order to support expressions in JSP 'authorize' tags."); |
||||
} |
||||
|
||||
WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() throws JspException { |
||||
ServletContext servletContext = pageContext.getServletContext(); |
||||
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); |
||||
Map<String, WebInvocationPrivilegeEvaluator> wipes = ctx.getBeansOfType(WebInvocationPrivilegeEvaluator.class); |
||||
|
||||
if (wipes.size() == 0) { |
||||
throw new JspException("No visible WebInvocationPrivilegeEvaluator instance could be found in the application " + |
||||
"context. There must be at least one in order to support the use of URL access checks in 'authorize' tags."); |
||||
} |
||||
|
||||
return (WebInvocationPrivilegeEvaluator) wipes.values().toArray()[0]; |
||||
} |
||||
|
||||
private static final FilterChain DUMMY_CHAIN = new FilterChain() { |
||||
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
}; |
||||
} |
||||
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
package org.springframework.security.taglibs.authz; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import javax.servlet.ServletContext; |
||||
import javax.servlet.ServletRequest; |
||||
import javax.servlet.ServletResponse; |
||||
import javax.servlet.jsp.JspException; |
||||
import javax.servlet.jsp.PageContext; |
||||
import javax.servlet.jsp.tagext.Tag; |
||||
|
||||
import org.springframework.web.util.ExpressionEvaluationUtils; |
||||
|
||||
/** |
||||
* A JSP {@link Tag} implementation of {@link AbstractAuthorizeTag}. |
||||
* |
||||
* @since 3.1.0 |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* |
||||
* @see AbstractAuthorizeTag |
||||
*/ |
||||
public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag { |
||||
|
||||
private Tag parent; |
||||
|
||||
protected String id; |
||||
|
||||
protected PageContext pageContext; |
||||
|
||||
/** |
||||
* Invokes the base class {@link AbstractAuthorizeTag#authorize()} method to |
||||
* decide if the body of the tag should be skipped or not. |
||||
* |
||||
* @return {@link Tag#SKIP_BODY} or {@link Tag#EVAL_BODY_INCLUDE} |
||||
*/ |
||||
public int doStartTag() throws JspException { |
||||
try { |
||||
setIfNotGranted(ExpressionEvaluationUtils.evaluateString("ifNotGranted", getIfNotGranted(), pageContext)); |
||||
setIfAllGranted(ExpressionEvaluationUtils.evaluateString("ifAllGranted", getIfAllGranted(), pageContext)); |
||||
setIfAnyGranted(ExpressionEvaluationUtils.evaluateString("ifAnyGranted", getIfAnyGranted(), pageContext)); |
||||
|
||||
return super.authorize() ? Tag.EVAL_BODY_INCLUDE : Tag.SKIP_BODY; |
||||
|
||||
} catch (IOException e) { |
||||
throw new JspException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Default processing of the end tag returning EVAL_PAGE. |
||||
* |
||||
* @return EVAL_PAGE |
||||
* |
||||
* @see Tag#doEndTag() |
||||
*/ |
||||
public int doEndTag() { |
||||
return EVAL_PAGE; |
||||
} |
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setId(String id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public Tag getParent() { |
||||
return parent; |
||||
} |
||||
|
||||
public void setParent(Tag parent) { |
||||
this.parent = parent; |
||||
} |
||||
|
||||
public void release() { |
||||
parent = null; |
||||
id = null; |
||||
} |
||||
|
||||
public void setPageContext(PageContext pageContext) { |
||||
this.pageContext = pageContext; |
||||
} |
||||
|
||||
@Override |
||||
protected ServletRequest getRequest() { |
||||
return pageContext.getRequest(); |
||||
} |
||||
|
||||
@Override |
||||
protected ServletResponse getResponse() { |
||||
return pageContext.getResponse(); |
||||
} |
||||
|
||||
@Override |
||||
protected ServletContext getServletContext() { |
||||
return pageContext.getServletContext(); |
||||
} |
||||
|
||||
} |
||||
@ -1,192 +0,0 @@
@@ -1,192 +0,0 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.security.taglibs.authz; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
import javax.servlet.jsp.JspException; |
||||
import javax.servlet.jsp.tagext.Tag; |
||||
import javax.servlet.jsp.tagext.TagSupport; |
||||
|
||||
import org.springframework.security.core.Authentication; |
||||
import org.springframework.security.core.GrantedAuthority; |
||||
import org.springframework.security.core.authority.AuthorityUtils; |
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl; |
||||
import org.springframework.security.core.context.SecurityContextHolder; |
||||
import org.springframework.web.util.ExpressionEvaluationUtils; |
||||
|
||||
|
||||
/** |
||||
* An implementation of {@link javax.servlet.jsp.tagext.Tag} that allows it's body through if some authorizations |
||||
* are granted to the request's principal. |
||||
* |
||||
* @author Francois Beausoleil |
||||
*/ |
||||
public class LegacyAuthorizeTag extends TagSupport { |
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private String ifAllGranted = ""; |
||||
private String ifAnyGranted = ""; |
||||
private String ifNotGranted = ""; |
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private Set<String> authoritiesToRoles(Collection<GrantedAuthority> c) { |
||||
Set<String> target = new HashSet<String>(); |
||||
|
||||
for (GrantedAuthority authority : c) { |
||||
if (null == authority.getAuthority()) { |
||||
throw new IllegalArgumentException( |
||||
"Cannot process GrantedAuthority objects which return null from getAuthority() - attempting to process " |
||||
+ authority.toString()); |
||||
} |
||||
|
||||
target.add(authority.getAuthority()); |
||||
} |
||||
|
||||
return target; |
||||
} |
||||
|
||||
public int doStartTag() throws JspException { |
||||
if (((null == ifAllGranted) || "".equals(ifAllGranted)) && ((null == ifAnyGranted) || "".equals(ifAnyGranted)) |
||||
&& ((null == ifNotGranted) || "".equals(ifNotGranted))) { |
||||
return Tag.SKIP_BODY; |
||||
} |
||||
|
||||
final Collection<GrantedAuthority> granted = getPrincipalAuthorities(); |
||||
|
||||
final String evaledIfNotGranted = ExpressionEvaluationUtils.evaluateString("ifNotGranted", ifNotGranted, |
||||
pageContext); |
||||
|
||||
if ((null != evaledIfNotGranted) && !"".equals(evaledIfNotGranted)) { |
||||
Set<GrantedAuthority> grantedCopy = retainAll(granted, parseAuthoritiesString(evaledIfNotGranted)); |
||||
|
||||
if (!grantedCopy.isEmpty()) { |
||||
return Tag.SKIP_BODY; |
||||
} |
||||
} |
||||
|
||||
final String evaledIfAllGranted = ExpressionEvaluationUtils.evaluateString("ifAllGranted", ifAllGranted, |
||||
pageContext); |
||||
|
||||
if ((null != evaledIfAllGranted) && !"".equals(evaledIfAllGranted)) { |
||||
if (!granted.containsAll(parseAuthoritiesString(evaledIfAllGranted))) { |
||||
return Tag.SKIP_BODY; |
||||
} |
||||
} |
||||
|
||||
final String evaledIfAnyGranted = ExpressionEvaluationUtils.evaluateString("ifAnyGranted", ifAnyGranted, |
||||
pageContext); |
||||
|
||||
if ((null != evaledIfAnyGranted) && !"".equals(evaledIfAnyGranted)) { |
||||
Set<GrantedAuthority> grantedCopy = retainAll(granted, parseAuthoritiesString(evaledIfAnyGranted)); |
||||
|
||||
if (grantedCopy.isEmpty()) { |
||||
return Tag.SKIP_BODY; |
||||
} |
||||
} |
||||
|
||||
return Tag.EVAL_BODY_INCLUDE; |
||||
} |
||||
|
||||
public String getIfAllGranted() { |
||||
return ifAllGranted; |
||||
} |
||||
|
||||
public String getIfAnyGranted() { |
||||
return ifAnyGranted; |
||||
} |
||||
|
||||
public String getIfNotGranted() { |
||||
return ifNotGranted; |
||||
} |
||||
|
||||
private Collection<GrantedAuthority> getPrincipalAuthorities() { |
||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication(); |
||||
|
||||
if (null == currentUser) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
return currentUser.getAuthorities(); |
||||
} |
||||
|
||||
private Set<GrantedAuthority> parseAuthoritiesString(String authorizationsString) { |
||||
final Set<GrantedAuthority> requiredAuthorities = new HashSet<GrantedAuthority>(); |
||||
requiredAuthorities.addAll(AuthorityUtils.commaSeparatedStringToAuthorityList(authorizationsString)); |
||||
|
||||
return requiredAuthorities; |
||||
} |
||||
|
||||
/** |
||||
* Find the common authorities between the current authentication's {@link GrantedAuthority} and the ones |
||||
* that have been specified in the tag's ifAny, ifNot or ifAllGranted attributes.<p>We need to manually |
||||
* iterate over both collections, because the granted authorities might not implement {@link |
||||
* Object#equals(Object)} and {@link Object#hashCode()} in the same way as {@link GrantedAuthorityImpl}, thereby |
||||
* invalidating {@link Collection#retainAll(java.util.Collection)} results.</p> |
||||
* <p> |
||||
* <strong>CAVEAT</strong>: This method <strong>will not</strong> work if the granted authorities |
||||
* returns a <code>null</code> string as the return value of {@link GrantedAuthority#getAuthority()}. |
||||
* </p> |
||||
* |
||||
* @param granted The authorities granted by the authentication. May be any implementation of {@link |
||||
* GrantedAuthority} that does <strong>not</strong> return <code>null</code> from {@link |
||||
* GrantedAuthority#getAuthority()}. |
||||
* @param required A {@link Set} of {@link GrantedAuthorityImpl}s that have been built using ifAny, ifAll or |
||||
* ifNotGranted. |
||||
* |
||||
* @return A set containing only the common authorities between <var>granted</var> and <var>required</var>. |
||||
* |
||||
*/ |
||||
private Set<GrantedAuthority> retainAll(final Collection<GrantedAuthority> granted, final Set<GrantedAuthority> required) { |
||||
Set<String> grantedRoles = authoritiesToRoles(granted); |
||||
Set<String> requiredRoles = authoritiesToRoles(required); |
||||
grantedRoles.retainAll(requiredRoles); |
||||
|
||||
return rolesToAuthorities(grantedRoles, granted); |
||||
} |
||||
|
||||
private Set<GrantedAuthority> rolesToAuthorities(Set<String> grantedRoles, Collection<GrantedAuthority> granted) { |
||||
Set<GrantedAuthority> target = new HashSet<GrantedAuthority>(); |
||||
|
||||
for (String role : grantedRoles) { |
||||
for (GrantedAuthority authority : granted) { |
||||
if (authority.getAuthority().equals(role)) { |
||||
target.add(authority); |
||||
|
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return target; |
||||
} |
||||
|
||||
public void setIfAllGranted(String ifAllGranted) throws JspException { |
||||
this.ifAllGranted = ifAllGranted; |
||||
} |
||||
|
||||
public void setIfAnyGranted(String ifAnyGranted) throws JspException { |
||||
this.ifAnyGranted = ifAnyGranted; |
||||
} |
||||
|
||||
public void setIfNotGranted(String ifNotGranted) throws JspException { |
||||
this.ifNotGranted = ifNotGranted; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue