I am using spring security in my website, but when I used custom login form (JSF form), and user entered bad credentials, authentication-failure-url is not working and user is not forwarded to failed.xhtml, but index.xhtml is appeared
I don't know the reason, please help:
applicationContext.xml:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
<context:component-scan base-package="com.myspring" />
<context:annotation-config />
<!-- beans configuration -->
<beans:bean id="userBo" class="com.myspring.user.bo.impl.UserBoImpl" />
<!-- security configuration -->
<http auto-config="true">
<intercept-url pattern="/login.xhtml" access="permitAll" />
<intercept-url pattern="/index.xhtml" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/authenticated.xhtml" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/views/admin/**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login.xhtml" default-target-url="/authenticated.xhtml"
authentication-failure-url="/failed.xhtml" />
<logout invalidate-session="true" delete-cookies="true" logout-success-url="/"/>
<csrf disabled="true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="user1" password="user1Pass" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
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 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="#{loginController.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="#{loginController.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="#{loginController.login}" styleClass="loginPanelBtn"></h:commandButton>
<h:commandButton id="btnCancelId" value="Cancel"
action="#{loginController.cancel}" styleClass="loginPanelBtn"
immediate="true" update="loginFormId"></h:commandButton>
</div>
</h:form>
</div>
<div>
<h:messages></h:messages>
</div>
</h:body>
</html>
and this is the loginController with login method:
package com.myspring.controllers;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
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;
#ManagedBean
#SessionScoped
public class LoginController {
private String userName;
private String password;
#ManagedProperty(value="#{authenticationManager}")
private AuthenticationManager authenticationManager = null;
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 "failed";
}
return "success";
}
public String logout(){
SecurityContextHolder.clearContext();
return "loggedout";
}
public AuthenticationManager getAuthenticationManager() {
return authenticationManager;
}
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public String cancel()
{
return "";
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
also I will add project structure:
Due to the fact that you are using JSF you are basically bypassing the login (and logout) functionality provided by Spring Security. Your LoginController is basically replacing that, due to that your sec:login-form and sec:legato are pretty much useless.
The solution is simple don't use JSF, you can still use Facelets to render your page, but simply include a normal form tag which posts to /login instead of an h:form tag and you can remove your LoginController.
Note: If your application is not the root application (i.e. mapped to /) you need to include the /context-path into your URL. So instead of /login use /context-path/login.
<!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 style="">
<form id="loginFormId" method="post" action="/login">
<div id="loginFieldsPnlId">
<div id="loginFieldUsrContId">
<label>Username:<label>
<input type="text" id="username" name="username" />
</div>
<div id="loginFieldPassContId">
<label>Password:<label>
<input type="password" id="password" name="password" />
</div>
</div>
<div id="loginBtnPanelId">
<button>Login</button>
</div>
</form>
</div>
</h:body>
</html>
If you still want to use JSF and the LoginController then don't directly use the AuthenticationManager but forward the request to the /login URL that way Spring Security will take over after JSF has done the required validation.
Related
My problem is quite similar to this one (How can I do Spring Security authentication from within a JSF form), but I've tried that solution and the problem still occurs.
index.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!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">
<h:head>
<title>Info</title>
</h:head>
<h:body>
<h:form prependId="false">
<p>Usuario <h:inputText id="j_username" value="#{control.idUsuario}"/></p>
<p>Password <h:inputSecret id="j_password" value="#{control.password}"/></p>
<h:commandButton value="Entrar" action="#{control.login}" />
</h:form>
</h:body>
</html>
Control.java
#ManagedBean
#SessionScoped
public class Control implements Serializable {
private static final long serialVersionUID = 1L;
private String idUsuario;
private String password;
private UsuarioDAO usuarios;
private Usuario usuario;
public Control() {}
public String login() {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext extenalContext = facesContext.getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest)extenalContext.getRequest()).getRequestDispatcher("/j_spring_security_check");
try {
dispatcher.forward((ServletRequest)
extenalContext.getRequest(), (ServletResponse)extenalContext.getResponse());
} catch (ServletException | IOException e) {
e.printStackTrace();
}
facesContext.responseComplete();
return null;
}
public String getIdUsuario() {return idUsuario;}
public void setIdUsuario(String idUsuario) {this.idUsuario = idUsuario;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public Usuario getUsuario() {return usuario;}
public void setUsuario(Usuario usuario) {this.usuario = usuario;}
public UsuarioDAO getUsuarios() {return usuarios;}
public void setUsuarios(UsuarioDAO usuarios) {this.usuarios = usuarios;}
}
applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns= "http://www.springframework.org/schema/security"
xmlns:beans= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http>
<intercept-url pattern="/faces/ok.xhtml" access="ROLE_ADMIN"/>
<intercept-url pattern="/faces/ko.xhtml" access="ROLE_USER"/>
<form-login
login-page="/faces/index.xhtml"
default-target-url="/login_success"
authentication-failure-url="/faces/failLogin.xhtml"
username-parameter="j_username"
password-parameter="j_password" />
<port-mappings>
<port-mapping http="8080" https="8443" /> <!-- Tomcat -->
</port-mappings>
</http>
<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/BUsuariosSecurity" />
<beans:property name="username" value="root" />
<beans:property name="password" value="" />
</beans:bean>
<authentication-manager>
<authentication-provider>
<password-encoder hash="bcrypt" />
<jdbc-user-service data-source-ref="dataSource"
authorities-by-username-query="SELECT IdUsuario, Rol FROM TUsuarios WHERE IdUsuario = ?"
users-by-username-query="SELECT IdUsuario, PwUsuario, Habilitado FROM TUsuarios WHERE IdUsuario = ?" />
</authentication-provider>
</authentication-manager>
</beans:beans>
When I try to login with a valid user, it sends me to failLogin.xhtml
My DataBase: https://gyazo.com/3997921c1c9bc2787a25c9b0ff904f4b
What's my mistake?
Any help please?
The problem was that the passwords in the DB were not well encrypted, I tried to encrypt them with another website and I went all.
I am developing a web application with consist of the following
Rest Web service (Spring 4) | JWT token authentication
Web pages (login.xhtml, index.xhtml) (JSF, primeface) | crsf
The problem I am facing now is weird.
If my spring security is enabled, any access to rest web services need to be authenticated before the access is granted. I am using JWT token authentication for my login. However my web pages will fail after I login. i.e my login is successful but any action after this, results in an invalid crsf token or null request error.
If my spring security is disabled, my rest services does not need to be authenticated to access the web services but my web pages works perfectly fine.
How do I integrate both solutions together?
All my web pages already included the following:
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
ApplicationContext-Security.xml:
<http pattern="/auth/login" security="none" />
<http pattern="/login.xhtml" security="none" />
<http pattern="/index.xhtml" security="none" />
<http pattern="/javax.faces.resource/**" security="none" />
<http pattern="/RES_NOT_FOUND" security="none" />
<http pattern="/img/**" security="none" />
<sec:http auto-config="false" create-session="stateless" entry-point-ref="customEntryPoint" use-expressions="true">
<intercept-url pattern="/admin/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<intercept-url pattern="/audit/**" access="hasRole('ADMIN')" />
<intercept-url pattern="/request/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<intercept-url pattern="/reporting/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<sec:custom-filter ref="customAuthenticationFilter"
before="PRE_AUTH_FILTER" />
<!-- <sec:csrf disabled="true" /> -->
</sec:http>
As you can see i included the <http pattern="/index.xhtml" security="none" /> so that i can allow what feature that is in my index.xhtml to work. But now i can access the index.xhtml directly.
Can someone advise on how to fix this?
===== EDITED. MORE INFO =====
To add on, this is my login page and controller.
login.xhtml:
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>BTS Upload</title>
<h:outputStylesheet library="css" name="bootstrap.min.css" />
<h:outputScript library="js" name="jquery-1.11.1.min.js" />
<h:outputScript library="js" name="bootstrap.min.js" />
</h:head>
<!-- Css here -->
<h:body>
<font color="red"> <h:outputLabel
value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
</font>
<div class="container">
<div class="row">
<div class="col-sm-6 col-md-4 col-md-offset-4">
<h1 class="text-center login-title">Sign in</h1>
<div class="account-wall">
<h:graphicImage class="profile-img" library="images"
name="photo.png" />
<h:form class="form-signin">
<h:outputLabel value="Enter UserName:" />
<h:inputText id="username" value="#{loginAction.username}"
required="true" requiredMessage="Please enter your username"
autofocus="true" class="form-control"></h:inputText>
<h:message for="username" id="msg"
errorStyle="color:red; display:block" />
<br />
<h:outputLabel value="Enter Password:" />
<h:inputSecret id="password" value="#{loginAction.pwd}"
required="true" requiredMessage="Please enter your password"
class="form-control"></h:inputSecret>
<h:message for="password" id="msg1"
errorStyle="color:red; display:block" />
<br />
<br />
<h:commandButton class="btn btn-lg btn-primary btn-block"
action="#{loginAction.login}"
value="Login"></h:commandButton>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</h:form>
</div>
</div>
</div>
</div>
</h:body>
</html>
Controller:
#ManagedBean(name="loginAction")
#SessionScoped
public class LoginAction extends BaseAction implements Serializable
{
private static final long serialVersionUID = 1094801825228386363L;
private String pwd;
private String msg;
private String username;
#ManagedProperty("#{accessControlService}")
private AccessControlService accessControlService;
public String getPwd()
{
return pwd;
}
public void setPwd(String pwd)
{
this.pwd = pwd;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public String getUsername()
{
return username;
}
public void setUsername(String user)
{
this.username = user;
}
//validate login and redirect to the specified website.
public String login()
{
System.out.println();
System.out.println("Call Log in");
if (username.equals("") || pwd.equals(""))
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Password", "Please enter correct username and Password"));
return "login";
}
boolean valid = false;
String token = "";
try
{
token = accessControlService.isAuthorizedUser(username, pwd, PropertiesUtil.LoginType.WEB_BTS.ordinal(), this.getRequest());
}
catch (Exception e)
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Error", e.getLocalizedMessage()));
}
if(token.contains(PropertiesUtil.TOKEN_HEADER))
{
valid = true;
}
if (valid)
{
HttpSession session = this.getSession();
session.setAttribute("username", username);
session.setAttribute("token", token);
return "admin";
}
else
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Password", "Please enter correct username and Password"));
return "login";
}
}
// logout event, invalidate session
public String logout()
{
System.out.println("**********************************************************");
try
{
accessControlService.logout(getUsername(), PropertiesUtil.LoginType.WEB_BTS.ordinal(), getRequest());
HttpSession session = this.getSession();
session.invalidate();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return "login";
}
public AccessControlService getAccessControlService()
{
return accessControlService;
}
public void setAccessControlService(AccessControlService accessControlService)
{
this.accessControlService = accessControlService;
}
}
Firstly you must be sure that you have spring security 4 compatible *-security.xml and *-servlet.xml look at this
From part of security.xml that you posted I can see that you don't have form-login tag. It should be something like this
<security:form-login default-target-url="/index"
login-page="/login"
username-parameter="j_username"
password-parameter="j_password"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/login?login_error=1"/>
Your login jsp needs to have action j_spring_security_check to trigger filter chain:
<form action="<c:url value="/j_spring_security_check"/>" method="POST"> ...
You don't need csrf hidden input because spring automatically injects it into request header and parameters (if you don't disable it) as of spring 4
I m using primefaces and spring security
the method below inside my backing bean works well.It invokes user details service and authenticates or rejects login attempts.
My problem is with redirection. What is the proper way of redirecting a user to the desired page after auth? Currently I can see that the user is authenticated but still the login form is displayed.
public String login(){
try{
Authentication request = new UsernamePasswordAuthenticationToken(this.getUsername(), this.getPassword());
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
}
catch(Exception e){
e.printStackTrace();
return "incorrect";
}
return "correct";
}
<http auto-config="true">
<intercept-url pattern="/web/*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page="/web/login.xhtml"
default-target-url="/main.xhtml"
always-use-default-target="true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="kullaniciDetayServisi" />
</authentication-manager>
</beans:beans>
<!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="center" 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="#{loginBean.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="#{loginBean.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="#{loginBean.login}" ajax="false"></h:commandButton>
<h:commandButton id="btnCancelId" value="Cancel" action="#{loginBean.cancel}" immediate="true" update="loginFormId" ajax="false"></h:commandButton>
</div>
</h:form>
</div>
<div>
<h:messages></h:messages>
</div>
</h:body>
</html>
Looks like you forgot to map the correct and incorrect path inside controller methods.
If I want to redirect than I might use
return "redirect:/correct/" + user.getUserName();
And handle this new request in a new controller method that map this new request.
or
return "redirect:/incorrect"
Return something like that from the controller method that handle login request.
or
Using proper navigation rules in /web/WEB-INF/faces-config.xml for JSF like this:
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-outcome>incorrect</from-outcome>
<to-view-id>/failure.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>correct</from-outcome>
<to-view-id>/sucess.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Plop,
Spring version: 4.0.2.RELEASE
Spring Security Version: 4.0.2.RELEASE
DB PostgreSQL Version: 9.4-1202-jdbc42
I'm trying to acces to my home page with a secure connection using spring-security.
When I try to connect with login/password I've got this error:
WARNING: No mapping found for HTTP request with URI
[/web-client-smarteo/j_spring_security_check] in DispatcherServlet
with name 'servlet-dispatcher'
When I submit with log/pass it's get me to:
http://localhost:8080/web-client-smarteo/j_spring_security_check?username=alfacamp&password=alfacam&submit=&%24%7B_csrf.parameterName%7D=%24%7B_csrf.token%7D
And show
HTTP 404 The requested ressource is unvailable
Details of my sample:
UPDATE
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/dispatcher-servlet.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<!-- Spring Security Filter -->
<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>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>servlet-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>servlet-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
dispatcher-servlet.xml
<mvc:annotation-driven />
<context:component-scan base-package="com.smarteo.laugustoni.*" />
[...]
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/vues/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
spring-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/welcome**" access="hasRole('CUSTOMER')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/connection"
default-target-url="/welcome"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/connection?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/connection?logout" />
<!-- enable csrf protection -->
<csrf/>
</http>
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query=
"select usr_name,usr_password from smarteo_user where usr_name=?"
authorities-by-username-query=
"select usr_name, usr_role from smarteo_user where usr_name =? " />
</authentication-provider>
</authentication-manager>
ConnectionController.java
package com.smarteo.laugustoni.controller;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.smarteo.laugustoni.services.User.IServiceUser;
#Controller
public class ConnectionController {
#RequestMapping(value={"/", "/welcome**"}, method = RequestMethod.GET)
public String defaultPage(ModelMap pModel)
{
return "connection";
}
#RequestMapping(value="/connexion", method = RequestMethod.GET)
public ModelAndView connection(
#RequestParam(value="error", required = false) String error,
#RequestParam(value = "logout", required = false)String logout)
{
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("connection");
return model;
}
Thanks for helping.
EDIT 1
connection.jsp
<%#page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%#taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%#page session="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<form name="loginForm" action="/j_spring_security_check">
<!-- TextBox Section -->
<div class="input-group visible">
<spring:message code="connection.label.account"/>
<input name="username" path="username" placeholder="Nom du compte" type="text" class="form-control" aria-describedby="basic-addon1"/>
<div class="alert alert-danger" role="alert"><form:errors path="username" cssclass="error"/></div>
</div><br />
<div class="input-group visible">
<spring:message code="connection.label.password"/>
<input name="password" path="password" placeholder="Mot de passe" type="password" class="form-control" aria-describedby="basic-addon1"/><br />
<div class="alert alert-danger" role="alert"><form:errors path="password" cssclass="error"/></div>
</div><br />
<!-- TextBoxSection -->
<!-- Button Section -->
<button name="submit" type="submit" class="btn btn-default visible">
<spring:message code="connection.button.label.connect"/>
</button><br />
<!-- Button Section -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
EDIT 2:
I'm now using:
<form name="loginForm" action="<c:url value='/login' />" method="POST" >
I had also change my spring-security.xml:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/welcome**" access="hasRole('CUSTOMER')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login"
default-target-url="/welcome**"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf/>
</http>
And my ConnectionController.java
#RequestMapping(value = "/welcome**", method = RequestMethod.GET)
public String defaultPage()
{
return "home";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(
#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout)
{
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("connection");
return model;
}
#RequestMapping(value = "/403", method = RequestMethod.GET)
public ModelAndView accesssDenied() {
ModelAndView model = new ModelAndView();
//check if user is login
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
UserDetails userDetail = (UserDetails) auth.getPrincipal();
model.addObject("username", userDetail.getUsername());
}
model.setViewName("403");
return model;
}
I'm now getting State HTTP 405 - Request method 'POST' not supported when I'm trying to login
My problem was due to spring security version.
Indeed for 4.x you have to put the csrf in your form action.
My sources modified with the solution:
connection.jsp
<form name="loginForm" action="<c:url value='/login?${_csrf.parameterName}=${_csrf.token} }' />" method="POST" >
<!-- TextBox Section -->
<div class="input-group visible">
<spring:message code="connection.label.account"/>
<input name="username" path="username" placeholder="Nom du compte" type="text" class="form-control" aria-describedby="basic-addon1"/>
<!--<div class="alert alert-danger" role="alert"><form:errors path="username" cssclass="error"/></div>-->
</div><br />
<div class="input-group visible">
<spring:message code="connection.label.password"/>
<input name="password" path="password" placeholder="Mot de passe" type="password" class="form-control" aria-describedby="basic-addon1"/><br />
<!--<div class="alert alert-danger" role="alert"><form:errors path="password" cssclass="error"/></div>-->
</div><br />
<!-- TextBoxSection -->
<!-- Button Section -->
<input name="submit" type="submit" class="btn btn-default visible" value=<spring:message code="connection.button.label.connect"/> />
<br />
<!-- Button Section -->
</form>
spring-security.xml:
<http auto-config="true" >
<intercept-url pattern="/welcome**" access="hasRole('CUSTOMER')" />
<form-login login-page="/login"
default-target-url="/welcome"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/403" />
<!-- enable csrf protection -->
<csrf disabled="true"/>
</http>
I searched some examples but i couldn't found any example. What I must do in loginController.login() method. How can I pass username and password text to spring-security?
Spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/pages/login.xhtml*" access="permitAll"/>
<intercept-url pattern="/**" access="hasRole('admin')" />
<form-login login-page='/pages/login.xhtml' default-target-url="/pages/index.xhtml"
authentication-failure-url="/pages/login.xhtml"/>
<logout logout-success-url="/pages/logout.xhtml" />
</http>
<!--Authentication Manager Details -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
My view login.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!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:p="http://primefaces.org/ui">
<h:head>
<title>User Login</title>
</h:head>
<h:body>
<h:form id="loginFormId">
<p:outputPanel id="loginOutputPanelId">
<p:panelGrid id="loginInformationPanel" columns="2">
<h:outputText value="Username: "/>
<p:inputText value="#{loginController.userName}"/>
<h:outputText value="Password: "/>
<p:inputText value="#{loginController.password}"/>
</p:panelGrid>
<p:commandButton value="Login" actionListener="#{loginController.login()}"/>
</p:outputPanel>
</h:form>
</h:body>
Personally I use this way to set Spring-Security context values:
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
//....
//In your login method:
List<Authority> auths = new ArrayList<Authority>();
auths.add(new Authority("ROLE_USER")); //Role here, like "admin"
Authentication authentication = new UsernamePasswordAuthenticationToken(token, null, auths);
SecurityContextHolder.getContext().setAuthentication(authentication);
The Authority class is as follow:
import org.springframework.security.core.GrantedAuthority;
public class Authority implements GrantedAuthority{
private static final long serialVersionUID = 9170140593525051237L;
private String authority;
public Authority(String authority) {
super();
this.authority = authority;
}
#Override
public String getAuthority() {
return authority;
}
#Override
public String toString() {
return "Authority [authority=" + authority + "]";
}
}
I hope this helps
You can you Pricipal object to get the user details as shown below.
login(Principal principal){
if (principal instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken userDetails = (UsernamePasswordAuthenticationToken) principal;
userDetails.getName();
}