Basic form login SpringBoot with Thymeleaf doesn't work? - spring-boot

I am a newbie in spring boot. I'm using basic thymeleaf form login. But when I login it returns "localhost:8080/login?error=true". I don't know why. My username and password in the database are correct. Maybe I must add a new controller with post method? please help me
And here, this is my security config class
protected void configure(HttpSecurity http) throws Exception {
logger.info("-----configure(HttpSecurity http)");
http.authorizeRequests()
.antMatchers("/**").permitAll()
.antMatchers("/user/**").hasAnyRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/home")
.permitAll()
.and()
.logout()
.permitAll()
.and().csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
logger.info("-----configureGlobal(AuthenticationManagerBuilder auth)");
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
login form page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Stacked form</h2>
<form th:action="#{/login}" method="post">
<div class="form-group">
<input type="text" name="username" id="username" class="form-control input-lg"
placeholder="UserName" required="true" autofocus="true"/>
</div>
<div class="form-group">
<input type="password" name="password" id="password" class="form-control input-lg"
placeholder="Password" required="true"/>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="remember"> Remember me
</label>
</div>
<a class="btn btn-success" th:href="#{'/register'}" role="button">Register</a>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</body>
</html>
My controller
#GetMapping("/login")
public String login() {
return "/login";
}
The entity
#Entity(name = "dbo_user")
public class User {
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
#Id
private int id;
private String email;
private String password;
private String username;
}

First of all, User class has to implement UserDetails interface like this:
// userdetails methods
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.roles.stream().map(SimpleGrantedAuthority::new).collect(toList());
}
#Override
public String getUsername() {
return this.getEmail();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
#Transient
private List<String> roles = Arrays.asList("ROLE_USER");
public List<String> getRoles() {
return roles;
}
2nd you need a class that implements UserDetailsService like this:
#Service("customCustomerDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private CredentialRepository users;
#Override
public UserDetails loadUserByUsername(String email) {
return this.users.findByEmail(email)
.orElseThrow(() -> new UsernameNotFoundException("Username: " + email + " not found"));
}
}
Then you autowire that class into your security config class
#Autowired
CustomUserDetailsService customCustomerDetailsService;
You need to implement DAO DaoAuthenticationProvider in your security config class like this:
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(encoder());
return authProvider;
I'm quite sure this question would have been answered on this platform.

Are you using thymeleaf security extras? If so, then you need to have dependency included with maven/gradle and thymeleaf namespaces on the login page.
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
and
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5" lang="en">

Related

Spring tags form do not show validation errors in jsp

I am writing a page with user registration. Faced a display problem in the form of validation errors
My Controller:
#Controller
public class UIController {
private final Logger log = LoggerFactory.getLogger(getClass());
#Autowired
private UserService service;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator validator;
#PostMapping(value = "/login")
public String signIn(#ModelAttribute("userForm") UserTo userForm, BindingResult bindingResult, Model model) {
validator.validate(userForm, bindingResult);
User user = service.findByLogin(UserUtil.createNewFromTo(userForm).getLogin());
if (!userForm.getPassword().equals(user.getPassword())) {
log.info("invalid password {}", user);
return "redirect:/login";
}
log.info("signIn {}", user);
securityService.autologin(user.getLogin(), user.getPassword());
return "redirect:/welcome";
}
}
My Validator:
#Component
public class UserValidator implements Validator {
#Autowired
private UserRepositoryImpl userRepository;
#Override
public boolean supports(Class<?> aClass) {
return UserTo.class.equals(aClass);
}
#Override
public void validate(Object o, Errors errors) {
UserTo user = (UserTo) o;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "login", "NotEmpty");
if (user.getLogin().length() < 6 || user.getLogin().length() > 32) {
errors.rejectValue("login", "Size.userForm.login");
}
if (userRepository.findByLogin(user.getLogin()) != null) {
errors.rejectValue("login", "Duplicate.userForm.login");
}
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "NotEmpty");
if (user.getPassword().length() < 8 || user.getPassword().length() > 32) {
errors.rejectValue("password", "Size.userForm.password");
}
}
}
My jsp form :
<div id="wrapper">
<!--SLIDE-IN ICONS-->
<div class="user-icon"></div>
<div class="pass-icon"></div>
<!--END SLIDE-IN ICONS-->
<!--LOGIN FORM-->
<form:form name="login-form" modelAttribute="userForm" class="login-form" method="post" id="form">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<!--CONTENT-->
<div class="content">
<!--USERNAME-->
<spring:bind path="login">
<div class="form-group ${status.error ? 'has-error' : ''}">
<form:input name="login" id="login" type="text" path="login" class="input username"
placeholder="Login"></form:input>
<form:errors path="login"></form:errors>
</div>
</spring:bind>
<!--END USERNAME-->
</div>
<!--END CONTENT-->
<!--FOOTER-->
<div class="footer">
<button class="button" type="submit">Login</button>
<button class="register" type="button" name="submit" onclick=" register_url('${contextPath}/registration')">
Register
</button>
</div>
<!--END FOOTER-->
</form:form>
</div>
When debugging in chrome when sending a POST request, a 302 HTTP error appears.
Accordingly, if I set a breakpoint in the controller, then the debug is not processed.
Tell me what could be the problem?
The "form" tag in your jsp does not have "action" attribute.
You should not redirect on errors, because the redirect will erase the binding result. Instead do :
if (!userForm.getPassword().equals(user.getPassword())) {
log.info("invalid password {}", user);
return "login";
}

spring-security:HTTP Status 405 - Request method 'POST' not supported

I have checked so many answers here for the same but it seems nothing worked for me. I have spring security with spring mvc. when my user is trying to sign up I am sending post data to my controller. but it is giving me 405 post not supported I have disabled csrf token in security config. please let me know where did I go wrong?
Here's my webSecurityConfigureDapter:
package org.pkb.springlogin.config;
import org.pkb.springlogin.authentication.MyDBAuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
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 = #EnableWebMVCSecurity + Extra features
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
MyDBAuthenticationService myDBAauthenticationService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// Users in memory.
auth.inMemoryAuthentication().withUser("user1").password("12345").roles("USER");
auth.inMemoryAuthentication().withUser("admin1").password("12345").roles("USER, ADMIN");
// For User in database.
auth.userDetailsService(myDBAauthenticationService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// The pages does not require login
http.authorizeRequests().antMatchers("/", "/welcome", "/login", "/logout","/signUp").permitAll();
// /userInfo page requires login as USER or ADMIN.
// If no login, it will redirect to /login page.
http.authorizeRequests().antMatchers("/userInfo").access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')");
// For ADMIN only.
http.authorizeRequests().antMatchers("/admin").access("hasRole('ROLE_ADMIN')");
// When the user has logged in as XX.
// But access a page that requires role YY,
// AccessDeniedException will throw.
http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/403");
// Config for Login Form
http.authorizeRequests().and().formLogin()//
// Submit URL of login page.
.loginProcessingUrl("/j_spring_security_check") // Submit URL
.loginPage("/login")//
.defaultSuccessUrl("/userInfo")//
.failureUrl("/login?error=true")//
.usernameParameter("username")//
.passwordParameter("password")
// Config for Logout Page
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/logoutSuccessful");
}
}
Here's my sign up page
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# page isELIgnored="false"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<html lang="en">
<head>
<link rel="stylesheet" href="<c:url value="/resources/css/bootstrap-theme.min.css"/>">
<link rel="stylesheet" href="<c:url value="/resources/css/bootstrap.min.css"/>">
<title>Sign Up Form</title>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
</head>
<body>
<div class="jumbotron page-header">
<h2>Login</h2>
</div>
<form:form class="form-horizontal" method="post"
name="userReg" id="userReg" modelAttribute="userForm" action="${contextPath}/login">
<div class="container">
<label class="col-sm-2 control-label">Name</label>
<div class="col-sm-4">
<input name="userName" type="text" class="form-control" id="userName" placeholder="Name" />
</div>
</div>
<br>
<div class="container">
<label class="col-sm-2 control-label">Email</label>
<div class="col-sm-4">
<input name="email" class="form-control" id="email" placeholder="Email" />
</div>
</div>
<br>
<div class="container">
<label class="col-sm-2 control-label">Date of Birth(dd-mm-yyyy)</label>
<div class="col-sm-4">
<input name="dob" type="text" class="form-control" id="dob" placeholder="Date of birth" />
</div>
</div>
<br>
<div class="container">
<label class="col-sm-2 control-label">Password</label>
<div class="col-sm-4">
<input name="password" type="password" class="form-control" id="password" placeholder="password" />
</div>
</div>
<br>
<div class="container">
<label class="col-sm-2 control-label">Confirm Password</label>
<div class="col-sm-4">
<input name="confirmPassword" type="password" class="form-control" id="cpassword" placeholder="confirm password" />
<span id='message'></span>
</div>
</div>
<br>
<div class="container">
<label class="col-sm-2 control-label">User type</label>
<div class="col-sm-4">
<select class="form-control" name="type" >
<option selected="selected">--select--</option>
<option value="user" >User</option>
<option value="admin">Admin</option>
</select>
</div>
</div>
<br>
<br>
<div class="col-md-6 center-block">
<input type="submit" class="btn-lg btn-primary center-block" value="save">
</div>
</form:form>
</body>
<script type = "text/javascript"
src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.validation/1.15.1/jquery.validate.min.js"></script>
<script src="<c:url value="/resources/js/form-validation.js"/>"></script>
<script src="<c:url value="/resources/js/passwordVerification.js"/>"></script>
</html>
Here's my MainController
package org.pkb.springlogin.controller;
import java.security.Principal;
import org.pkb.springlogin.manager.SignUpHandler;
import org.pkb.springlogin.model.SignUpInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class MainController {
#Autowired
SignUpHandler signupHandler;
private static final Logger logger =LoggerFactory.getLogger(MainController.class);
#RequestMapping(value = { "/", "/welcome" }, method = RequestMethod.GET)
public String welcomePage(Model model) {
model.addAttribute("title", "Welcome");
model.addAttribute("message", "Hello friend!");
return "welcomePage";
}
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public String adminPage(Model model) {
return "adminPage";
}
#RequestMapping(value="/signUp",method=RequestMethod.POST)
public String userLogin(#ModelAttribute("userForm") SignUpInfo user,ModelMap model){
System.out.println(user);
Integer id=signupHandler.process(user);
if(id!=null){
logger.debug("ID in controller:"+id);
return "success";
}
logger.error("error in controller");
return "Failure";
}
#RequestMapping(value="/signUp",method=RequestMethod.GET)
public String register(Model model){
SignUpInfo user=new SignUpInfo();
model.addAttribute("userForm", user);
return "signUp";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(Model model ) {
return "loginPage";
}
#RequestMapping(value = "/logoutSuccessful", method = RequestMethod.GET)
public String logoutSuccessfulPage(Model model) {
model.addAttribute("title", "Logout");
return "logoutSuccessfulPage";
}
#RequestMapping(value = "/userInfo", method = RequestMethod.GET)
public String userInfo(Model model, Principal principal) {
// After user login successfully.
String userName = principal.getName();
System.out.println("User Name: "+ userName);
return "userInfoPage";
}
#RequestMapping(value = "/403", method = RequestMethod.GET)
public String accessDenied(Model model, Principal principal) {
if (principal != null) {
model.addAttribute("message", "Hi " + principal.getName()
+ "<br> You do not have permission to access this page!");
} else {
model.addAttribute("msg",
"You do not have permission to access this page!");
}
return "403Page";
}
}
Here's my signUpInfo
package org.pkb.springlogin.model;
public class SignUpInfo {
private String userName;
private String password;
private String confirmPassword;
private Type type;
private Byte enabled;
public Byte getEnabled() {
return enabled;
}
public void setEnabled(Byte enabled) {
this.enabled = enabled;
}
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;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
#Override
public String toString() {
return "SignUpInfo [userName=" + userName + ", password=" + password + ", confirmPassword=" + confirmPassword
+ ", type=" + type + "]";
}
}
Form is POST-ed to /login
action="${contextPath}/login"
but login is annotated to support only GET
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(Model model ) {
return "loginPage";
}
maybe you should post to /signUp

Spring form data is not received in controller with mustache

I'm using a simple Spring form with mustache. However the data is not received in Spring controller. login.getId(), login.getPass() are always received as null in controller. Any clues if something have to be fixed in template or controller?
My template and controller code as below.
<form class="form-signin" id="loginForm" action="{{{appCtxt}}}/login" method="post">
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" name="{{id}}" id="id" class="form-control" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="{{pass}}" id="pass" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
Controller
#Controller
public class LoginController {
private LoginService loginService;
#Autowired
public void setLoginService(LoginService loginService) {
this.loginService = loginService;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(HttpServletRequest request, Model model) {
ModelAndView result = new ModelAndView();
model.addAttribute("login", new Login());
result.addObject("resources", request.getContextPath() + "/resources");
result.addObject("appCtxt", request.getContextPath());
// return "redirect:/users";
result.setViewName("home");
return result;
}
#RequestMapping(value = "login", method = RequestMethod.POST)
public String login(Login login, HttpServletRequest request){
boolean status = loginService.verifyLogin(login.getId(), login.getPass());
if(status == true) {
return "redirect:/users";
}
else
{
return "error";
}
}
}
Instead of the name="{{pass}}" you can use name="pass" assuming you Login class contains a field with the very same name. Another thing is that you need '#ModelAttribute' annotation near the Login parameter.
For easier understanding how it works, please consider following example:
Student.java
package me.disper.model;
public class Student {
private String name;
private String surname;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
}
student.html
<!DOCTYPE html>
<html lang="en" xmlns:form="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>Create new student</title>
</head>
<body>
<form name="student" action="add" method="post">
Name: <input type="text" name="name" /><br/>
Surname: <input type="text" name="surname" /><br/>
<input type="submit" value="Save" />
</form>
</body>
</html>
MyMustacheController.java
package me.disper;
import me.disper.model.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class MyMustacheController {
#GetMapping("/student")
public ModelAndView createStudent(){
ModelAndView modelAndView = new ModelAndView("student", "student", new Student());
return modelAndView;
}
#PostMapping("/add")
public ModelAndView addStudent(#ModelAttribute Student student){
ModelAndView modelAndView = new ModelAndView("created", "student", student);
return modelAndView;
}
}
created.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Student created</title>
</head>
<body>
{{#student}}
Hello {{name}} {{surname}}
{{/student}}
</body>
</html>
Take a look at the following tutorial: A guide to forms in Spring MVC. There are some helpful hints like #ModelAttribute.

HDIV + Spring tag library (form) = Error, possible bug?

I'm finding troubles using HDIV with the tag Spring element: "< form:form >".
First, I'm going to explain the architecture of my application:
I'm using Spring framework 4.1.6, Spring Security 4.0.0 and HDIV 2.1.10.
So far I'm not having errors during the development, nevertheless now I 've found one in a jsp file, when I'm using the form tag from Spring:
<form:form
action="${pageContext.servletContext.contextPath}/newUser"
method="POST" class="form-horizontal" commandName="user">
I obtained this error in the line 34: "< form:form "
java.lang.NullPointerException at
org.hdiv.web.servlet.support.HdivRequestDataValueProcessor.processAction(HdivRequestDataValueProcessor.java:122)
at
org.springframework.web.servlet.tags.form.FormTag.processAction(FormTag.java:479)
at
org.springframework.web.servlet.tags.form.FormTag.resolveAction(FormTag.java:433)
at
org.springframework.web.servlet.tags.form.FormTag.writeTagContent(FormTag.java:349)
at
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
at
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
at
org.apache.jsp.WEB_002dINF.jsp.newUser_jsp._jspx_meth_form_005fform_005f0(newUser_jsp.java:197)
at
org.apache.jsp.WEB_002dINF.jsp.newUser_jsp._jspService(newUser_jsp.java:137)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
and more at.....(if it's necessary, I can provide it)
When I try the same code, but exchanging the tag "< form:form >" for the tag "< form >" It works.
When I examined in detail the code from HDIV:
HdivRequestDataValueProcessor.class
public class HdivRequestDataValueProcessor implements RequestDataValueProcessor
protected LinkUrlProcessor linkUrlProcessor;
protected FormUrlProcessor formUrlProcessor;
if (this.innerRequestDataValueProcessor != null) {
String processedAction = this.innerRequestDataValueProcessor.processAction(request, action, method);
if (processedAction != action) {
action = processedAction;
}
}
String result = this.formUrlProcessor.processUrl(request, action, method);//line 122
return result;
}
I wondered that maybe due to the fact that 'form:form' has a different structure than 'form', HDIV cannot find some parameters such as 'action', 'method'...But I'm not sure.
Also I attached my config files to provide more useful information (Java-based Config):
WebApplicationInit.class
import javax.servlet.Filter;
import javax.servlet.ServletContext;
import org.hdiv.filter.ValidatorFilter;
import org.hdiv.listener.InitListener;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebApplicationInit extends
AbstractAnnotationConfigDispatcherServletInitializer {
// http://www.robinhowlett.com/blog/2013/02/13/spring-app-migration-from-xml-to-java-based-config/
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfig.class, DatabaseConfig.class,
SecurityConfig.class, HdivSecurityConfig.class };
// , HdivSecurityConfig.class
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { MvcConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
//web.xml filter
#Override
protected Filter[] getServletFilters(){
return new Filter[] { new ValidatorFilter()};
}
// web.xml listener
#Override
protected void registerDispatcherServlet(ServletContext servletContext) {
super.registerDispatcherServlet(servletContext);
servletContext.addListener(InitListener.class);
}
}
HdivSecurityConfig.class
#Configuration
#EnableHdivWebSecurity
public class HdivSecurityConfig extends HdivWebSecurityConfigurerAdapter {
#Override
public void addExclusions(ExclusionRegistry registry) {
registry.addUrlExclusions("/login").method("GET");
registry.addUrlExclusions("/newUser").method("GET");
registry.addUrlExclusions("/newUser").method("POST");
registry.addUrlExclusions("/about").method("GET");
registry.addUrlExclusions("/resources/.*").method("GET");
registry.addUrlExclusions("/bst-lib/.*").method("GET");
registry.addUrlExclusions("/images/.*").method("GET");
}
#Override
public void configure(SecurityConfigBuilder builder) {
//the session has expired, go to login again
builder.sessionExpired().homePage("/").loginPage("/login");
//Execution strategy
builder.strategy(Strategy.CIPHER);
//error page
builder.errorPage("/error");
}
}
SecurityConfig.class
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DriverManagerDataSource myWebAppDataSource;
#Autowired
private MyWebAppSimpleAuthenticationProvider myWebAppAuthenticationProvider;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(myWebAppAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**", "/bst-lib/**", "/images/**",
"/about", "/newUser").permitAll().anyRequest()
.authenticated().and().formLogin().loginPage("/login")
.permitAll();
}
}
SecurityWebApplicationInit.class
public class SecurityWebApplicationInit extends
AbstractSecurityWebApplicationInitializer {}
Thank you in advance!!
Best Regards,
Alberto
----EDIT---
Following the given example, This is now my code:
WebApplicationInit.class
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebApplicationInit extends
AbstractAnnotationConfigDispatcherServletInitializer {
// http://www.robinhowlett.com/blog/2013/02/13/spring-app-migration-from-xml-to-java-based-config/
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfig.class, DatabaseConfig.class,
SecurityConfig.class, HdivSecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { MvcConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected String getServletName(){
return "myDispatcher";
}
}
HDIVSecurityConfig.class
import org.hdiv.config.Strategy;
import org.hdiv.config.annotation.EnableHdivWebSecurity;
import org.hdiv.config.annotation.ExclusionRegistry;
import org.hdiv.config.annotation.RuleRegistry;
import org.hdiv.config.annotation.ValidationConfigurer;
import org.hdiv.config.annotation.builders.SecurityConfigBuilder;
import org.hdiv.config.annotation.configuration.HdivWebSecurityConfigurerAdapter;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableHdivWebSecurity
public class HdivSecurityConfig extends HdivWebSecurityConfigurerAdapter {
#Override
public void addExclusions(ExclusionRegistry registry) {
registry.addUrlExclusions("/login").method("GET");
registry.addUrlExclusions("/newUser").method("GET");
registry.addUrlExclusions("/newUser").method("POST");
registry.addUrlExclusions("/about").method("GET");
registry.addUrlExclusions("/resources/.*").method("GET");
registry.addUrlExclusions("/bst-lib/.*").method("GET");
registry.addUrlExclusions("/images/.*").method("GET");
registry.addParamExclusions("_csrf");
}
#Override
public void configure(SecurityConfigBuilder builder) {
// the session has expired, go to login again
builder.sessionExpired().homePage("/").loginPage("/login");
// Execution strategy
builder.strategy(Strategy.MEMORY);
builder.maxPagesPerSession(5);
// error page
builder.errorPage("/error");
}
#Override
public void addRules(RuleRegistry registry) {
//registry.addRule("safeText").acceptedPattern("^[a-zA-Z0-9#.\\-_]*$");
}
#Override
public void configureEditableValidation(
ValidationConfigurer validationConfigurer) {
validationConfigurer.addValidation("/.*");
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>myWebApp</display-name>
<listener>
<listener-class>org.hdiv.listener.InitListener</listener-class>
</listener>
<!-- HDIV Validator Filter -->
<filter>
<filter-name>ValidatorFilter</filter-name>
<filter-class>org.hdiv.filter.ValidatorFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ValidatorFilter</filter-name>
<servlet-name>myDispatcher</servlet-name>
</filter-mapping>
<jsp-config>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/tlds/hdiv-c.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
newUser.jsp
<form:form
action="${pageContext.servletContext.contextPath}/newUser"
method="POST" class="form-horizontal" commandName="user">
<div class="form-group">
<label for="inputName"
class="col-sm-offset-2 col-sm-2 control-label">Name:</label>
<div class="col-sm-6">
<form:input class="form-control" id="inputName"
placeholder="Name" path="name" />
</div>
</div>
<div class="form-group">
<label for="inputSurname"
class="col-sm-offset-2 col-sm-2 control-label">Surname:</label>
<div class="col-sm-6">
<form:input class="form-control" id="inputSurname"
placeholder="Surname" path="surname" />
</div>
</div>
<div class="form-group">
<label for="inputOrganisation"
class="col-sm-offset-2 col-sm-2 control-label">Organization:</label>
<div class="col-sm-6">
<form:input class="form-control" id="inputOrganisation"
placeholder="Organization" path="organization" />
</div>
</div>
<div class="form-group">
<label for="inputEmail"
class="col-sm-offset-2 col-sm-2 control-label">Email:</label>
<div class="col-sm-6">
<form:input type="email" class="form-control" id="inputEmail"
placeholder="Email" path="email" />
</div>
</div>
<div class="form-group">
<label for="inputPassword"
class="col-sm-offset-2 col-sm-2 control-label">Password:</label>
<div class="col-sm-6">
<form:password class="form-control" id="inputPassword"
placeholder="Password" path="password" />
</div>
</div>
<div class="form-group">
<label for="inputRPassword"
class="col-sm-offset-2 col-sm-2 control-label">Repeat
Password:</label>
<div class="col-sm-6">
<form:password class="form-control" id="inputRPassword"
placeholder="Repeat Password" path="rPassword" />
</div>
</div>
<div class="col-sm-offset-4 col-sm-8">
<button type="submit" class="btn btn-default login-button">Sing
in</button>
<button type="button" class="btn btn-default login-button"
onclick="clearAll()">Clear All</button>
<button type="button" class="btn btn-default login-button"
onclick="comeBack()">Come Back</button>
</div>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form:form>
MvcConfig.class
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.ec.myWebApp" })
public class MvcConfig extends WebMvcConfigurerAdapter {
#Autowired
/*
* If I use this commented line, The application fails due to the fact that the bean "hdivEditableValidator" can't be found...If I don't use the tag "Qualifier" it does not fail
*/
// #Qualifier("hdivEditableValidator")
private Validator hdivEditableValidator;
// View Name -> View
#Bean
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
// static resources
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/public-resources/");
registry.addResourceHandler("/bst-lib/**").addResourceLocations(
"/public-resources/lib/bootstrap-3.3.2-dist/");
registry.addResourceHandler("/images/**").addResourceLocations(
"/public-resources/images/");
}
#Bean
public MultipartResolver multipartResolver() {
HdivCommonsMultipartResolver resolver = new HdivCommonsMultipartResolver();
resolver.setMaxUploadSize(100000);
return resolver;
}
#Override
public Validator getValidator() {
return hdivEditableValidator;
}
}
I changed the way to add the HDIV to my Web Application, adding it in the xml file, instead of doing that in using java-based configuration. Additionally, I added the Qualifier tag (MvcConfig.class), using the example, but it does not work when I use it...(It can not find the bean...).
The null error hasn't disappeared...
The problem has been solved changing this line:
#ComponentScan(basePackages = { "com.ec.myWebApp" })
in the class: MvcConfing, for this:
#ComponentScan(basePackages = { "com.ec.myWebApp.controllers",
"com.ec.myWebApp.dao", "com.ec.myWebApp.services" })
My original line scanned twice the HDIV config class, first during the context creation and the second one by the "#ComponentScan". This gave place to an incorrect initialization. So, the config package was used twice, instead of once.
Thank you.

http 404 error in j_security_check

I am stuck with this persistent error while creating my spring 4 app. Here's my code:
Initializer.java:
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer implements WebApplicationInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return new Class[] { RootConfig.class, SecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
// TODO Auto-generated method stub
return new Class[] { WebAppConfig.class };
}
#Override
protected String[] getServletMappings() {
// TODO Auto-generated method stub
return new String[] { "/" };
}
// I have tried adding the following but it doesn't seem to work also:
#Override
protected Filter[] getServletFilters() {
// TODO Auto-generated method stub
return new Filter[] { new DelegatingFilterProxy("springSecurityFilterChain") };
}
}
WebAppConfig.java:
#Configuration
#EnableWebMvc
#ComponentScan("com.myco.controller")
public class WebAppConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
}
RootConfig.java:
#Configuration
#EnableTransactionManagement
#ComponentScan("com.mycompany")
#PropertySource("classpath:application.properties")
public class RootConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
#Resource
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
}
SecurityConfig.java:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().userDetailsService(userDetailsService)
.authorizeRequests()
.antMatchers("/sec/moderation.html").hasRole("MODERATOR")
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/user-login.html")
.defaultSuccessUrl("/success-login.html")
.failureUrl("/error-login.html")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/index.html");
}
}
And lastly, my login jsp (login-form.jsp):
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Login page</title>
<style>
.error {
color: red;
}
</style>
</head>
<body>
<h1>Login page</h1>
<p>
<c:if test="${error == true}">
<b class="error">Invalid login or password.</b>
</c:if>
</p>
<form method="post" action="<c:url value='j_spring_security_check'/>" >
<table>
<tbody>
<tr>
<td>Login:</td>
<td><input type="text" name="j_username" id="j_username"size="30" maxlength="40" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="j_password" id="j_password" size="30" maxlength="32" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Login" /></td>
</tr>
</tbody>
</table>
</form>
<p>
Home page<br/>
</p>
</body>
</html>
My error:
If you are using Spring Security 3.2 the login url is changed to /login from /j_spring_security_check also the username and password paremeters are changed.
username : from j_username to username
password : from j_password to password
So your form will be.
<form method="post" action="<c:url value='login'/>" >
<table>
<tbody>
<tr>
<td>Login:</td>
<td><input type="text" name="username" id="username"size="30" maxlength="40" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="password" id="password" size="30" maxlength="32" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Login" /></td>
</tr>
</tbody>
</table>
</form>

Resources