Spring security: New user workflow - spring

I am new to Spring security.
I have created a custom form that logs a user in and then, upon successful login, the user continues to his/her intended webpage. My implementation is standard and it works.
Here's my problem.
A user wants to go to page mywebpage.html.
The user is not logged in. The
user is redirected (by Spring Security) to the login page.
The user
does not have an account.
The user clicks on the createAccount link
and goes via standard MVC protocols to a registration page.
How do I now get the user's originally intended destination (mywebpage.html) from Spring Security, so I can redirect the user to that page once he/she has created an account?
For the record, security.xml
<http auto-config="true">
<intercept-url pattern="/login" access="permitAll()" />
<intercept-url pattern="/flow-entry.html" access="hasRole('ROLE_USER')"/>
<form-login
login-page="/login"
authentication-failure-url="/login?error=true" />
<logout logout-success-url="/login" />
</http>
login form
<form name='f' action="login" method='POST'>
<table style="text-align:left" class="w3-table" >
<tr style="text-align:center;color:red" th:if="${loginresponse}">
<td colspan="2" style="text-align:center" th:text="#{${loginresponse}}"> </td>
</tr>
<tr>
<td th:text="#{label.emaillogin}"></td>
<td><input type="text" name="username" value=''/></td>
</tr>
<tr>
<td th:text="#{label.password}">Password:</td>
<td><input type="password" name="password" /></td>
</tr>
<tr>
<td colspan="2" style="text-align:center"><input name="submit" type="submit" class="w3-btn w3-blue w3-hover-aqua w3-round-large" th:value="#{label.ok}" /></td>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
</tr>
<tr style="text-align:center">
<td colspan="2" style="text-align:center"> <span th:text="#{label.register}"></span> </td>
</tr>
</table>
</form>
Controller Method. I need originally intended web page in this method
#RequestMapping(value = "/doRegistration", method=RequestMethod.POST)
public ModelAndView doRegistration(ModelAndView mv, HttpServletRequest request)
{
mv.setViewName("register");
SSm.getLogger().debug("registering new user");
String email = request.getParameter("username");
String email1 = request.getParameter("username1");
if(email.equals(email1))
{
if(email.contains("#")&&email.contains("."))
{
SSm.getLogger().debug("got legit email");
String password = request.getParameter("password");
String password1 = request.getParameter("password1");
if(password.equals(password1))
{
SSm.getLogger().debug("ready to login");
I NEED USERS ORIGINALLY INTENDED DESTINATION RIGHT HERE SO I CAN SET THE VIEW
}
else
{
mv.setViewName("register");
mv.addObject("loginresponse", "message.passwordmismatch");
}
}
else
{
mv.setViewName("register");
mv.addObject("loginresponse", "message.invalidemail");
}
}
else
{
mv.setViewName("register");
mv.addObject("loginresponse", "message.emailmismatch");
}
return mv;
}

You could use a SavedRequestAwareAuthenticationSuccessHandler.
When a non authorized request reaches the ExceptionTranslationFilter, a RequestCache of class HttpSessionRequestCache is created and the original request is saved on it.
This way, if you do not set alwaysUseDefaultTargetUrl to true, httpRequest would be reconstructed and used as target url while correct login is performed.
So, try to #Autowire (I use #Resource instead as I have more than one AuthenticationManager and AuthenticationSuccessHandler in my security config) the AuthenticationSuccessHandler in your controller and calling determineTargetUrl() like this:
I made a little modifications such as use #Valid annotations and implement a Validator to validate the registration form
Security.xml
<beans:bean id="savedRequestSuccesHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/zone4/secured/securedPage.htm" />
</beans:bean>
<security:http pattern="/zone4/**" use-expressions="true" authentication-manager-ref="mainAuthenticationManager">
<security:intercept-url pattern="/zone4/simple/**" access="permitAll()" />
<security:intercept-url pattern="/zone4/secured/**" access="isAuthenticated()"/>
<security:form-login
login-page="/zone4/simple/login.htm"
authentication-failure-url="/login.htm?error=true"
authentication-success-handler-ref="savedRequestSuccesHandler"
username-parameter="email"
password-parameter="password"
login-processing-url="/zone4/secured/performLogin.htm"
/>
<security:logout
logout-url="/zone4/secured/performLogout.htm"
logout-success-url="/zone4/simple/login.htm" />
<security:csrf disabled="true"/>
</security:http>
Controller:
/**
*
*/
package com.eej.ssba2.controller.test;
import java.io.IOException;
import java.util.Arrays;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
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 com.eej.ssba2.model.test.zone4.RegisterModel;
import com.eej.ssba2.model.test.zone4.RegisterModelValidator;
/**
*
*/
#Controller
#RequestMapping("/zone4")
public class Zone4TestController {
private Logger logger = Logger.getLogger(this.getClass());
#Resource(name="mainAuthenticationManager")
private AuthenticationManager authenticationManager;
#Resource(name="savedRequestSuccesHandler")
private SavedRequestAwareAuthenticationSuccessHandler successHandler;
#RequestMapping("/simple/unsecuredPage.htm")
public String unsecuredPage(){
return "simple/unsecuredPage";
}
#RequestMapping("/secured/securedPage.htm")
public String securedPage1(){
return "simple/secured/securedPage";
}
#RequestMapping("/secured/securedPage2.htm")
public String securedPage2(){
return "simple/secured/securedPage2";
}
#RequestMapping("/secured/securedPage3.htm")
public String securedPage3(){
return "simple/secured/securedPage3";
}
#RequestMapping("/simple/login.htm")
public String login(){
return "simple/login/login";
}
#RequestMapping(value="/simple/register.htm", method=RequestMethod.GET)
public String register(ModelMap model){
logger.debug("Entrada en register.htm");
if(!model.containsAttribute("registerModel")){
model.addAttribute("registerModel", new RegisterModel());
}
return "simple/login/register";
}
#RequestMapping(value="/simple/register.htm", method=RequestMethod.POST)
public String register(
HttpServletRequest request, HttpServletResponse response,
#Valid RegisterModel registerModel, ModelMap model, BindingResult bindingResult){
logger.info("entrada en register");
RegisterModelValidator userValidator = new RegisterModelValidator();
userValidator.validate(registerModel, bindingResult);
if(bindingResult.hasErrors()){
logger.info("BindingResult has errors: " + bindingResult.getAllErrors());
model.addAttribute("errors", bindingResult.getAllErrors());
model.addAttribute("registerModel", registerModel);
return "simple/login/register";
}
// Your user register business
Authentication authenticated = null;
/*
* If the user is created at this time due to your business logic, you could authenticate it directly
* through the manager
*
authenticated =
this.authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
registerModel.getMail1(),
registerModel.getPassword1()
)
);
*/
authenticated = new UsernamePasswordAuthenticationToken(
registerModel.getMail1(),
registerModel.getPassword1(),
Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))
);
SecurityContextHolder.getContext().setAuthentication(authenticated);
try {
this.successHandler.onAuthenticationSuccess(request, response, authenticated);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Registration model bean:
package com.eej.ssba2.model.test.zone4;
import java.io.Serializable;
import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import org.apache.log4j.Logger;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.eej.ssba2.ApplicationVersion;
/**
*
*
*/
public class RegisterModel implements Serializable{
private Logger logger = Logger.getLogger(this.getClass());
/**
*
*/
private static final long serialVersionUID = 1L;
#NotEmpty
#Pattern(regexp = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*" +
"#[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$|")
public String mail1;
#NotEmpty
#Pattern(regexp = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*" +
"#[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$|")
public String mail2;
#NotEmpty
public String password1;
#NotEmpty
public String password2;
// getters and setters
}
The Validator imiplementation I use to validate the fields in the model:
package com.eej.ssba2.model.test.zone4;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public class RegisterModelValidator implements Validator {
#Override
public boolean supports(Class<?> arg0) {
return RegisterModel.class.equals(arg0);
}
#Override
public void validate(Object target, Errors errors) {
RegisterModel user = (RegisterModel) target;
if(!user.getMail1().equals(user.getMail2())){
errors.rejectValue("mail1", "lbl_mail1_and_mail2_must_be_equal");
errors.rejectValue("mail2", "lbl_mail1_and_mail2_must_be_equal");
}
if(!user.getPassword1().equals(user.getPassword2())){
errors.rejectValue("password1", "lbl_pass1_and_pass2_must_be_equal");
errors.rejectValue("password2", "lbl_pass1_and_pass2_must_be_equal");
}
}
Finally, the registration jsp:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%# taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Login</title>
</head>
<body>
<form:form role="registerModel" commandName="registerModel" method="POST" action="${pageContext.request.contextPath}/zone4/simple/register.htm">
<form:errors path="*" cssClass="errorblock" element="div" />
<fieldset>
<div class="form-group">
<form:input path="mail1" id="mail1" name="mail1" placeHolder="email" />
<form:errors path="mail1" id="mail1" name="mail1" placeHolder="email" cssClass="error" />
</div>
<div class="form-group">
<form:input path="mail2" id="mail2" name="mail2" placeHolder="email" />
<form:errors path="mail2" id="mail2" name="mail2" placeHolder="email" cssClass="error" />
</div>
<div class="form-group">
<form:input path="password1" id="password1" name="password1" placeHolder="password" />
<form:errors path="password1" id="password1" name="password1" placeHolder="password" cssClass="error" />
</div>
<div class="form-group">
<form:input path="password2" id="password2" name="password2" placeHolder="password" />
<form:errors path="password2" id="password2" name="password2" placeHolder="password" cssClass="error" />
</div>
<div class="checkbox">
<label>
<input name="remember-me" id="remember-me" type="checkbox" value="Remember Me">Remember Me
</label>
</div>
<!-- Change this to a button or input when using this as a form -->
<button type="submit" class="btn btn-lg btn-success btn-block" name="submit"><spring:message code="lblRegistration"/></button>
</fieldset>
</form:form>
</body>
</html>

Related

Spring Security with custom login form not working

I have a custom login form with spring security and when logging in I keep getting a 404
Heres my web config
package coffee.web;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("/regular/index.html");
}
}
Heres my security config
package coffee.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("peter").password("peter").authorities("ROLE_USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**").hasRole("USER").antMatchers("/", "/**").permitAll()
.and().formLogin().loginPage("/regular/login.html").permitAll().defaultSuccessUrl("/admin/adminIndex.html").and().csrf().disable();
}
}
Heres my login html form
<head>
<link href="index.css" type="text/css" rel="stylesheet" />
<link href="adminIndex.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div id="page">
<div id="bar"></div>
<header>
<h1><img id="logo" src="resources/logo.png" width="300" height="75" /></h1>
</header>
<section id="main">
<div id="container">
<div id="loginDiv">
<form name="login" id="login" action="login" method="POST">
<div id="formDiv">
<label for="addUsername" class="title">Username</label>
<span id="validateUsername" class="error"></span>
<input class="input" type="text" id="addUsername" name="username" />
<br />
<label for="addPassword" class="title">Password</label>
<span id="validatePassword" class="error"></span>
<input class="input" type="text" id="addPassword" name="password" />
<br />
<button id="submit" name="submit" type="submit" class="submit">submit</button>
</div>
</form>
</div>
</div>
</section>
</div>
</body>
Even when I turn authorization off, and only authentication is on, i still get the 403 error code after logging in. Even though I could still go directly to admin.adminIndex.html directly and it works.. (with authorization off and only authentication on).
Okay, I updated my security code with ".and().csrf().disable();" and now I am getting a 404 not found error when i log in.
That happened to me too (or at least something similar).
Try to add .and().csrf().disable() after .defaultSuccessUrl("/admin/adminIndex.html") to your configure method.

Internationalization of placeholders in Spring

I can not find the way to internationalize the text inside a placeholder like I do with regular text. I would like to place my internationalization in:
input type="text" class="form-control" name="s" placeHolder="Search Hobbies"
with input type="text" class="form-control" name="s" placeHolder="ctrlpanel.search.placeholder"
ctrlpanel.search.placeholder=Search Hobbies
Right now, in my JSP I include the tag
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<c:set var="contextRoot" value="${pageContext.request.contextPath}" />
<c:url var="search" value="/search" />
<hr/>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form action="${search}" method="post">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
<div class="input-group input-group-lg">
<input type="text" class="form-control" name="s" placeHolder="Search Hobbies">
<span class="input-group-btn">
<button id="search-button" class="btn btn-primary" type="submit">
<spring:message code="ctrlpanel.find.button" text="default text" />
</button>
</span>
</div>
</form>
</div>
</div>
My configuration works fine:
package com.caveofprogramming.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import java.util.Locale;
#Configuration
public class SpringMvcConfiguration extends WebMvcConfigurerAdapter {
#Bean
public LocaleResolver localeResolver(){
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(new Locale("es", "ES"));
//sessionLocaleResolver.setDefaultLocale(Locale.US);
return sessionLocaleResolver;
}
#Bean
LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry interceptorRegistry){
interceptorRegistry.addInterceptor(localeChangeInterceptor());
}
}
Since this does not work.
<input type="text" class="form-control" name="s" placeHolder="<spring:message code="ctrlpanel.search.placeholder"/>">
Use var attribute of spring:message which is used when binding the result to the page, request, session or application scope.
<spring:message code="ctrlpanel.search.placeholder" var="searchPlaceholder"/>
And then update your input field like this:
<input type="text" class="form-control" name="s" placeHolder="${searchPlaceholder}">

why authentication-failure-url in spring security not working

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.

Request processing failed; nested exception is java.lang.NullPointerException

i created a form and on post i want to save those values to the database and show the saved values on the page.
i am new to spring mvc and hence i am not understanding where i am going wrong.
Here is the StackTrace -
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
root cause
java.lang.NullPointerException
com.projects.data.HomeController.addCustomer(HomeController.java:36)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
note The full stack trace of the root cause is available in the VMware vFabric tc Runtime 2.7.2.RELEASE/7.0.30.A.RELEASE logs.
Model class
package com.projects.model;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="customer")
public class Customer {
#Id
int custid;
String name;
int age;
public Customer()
{}
public Customer(int custid,String name,int age)
{
this.custid=custid;
this.name=name;
this.age=age;
}
//Getters And Setters
public int getCustid() {
return custid;
}
public void setCustid(int custid) {
this.custid = custid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Dao Class
package com.projects.model;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.projects.model.Customer;
#Repository
public class CustomerDao {
#Autowired
private SessionFactory sessionfactory;
public SessionFactory getSessionfactory() {
return sessionfactory;
}
public void setSessionfactory(SessionFactory sessionfactory) {
this.sessionfactory = sessionfactory;
}
public int save(Customer customer)
{
return (Integer) sessionfactory.getCurrentSession().save(customer);
}
}
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.projects.model" />
<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/customerdb" />
<beans:property name="username" value="root" />
<beans:property name="password" value="root" />
</beans:bean>
<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="packagesToScan" value="com.projects.model" />
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<beans:bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
</beans:beans>
Controller class
package com.projects.model;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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 com.projects.model.CustomerDao;
import com.projects.model.Customer;
/**
* Handles requests for the application home page.
*/
#Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
private CustomerDao dao;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String customer(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Customer customer=new Customer();
model.addAttribute(customer);
return "home";
}
#RequestMapping(value = "/customer", method = RequestMethod.POST)
public String addCustomer(#ModelAttribute("customer") Customer customer, ModelMap model) {
model.addAttribute("custid", customer.getCustid());
model.addAttribute("name",customer.getName());
model.addAttribute("age", customer.getAge());
dao.save(customer);
return "customer/customer";
}
}
View Files
//home.jsp
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# page session="false" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<form:form action="${customer}" method="post" modelAttribute="customer">
<form:label path="custid">Id:</form:label>
<form:input path="custId"/> <br>
<form:label path="name">Name:</form:label>
<form:input path="name"/> <br>
<form:label path="age">Age:</form:label>
<form:input path="age"/> <br>
<input type="submit" value="Save"/>
//customer.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Submitted Information</title>
</head>
<body>
<h2>Submitted Information</h2>
<table>
<tr>
<td>Cust id</td>
<td>${custid}</td>
</tr>
<tr>
<td>Name</td>
<td>${name}</td>
</tr>
<tr>
<td>Age</td>
<td>${age}</td>
</tr>
</table>
</body>
</html>
After i click the save button i get the above mentioned error.Please help me resolve this.
Seems to be a problem in your form. At least, the inputs must be given the name attributes:
<form method="post" action="<c:url value='/customer/'/>">
Cust_Id :
<input type="text" name="custid">
<br>
Name :
<input type="text" name="name">
<br>
Age :
<input type="text" name="age">
<input type="submit" value="Save">
</form>
But since you are using Spring, it is preferable to use the Spring forms (and spring url's also):
<spring:url var="customer" value="/customer"/>
<form:form action="${customer}" method="post" modelAttribute="customer">
<form:label path="custid">Id:</form:label>
<form:input path="custId"/> <br>
<form:label path="name">Name:</form:label>
<form:input path="name"/> <br>
<form:label path="age">Age:</form:label>
<form:input path="age"/> <br>
<input type="submit" value="Save"/>
</form:form>
Edit
And you should initialize dao!
#Autowired
private CustomerDao dao;
The attribute of your model has annotated with #ModelAttribute to be nulleable. This is so that when an exception occurs in times of bind there is something to return.
Note the difference between the model attribute and the model attribute parameter.
An exception during bind and validation times could be passing text in an integer field.
Exception:
org.springframework.web.util.NestedServletException:
Request processing failed; nested exception is java.lang.NullPointerException:
Parameter specified as non-null is null: method yourMethod, parameter yourParam
In Kotlin
Going from student: Student to student: Student? exception is avoided.
#RequestMapping("/processFormRegister")
fun processFormRegister(
#Valid #ModelAttribute("firstStudent") student: Student?,
validationResult: BindingResult
): String {
return if (validationResult.hasErrors()) {
"StudentFormRegister"
} else {
"ResultFormRegister"
}
}
And also to see the exception transformed into a validation you could use #Valid and Binding Result of Hibernate Validator obtaining:
failed to convert value of type java.lang.string[] to required type java.lang.integer; nested exception is java.lang.numberformatexception: for input string: "a"
GL

Problems with Hibernate Validator and Spring Webflow

I'm trying to validate a form using Spring WebFlow and Hibernate Validator Annotations, but I'm doing something wrong.
If I use the Spring validation way (ValidationContext, MessageContext, validate${state}, etc), all works fine, but I want to use the Hibernate Annotations like #Email, #NotEmpty, etc.
I've read a lot of forums, Spring documentation, but I don't know what I'm doing wrong.
At this moment, this is my view-state and next action code:
<var name="user" class="myproject.web.pojo.User"/>
<view-state id="startSignup" model="user">
<binder>
<binding property="email" />
<binding property="name" />
<binding property="lastName" />
<binding property="password" />
</binder>
<on-entry>
<set name="flowScope.user" value="new info.teaming.web.pojo.User()" />
</on-entry>
<transition on="dataEntered" to="lookupUser" />
</view-state>
<action-state id="lookupUser">
<evaluate expression="signupActions.lookupUser(user)" />
<transition to="startSignup" on-exception="myproject.web.service.exception.UserAlreadyExistsException" />
<transition to="saveOrder" />
</action-state>
(...)
This is the startSignup.jsp code:
<!-- sf:form method="POST" modelAttribute="user" -->
<sf:form method="POST" commandName="user" >
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" />
<fieldset>
<table cellspacing="0">
<tr>
<th>
<label for="name"><fmt:message key="signUp.name"/></label>
</th>
<td>
<sf:input path="name" size="25" id="name" />
</td>
<sf:errors path="name" />
</tr>
<tr>
<th>
<label for="lastName"><fmt:message key="signUp.lastName"/></label>
</th>
<td>
<sf:input path="lastName" size="45" maxlength="45" id="lastName" />
</td>
</tr>
<tr>
<th>
<label for="password"><fmt:message key="signUp.password"/></label>
</th>
<td>
<sf:password path="password" size="20" showPassword="true" id="password" />
</td>
</tr>
<tr>
<th>
<label for="email"><fmt:message key="signUp.email"/></label>
</th>
<td>
<sf:input path="email" size="30" id="email" />
</td>
</tr>
<tr>
<td>
<input type="submit" name="_eventId_dataEntered" value="<fmt:message key="signUp.register"/>"/>
</td>
</tr>
</table>
</fieldset>
</sf:form>
This is the myproject.web.pojo.User POJO code:
import java.io.Serializable;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#NotEmpty
#Length(min = 2, max = 25)
private String name;
#NotEmpty
#Email
private String email;
#NotEmpty
#Length(min = 2, max = 45)
private String lastName;
#NotEmpty
#Length(min = 6, max = 20)
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
// public void validateStartSignup(ValidationContext context) {
// MessageContext messages = context.getMessageContext();
//
// messages.addMessage(new MessageBuilder().error().source("name").code("user.name.notEmpty").build());
// }
}
(note: as you can see, when I work with Spring Validation (uncomment the validate method), the form validates successfully)
And finally, this is my SignupAction code:
import myproject.web.model.UsrUser;
import myproject.web.model.dao.UsrUserDAO;
import myproject.web.pojo.User;
import myproject.web.service.exception.UserAlreadyExistsException;
import javax.annotation.Resource;
import javax.validation.Valid;
import org.springframework.stereotype.Component;
import org.springframework.webflow.action.MultiAction;
import org.springframework.webflow.execution.Event;
#Component
public class SignupActions extends MultiAction {
#Resource
UsrUserDAO usrUserDAO;
private static final long serialVersionUID = 1L;
public Event lookupUser(#Valid User user) throws UserAlreadyExistsException {
try {
usrUserDAO.findByEmail(user.getEmail());
} catch (javax.persistence.NoResultException e) {
return success();
}
throw new UserAlreadyExistsException();
}
public void saveUser(UsrUser user) {
return;
}
}
When I work with Hibernate Validation, the flow arrives to the saveUser method, without any validation.
I'm using Spring 3:
Spring 3.0.5.RELEASE
Spring WebFlow 2.2.1.RELEASE
Hibernate Validator 4.0.2.GA
What I'm doing wrong?
Thanks a lot for helping me! :)
have you defined your validator in Spring configuration XML file?
According to Spring Webflow reference it shoud be defined like this:
<webflow:flow-registry flow-builder-services="flowBuilderServices" />
<webflow:flow-builder-services id="flowBuilderServices" validator="validator" />
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
Try,
Changing:
#Resource
UsrUserDAO usrUserDAO;
By:
#Autowired
private UsrUserManager UsrUserManager;
Using MVC manager.
And:
#Transactional
public Event lookupUser(#Valid User user) throws UserAlreadyExistsException { ...
as a Spring MVC controller, or reusing this MVC code if you already desing it ;)

Resources