In the previous post we saw how to integrate Spring Security 3.1 and JSF 2.0.
To access the secure page Spring Security Provided us with a default login page.
In this post we will see how can we have a custom login page and use Spring Security for authentication.
First under pages folder create a new folder and name it common. Create a new xhtml under common folder and name it login.xhtml
.
login.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> <div align="right" style=""> <h:form id="loginFormId" prependId="false"> <div id="loginFieldsPnlId"> <div id="loginFieldUsrContId"> <h:outputText id="outTxtUserNameId" value="Username:" name="outTxtUserNameNm"></h:outputText> <h:inputText id="userName" required="true" value="#{loginMgmtBean.userName}" requiredMessage="Please enter username"></h:inputText> <h:outputLabel id="outLblUserNameId" for="userName" name="outLblUserNameNm"></h:outputLabel> </div> <div id="loginFieldPassContId"> <h:outputText id="outTxtPasswordId" value="Password:" name="outTxtPasswordNm"></h:outputText> <h:inputSecret id="password" required="true" value="#{loginMgmtBean.password}" requiredMessage="Please enter password" name="inTxtPasswordNm"></h:inputSecret> <h:outputLabel id="outLblPasswordId" for="password" name="outLblPasswordNm"></h:outputLabel> </div> </div> <div id="loginBtnPanelId"> <h:commandButton id="btnLoginId" value="Login" action="#{loginMgmtBean.login}" styleClass="loginPanelBtn"></h:commandButton> <h:commandButton id="btnCancelId" value="Cancel" action="#{loginMgmtBean.cancel}" styleClass="loginPanelBtn" immediate="true" update="loginFormId"></h:commandButton> </div> </h:form> </div> <div> <h:messages></h:messages> </div> </h:body> </html>
Second lets write our LoginBean
.
LoginBean
package com.mumz.jsfspringsec.beans; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.RequestScoped; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; /** * The Class LoginBean. */ @ManagedBean(name="loginMgmtBean") @RequestScoped public class LoginBean { /** The user name. */ private String userName = null; /** The password. */ private String password = null; @ManagedProperty(value="#{authenticationManager}") private AuthenticationManager authenticationManager = null; /** * Login. * * @return the string */ public String login() { try { Authentication request = new UsernamePasswordAuthenticationToken(this.getUserName(), this.getPassword()); Authentication result = authenticationManager.authenticate(request); SecurityContextHolder.getContext().setAuthentication(result); } catch (AuthenticationException e) { e.printStackTrace(); } return "secured"; } /** * Cancel. * * @return the string */ public String cancel() { return null; } public AuthenticationManager getAuthenticationManager() { return authenticationManager; } public void setAuthenticationManager(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } /** * Gets the user name. * * @return the user name */ public String getUserName() { return userName; } /** * Sets the user name. * * @param userName * the new user name */ public void setUserName(String userName) { this.userName = userName; } /** * Gets the password. * * @return the password */ public String getPassword() { return password; } /** * Sets the password. * * @param password * the new password */ public void setPassword(String password) { this.password = password; } }
Third we have to configure our bean in spring bean definition, since we are not using annotation based injection.
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:bean> </beans:beans>
Fourth we need to specify our login page to Spring Security, for this we need to change our jsfspring-sec-security-config.xml
.
jsfspring-sec-security-config.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" 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"> <sec:http auto-config="true" use-expressions="true"> <sec:intercept-url pattern="/pages/secure/**" access="hasRole('ROLE_USER')" /> <sec:intercept-url pattern="/pages/unsecure/**" access="permitAll"/> <sec:intercept-url pattern="/**" access="permitAll"/> <sec:form-login login-page="/pages/common/login.jsf"/> </sec:http> <sec:authentication-manager alias="authenticationManager"> <sec:authentication-provider> <sec:user-service> <sec:user authorities="ROLE_USER" name="admin" password="admin" /> </sec:user-service> </sec:authentication-provider> </sec:authentication-manager> </beans:beans>
Last portion is that we have to modify our faces-config.xml
since we are not depending on implicit navigation.
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> <!-- Enable Spring --> <application> <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> </application> <!-- Simple Navigation Rule --> <!-- If user keys in ToSecure, move to /pages/secure/secured.xhtml--> <!-- Else If user keys in ToUnSecure, move to /pages/unsecure/unsecured.xhtml--> <navigation-rule> <display-name>pages/home/home.xhtml</display-name> <from-view-id>/pages/home/home.xhtml</from-view-id> <navigation-case> <from-action>#{navigator.navigateTo}</from-action> <from-outcome>Secured</from-outcome> <to-view-id>/pages/secure/secured.xhtml</to-view-id> <redirect></redirect> </navigation-case> </navigation-rule> <navigation-rule> <display-name>pages/home/home.xhtml</display-name> <from-view-id>/pages/home/home.xhtml</from-view-id> <navigation-case> <from-action>#{navigator.navigateTo}</from-action> <from-outcome>UnSecured</from-outcome> <to-view-id>/pages/unsecure/unsecured.xhtml</to-view-id> <redirect></redirect> </navigation-case> </navigation-rule> <navigation-rule> <display-name>pages/secure/secured.xhtml</display-name> <from-view-id>/pages/secure/secured.xhtml</from-view-id> <navigation-case> <from-action>#{loginMgmtBean.logout}</from-action> <from-outcome>loggedout</from-outcome> <to-view-id>/pages/home/home.xhtml</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <display-name>pages/common/login.xhtml</display-name> <from-view-id>/pages/common/login.xhtml</from-view-id> <navigation-case> <from-action>#{loginMgmtBean.login}</from-action> <from-outcome>Secured</from-outcome> <to-view-id>/pages/secure/secured.xhtml</to-view-id> </navigation-case> </navigation-rule> </faces-config>
If you have followed every step as detailed in the earlier post and this one your project structure should look like below:
That’s it, deploy and run, we have successfully integrated Spring Security with custom login page using JSF 2.0.
I have some problem – at the Authentication result = authenticationManager.authenticate(request) causes the NullPointer assignment error
what is wrong?
Can you check if your authentication manager dependency is injected ?
You may need to use @Resource instead of @ManagedProperty
Even @ManagedProperty works well
Hi there
I have you solved your problem. I am facing the exact same one.
I am novice in this field. Any help will be appreciated
I had the same problem because I forget the alias=”authenticationManager” on the jsfspring-sec-security-config.xml
I’m wonder how to use spring security redirection (defined in security-config.xml, form-login) after login, logout, session expire etc. – here you use navigation-rules which is not a perfect way e.g. someone bookmarked page which is restricted and in your case it will always go to the same start page after logging in.
You can try using a concept called as fully authenticated where in you decide if user is authenticated and then do authentication first and then let user navigate to the original URL , I will post a sample too.
They provide the source code, to see all the complete configurations. I am studying the security spring.
Can you provide source code of this project pls?
Seems like u truly fully understand a lot related to this particular subject matter and that demonstrates thru this excellent article, termed “Spring Security 3.
1 and JSF 2.0 Custom Form Java Holic”.
Thanks a lot ,Chantal
Nice topic, but I have a problem! The program is constantly
displays the message “Bad credentials”. I added a logging into
setUserName() method of LoginBean. As I see it, the problem is that
the bean is created twice. And in the latter case, the userName
sets as NULL. DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml
reached end of additional filter chain; proceeding with original
chain DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
org.springframework.security.web.access.ExceptionTranslationFilter
– Chain processed normally DEBUG:
org.springframework.security.web.context.HttpSessionSecurityContextRepository
– SecurityContext is empty or contents are anonymous – context will
not be stored in HttpSession. DEBUG:
org.springframework.security.web.context.SecurityContextPersistenceFilter
– SecurityContextHolder now cleared, as request processing
completed DEBUG: org.springframework.security.web.FilterChainProxy
– /login.xhtml at position 1 of 10 in additional filter chain;
firing Filter: ‘SecurityContextPersistenceFilter’ DEBUG:
org.springframework.security.web.context.HttpSessionSecurityContextRepository
– HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG:
org.springframework.security.web.context.HttpSessionSecurityContextRepository
– No SecurityContext was available from the HttpSession:
org.apache.catalina.session.StandardSessionFacade@1a81ed21. A new
one will be created. DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 2 of 10 in additional filter chain; firing Filter:
‘LogoutFilter’ DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 3 of 10 in additional filter chain; firing Filter:
‘UsernamePasswordAuthenticationFilter’ DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 4 of 10 in additional filter chain; firing Filter:
‘BasicAuthenticationFilter’ DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 5 of 10 in additional filter chain; firing Filter:
‘RequestCacheAwareFilter’ DEBUG:
org.springframework.security.web.savedrequest.DefaultSavedRequest –
pathInfo: both null (property equals) DEBUG:
org.springframework.security.web.savedrequest.DefaultSavedRequest –
queryString: both null (property equals) DEBUG:
org.springframework.security.web.savedrequest.DefaultSavedRequest –
requestURI: arg1=/; arg2=/login.xhtml (property not equals) DEBUG:
org.springframework.security.web.savedrequest.HttpSessionRequestCache
– saved request doesn’t match DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 6 of 10 in additional filter chain; firing Filter:
‘SecurityContextHolderAwareRequestFilter’ DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 7 of 10 in additional filter chain; firing Filter:
‘AnonymousAuthenticationFilter’ DEBUG:
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
– Populated SecurityContextHolder with anonymous token:
‘org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc:
Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated:
true; Details:
org.springframework.security.web.authentication.WebAuthenticationDetails@b364:
RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId:
52197670D90C7A1A2097082E4C48EAB8; Granted Authorities:
ROLE_ANONYMOUS’ DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 8 of 10 in additional filter chain; firing Filter:
‘SessionManagementFilter’ DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 9 of 10 in additional filter chain; firing Filter:
‘ExceptionTranslationFilter’ DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml at
position 10 of 10 in additional filter chain; firing Filter:
‘FilterSecurityInterceptor’ DEBUG:
org.springframework.security.web.util.AntPathRequestMatcher –
Checking match of request : ‘/login.xhtml’; against ‘/pages/**’
DEBUG:
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
– Secure object: FilterInvocation: URL: /login.xhtml; Attributes:
[permitAll] DEBUG:
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
– Previously Authenticated:
org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc:
Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated:
true; Details:
org.springframework.security.web.authentication.WebAuthenticationDetails@b364:
RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId:
52197670D90C7A1A2097082E4C48EAB8; Granted Authorities:
ROLE_ANONYMOUS DEBUG:
org.springframework.security.access.vote.AffirmativeBased – Voter:
org.springframework.security.web.access.expression.WebExpressionVoter@6a8c1b5a,
returned: 1 DEBUG:
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
– Authorization successful DEBUG:
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
– RunAsManager did not change Authentication object DEBUG:
org.springframework.security.web.FilterChainProxy – /login.xhtml
reached end of additional filter chain; proceeding with original
chain DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
com.exadel.library.beans.Login – SET LOGIN: admin DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Creating instance of bean ‘login’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Returning cached instance of singleton bean
‘org.springframework.security.authenticationManager’ DEBUG:
org.springframework.beans.factory.support.DefaultListableBeanFactory
– Finished creating instance of bean ‘login’ DEBUG:
com.exadel.library.beans.Login – LOGIN: null DEBUG:
org.springframework.security.authentication.ProviderManager –
Authentication attempt using
org.springframework.security.authentication.dao.DaoAuthenticationProvider
DEBUG:
org.springframework.security.authentication.dao.DaoAuthenticationProvider
– User ‘NONE_PROVIDED’ not found трав 10, 2013 7:11:34 PM
com.sun.faces.lifecycle.InvokeApplicationPhase execute WARNING:
#{login.login}:
org.springframework.security.authentication.BadCredentialsException:
Bad credentials
very good thx 😀
good afternoon friends, I could help with this error: An
Error Occurred: userName – Stack Trace
java.lang.IllegalArgumentException: userName at
javax.faces.component.UIComponentBase.validateId(UIComponentBase.java:551)
… Index.jsp Thanks
index.jsp
response.sendRedirect(“pages/common/login.jsf”);
thank you . this works great.
i have a issue, this code works for me but, when i use the
jsf taglib , i realize that the user role it’s not stored into the
session because the parts of the view that are hidden or shown
depending of user privileges, only works at request scope. For
example when the web page is retrieve/refreshed again or the user
navigate to other page the buttons that are shown only to admin
role, didn’t show even if the user has been logged as
administrator, is like the user was navigating as
anonymous.
the tag lib that i use is sec:authorize like this:
sec:authorize ifAllGranted=’ROLE_ADMIN’
You can save the granted authority at session for later use