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.
- Use Spring Security tag lib
- 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.
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?