Custom Loginpage with SpringSecurity 3, JSF2 and Facelets

These days I tried to integrate a custom login page into my Web Application. I found a lot of hints in the Web
using a a plain form tag for the Login page but nothing was working and I always got a errors like “No navigation case match for viewId action j_spring_security_check and outcome…” I didn’t get it work by using the j_security_check mechanism, therefore I used a custom bean and controller.

Here is the solution:

my web.xml:


       <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
            /WEB-INF/applicationContext.xml,
            /WEB-INF/applicationsContext-Security.xml
        </param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
		<dispatcher>FORWARD</dispatcher>
   		<dispatcher>REQUEST</dispatcher>
	</filter-mapping>

the applicationContext.xml:


        <bean scope="session" id="loginBean" class="com.XXX.security.LoginBean">
		<aop:scoped-proxy />
	</bean>
	<bean scope="singleton" id="loginController"
		class="com.XXX.security.LoginController">
		<property name="loginBean" ref="loginBean" />
		<property name="authenticationManager" ref="authenticationManager" />
	</bean>

the applicationContext-Security.xml:


	<sec:http auto-config='true' use-expressions="true">

		<sec:intercept-url pattern="/xhtml/loggedout.xhtml" access="permitAll" />
		<sec:intercept-url pattern="/xhtml/timeout.xhtml" access="permitAll" />
		<sec:intercept-url pattern="/xhtml/login.xhtml" access="permitAll" />
		<sec:intercept-url pattern="/xhtml/**" access="isAuthenticated()" />
			
		<sec:form-login login-page="/xhtml/login.xhtml"  />
			
	</sec:http>

	<!-- AuthenticationManager - add your User-Service-->
	<authentication-manager alias="authenticationManager">
		<authentication-provider user-service-ref="XXXXXX">
			<password-encoder hash="md5" />
		</authentication-provider>
	</authentication-manager>

the Form: /xhtml/login.xhtml

		
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:my="http://www.XXXX.com/my/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:security="http://www.springframework.org/security/facelets/tags">


<my:myMainTemplate title="Login" class="mainContent" >
      
       <h:form id="loginForm" prependId="false">
        	
            <h:panelGrid columns="2">  
                <h:outputLabel for="j_username" value="User: " />  
                <h:inputText id="j_username" value="#{loginBean.userName}" required="true" requiredMessage="Username !"/>  
                <h:outputLabel for="j_password" value="Password: " />  
                <h:inputSecret id="j_password" value="#{loginBean.password}" required="true" requiredMessage="Passwort !"/>  
				<h:commandButton id="submitButton" value="Start" action="#{loginController.login}" />  
            </h:panelGrid>  
        </h:form>  
</my:myMainTemplate>
	
</html>

my beans – loginBean.java:


package com.XXXX.security;

import java.io.Serializable;
public class LoginBean  implements Serializable{

	private static final long serialVersionUID = 6175255537226165236L;

	private String userName;
	private String password;
	
	
	public void reset(){
		userName = "";
		password = "";
	}
		
	
... getter/setter...

}

and loginController.java


package com.XXXX.security;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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;


public class LoginController {
	
	private static final Log LOG = LogFactory.getLog(LoginController.class);

        // beans used by this controller, injected by spring
	private LoginBean loginBean;
	private AuthenticationManager authenticationManager;
	
        /**
	 * the login action called by the view
	 * @return
	 */
	public String login() {
		try{
		LOG.info("Login started for User with Name: "+getLoginBean().getUserName());
		
		 // check if userdata is given 
		 if (getLoginBean().getUserName() == null || getLoginBean().getPassword() == null) {
	            FacesMessage facesMsg = new FacesMessage(
	            FacesMessage.SEVERITY_ERROR, "Error", "login.failed" );
	            FacesContext.getCurrentInstance().addMessage(null, facesMsg);
	            LOG.info("Login not started because userName or Password is empty: "+getLoginBean().getUserName());
	            return null;
	        }
	       
		 // authenticate afainst spring security
		 Authentication request = new UsernamePasswordAuthenticationToken(
				 getLoginBean().getUserName(), getLoginBean().getPassword());            
	            
	        Authentication result = authenticationManager.authenticate(request);
	        SecurityContextHolder.getContext().setAuthentication(result);
	 
	    } catch (AuthenticationException e) {
	    	LOG.info("Login failed: " + e.getMessage());
	        FacesMessage facesMsg = new FacesMessage(
	            FacesMessage.SEVERITY_ERROR, "Error", "login.failed") ;
	        FacesContext.getCurrentInstance().addMessage(null, facesMsg);
	            
	        return null;
	    }
	    return "success";
		
	}

	
	/**
	 * @return the loginBean
	 */
	public LoginBean getLoginBean() {
		return loginBean;
	}


	/**
	 * @param loginBean the loginBean to set
	 */
	public void setLoginBean(LoginBean loginBean) {
		this.loginBean = loginBean;
	}

	/**
	 * @return the authenticationManager
	 */
	public AuthenticationManager getAuthenticationManager() {
		return authenticationManager;
	}

	/**
	 * @param authenticationManager the authenticationManager to set
	 */
	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}
}

and Last but not least, add navigationRules to your
faces-config.xml:


<navigation-rule>
  <from-view-id>/xhtml/login.xhtml</from-view-id>
    <navigation-case>
      <from-outcome>success</from-outcome>
	 <to-view-id>/xhtml/main/main.xhtml</to-view-id>
   </navigation-case>
 </navigation-rule>

2 thoughts on “Custom Loginpage with SpringSecurity 3, JSF2 and Facelets

Leave a Reply

Your email address will not be published. Required fields are marked *

*