Spring Security login with own login page does not work - spring

I tried to login with my own login page and following error:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Aug 22 07:52:15 CEST 2017
There was an unexpected error (type=Not Found, status=404).
No message available
Here ist my SecurityConfiguration
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login", "/css/**",
"/image/**").permitAll().anyRequest()
.authenticated().and().formLogin().loginPage("/login.html").permitAll()
.and().logout().permitAll().and().csrf().disable();
}
#Autowired
protected void configureLDAP(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().userSearchFilter("uid={0}").contextSource()
.url("ldap://ldap.forumsys.com:389/dc=example,dc=com").managerPassword("password");
}
Login
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Login</title>
<meta name="description" content="description">
<meta name="author" content="author">
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<div class="container">
<div class="background"> </div>
<div class="card">
<img style="height:60px; width: auto; margin: 45px 100px;" src="image/picture.png">
<form name="f" action="/login" method="POST">
<div class="input">
<input placeholder="Benutzername" type="text" class="" name="username" required>
</div>
<div class="input">
<input placeholder="Passwort" type="password" class="" name="password" required>
</div>
<div class="">
<input name="submit" value="Login" class="btn" type="submit">
</div>
</form>
</div>
</div>
</body>
</html>
With the Login page from Spring it works without problems.

I think you got confused on what loginPage method does. JavaDoc:
Specifies the URL to send users to if login is required. ...
You must provide an URL to which your client will be redirected.
Change loginPage("/login.html") to loginPage("/login") and configure view resolving for that url. For example you can create another configuration like this:
#Configuration
public class LoginViewConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
Or add similar thing to your existing mvc config. This assumes you have view reolving configured somewhere else.

Related

ERR_TOO_MANY_REDIRECTS Spring Security

When using custom login page I am getting this error, please let me know where I am going wrong.
Controller:
<!-- language: java -->
#GetMapping("/login")
public String login(ModelMap model) {
List<String> authType = ldapAuthConfigService.getEnabledAuthentications();
model.addAttribute("authList", authType);
return "home";
}
Security config:
#EnableWebSecurity
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/**").authenticated().and().formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/layout", true).and()
.logout().clearAuthentication(true).invalidateHttpSession(true)
.logoutRequestMatcher(new AntPathRequestMatcher(
"/logout"))
.logoutSuccessUrl(
"/login?logout")
.permitAll().and().authenticationProvider(
customeAuthenticationProvider());
http.headers().disable();
if (protocol != null && protocol.equalsIgnoreCase("http")) {
http.requiresChannel().anyRequest().requiresInsecure();
} else {
http.requiresChannel().anyRequest().requiresSecure();
}
}
}
I added viewController and removed it from GetMapping in controller, it was working fine but i need to add a model map before loading login page
'''
#Component
public class WebConfig implements WebMvcConfigurer {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/script-api/**").addResourceLocations("classpath:/static/script-api/");
registry.addResourceHandler("/theme/**").addResourceLocations("classpath:/static/theme/");
if (!registry.hasMappingForPattern("/webjars/**")) {
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
if (!registry.hasMappingForPattern("/**")) {
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
}
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("home");
}
}
'''
This is my view page home.html
'''
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<title>EZENGAGE</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<!-- VENDOR CSS -->
<link rel="stylesheet" type="text/css"
th:href="#{/theme/assets/vendor/bootstrap/css/bootstrap.min.css}" />
<link rel="stylesheet" type="text/css"
th:href="#{/theme/assets/vendor/daterangepicker/daterangepicker.css}" />
<link rel="stylesheet" type="text/css"
th:href="#{/theme/assets/vendor/font-awesome/css/font-awesome.min.css}" />
<link rel="stylesheet" type="text/css"
th:href="#{/theme/assets/vendor/animate-css/vivify.min.css}" />
<link rel="stylesheet" type="text/css"
th:href="#{/theme/assets/vendor/c3/c3.min.css}" />
<link rel="stylesheet" type="text/css"
th:href="#{/theme/assets/vendor/chartist/css/chartist.css}" />
<link rel="stylesheet" type="text/css"
th:href="#{/theme/assets/vendor/chartist-plugin-tooltip/chartist-plugin-tooltip.css}" />
<link rel="stylesheet" type="text/css"
th:href="#{/theme/assets/vendor/toastr/toastr.min.css}" />
<!-- MAIN CSS -->
<link rel="stylesheet" type="text/css"
th:href="#{/theme/dark/assets/css/site.min.css}" />
</head>
<body class="theme-cyan">
<div class="pattern">
<span class="red"></span> <span class="indigo"></span> <span
class="blue"></span> <span class="green"></span> <span class="orange"></span>
</div>
<div class="auth-main particles_js">
<div class="auth_div vivify popIn">
<div class="card text-white text-center mx-auto"
style="width: 350px; background: #343840; box-shadow: 5px 5px 10px black;">
<div class="card-header">
<img class=" card-title img-fluid logo"
th:src="#{/theme/assets/images/ezelink-white-logo.png}"
alt="EZELink Logo" style="width: 150px;" />
</div>
<form class="form-auth-small m-t-20" th:action="#{/login}" method="post"
name="login-form" th:autocomplete="off">
<div th:if="${param.error}">
<div class="alert alert-danger">Username or password is
invalid, please try again.</div>
</div>
<div th:if="${param.logout}">
<div class="alert alert-danger">You have been logged out.</div>
</div>
<div class="card-body form-group">
<div class="mb-3">
<label for="login-username" class="form-label"></label> <input
type="text" name="username" id="login-username"
class="form-control" placeholder="Username"
aria-describedby="helpId">
</div>
<div class="mb-3 form-group">
<label for="login-password" class="form-label"></label> <input
type="password" class="form-control" name="password"
id="login-password" placeholder="Password">
</div>
<div class="mb-3 form-group">
<th:block th:if="${#lists.size(authList) > 0}">
<select class="form-control" th:required="required"
id="authType" name="authType" th:size="1">
<option th:each="list : ${authList}" th:value="${list}"
th:text="${list}" th:checked="${list}"></option>
</select>
</th:block>
</div>
</div>
<div class="card-footer text-muted" style="background: #343840">
<button type="submit" class="btn btn-primary btn-block form-group"
style="width: 300px; right: 20px;">Login</button>
</div>
</form>
</div>
</div>
<div id="particles-js"></div>
<script th:src="#{/theme/dark/assets/bundles/libscripts.bundle.js}"></script>
<script
th:src="#{/theme/dark/assets/bundles/vendorscripts.bundle.js}"></script>
<script
th:src="#{/theme/dark/assets/bundles/mainscripts.bundle.js}"></script>
</div>
</body>
</html>
'''
This is my view page
I was able to reproduce this issue. Whith a login page defined as
.loginPage("/login")
and with the original controller
#GetMapping("login")
public String login() {
return "home";
}
I get
http: error: Too many redirects (--max-redirects=30).
With the following config
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/**").authenticated()
.and().formLogin()
.loginPage("/login")
I get an expected response
home
The issue may also be solved with this config:
http.csrf().disable()
.authorizeRequests()
.antMatchers("/**").authenticated()
.and().formLogin()
.loginPage("/login").permitAll()

Securing Web Application with Spring Boot is not working

I have implemented an example from official spring guide:
Securing a Web Application
I put three html files /resources/templates:
HELLO.HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="#{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
HOME HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
<p>Click <a th:href="#{/hello}">here</a> to see a greeting.</p>
</body>
</html>
LOGIN HTML
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="#{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
The MVC configuration is
#Configuration
public class MVCConfig {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
The security configuration class:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/home").permitAll().anyRequest().authenticated().and().formLogin()
.loginPage("/login").permitAll().and().logout().permitAll();
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
When I run the application and open the 127.0.0.1:8080/ link, I encounter the error:
There was an unexpected error (type=Not Found, status=404).
No message available
I removed the thymeleaf tags from the files and made the files static. Then I moved them to /static.
The login form is as follows:
<form "/login" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
And changed the SecurityConfig:
http.authorizeRequests().antMatchers("/", "/home").permitAll().anyRequest().authenticated().and().formLogin()
.loginPage("**/login.html**").permitAll().and().logout().permitAll();
Now I can open the location 127.0.0.1:8080/login.html, but no authentication happens after submitting the form. (403 Error is shown)
What should I do?
This is an old question and you should have already solved it. Anyway, if someone else has this problem, I am also new in the spring and had the same problem as you in this tutorial. So I tried to solve the thymeleaf problem and everything started to work correctly, including authentication.
All I did was include the following dependencies in my pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

Springboot authentication issue

I have a spring boot application with spring security configured. I have redirected the login request to http://localhost:8000 where I'm running my front-end on a python server. Now when I try to post the login to my springboot application, it doesn't work. Even when I try from my postman, it says 405 error. How can I get this working. It works from /login if I put it as html in the same project but not from the python server or postman. What is the difference.
"message": "Request method 'POST' not supported",
"path": "/login"
Form Data
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<!-- Add page specific code/html START -->
<div class="container">
<h1 th:text="#{welcome.message}"></h1>
<form class="form-signin" name="loginForm" th:action="#{/login}" action="/login" method="POST">
<h2 class="form-signin-heading">Please sign in</h2>
<label for="username" class="sr-only">Email address</label>
<input type="text" name="username" id="username" class="form-control" placeholder="Username" required="required" autofocus="autofocus" />
<label for="password" class="sr-only">Password</label>
<input type="password" name="password" id="password" class="form-control" placeholder="Password" required="required" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div> <!-- /container -->
</body>
</html>
HTML code hosted on photon server
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Assessment App</title>
<link href="../css/bootstrap.min.css" rel="stylesheet">
<link href="../css/main.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid">
<div class="panel panel-default main-header">
<div class="panel-body">
<div class ="pull-left">Assessments</div>
</div>
</div>
<div class="row">
<div class="login-container col-md-4 col-md-offset-4 col-sm-10 col-sm-offset-1 col-xs-12 col-xs-offset-0">
<div class="panel panel-login">
<div class="panel-heading">
<div class="panel-title">Sign In</div>
</div>
<div class="panel-body">
<form id="loginform" class="form-horizontal" role="form">
<div class="input-group assessment-input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input id="login-username" type="text" class="form-control" name="username" value="" placeholder="Username">
</div>
<div class="input-group assessment-input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
<input id="login-password" type="password" class="form-control" name="password" placeholder="Password">
</div>
<div class="form-group">
<div class="col-sm-12 controls">
<input class="btn btn-primary" type="submit" value="Login">
</div>
</div>
</form>
<div class="login-form-error-text hidden">Invalid credentials</div>
</div>
</div>
</div>
</div>
</div>
<script src="../javascript/jquery-3.3.1.min.js"></script>
<script src ="../javascript/bootstrap.min.js"></script>
<script src="../javascript/lodash.min.js"></script>
<script src="../javascript/login.js"></script>
</body>
</html>
Corresponding js
$(document).ready(function () {
$('#loginform').submit(function (event) {
event.preventDefault();
$.ajax({
url : 'http://localhost:8080/j_spring_security_check',
type : 'POST',
contentType : 'application/json',
data : JSON.stringify({ j_username : $('#login-username').val(), j_password : $('#login-password').val() }),
success : function () {
window.location.href = '../html/assessment.html';
},
error : function () {
event.preventDefault();
alert('failed');
}
});
});
$('.form-tab-header').on('click', function () {
$('.login-form-error-text').addClass('hidden');
$('.form-tab-header').removeClass('active');
$(this).addClass('active');
$('.form-horizontal').addClass('hidden');
$('.' + $(this).attr('id') + '-content').removeClass('hidden');
});
});
Security Config
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${ldap.urls}")
private String ldapUrls;
#Value("${ldap.base.dn}")
private String ldapBaseDn;
#Value("${ldap.user.dn.pattern}")
private String ldapUserDnPattern;
#Value("${ldap.enabled}")
private String ldapEnabled;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login**").permitAll()
.antMatchers("/assessments/**").fullyAuthenticated()
.antMatchers("/").permitAll()
.and()
.formLogin()
//.loginPage("http://htmlcode.s3-website.us-east-2.amazonaws.com")
.loginPage("http://localhost:8000")
.loginProcessingUrl("/j_spring_security_check")
.usernameParameter("j_username")
.passwordParameter("j_password")
//.loginPage("/login")
.failureUrl("/login?error")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/register");
// .antMatchers("/assessments/**");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
if(Boolean.parseBoolean(ldapEnabled)) {
auth.ldapAuthentication()
.userDetailsContextMapper(userDetailsContextMapper())
.userDnPatterns(ldapUserDnPattern)
.contextSource()
.url(ldapUrls+ldapBaseDn);
}
}
#Bean
public UserDetailsContextMapper userDetailsContextMapper() {
return new LdapUserDetailsMapper() {
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
UserDetails details = super.mapUserFromContext(ctx, username, authorities);
return details;
}
};
}
#Bean
CorsFilter corsFilter() {
CorsFilter filter = new CorsFilter();
return filter;
}
}
You have forgotten to include csrf values.this is a security precaution mechanism to prevent cross site attacks. your have two options as a workaround :
1.Disabling CSRF:
as csrf is enabled by default, both POSTs and PUT Http methods are not allowed with CSRF enabled.
for disabling it you should add this to your security config
.csrf().disable()
for example you could have such thing:
http.
.csrf().disable().
authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.and()
.formLogin().loginPage("/login").failureUrl("/login?error")
.usernameParameter("username").passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/login?logout")
.and()
.exceptionHandling().accessDeniedPage("/403");
2.Send csrf token values :
If you are using login page with login form, we need to always include the CSRF token in the login form as a hidden parameter manually in the code:
<input
type="hidden"
th:name="${_csrf.parameterName}"
th:value="${_csrf.token}" />
if you want to login by ajax you should also include these two parameters included:
first hold the values in some variables:
<script type="text/javascript">
var csrfParameter = '${_csrf.parameterName}';
var csrfToken = '${_csrf.token}';
</script>
then include those into
var jsonParams = {};
jsonParams['parentId'] = 1;
jsonParams[csrfParameter] = csrfToken;
// include other values pass ,user, etc.
$.ajax({
type: 'POST',
cache: false,
url: /login,
data: jsonParams,
dataType = 'json',
contentType = 'application/json',
...
});
More Information
https://www.baeldung.com/spring-security-csrf
Ajax POST results in a 405 (Method Not Allowed) - Spring MVC
https://matthewbusche.com/2016/08/06/using-csrf-with-spring-security-and-ajax-calls/
Spring Security - 405 Request Method 'POST' Not Supported
HTTP 405 Not Allowed - Spring Boot + Spring Security
405 Method Not Allowed for POST
Spring Boot + Security + Thymeleaf and CSRF token not injected automatically

Springboot authentication issue with customer login

I have a spring boot application with spring security configured. I have redirected the login request to http://localhost:8000 where I'm running my front-end on a python server. Now when I try to post the login to my springboot application, it doesn't work. I looked into some posts online and changed the login path to /j_spring_security_check but it doesn't even seem to be trying to login as I don't see any logs in the console. Its taking me to login?error .Are there any other places where I can check the logs. Can I debug this somehow from some springboot classes.
Form Data
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<!-- Add page specific code/html START -->
<div class="container">
<h1 th:text="#{welcome.message}"></h1>
<form class="form-signin" name="loginForm" th:action="#{/login}" action="/login" method="POST">
<h2 class="form-signin-heading">Please sign in</h2>
<label for="username" class="sr-only">Email address</label>
<input type="text" name="username" id="username" class="form-control" placeholder="Username" required="required" autofocus="autofocus" />
<label for="password" class="sr-only">Password</label>
<input type="password" name="password" id="password" class="form-control" placeholder="Password" required="required" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div> <!-- /container -->
</body>
</html>
HTML code hosted on photon server
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Assessment App</title>
<link href="../css/bootstrap.min.css" rel="stylesheet">
<link href="../css/main.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid">
<div class="panel panel-default main-header">
<div class="panel-body">
<div class ="pull-left">Assessments</div>
</div>
</div>
<div class="row">
<div class="login-container col-md-4 col-md-offset-4 col-sm-10 col-sm-offset-1 col-xs-12 col-xs-offset-0">
<div class="panel panel-login">
<div class="panel-heading">
<div class="panel-title">Sign In</div>
</div>
<div class="panel-body">
<form id="loginform" class="form-horizontal" role="form">
<div class="input-group assessment-input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input id="login-username" type="text" class="form-control" name="username" value="" placeholder="Username">
</div>
<div class="input-group assessment-input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
<input id="login-password" type="password" class="form-control" name="password" placeholder="Password">
</div>
<div class="form-group">
<div class="col-sm-12 controls">
<input class="btn btn-primary" type="submit" value="Login">
</div>
</div>
</form>
<div class="login-form-error-text hidden">Invalid credentials</div>
</div>
</div>
</div>
</div>
</div>
<script src="../javascript/jquery-3.3.1.min.js"></script>
<script src ="../javascript/bootstrap.min.js"></script>
<script src="../javascript/lodash.min.js"></script>
<script src="../javascript/login.js"></script>
</body>
</html>
Corresponding js
$(document).ready(function () {
$('#loginform').submit(function (event) {
event.preventDefault();
$.ajax({
url : 'http://localhost:8080/j_spring_security_check',
type : 'POST',
contentType : 'application/json',
data : JSON.stringify({ j_username : $('#login-username').val(), j_password : $('#login-password').val() }),
success : function () {
window.location.href = '../html/assessment.html';
},
error : function () {
event.preventDefault();
alert('failed');
}
});
});
$('.form-tab-header').on('click', function () {
$('.login-form-error-text').addClass('hidden');
$('.form-tab-header').removeClass('active');
$(this).addClass('active');
$('.form-horizontal').addClass('hidden');
$('.' + $(this).attr('id') + '-content').removeClass('hidden');
});
});
Security Config
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${ldap.urls}")
private String ldapUrls;
#Value("${ldap.base.dn}")
private String ldapBaseDn;
#Value("${ldap.user.dn.pattern}")
private String ldapUserDnPattern;
#Value("${ldap.enabled}")
private String ldapEnabled;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login**").permitAll()
.antMatchers("/assessments/**").fullyAuthenticated()
.antMatchers("/").permitAll()
.and()
.formLogin()
//.loginPage("http://htmlcode.s3-website.us-east-2.amazonaws.com")
.loginPage("http://localhost:8000")
.loginProcessingUrl("/j_spring_security_check")
.usernameParameter("j_username")
.passwordParameter("j_password")
//.loginPage("/login")
.failureUrl("/login?error")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/register");
// .antMatchers("/assessments/**");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
if(Boolean.parseBoolean(ldapEnabled)) {
auth.ldapAuthentication()
.userDetailsContextMapper(userDetailsContextMapper())
.userDnPatterns(ldapUserDnPattern)
.contextSource()
.url(ldapUrls+ldapBaseDn);
}
}
#Bean
public UserDetailsContextMapper userDetailsContextMapper() {
return new LdapUserDetailsMapper() {
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
UserDetails details = super.mapUserFromContext(ctx, username, authorities);
return details;
}
};
}
#Bean
CorsFilter corsFilter() {
CorsFilter filter = new CorsFilter();
return filter;
}
}
I was finally able to fix this by removing JSON.stringfy in my post body of ajax request and setting the content type to application/x-www-form-urlencoded.

Spring Security doesn't post to provided login processing url

For some weird reason, I cannot hit the controller that is registered to handle login posts. I just get redirected to this silly image that is in my resources folder:
https://localhost:8443/images/piggy-bank.jpeg
Here is my controller.
#RequestMapping(value = "/login/process", method = RequestMethod.POST)
public String loginPost(HttpSession session, Authentication authentication) {
String client_id = (String) session.getAttribute("client_id");
if (client_id.equals(Constants.TRUSTED_CLIENT)) {
//TODO:
/*
* 1. Generate an access_token
* 2. Save to database
* 3. Form redirect url with all necessary tokens
* 4. Return redirect url string
*/
return "redirect:" + Constants.REDIRECT_TRUSTED_CLIENT;
}
long userId = AuthenticationUtils.getAuthenticatedUserId(authentication);
return "/user/" + userId;
}
Here is my security configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/","/sign_up","/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.loginPage("/login")
.loginProcessingUrl("/login/process")
.defaultSuccessUrl("/")
.failureUrl("/access_denied")
.and()
.csrf()
.and()
.exceptionHandling()
.accessDeniedPage("/access_denied")
.and()
.logout()
.permitAll();
}
}
And here's the view:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<title>Spring App</title>
<!--/*/ <th:block th:include="fragments/headerinc :: head"></th:block> /*/-->
</head>
<body>
<div class="container">
<!--/*/ <th:block th:include="fragments/header :: header"></th:block> /*/-->
<div id="mainWrapper">
<div class="login-container">
<div class="login-card">
<div class="login-form">
<form th:action="#{/login/process}" method="post" class="form-horizontal">
<div th:if="${param.error != null}">
<div class="alert alert-danger">
<p>Invalid username and password.</p>
</div>
</div>
<div th:if="${param.logout != null}">
<div class="alert alert-success">
<p>You have been logged out successfully.</p>
</div>
</div>
<div class="input-group input-sm">
<label class="input-group-addon" for="username"><i class="fa fa-user"></i></label>
<input type="text" class="form-control" id="username" name="username" placeholder="Enter Username" />
</div>
<div class="input-group input-sm">
<label class="input-group-addon" for="password"><i class="fa fa-lock"></i></label>
<input type="password" class="form-control" id="password" name="password" placeholder="Enter Password" />
</div>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<div class="form-actions">
<input type="submit"
class="btn btn-block btn-primary btn-default" value="Log in"/>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Inspecting my network data, I see that the form post to /login/process was successful and the server responded fine!
Request URL:https://localhost:8443/login/process
Request Method:POST
Status Code:302 Found
Remote Address:[::1]:8443
The log during spring startup also affirms the registration of url "/login/post" to the aforementioned controller. Corresponding log:
2016-04-21 20:44:30.725 INFO 25290 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/login/process],methods=[POST]}" onto public java.lang.String com.springapp.controllers.UserController.loginPost(javax.servlet.http.HttpSession,org.springframework.security.core.Authentication)
The situation may be something more insidious, because I can't seem to be redirected to even the defaultSuccessURL page, i.e. the index ("/"). The same is the case (i.e. loginProcessingURL and defaultSuccessfulURL not redirecting) exists even if I use the default out-of-box login view. Is there something wrong with my jsp view? Am I missing some security configuration?
However, manually entering /user/{id} OR any other url successfully lands me to the target url as long as I'm properly authenticated. What does that mean?
Finally here is the 'header.html' and 'headerinc.html' thymeleaf fragments which are inserted in all my jsp:
header.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<link href="../../static/css/app.css"
th:href="#{css/app.css}" rel="stylesheet" media="screen"/>
<link href="../../static/css/bootstrap.css"
th:href="#{css/bootstrap.css}" rel="stylesheet" media="screen"/>
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css"
th:href="#{/webjars/font-awesome/4.2.0/font-awesome.css}" rel="stylesheet" media="screen"/>
</head>
<body>
<div class="container">
<div th:fragment="header">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#" th:href="#{/}">Home</a>
<ul class="nav navbar-nav">
<!-- if logged in, then display -logout, else display -login, -Sign up. -->
<div th:with="currentUser=${#httpServletRequest.userPrincipal?.name}">
<div th:if="${currentUser != null}">
<form th:action="#{/logout}" method="post">
<input type="submit" value="Log out"/>
</form>
</div>
<div th:if="${currentUser == null}">
<li>Log in</li>
<li>Sign up</li>
</div>
<!-- This is to simply test some authentication logic-->
All Users
</div>
</ul>
</div>
</div>
</nav>
<div class="jumbotron">
<div class="row text-center">
<div class="">
<h2>Spring Framework Example..</h2>
<h3>Spring Boot Web App</h3>
</div>
</div>
<div class="row text-center">
<img src="../../static/images/NewBannerBOOTS_2.png" width="400"
th:src="#{/images/piggy-bank.jpeg}"/>
</div>
</div>
</div>
</div>
</body>
</html>
headerinc.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en" th:fragment="head">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" media="screen" />
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="../static/css/guru.css"
th:href="#{/css/guru.css}" rel="stylesheet" media="screen"/>
</head>
<body>
</body>
</html>
This line:
.loginProcessingUrl("/login/process")
tells Spring Security to process the submitted credentials when sent the specified path and, by default, redirect user back to the page user came from. It will not pass the request to Spring MVC and your controller.
Maybe what you want instead of a request mapping is a custom AuthenticationSuccessHandler.
I had also the same issue very recently.
In my case, I had to add this code
<public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**","/assets/**", "/css/**");
}
Note:
Be careful not to use .anyRequest() here, like in
web.ignoring().antMatchers("/js/**","/assets/**", "/css/**").anyRequest()
Because that also gave me a lot of problems ...

Resources