Spring Security 3.1 conditionally securing your web page with JSF 2.0

Posted on

Hello, in all our previous use cases we secured a whole page, but what if we want to secure only a certain element or part ?

Consider a scenario where message displayed on admin login and guest login is different, message is a very simple example, you may want to show different menu to admin. Using Spring Security there are two ways to accomplish this.

  1. Use Spring Security tag lib
  2. Use JSF attributes and use managed bean to manage security

In this tutorial we will enhance our application from Spring Security 3.1 Adding Salt to Password using BCryptPasswordEncoder and JSF 2.0 and add conditional rendering of element.

First we will change our secured.xhtml to add different message for admin and guest.

secured.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
</h:head>
<h:body>
	<h:form>
		<h:outputText value="This message is for admin only" id="adminonlyoutputtext" rendered="#{securityBean.isUserAdmin}"></h:outputText>
		<br/>
		<h:outputText value="This message is for guest only" id="guestonlyoutputtext" rendered="#{securityBean.isUserGuest}"></h:outputText>
		<br/>
		<h:outputLabel value="I am secured, if you are seeing me it means you have logged in correctly, great!"></h:outputLabel>
		<h:commandLink id="logout" action="#{loginMgmtBean.logout}" value="Logout"></h:commandLink>
		<h:messages></h:messages>
	</h:form>
</h:body>
</html>

Second we will write one simple managed bean which will tell us if the logged in user is admin or guest.

SecurityHolderBean

package com.mumz.jsfspringsec.beans;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

@ManagedBean(name = "securityBean")
@SessionScoped
public class SecurityHolderBean {
	private boolean isUserAdmin = false;
	private boolean isUserGuest = false;

	public boolean getIsUserAdmin() {
		isUserAdmin = false;
		Authentication authentication = SecurityContextHolder.getContext()
				.getAuthentication();
		for (GrantedAuthority grantedAuthority : authentication
				.getAuthorities()) {
			if ("ROLE_ADMIN".equals(grantedAuthority.getAuthority())) {
				isUserAdmin = true;
				break;
			}
		}
		return isUserAdmin;
	}

	public boolean getIsUserGuest() {
		isUserGuest = false;
		Authentication authentication = SecurityContextHolder.getContext()
				.getAuthentication();
		for (GrantedAuthority grantedAuthority : authentication
				.getAuthorities()) {
			if ("ROLE_GUEST".equals(grantedAuthority.getAuthority())) {
				isUserGuest = true;
				break;
			}
		}
		return isUserGuest;
	}

	public void setUserAdmin(boolean isUserAdmin) {
		this.isUserAdmin = isUserAdmin;
	}

	public void setUserGuest(boolean isUserGuest) {
		this.isUserGuest = isUserGuest;
	}
}

Last we will update our jsfspring-sec-bean-config.xml to add our managed bean to Spring configuration.

jsfspring-sec-bean-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:sec="http://www.springframework.org/schema/security"
	xsi:schemaLocation="
	   http://www.springframework.org/schema/beans
	   http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
       http://www.springframework.org/schema/security
	   http://www.springframework.org/schema/security/spring-security-3.1.xsd"
	   >
       
	<beans:bean id="navigator" name="navigator" class="com.mumz.jsfspringsec.beans.Navigator" scope="session">
	</beans:bean>
	
	<beans:bean id="loginBean" name="loginBean" class="com.mumz.jsfspringsec.beans.LoginBean" scope="prototype">
		<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
		<beans:property name="rememberMeServices" ref="rememberMeServices"></beans:property>
		<beans:property name="userDetailsService" ref="customjdbcUserService"></beans:property>
	</beans:bean>
	
	<beans:bean id="securityBean" class="com.mumz.jsfspringsec.beans.SecurityHolderBean" scope="session">
	</beans:bean>
	
	<beans:bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	 	<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<beans:property name="url" value="jdbc:mysql://localhost:3306/jsf-spring-security" />
		<beans:property name="username" value="root" />
		<beans:property name="password" value="root" />
   </beans:bean>
   
   <beans:bean id="customjdbcUserService" class="com.mumz.jsfspringsec.dao.CustomJDBCDaoImpl">
   		<beans:property name="dataSource" ref="dataSource"/>
		<beans:property name="enableAuthorities" value="false"/>
		<beans:property name="enableGroups" value="true"></beans:property>
		<beans:property name="usersByUsernameQuery">
			<beans:value>SELECT JSF_SPRING_SEC_USERS_USERNAME, JSF_SPRING_SEC_USERS_PASSWORD, JSF_SPRING_SEC_USERS_ENABLED FROM JSF_SPRING_SEC_USERS WHERE JSF_SPRING_SEC_USERS_USERNAME = ?</beans:value>
		</beans:property>
		<beans:property name="authoritiesByUsernameQuery">
			<beans:value>
				 SELECT JSF_SPRING_SEC_ROLES_USERNAME,JSF_SPRING_SEC_ROLES_ROLE_NAME from JSF_SPRING_SEC_ROLES where JSF_SPRING_SEC_ROLES_USERNAME = ?
			</beans:value>
		</beans:property>
		<beans:property name="groupAuthoritiesByUsernameQuery">
			<beans:value>
				SELECT 
						GROUPDTLS.JSF_SPRING_GROUPS_GROUP_ID, 
						GROUPDTLS.JSF_SPRING_GROUPS_GROUP_NAME, 
						GROUPPERMISSION.JSF_SPRING_SEC_GROUP_AUTHORITIES_AUTHORITY 
				FROM 
						JSF_SPRING_GROUPS GROUPDTLS, 
						JSF_SPRING_SEC_GROUP_AUTHORITIES GROUPPERMISSION, 
						JSF_SPRING_SEC_GROUP_MEMBERS GROUPMEMBERS, 
						JSF_SPRING_SEC_USERS USERS 
				WHERE 
						USERS.JSF_SPRING_SEC_USERS_USERNAME = ? AND 
						GROUPMEMBERS.JSF_SPRING_SEC_GROUP_MEMBERS_USER_ID = USERS.PK_JSF_SPRING_SEC_USERS AND 
						GROUPMEMBERS.JSF_SPRING_SEC_GROUP_MEMBERS_GROUP_ID = GROUPDTLS.JSF_SPRING_GROUPS_GROUP_ID AND 
						GROUPPERMISSION.JSF_SPRING_SEC_GROUP_AUTHORITIES_GROUP_ID = GROUPDTLS.JSF_SPRING_GROUPS_GROUP_ID 
			</beans:value>
		</beans:property>
   </beans:bean>
   
	<beans:bean id="rememberMeServices"
		class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
		<beans:property name="key" value="jsfspring-sec" /> 
		<beans:property	name="userDetailsService" ref="customjdbcUserService" /> 
		<beans:property	name="alwaysRemember" value="true" /> 
		<beans:property	name="tokenValiditySeconds" value="60" /> 
	</beans:bean>
	
	<beans:bean id="rememberMeAuthenticationProvider" 
		class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
  		<beans:property name="key" value="jsfspring-sec"/>
	</beans:bean>
	
	<beans:bean id="rememberMeFilter" 
		class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
  		<beans:property name="rememberMeServices" ref="rememberMeServices"/>
  		<beans:property name="authenticationManager" ref="authenticationManager" />
	</beans:bean>
	
	<beans:bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder">
	</beans:bean>
	
	<beans:bean id="databasePasswordEncrypter" class="com.mumz.jsfspringsec.dao.security.DBPasswordEncrypterBean" init-method="encryptDBPassword" depends-on="dataSource">
		<beans:property name="passwordEncoder" ref="passwordEncoder"></beans:property>
		<beans:property name="dataSource" ref="dataSource"></beans:property>
		<beans:property name="selectQuery">
			<beans:value>SELECT JSF_SPRING_SEC_USERS_USERNAME, JSF_SPRING_SEC_USERS_PASSWORD, JSF_SPRING_SEC_USERS_ENCRYPTED FROM JSF_SPRING_SEC_USERS WHERE (JSF_SPRING_SEC_USERS_ENCRYPTED='' || JSF_SPRING_SEC_USERS_ENCRYPTED IS NULL)</beans:value>
		</beans:property>
		<beans:property name="updateQuery">
			<beans:value>UPDATE JSF_SPRING_SEC_USERS SET JSF_SPRING_SEC_USERS_PASSWORD = ?, JSF_SPRING_SEC_USERS_ENCRYPTED='YES' WHERE JSF_SPRING_SEC_USERS_USERNAME = ? </beans:value>
		</beans:property>
	</beans:bean>
</beans:beans>

All done, login as admin and guest and see the result in action.

One thought on “Spring Security 3.1 conditionally securing your web page with JSF 2.0

    Spyros Non Serviam said:
    January 17, 2014 at 6:53 PM

    Why am I getting a NullPointerException when I check the remember me button?
    Also I am getting an access denied when I try logout after I was logged in as Guest.
    Can you please help me fix them?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s