April 27th, 2009 by Lincoln Baxter III

Revisited – Acegi/Spring Security & JSF Login Page

A correction has been made to the post: http://ocpsoft.com/java/acegi-spring-security-jsf-login-page/, fixing an issue where FacesMessages were not being displayed on failed authentications. Because the example had initially used the @PostConstruct annotation to trigger a method to handle the error message, the handleError() method was being called before the actual authentication event had taken place, thus, the handleError() method was triggering before any BadCredentialsExceptions were stored in the Session. Instead of creating an error handling method in the LoginBean itself, instead attach a PhaseListener which will intercept failed logins, and add the new FacesMessage before the RENDER_RESPONSE phase.

LoginErrorPhaseListener

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
 
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ui.AbstractProcessingFilter;
 
impot util.FacesUtils;
 
public class LoginErrorPhaseListener implements PhaseListener
{
    private static final long serialVersionUID = -1216620620302322995L;
 
    @Override
    public void beforePhase(final PhaseEvent arg0)
    {
        Exception e = (Exception) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(
                AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
 
        if (e instanceof BadCredentialsException)
        {
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(
                    AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY, null);
            FacesUtils.addErrorMessage("Username or password not valid.");
        }
    }
 
    @Override
    public void afterPhase(final PhaseEvent arg0)
    {}
 
    @Override
    public PhaseId getPhaseId()
    {
        return PhaseId.RENDER_RESPONSE;
    }
 
}

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xi="http://www.w3.org/2001/XInclude"
	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_1_2.xsd">
	<lifecycle>
		<phase-listener>login.LoginErrorPhaseListener</phase-listener>
	</lifecycle>
</faces-config>

Happy developing!


Lincoln Baxter, III

About the author:

Lincoln Baxter, III is the Chief Editor of Red Hat Developers, and has worked extensively on JBoss open-source projects; most notably as creator & project lead of JBoss Forge, author of Errai UI, and Project Lead of JBoss Windup. This content represents his personal opinions, not those of his employer.

He is a founder of OCPsoft, the author of PrettyFaces and Rewrite, the leading URL-rewriting extensions for Servlet, Java EE, and Java web frameworks; he is also the author of PrettyTime, social-style date and timestamp formatting for Java. When he is not swimming, running, or playing competitive Magic: The Gathering, Lincoln is focused on promoting open-source software and making technology more accessible for everyone.

Posted in JSF, Spring

Leave a Comment




Please note: In order to submit code or special characters, wrap it in

[code lang="xml"][/code]
(for your language) - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.