Today we discuss about the security tags provided with Spring Security package. These tags allow you to customize your web pages to include/exclude elements based on user roles and credentials
The below description of Spring Security Tag is based on official Spring Security 3.1.0 RELEASE. It may not apply to older versions
I Configuration
To enable JSP page-level security, we need to import the Spring Security tag library as follow:
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
We also need to add the spring security taglib Maven dependency into our project pom.xml
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>3.1.0.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency>
II Security tags
A The Authorization tag
To enable the rendering of some portion based on user credentials, we can rely on the <sec:authorize> tag:
<sec:authorize access="hasRole('admin')"> <table> <tr> <td>xxx</td> <!-- Some administrator data here --> </tr> </table> </sec:authorize> <sec:authorize access="hasRole('guest')"> Restricted data, you are not allowed to access this resource </sec:authorize>
The “access” attribute allows us to define the access rules. In the above example we simply check for user role (admin or guest). The hasRole is a SpEL (Spring Expression Language) syntax. Complete list of spEL expressions for security is given below:
- hasRole([role]): Returns true if the current principal has the specified role.
- hasAnyRole([role1,role2]): Returns true if the current principal has any of the supplied roles (given as a comma-separated list of strings)
- principal: Allows direct access to the principal object representing the current user
- authentication: Allows direct access to the current Authentication object obtained from the SecurityContext
- permitAll: Always evaluates to true
- denyAll: Always evaluates to false
- isAnonymous(): Returns true if the current principal is an anonymous user
- isRememberMe(): Returns true if the current principal is a remember-me user
- isAuthenticated(): Returns true if the user is not anonymous
- isFullyAuthenticated(): Returns true if the user is not an anonymous or a remember-me user
Among this list, only some expressions are usefull for the access attribute, mainly hasRole([role]), hasAnyRole([role1,role2]), isAnonymous(), isRememberMe(), isAuthenticated() and isFullyAuthenticated(). The other expressions are more informative and serve in different contexts (we’ll see them soon)
Apart from the “access” attribute, the <sec:authorize> tag offers other interesting attributes:
- url: an URL within the application. The tag <sec:authorize> is renderd if the user is grated access to this URL (based on rules defined by the FilterSecurityInterceptor)
- method: GET or POST. Specify the HTTP method user to access the url. This attribute can only be used along with the previous url attribute.
- var: a page scope variable to store the evaluation of this tag (true or false) so it can be re-used later in the page for different purpose.
Please note that for the “url” attribute to work, you need to declare an additional DefaultWebInvocationPrivilegeEvaluator bean in the Spring context with the filterSecurityInterceptor injected as constructor argument:
<!-- Filter for role checking --> <bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager"/> <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/> <property name="securityMetadataSource"> <sec:filter-security-metadata-source lowercase-comparisons="true" request-matcher="ant" use-expressions="true"> <sec:intercept-url pattern="/pages/Security/**" access="permitAll"/> <sec:intercept-url pattern="/resources/**" access="permitAll"/> <sec:intercept-url pattern="/pages/Settings/**" access="hasRole('SETTINGS')"/> <sec:intercept-url pattern="/pages/Home/*" access="hasRole('HOME')"/> <sec:intercept-url pattern="/pages/Admin/**" access="hasRole('ADMINISTRATOR')"/> <sec:intercept-url pattern="/servlet/Download" access="hasAnyRole('DOWNLOAD','PREMIUM_ACCOUNT')"/> <sec:intercept-url pattern="/**" access="isAuthenticated()"/> </sec:filter-security-metadata-source> </property> </bean> <!-- webInvocationPrivilegeEvaluator necessary to use <sec:authorized url="xx"> --> <bean id="webInvocationPrivilegeEvaluator" class="org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator"> <constructor-arg ref="filterSecurityInterceptor"> </bean>
Below is an example of the var attribute usage:
<sec:authorize access="hasRole('admin')" var="isAdmin"> <table> <tr> <td>xxx</td> <!-- Some administrator data here --> </tr> </table> </sec:authorize> ... <c:if test="${isAdmin}"> // Some block here if the user is Admin </c:if>
B The Authentication tag
The <sec:authentication> tag gives access to the Authentication object of the security context. The attribute “property” allows us to access some property of the Authentication object itself and display it directly to the page.
The Authentication interface exposes the following methods:
- authorities: collection of GrantedAuthority instances. Corresponds in most case to user roles
- credentials: user’ credentials (usually password)
- details: object containing the details of the authentication process itself. The content of this object depends on the implementation of the Authentication interface. The default implementation returns null
- principal: the principal object, which is most of the time an instance of the UserDetails interface
- isAuthenticated: return true or false whether the use is authenticated or not
As with the previous tag, the <sec:authentication> tag offers some interesting other attributes:
- var: a page variable to store the result of the property attribute so it can be re-used later in the page for different purposes
- scope: scope of the above “var” attribute. Can be “page“, “request“,”session” or “application“
- htmlEscape: if true, enable HTML escape for the “property” attribute display
Usage examples:
<!-- Credentials display --> Your password is <sec:authentication property="credentials"/> ... <!-- Roles display --> <sec:authentication property="authorities" var="roles" scope="page" /> Your roles are: <ul> <c:forEach var="role" items="${roles}"> <li>${role}</li> </c:forEach> </ul> <!-- Username display --> Your username is <sec:authentication property="principal.username"/>
C The Accesscontrollist tag
This <sec:accesscontrollist> tag is rarely used and can only be evaluated if Spring Security’s ACL module is activated.
The available attributes are:
- hasPermission: a list of permission (coma as separator) to be checked against domain object. The permission strings will be converted first into Permission instance by the PermissionFactory before performing evaluation. The evaluation is true if at least one of the listed permission is found in the domain object
- domainObject: domain object for which the above permissions are evaluated
- var: a page scope variable to store the evaluation of this tag (true or false) so it can be re-used later in the page for different purpose
Usage example:
<sec:accesscontrollist hasPermission="admin,designer" domainObject="${someObject}"> //Displayed only if the domainObject has "admin" OR "designer" permission </sec:accesscontrollist>
III Security tags for Facelet
The above security tags are only available for JSP pages. If you are a JSF-user with Facelet as templating solution, no chance.
Luckily, some brillant people had a good idea to adapt these tags for Facelet. You can download the binaries here http://www.dominikdorn.com/facelets/
By looking around, I found out that there is a tag library out there for JSF shipped with Spring Web Flow: http://static.springsource.org/spring-webflow/docs/2.2.x/reference/html/ch13s09.html
You need to add the following dependency to your pom.xml
<dependency> <groupId>org.springframework.webflow</groupId> <artifactId>spring-faces</artifactId> <version>2.2.0.RELEASE</version> </dependency>
This jar contains many packages, among others the org.springframework.faces.security which is of interest. Alternatively if you do not want to get all the packages not related to security you can just copy the org.springframework.faces.security package into your source code.
Adding the above dependency is not enough. You need also to declare this new taglib in a springsecurity.taglib.xml file for example:
<?xml version="1.0"?> <!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd"> <facelet-taglib> <namespace>http://www.springframework.org/security/tags</namespace> <tag> <tag-name>authorize</tag-name> <handler-class>org.springframework.faces.security.FaceletsAuthorizeTagHandler</handler-class> </tag> <function> <function-name>areAllGranted</function-name> <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class> <function-signature>boolean areAllGranted(java.lang.String)</function-signature> </function> <function> <function-name>areAnyGranted</function-name> <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class> <function-signature>boolean areAnyGranted(java.lang.String)</function-signature> </function> <function> <function-name>areNotGranted</function-name> <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class> <function-signature>boolean areNotGranted(java.lang.String)</function-signature> </function> <function> <function-name>isAllowed</function-name> <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class> <function-signature>boolean isAllowed(java.lang.String, java.lang.String)</function-signature> </function> <function> <function-name>access</function-name> <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class> <function-signature>boolean access(java.lang.String)</function-signature> </function> </facelet-taglib>
The above declaration sheds some light on the available infrastructure:
- authorize: new tag
- areAllGranted(roles): new EL function. Returns true if all listed roles are granted to the current user
- areAnyGranted(roles): new EL function. Returns true if at least one listed role is granted to the current user
- areNotGranted(roles): new EL function. Returns true if all listed roles are not granted to the current user
- isAllowed(url,method): new EL function. Returns true if the given url with corresponding HTTP method can be accessed by the current user
- access(webExpression): new EL function. Returns true if the given web expression holds for the current user
The tag exposes the following attributes:
- access: see above
- url: see above
- method: see above
- areAllGranted: see above
- areAnyGranted: see above
- areNotGranted: see above
- var: set the result of the access evaluation (true or false) into the Faces context
We need to declare this taglib in the web.xml file:
<context-param> <param-name>javax.faces.FACELETS_LIBRARIES</param-name> <param-value>/WEB-INF/springsecurity.taglib.xml</param-value> </context-param>
Usage example:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:sec="http://www.springframework.org/security/tags"> <ui:composition template="/pages/Templates/techWebTemplate.xhtml"> ... ... <h:panelGroup id="secureBlock" layout="block" rendered="#{sec:areAnyGranted('DESIGNER, ADMINISTRATOR')}"> // Section rendered only for DESIGNER or ADMINISTRATOR roles </h:panelGroup> ... ... <sec:authorize access="hasAnyRole('ADMINISTRATOR',"DESIGNER')"> <h:panelGroup id="administrationBlock" layout="block"> ... </h:panelGroup> </sec:authorize> </ui:composition> </html>
Please pay attention to the special typo for the tag version and the EL function version.
<sec:areAnyGranted(‘DESIGNER, ADMINISTRATOR’)>: the roles are separated by a coma and the whole chain is enclosed in simple quotes
hasAnyRole(‘ADMINISTRATOR’,’DESIGNER’): the roles are enclosed first in simple quotes then separated by a coma
Pingback: Spring MVC part VI: ThymeLeaf advanced usage « Yet Another Java Blog
Pingback: Spring MVC part IV: ThymeLeaf advanced usage « Yet Another Java Blog
Great blog entry. Thank you very much for this information¡
I edit for to say that in version 5.0:
– It isnt necesary to create file springsecurity.taglib.xml
– Maven dependencies are not correct in the principal website. The correct dependencies are:
org.springframework.security
facelets-taglib-jsf20-spring-3
0.5
– The name of methods have changed: areAllGranted is ifAllGranted,….. It is advisable to see javadoc for version 5.0.
Kind regards.
Thanks Rafael. By looking into the code again, I realized that what is in the article is not the code from http://www.dominikdorn.com/facelets/ but an extract of the spring-faces.jar from Spring Webflow. I just modify the article accordingly.
Thank you
Hi , I use the same dependencies in my project ( facelets-taglib-jsf20-spring-3
0.5 and spring-security) but I have problem when I use for example :
i get an ERROR : Function ‘:ifAnyGranted’ not found, and if i use :
my compenent
it’s ingnored , my compenent is not hiding.
@ouafae
I have updated the article, you should use “areAnyGranted” instead of “ifAnyGranted”
I’m not able to make it work… JSF 1.2 & spring 3.1, security 3.1 & webflow 2.3 library…
Every sec tags are ignored or not found. I use the right springsecurity.taglib.xml for JSF 1.2 as stated in spring webflow configuration
@Andrea
Did you declare the taglib file in the web.xml as mentioned above ?
javax.faces.FACELETS_LIBRARIES
/WEB-INF/springsecurity.taglib.xml
Can you put your code on GitHub or a public repo so I can have a look ?
I can not make it work.
I use JSF 2.1.7 and spring webflow, It seems that the stop working whenever I introduce the spring webflow, below is my maven dependency:
org.springframework.webflow
spring-faces
2.3.1.RELEASE
commons-logging
commons-logging
Hello Hong.
What do you mean by “it stop working” ? Did you have some exception or stack trace in the logs ?
Hello Hong
Do you implement the Authentication tag in a similar way to the Authorization tag for jsf2 with facelets. Is there a FaceletsAuthenticationTagUtils that I have to setup in springsecurity.taglib.xml. I’m trying to display the principal.username
Hi Richie,
Any luck even i try to display principal.username in jsf, but no luck.
great tip. thanks!
Welcomed!
Why the tag in my page output nothing?
WordPress is escaping some HTML characters I believe. You should enclose them in special characters to escape
Howdy! I could have sworn Ive been to this website before but after browsing through some of the post I realized its new to me.
Anyhow, Im definitely happy I found it and Ill be
book-marking and checking back frequently!
Welcomed !
Nice tip. I’m actually facing a problem with JSF2 and Taglib security…I post on StackOverflow http://stackoverflow.com/questions/19387228/spring-security-taglib-authorize-authentication-are-not-working-with-role-hierar
If you have some time to loose … : ) Thanks
Pingback: Spring Security 3.1.4 taglib authorize/authentication are not working with role hierarchy in JSF 2.1 | Technology & Programming Answers