From c296298b01bb06e4be6907b8ba69c14176cd8ee1 Mon Sep 17 00:00:00 2001 From: Stevo Slavic Date: Sun, 3 Feb 2013 15:02:02 +0100 Subject: [PATCH] Consolidate SWF security tags with SEC taglibs Before this change, SWF had its own faclets security tag library with hierarchy root in AbstractAuthorizeTag. As of this change SWF facelets security tag library inherits Spring SEC AbstractAuthorizeTag instead, consolidating the two frameworks making it easier to maintain, extend and reuse. This is made possible by adding Spring security taglibs module as optional SWF facelets dependecy. Because the dependency is optional, existing SWF facelets security tag library users will have to explicitly add Spring Security taglibs module as dependency. Issue: SWF-1557 --- build.gradle | 1 + .../faces/security/AbstractAuthorizeTag.java | 336 ------------------ .../faces/security/FaceletsAuthorizeTag.java | 4 +- 3 files changed, 4 insertions(+), 337 deletions(-) delete mode 100644 spring-faces/src/main/java/org/springframework/faces/security/AbstractAuthorizeTag.java diff --git a/build.gradle b/build.gradle index 343e6db5..05eb0d94 100644 --- a/build.gradle +++ b/build.gradle @@ -210,6 +210,7 @@ project("spring-faces") { optional("com.sun.facelets:jsf-facelets:1.1.14") optional("org.springframework.security:spring-security-core:$springSecurityVersion") optional("org.springframework.security:spring-security-web:$springSecurityVersion") + optional("org.springframework.security:spring-security-taglibs:$springSecurityVersion") optional("org.springframework:spring-webmvc-portlet:$springVersion") testCompile("log4j:log4j:$log4jVersion") { exclude group: "javax.mail", module: "mail" diff --git a/spring-faces/src/main/java/org/springframework/faces/security/AbstractAuthorizeTag.java b/spring-faces/src/main/java/org/springframework/faces/security/AbstractAuthorizeTag.java deleted file mode 100644 index 1a1f0150..00000000 --- a/spring-faces/src/main/java/org/springframework/faces/security/AbstractAuthorizeTag.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2004-2012 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.faces.security; - -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.expression.Expression; -import org.springframework.expression.ParseException; -import org.springframework.security.access.expression.ExpressionUtils; -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.security.web.access.expression.WebSecurityExpressionHandler; -import org.springframework.util.StringUtils; -import org.springframework.web.context.support.WebApplicationContextUtils; - -/** - *

- * A base class for an <authorize> tag used to make Spring Security based authorization decisions. - *

- * - *

- * This class is independent of tag rendering technology (JSP, Facelets). It treats tag attributes as simple strings - * (with the notable exception of the "access" attribute, which is always expected to contain a Spring EL expression). - * Therefore subclasses are expected to extract tag attribute values from the specific rendering technology, evaluate - * them as expressions if necessary, and use the result to set the String-based attributes of this class. - *

- * - * @author Francois Beausoleil - * @author Luke Taylor - * @author Rossen Stoyanchev - * - * @since 2.2.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: - * - * 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 granted = getPrincipalAuthorities(); - - if (hasTextAllGranted) { - if (!granted.containsAll(parseAuthoritiesString(getIfAllGranted()))) { - return false; - } - } - - if (hasTextAnyGranted) { - Set grantedCopy = retainAll(granted, parseAuthoritiesString(getIfAnyGranted())); - if (grantedCopy.isEmpty()) { - return false; - } - } - - if (hasTextNotGranted) { - Set grantedCopy = retainAll(granted, parseAuthoritiesString(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; - } - - WebSecurityExpressionHandler 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 this.access; - } - - public void setAccess(String access) { - this.access = access; - } - - public String getUrl() { - return this.url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getMethod() { - return this.method; - } - - public void setMethod(String method) { - this.method = (method != null) ? method.toUpperCase() : null; - } - - public String getIfAllGranted() { - return this.ifAllGranted; - } - - public void setIfAllGranted(String ifAllGranted) { - this.ifAllGranted = ifAllGranted; - } - - public String getIfAnyGranted() { - return this.ifAnyGranted; - } - - public void setIfAnyGranted(String ifAnyGranted) { - this.ifAnyGranted = ifAnyGranted; - } - - public String getIfNotGranted() { - return this.ifNotGranted; - } - - public void setIfNotGranted(String ifNotGranted) { - this.ifNotGranted = ifNotGranted; - } - - /*------------- Private helper methods -----------------*/ - - private Collection getPrincipalAuthorities() { - Authentication currentUser = SecurityContextHolder.getContext().getAuthentication(); - if (null == currentUser) { - return Collections.emptyList(); - } - return currentUser.getAuthorities(); - } - - private Set parseAuthoritiesString(String authorizationsString) { - final Set requiredAuthorities = new HashSet(); - requiredAuthorities.addAll(AuthorityUtils.commaSeparatedStringToAuthorityList(authorizationsString)); - return requiredAuthorities; - } - - private Set retainAll(final Collection granted, - final Set required) { - Set grantedRoles = authoritiesToRoles(granted); - Set requiredRoles = authoritiesToRoles(required); - grantedRoles.retainAll(requiredRoles); - - return rolesToAuthorities(grantedRoles, granted); - } - - private Set authoritiesToRoles(Collection c) { - Set target = new HashSet(); - 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 rolesToAuthorities(Set grantedRoles, Collection granted) { - Set target = new HashSet(); - for (String role : grantedRoles) { - for (GrantedAuthority authority : granted) { - if (authority.getAuthority().equals(role)) { - target.add(authority); - break; - } - } - } - return target; - } - - private WebSecurityExpressionHandler getExpressionHandler() throws IOException { - ApplicationContext appContext = WebApplicationContextUtils - .getRequiredWebApplicationContext(getServletContext()); - Map expressionHandlres = appContext - .getBeansOfType(WebSecurityExpressionHandler.class); - - if (expressionHandlres.size() == 0) { - 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."); - } - - return (WebSecurityExpressionHandler) expressionHandlres.values().toArray()[0]; - } - - private WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() throws IOException { - ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); - Map 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]; - } -} diff --git a/spring-faces/src/main/java/org/springframework/faces/security/FaceletsAuthorizeTag.java b/spring-faces/src/main/java/org/springframework/faces/security/FaceletsAuthorizeTag.java index cd4e3c8c..e38eae8d 100644 --- a/spring-faces/src/main/java/org/springframework/faces/security/FaceletsAuthorizeTag.java +++ b/spring-faces/src/main/java/org/springframework/faces/security/FaceletsAuthorizeTag.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2010 the original author or authors. + * Copyright 2004-2013 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. @@ -24,6 +24,8 @@ import javax.servlet.ServletContext; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import org.springframework.security.taglibs.authz.AbstractAuthorizeTag; + /** * A concrete implementation of {@link AbstractAuthorizeTag} for use with standard Facelets rendering technology. *