The problem is:
The site has one content for people who have not yet registered and another for those who have already registered and logged in. When I enter the site, I am thrown onto the page /login as I have indicated in Spring Security and this page does not allow me to go anywhere until I log in. But I need to throw me at the entrance to the site to the home page for unregistered users where i can view information about the event, and etc, and then register or log in. I almost decided that, I added to the Spring Security class .loginPage("/index") instead of ("/login") + added antMatchers, where he indicated all the pages that an unregistered user can visit. But there was a problem. It is shown in the picture. My styles do not work, it also stops showing pictures.
I add to antMatchers "/resources/**" but this does not help. Also, when I go to the "log in" tab from the main page, and I try to log in by entering my login and password, write an error
"Request method 'POST' not supported
org.springframework.web.HttpRequestMethodNotSupportedException:
Request method 'POST' not supported at "
My Sping Secutiry code before update -
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Qualifier("userDetailsServiceImpl")
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private SimpleAuthenticationSuccessHandler successHandler;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasAnyRole("ADMIN")
.antMatchers("/runner/**").hasAnyRole("RUNNER","ADMIN")
.antMatchers("/coordinator/**").hasAnyRole("COORDINATOR","ADMIN")
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/login")
.successHandler(successHandler)
.permitAll().and()
.logout()
.permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers( "/static/**", "/css/**", "/js/**","/error");
}
}
My Sping Secutiry code after update - the rest is the same
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasAnyRole("ADMIN")
.antMatchers("/runner/**").hasAnyRole("RUNNER","ADMIN")
.antMatchers("/coordinator/**").hasAnyRole("COORDINATOR","ADMIN")
.antMatchers( "/aboutEvent","/marathonCompare","/charityOrgList",
"/calculatorBMI","/calculatorBMR","/learnMore","/registerAsRunner","/becomeSponsor","/",
"/allResults","/interactiveMap","/becomeRunner","/login","/resources/**").permitAll()
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/index")
.successHandler(successHandler)
.permitAll().and()
.logout()
.permitAll();
}
Login Controller
#Controller
public class LoginController {
#GetMapping("/login")
public String login(){
return "login/login";
}
}
Login Page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous" th:href="#{/webjars/bootstrap/4.1.3/css/bootstrap.min.css}">
<link rel="stylesheet" type="text/css" media="all" th:href="#{/css/runnerstyle/register.css}"/>
</head>
<body class="align">
<div class="register-top flex-container">
<form th:action="#{/index}">
<button type="submit" class="register-back">Назад</button>
</form>
<h1><b>MARATHON SKILLS 2018</b></h1>
</div>
<div class="login-middle">
<div class="login-text">
<h2>Форма авторизации<br/></h2>
<h4>Пожалуйста, авторизуйтесь в системе, используя ваш адресс электронной почты<br>
и пароль.
</h4>
</div>
<div th:if="${param.error}" class="alert alert-danger">
<p>Invalid username or password</p>
</div>
<div th:if="${param.logout}" class="alert alert-success">
<p>You've been logged out</p>
</div>
<form th:action="#{/login}" method="post" class="form-input">
<table>
<tr th:class="${param.error} ? 'form-group has-error' : 'form-group'">
<th><h4>Email:</h4></th>
<th style="padding-left: 20px">
<input type="email" id="username" name="username" placeholder="Enter your email address" size="60px" class="input-field">
</th>
</tr>
<tr th:class="${param.error} ? 'form-group has-error' : 'form-group'">
<th><h4>Password:</h4></th>
<th style="padding-left: 20px">
<input type="password" id="password" name="password" placeholder="Enter your email password" size="60px" class="input-field">
</th>
</tr>
<tr>
<th></th>
<th style="padding-right: 13vw;">
<button type="submit" class="login-button">Login</button>
Cancel
</th>
</tr>
</table>
</form>
</div>
<div class="register-bot">
18 дней 8 часов и 17 минут осталось до старта марофона!
</div>
</body>
</html>
Index controller
#Controller
public class IndexController {
#GetMapping({"/","/index",""})
public String getIndexPage(){
return "index";
}
#GetMapping("/registerAsRunner")
public String registerRunner(){
return "runner/createOrRegister";
}
#GetMapping("/learnMore")
public String getLearnMorePage(){return "learnmore/main";}
}
How can I solve this problem and do what I have in mind? Thanks!
Related
I know that there is many questions like this, but nothing I found helped me fix the issue.
I'm using Spring Boot with security to handle login, with custom login page. This is my config:
#SpringBootApplication
public class CompetencyMatrixApplication {
public static void main(String[] args) {
SpringApplication.run(CompetencyMatrixApplication.class, args);
}
}
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
private final UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService)
{
this.userDetailsService = userDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/matrix", "/matrix/show", "/cas/getImage", "/documentModal").access("hasRole('2')")
.antMatchers("/matrix/fromFile", "/matrix/upload").access("hasRole('1')")
.antMatchers("/cas/new", "/cas/uploadImage").access("hasRole('1')")
.antMatchers("/department/**", "/departmentType/**").access("hasRole('1')")
.antMatchers("/employee/**").access("hasRole('1')")
.antMatchers("/position", "/position/**").access("hasRole('1')")
.antMatchers("/login").permitAll()
.antMatchers("/resources/**").permitAll()
.and().formLogin()
.loginPage("/sign-in").permitAll()
.defaultSuccessUrl("/",true)
.failureUrl("/sign-in?error")
.usernameParameter("email")
.passwordParameter("password")
.and().logout().logoutSuccessUrl("/sign-in?logout")
.and().exceptionHandling().accessDeniedPage("/403");
}
}
and login page (just the form part)
<c:url var="loginUrl" value="/login"/>
<form action="${loginUrl}" method="post">
<div class="mb-4">
<label for="email" class="block text-gray-700 text-sm font-bold mb-2">Email</label>
<input id="email" type='text' name='email' value=''
class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500">
</div>
<div class="mb-4">
<label for="password" class="block text-gray-700 text-sm font-bold mb-2">Hasło</label>
<input id="password" type='password' name='password'
class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500">
</div>
<input name="submit" type="submit" value="Zaloguj"
class="shadow bg-purple-500 hover:bg-purple-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"/>
</form>
So I get my custom page for login, but when I submit it I get 404 Whitelabel Error Page.
What am I missing here? Every example I saw was just using the default /login url to post login details and it worked, mine obviously doesn't even reach UserDetailsService
Found the issue, if someone comes here looking for solution, for me adding
http.csrf().disable(); did the trick
I'm implementing Spring Security for Spring Boot project.
The problem is: if I use Spring Security configuration like:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
public SecurityConfiguration(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
#Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(bCryptPasswordEncoder());
return authProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().
antMatchers("/index", "/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").failureUrl("/error")
.defaultSuccessUrl("/CarRentalServlet", true)
.permitAll()
.and()
.logout()
.permitAll()
.and()
.httpBasic();
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
Logic for Controller is:
#Controller
public class CarRentalController {
final OrderRepository orderRepository;
final VehicleRepository vehicleRepository;
private final CommandFactory commandFactory;
public CarRentalController(OrderRepository orderRepository, VehicleRepository vehicleRepository, CommandFactory commandFactory) {
this.orderRepository = orderRepository;
this.vehicleRepository = vehicleRepository;
this.commandFactory = commandFactory;
}
#GetMapping("/{view}")
public String viewMapping(#PathVariable String view) {
return view;
}
#RequestMapping(value = { "/CarRentalServlet" }, method = { RequestMethod.GET, RequestMethod.POST })
public ModelAndView getCommand(#RequestParam(required = false) String command,
HttpServletRequest req, HttpServletResponse res,
HttpSession session,
#RequestParam(value = "page", required = false, defaultValue = "0") Integer page
) throws ServletException, IOException {
Page<Vehicle> vehiclePage = vehicleRepository.findAll(new PageRequest(page, 2, new Sort(Sort.Direction.DESC, "dailyPrice")));
session.setAttribute("number", vehiclePage.getNumber());
session.setAttribute("totalPages", vehiclePage.getTotalPages());
session.setAttribute("totalElements", vehiclePage.getTotalElements());
session.setAttribute("size", vehiclePage.getSize());
session.setAttribute("data",vehiclePage.getContent());
session.setAttribute("orderList", orderRepository.findAll());
session.setAttribute("vehicleList", vehicleRepository.findAll());
return commandFactory.getCommand(command).execute(req, res, session);
}
}
And login.jspx file as jsp form:
<div class="col-md-4 col-md-offset-4">
<div class="login-panel panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><fmt:message key="login.paneltitle" /></h3>
</div>
<div class="panel-body">
<form role="form" name="loginForm" method="POST" action="${pageContext.request.contextPath}/login">
<input type="hidden" name="command" value="logInCommand"/>
<fieldset>
<div class="form-group">
<fmt:message key="login.label.login" var="loginValue" />
<input class="form-control" placeholder="${loginValue}" name="username" type="text" autofocus=""/>
</div>
<div class="form-group">
<fmt:message key="login.label.password" var="passwordValue" />
<input class="form-control" placeholder="${passwordValue}" name="password" type="password" value=""/>
</div>
<fmt:message key="login.button.login" var="loginButtonValue" />
<input type="submit" class="btn btn-lg btn-success btn-block" value="${loginButtonValue}" />
</fieldset>
</form>
</div>
</div>
</div>
Another jsp form as index.jsp:
<div class="navbar-default navbar-static-side" role="navigation">
<div class="sidebar-collapse">
<ul class="nav" id="side-menu">
<c:if test="${!empty sessionScope.userName}">
<li>
<form name="makeOrderButton" method="post" action="CarRentalServlet">
<input type="hidden" name="command" value="makeOrderButtonCommand"/>
<a href="" onclick="parentNode.submit();
return false;">
<i class="fa fa-shopping-cart fa-fw"></i>
<fmt:message key="index.button.makeOrder" />
</a>
</form>
</li>
<c:if test="${sessionScope.userTypeID == 1}">
<li>
<form name="adminZoneButton" method="post" action="CarRentalServlet">
<input type="hidden" name="command" value="adminZoneButtonCommand"/>
<a href="" onclick="parentNode.submit();
return false;">
<i class="fa fa-wrench fa-fw"></i>
<fmt:message key="index.button.adminZone" />
</a>
</form>
</li>
</c:if>
</c:if>
</ul>
<!-- /#side-menu -->
</div>
<!-- /.sidebar-collapse -->
</div>
it redirects me to the correct endpoint /CarRentalServlet, but login isn't working at all.
For example, if I don't use SecurityConfiguration class, but I'll modify my jsp file like:
action="CarRentalServlet" instead of action="${pageContext.request.contextPath}/login" and name="login" instead of name="username"
it works as expected and login is working, but in this case I don't use Spring Security.
Can someone suggest me how to fix Spring Security configuration or JSP form to make login work as it works without Spring Security.
The problem was because of usage <c:if test="${!empty sessionScope.userName}"> and <c:if test="${sessionScope.userTypeID == 1}"> in jsp files.
To fix it, I've used authorize tag. So I've changed to <sec:authorize access="isAuthenticated()"> and <sec:authorize access="hasRole('ADMIN')"> accordingly.
I do not know why registerSubmit function is not running when submitting the registration form (register.html), my guess is that it has something to do with how Spring Security works. Even tried with a simple controller method that returns a view, but that is not executed at all, all I see when clicking submit is the same page.
RegisterController.java
#RequestMapping(value = {"/register"}, method = RequestMethod.POST)
public String registerSubmit(#Valid User user, BindingResult bindingResult){
if (bindingResult.hasErrors()){
return "register";
}
User userFound = userRepository.findByEmail(user.getEmail());
if (userFound != null)
{
System.out.println("User already in database");
return "register";
}
return "result";
}
register.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Register Page</title>
</head>
<body>
<h1>Register page</h1>
<form action="#" th:action="#{/register}" th:object="${user}" method="post">
<table>
<tr>
<td> <label for="firstName">First name:</label> </td>
<td><input type="text" th:field="*{firstName}" id="firstName" /> </td>
<td th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}">firstName error</td>
</tr>
<tr>
<td><label for="lastName">Last name:</label> </td>
<td><input type="text" th:field="*{lastName}" id="lastName" /></td>
<td th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}">lastName error</td>
</tr>
<tr>
<td><label for="email">email:</label> </td>
<td><input type="text" th:field="*{email}" id="email" /></td>
<td th:if="${#fields.hasErrors('email')}" th:errors="*{email}">email error</td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
<a th:href="#{/login}">Login</a>
</body>
</html>
SecurityConfig.java, I've disabled csrf protection as #M. Deinum suggested, but that doesn't work either.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user#mail.com"). password("{noop}pass").roles("USER");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers( "/register", "/login").permitAll()
.antMatchers("/result").permitAll()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("email")
.defaultSuccessUrl("/profile", true)
.permitAll()
.and()
.logout()
.permitAll();
}
}
Try by adding consuming data type to headers.
#RequestMapping(
value = "/register",
method = RequestMethod.POST,
headers="Accept=application/x-www-form-urlencoded")
public String registerSubmit(#Valid User user, BindingResult bindingResult){
if (bindingResult.hasErrors()){
return "register";
}.....
If this is not working you can find more details about your error by using Postman like a tool to send requests and find out what are the accepting request by debugging your server-side code. If there is an issue with spring security such as AuthenticationFailure the error should be logged in the console.
Ok, apparently the register method was stuck here
if (bindingResult.hasErrors()){
return "register";
}
I've built a webapp from scratch using Spring boot and Java. Now I want to integrate Spring Security into the system.
However, I'm having problem with logging in using Spring Security. I used a customize login page and I had configured it correctly. Not sure what am I missing.
Main
#SpringBootApplication
#ComponentScan(basePackages = {"com.security"}, basePackageClasses = {LoginController.class})
#EntityScan(basePackages = {"com.auth"})
#EnableJpaRepositories(basePackages = {"com.auth.repository"})
public class CpexProjectApplication {
public static void main(String[] args) {
SpringApplication.run(CpexProjectApplication.class, args);
}
}
Controller
#Controller
public class LoginController {
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String getLogin() {
return "login";
}
}
Security Config
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
#EnableJpaRepositories(basePackageClasses = UserRepository.class)
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(getPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/css/**","/scss/**","/vendor/**","/img/**","/js/**").permitAll()
.antMatchers(HttpMethod.POST, "/home/**").hasRole("ADMIN")
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/home/**")
.permitAll();
}
private PasswordEncoder getPasswordEncoder() {
return new PasswordEncoder() {
#Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
#Override
public boolean matches(CharSequence charSequence, String s) {
return true;
}
};
}
}
Custom class of UserDetails
#SuppressWarnings("serial")
public class CustomUserDetails extends User implements UserDetails {
public CustomUserDetails(final User user) {
super(user);
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getRoles()
.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
.collect(Collectors.toList());
}
#Override
public String getPassword() {
return super.getPassword();
}
#Override
public String getUsername() {
return super.getName();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
application.properties
#CPEX database - UAT
spring.datasource.url=jdbc:sqlserver://10.100.2.254;databaseName=ROOT
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.hibernate.ddl-auto=update
#View Resolver
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
#Bean Override
spring.main.allow-bean-definition-overriding=true
#For detailed logging during dev
logging.level.org.springframework=DEBUG
#Tomcat default port
server.port=8888
login page
<!DOCTYPE html>
<html lang="en">
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>CPEX - Login</title>
<!-- Custom fonts for this template-->
<link type="text/css" href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="css/sb-admin-2.min.css" rel="stylesheet">
</head>
<body class="bg-gradient-primary">
<div class="container">
<!-- Outer Row -->
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<!-- Nested Row within Card Body -->
<div class="row">
<div class="col-lg-6 d-none d-lg-block bg-login-image border-right border-3">
<img class="img-responsive" src="img/sbc-logo.png" alt="">
<div id="loginSuccessAlert" class="alert alert-success" style="display: none;">
<strong>Login Successful!</strong>
</div>
<div id="loginDangerAlert" class="alert alert-danger" style="display: none;">
<strong>Please check your credentials.</strong>
</div>
</div>
<div class="col-lg-6">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4 display-4">CP Exchange</h1>
</div>
<form id="loginForm" class="user" action="home" method="POST">
<div class="form-group">
<input type="text" class="form-control form-control-user" id="name" name="name" placeholder="Enter Username...">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-user" id="password" name="password" placeholder="Password">
</div>
<input class="btn btn-primary btn-user btn-block" type="submit" value="Login" />
<hr>
</form>
<div class="text-center">
<a class="small" href="#">Forgot Password?</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="js/sb-admin-2.min.js"></script>
<!-- <script src="js/custom/validateLogin.js"></script> -->
</body>
</html>
home page
code is too long
CustomUserDetailsService
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
Optional<User> optionalUsers = userRepository.findByName(name);
optionalUsers
.orElseThrow(() -> new UsernameNotFoundException("Username not found"));
return optionalUsers
.map(CustomUserDetails::new).get();
}
}
TIA
Just noticed your Login JSP Submit will trigger /home which you have configured as defaultSuccessUrl and it will return Login page as you are not yet logged in.
Please change below line in your login.jsp
<form id="loginForm" class="user" action="home" method="POST">
to
<form id="loginForm" class="user" action="perform_login" method="POST">
Also you can remove this line
.antMatchers(HttpMethod.POST, "/home/**").hasRole("ADMIN")
and add
.loginProcessingUrl("/perform_login")
from configure method for now just to try.
If it works go ahead and add other configuration one by one.
http
.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/css/**","/scss/**","/vendor/**","/img/**","/js/**").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/perform_login") // add Login submit url
.defaultSuccessUrl("/home/**")
.permitAll();
EDIT 1:
If you are using inMemoryAuthentication add userDetailsService as well like this
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(getPasswordEncoder())
.withUser("admin").password("aaa11111").roles("ADMIN").and()
.withUser("user").password("bbb22222").roles("USER");
auth.userDetailsService(userDetailsService);
}
I've generated a Spring Boot web application using Spring Initializer, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file.
Technologies used:
Spring Boot 1.4.2.RELEASE, Spring 4.3.4.RELEASE, Thymeleaf 2.1.5.RELEASE, Tomcat Embed 8.5.6, Maven 3, Java 8
This is my security config class:
#Configuration
#EnableWebSecurity
#PropertySource("classpath:/config/app-${APP-KEY}.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${securityConfig.formLogin.loginPage}")
private String loginPage;
#Bean
public StandardPasswordEncoder encoder() {
return new StandardPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage(loginPage)
.permitAll()
.loginProcessingUrl("/tdk/login")
.failureUrl("/tdk/login?error=true")
.defaultSuccessUrl("/events/list")
.and()
.exceptionHandling()
.accessDeniedPage("/denied")
.and()
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/mockup/**").permitAll()
.antMatchers("/users/**").permitAll()
.antMatchers("/books/**").permitAll()
.antMatchers("/welcome/**").authenticated()
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/index.html");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.passwordEncoder(new StandardPasswordEncoder())
.withUser("test1").password("c1f02fa50809b7f715576198eda6466cd17f63404ae6eded7c22290b025baf3868bc8f785267d4ae").roles("ADMIN").and()
.withUser("test2").password("test2").roles("USER").and()
.withUser("test3").password("test3").roles("SUPERADMIN");
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyDefaultConfig() {
return new PropertySourcesPlaceholderConfigurer();
}
}
This is my Junit Tests that works properly
public class StandardPasswordEncoderTests {
#Test
public void getPasswordForTest1() {
StandardPasswordEncoder encoder = new StandardPasswordEncoder();
String password = "test1";
assertTrue(
encoder.matches(password, "c1f02fa50809b7f715576198eda6466cd17f63404ae6eded7c22290b025baf3868bc8f785267d4ae"));
}
}
Here my login template
<form th:action="#{/tdk/login}" method="post">
<p th:if="${param.error}">
Bad Credentials ${param.error}
</p>
<p th:if="${loginError}" class="error">Wrong user or password</p>
<div class="input_label"><i class="fa fa-user"></i><input type="text" name="user" placeholder="User" /></div>
<div class="input_label"><i class="fa fa-key"></i><input type="password" name="pass" placeholder="Password" /></div>
<input type="submit" value="LOGIN" />
</form>
But whatever I put:
test1 / c1f02fa50809b7f715576198eda6466cd17f63404ae6eded7c22290b025baf3868bc8f785267d4ae
or
test2 / test2
I see the message Bad Credentials ${param.error} in the output of my template
The parameter names for username and password in your login page are not matching the names in Spring Security configuration.
You could change the Spring Security configuration to use the parameter names from your login page. Or you could change the login page to use the default parameter names.
See FormLoginConfigurer#usernameParameter:
The HTTP parameter to look for the username when performing authentication. Default is "username".
and FormLoginConfigurer#passwordParameter:
The HTTP parameter to look for the password when performing authentication. Default is "password".
Your modified login page (with default parameter names):
<form th:action="#{/tdk/login}" method="post">
<p th:if="${param.error}">
Bad Credentials ${param.error}
</p>
<p th:if="${loginError}" class="error">Wrong user or password</p>
<div class="input_label">
<i class="fa fa-user"></i>
<input type="text" name="username" placeholder="User" />
</div>
<div class="input_label">
<i class="fa fa-key"></i>
<input type="password" name="password" placeholder="Password" />
</div>
<input type="submit" value="LOGIN" />
</form>