mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-02-25 17:06:42 +00:00
SEC-1552 Refactor AuthorizeTag and LegacyAuthorize tag to make them independent of JSP tag rendering.
This commit is contained in:
parent
7258abbbf4
commit
70600a0277
@ -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 @@
|
|||||||
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 @@
|
|||||||
|
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 @@
|
|||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,7 @@ import javax.servlet.jsp.tagext.Tag;
|
|||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.security.taglibs.authz.AuthenticationTag;
|
import org.springframework.security.taglibs.authz.AuthenticationTag;
|
||||||
import org.springframework.security.taglibs.authz.LegacyAuthorizeTag;
|
import org.springframework.security.taglibs.authz.JspAuthorizeTag;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,10 +72,10 @@ public class AuthzImpl implements Authz {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* implementation of LegacyAuthorizeTag
|
* implementation of JspAuthorizeTag
|
||||||
*/
|
*/
|
||||||
private boolean ifGranted(String roles, int grantType) {
|
private boolean ifGranted(String roles, int grantType) {
|
||||||
LegacyAuthorizeTag authorizeTag = new LegacyAuthorizeTag();
|
JspAuthorizeTag authorizeTag = new JspAuthorizeTag();
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<tag>
|
<tag>
|
||||||
<name>authorize</name>
|
<name>authorize</name>
|
||||||
<tag-class>org.springframework.security.taglibs.authz.AuthorizeTag</tag-class>
|
<tag-class>org.springframework.security.taglibs.authz.JspAuthorizeTag</tag-class>
|
||||||
<description>
|
<description>
|
||||||
A tag which outputs the body of the tag if the configured access expression
|
A tag which outputs the body of the tag if the configured access expression
|
||||||
evaluates to true for the currently authenticated principal.
|
evaluates to true for the currently authenticated principal.
|
||||||
|
@ -36,7 +36,7 @@ import javax.servlet.jsp.tagext.Tag;
|
|||||||
public class AuthorizeTagAttributeTests extends TestCase {
|
public class AuthorizeTagAttributeTests extends TestCase {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final LegacyAuthorizeTag authorizeTag = new LegacyAuthorizeTag();
|
private final JspAuthorizeTag authorizeTag = new JspAuthorizeTag();
|
||||||
private TestingAuthenticationToken currentUser;
|
private TestingAuthenticationToken currentUser;
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
@ -34,7 +34,7 @@ import javax.servlet.jsp.tagext.Tag;
|
|||||||
public class AuthorizeTagCustomGrantedAuthorityTests extends TestCase {
|
public class AuthorizeTagCustomGrantedAuthorityTests extends TestCase {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final LegacyAuthorizeTag authorizeTag = new LegacyAuthorizeTag();
|
private final JspAuthorizeTag authorizeTag = new JspAuthorizeTag();
|
||||||
private TestingAuthenticationToken currentUser;
|
private TestingAuthenticationToken currentUser;
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
@ -33,7 +33,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
|||||||
public class AuthorizeTagExpressionLanguageTests extends TestCase {
|
public class AuthorizeTagExpressionLanguageTests extends TestCase {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final LegacyAuthorizeTag authorizeTag = new LegacyAuthorizeTag();
|
private final JspAuthorizeTag authorizeTag = new JspAuthorizeTag();
|
||||||
private MockPageContext pageContext;
|
private MockPageContext pageContext;
|
||||||
private TestingAuthenticationToken currentUser;
|
private TestingAuthenticationToken currentUser;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ import org.springframework.web.context.support.StaticWebApplicationContext;
|
|||||||
public class AuthorizeTagTests {
|
public class AuthorizeTagTests {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private AuthorizeTag authorizeTag;
|
private JspAuthorizeTag authorizeTag;
|
||||||
private final TestingAuthenticationToken currentUser = new TestingAuthenticationToken("abc", "123", "ROLE SUPERVISOR", "ROLE_TELLER");
|
private final TestingAuthenticationToken currentUser = new TestingAuthenticationToken("abc", "123", "ROLE SUPERVISOR", "ROLE_TELLER");
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
@ -56,7 +56,7 @@ public class AuthorizeTagTests {
|
|||||||
ctx.registerSingleton("wipe", MockWebInvocationPrivilegeEvaluator.class);
|
ctx.registerSingleton("wipe", MockWebInvocationPrivilegeEvaluator.class);
|
||||||
MockServletContext servletCtx = new MockServletContext();
|
MockServletContext servletCtx = new MockServletContext();
|
||||||
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
|
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
|
||||||
authorizeTag = new AuthorizeTag();
|
authorizeTag = new JspAuthorizeTag();
|
||||||
authorizeTag.setPageContext(new MockPageContext(servletCtx, new MockHttpServletRequest(), new MockHttpServletResponse()));
|
authorizeTag.setPageContext(new MockPageContext(servletCtx, new MockHttpServletRequest(), new MockHttpServletResponse()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,9 +125,18 @@ public class AuthorizeTagTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultsToNotOutputtingBodyWhenNoRequiredAuthorities() throws JspException {
|
public void testDefaultsToNotOutputtingBodyWhenNoRequiredAuthorities() throws JspException {
|
||||||
assertEquals("", authorizeTag.getIfAllGranted());
|
assertEquals(null, authorizeTag.getIfAllGranted());
|
||||||
assertEquals("", authorizeTag.getIfAnyGranted());
|
assertEquals(null, authorizeTag.getIfAnyGranted());
|
||||||
assertEquals("", authorizeTag.getIfNotGranted());
|
assertEquals(null, authorizeTag.getIfNotGranted());
|
||||||
|
|
||||||
|
assertEquals(Tag.SKIP_BODY, authorizeTag.doStartTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultsToNotOutputtingBodyWhenNoAuthoritiesProvided() throws JspException {
|
||||||
|
authorizeTag.setIfAllGranted("");
|
||||||
|
authorizeTag.setIfAnyGranted("");
|
||||||
|
authorizeTag.setIfNotGranted("");
|
||||||
|
|
||||||
assertEquals(Tag.SKIP_BODY, authorizeTag.doStartTag());
|
assertEquals(Tag.SKIP_BODY, authorizeTag.doStartTag());
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,6 @@ public class JaasApiIntegrationFilterTest {
|
|||||||
authenticatedSubject.getPrivateCredentials().add("password");
|
authenticatedSubject.getPrivateCredentials().add("password");
|
||||||
authenticatedSubject.getPublicCredentials().add("username");
|
authenticatedSubject.getPublicCredentials().add("username");
|
||||||
callbackHandler = new CallbackHandler() {
|
callbackHandler = new CallbackHandler() {
|
||||||
@Override
|
|
||||||
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
|
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
|
||||||
for (Callback callback : callbacks) {
|
for (Callback callback : callbacks) {
|
||||||
if (callback instanceof NameCallback) {
|
if (callback instanceof NameCallback) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user