I’m using spring security 3 in my jsf2 web app.
How can I show a bad credential message in my login form without appending a get param ?login_error to the authenticated-fail-login-page?
I’ve tried using a phase listener like this tutorial says:
http://tutorials.slackspace.de/tutorial/Custom-login-page-with-JSF-and-Spring-Security-3
But it doesn’t work.
Neither with a preRenderView listener.
And neither checking the spring security last exception for rendering the message.
Any ideas?
UPDATE:
My login page:
<f:metadata>
<f:viewParam name="error" value="#{autenticacionController.error}" />
<f:event listener="#{autenticacionController.comprobarAuthException}" type="preRenderView" />
</f:metadata>
<h:messages globalOnly="true" layout="table" />
<h:form id="formLogin" prependId="false">
<h:outputLabel for="j_username" value="Usuario:" />
<h:inputText id="j_username" value="#{autenticacionController.administrador.login}" />
<h:outputLabel for="j_password" value="Contraseña:" />
<h:inputSecret id="j_password" value="#{autenticacionController.administrador.password}" />
<h:commandButton value="Entrar" action="#{autenticacionController.loginAction}" />
<h:commandButton value="Cancelar" immediate="true" action="#{autenticacionController.cancelarAction}" />
</h:form>
My managed bean:
@ManagedBean(name="autenticacionController")
@RequestScoped
public class AutenticacionController extends BaseController {
//entidad "administrador" contra el que validar los campos del form login
private Administrador administrador = new Administrador();
//propiedad de spring-security (true si el usuario no es anónimo)
@SuppressWarnings("unused")
private boolean autenticado;
//propiedad para guardar el param GET si hubo fallo en la autenticación de SS
private int error;
//Constructor vacío del Backing Bean controlador
public AutenticacionController() {
log.info("Creación del backing bean AutenticacionController");
}
@PostConstruct
public void init() {
//inicializar atributos del backing bean
log.info("PostConstruct del backing bean BarcoController");
}
//Getters y setters de atributos del backing bean
public Administrador getAdministrador() {
return administrador;
}
public void setAdministrador(Administrador administrador) {
this.administrador = administrador;
}
public boolean isAutenticado() {
Authentication autenticacion = SecurityContextHolder.getContext().getAuthentication();
boolean resultado = (autenticacion != null) &&
!(autenticacion instanceof AnonymousAuthenticationToken) &&
autenticacion.isAuthenticated();
return resultado;
}
public int getError() {
return error;
}
public void setError(int error) {
this.error = error;
}
//MÉTODO LISTENER del evento preRenderView en la página login.
//Para comprobar si la autenticación de Spring Security falló (error=1).
//En ese caso muestra el error con un faces message.
public void comprobarAuthException (ComponentSystemEvent event){
log.info("listener comprobarAuth");
if (error==1) {
String msj = "";
Exception e = (Exception) UtilJsf.getParamSessionMap(WebAttributes.AUTHENTICATION_EXCEPTION);
log.info("SSexception = "+((e==null)?"null":e.getMessage()));
if (e != null) {
String ultimoUsuario = (String) UtilJsf.getParamSessionMap(WebAttributes.LAST_USERNAME);
log.info("SS last_username = "+ultimoUsuario);
administrador.setLogin(ultimoUsuario);
if (e instanceof BadCredentialsException) {
msj = UtilJsf.getMsjProperties("msjsInfo", "UsuPwdIncorrectos");
} else {
msj = UtilJsf.getMsjProperties("msjsInfo", "ErrorAutenticacion");
}
UtilJsf.mostrarFacesMsjGlobal(msj);
}
}
return;
}
/* ******************************* */
/* Métodos "action" del form login */
/* ******************************* */
// EVENTO: Pulsar el botón "entrar" del form login
// Reenviar(FORWARD) la petición a la URL "/j_spring_security_check" para autenticarse
// También se debe configurar el filtro de spring-security para que procese forwards
public void loginAction () {
try {
FacesContext.getCurrentInstance().getExternalContext().dispatch("/j_spring_security_check");
} catch (IOException e) {
}
}
// EVENTO: Pulsar el boton "cancelar" en el form login
// No hacer nada --> Ir a la pantalla de inicio de la aplic
public String cancelarAction () {
return "/inicio";
}
}
In my configuration of Spring Security I have:
authentication-failure-url="/faces/paginas/autenticacion/login.xhtml?error=1"
If I remove the error param, and the viewParam from the login page, and in the listener I just check for the Spring Security exception, it doesn’t work.
Thanks for the logout, my approach for it is similar, I have the following link for it:
<h:outputLink value="#{request.contextPath}/j_spring_security_logout" rendered="#{autenticacionController.autenticado}">Cerrar sesión (Administrador)</h:outputLink>
I tend to use an
<f:event>on preRenderView that will update the messages component on my form. This is how I did it.And then in my LoginBean managed bean, I forward the request onto the Spring Security servlet as so, and update the messages. You will notice that I also have code for a logout action if you are interested in seeing how I approached that problem as well.
EDIT:
I think I better understand your problem now. I remember that I had trouble getting this to work too, so basically I had to write my own class that implements
AuthenticationFailureHandlerand properly implement the method:Basically you see that I am instantiating an exception and setting it as a session attribute so that later in my managed bean it can be retrieved and converted into a
FacesMessage.You will also have to declare this
AuthenticationFailureHandleras a custom handler for authentication failure events in your Spring Security configuration file (Note that I am also showing that I do the same thing for an authentication success handler, but you may or may not want to do that as well).