spring security always returning anonymousUser - java

i have a spring security implementation for the existing spring based application, it always returns anonymous user regardless of what i supply at login page.
#Configuration
#EnableWebSecurity
#EnableGlobalAuthentication
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("ROLE_USER");
auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("configure called");
http.authorizeRequests()
.antMatchers("/*").access("hasRole('ROLE_USER')")
//.antMatchers("/*").access("IS_AUTHENTICATED")
.and().formLogin().loginPage("/login")
.usernameParameter("user").passwordParameter("passWord")
.and().csrf()
.and().exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
form from login.jsp:
<form action="/Patching/Authen" name="form1" method="POST" onsubmit="return validateForm();"><br><br>
<h1>User Login</h1>
<table>
<tr>
<th>Username</th>
<td><input type="text" name="username" id="user" required/></td>
</tr>
<tr>
<th>Password</th>
<td><input type="password" name="password" required/></td>
</tr>
</table><br><input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<input type="submit"><br><br><br>
</form>
While i do at my controller post the form submit :
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
anonymous authentication is returned.
P.S. I already have a login.jsp where I have the configured user and password parameter.
Help appreciated.

I tried whatever you suggest above...what worked for me is changing the form action on the login.jsp to "login" and modifying configure to
http.authorizeRequests()
.antMatchers("/", "/home").access("hasRole('USER')")
.antMatchers("/resources/**").permitAll()
//.antMatchers("/*").access("IS_AUTHENTICATED")
.anyRequest().authenticated()
.and().csrf().disable().formLogin().loginPage("/login").permitAll()
//.loginProcessingUrl("/Authen")
.usernameParameter("user").passwordParameter("passWord")
.defaultSuccessUrl("/Authen")
.failureUrl("/failedLogin")
.and().exceptionHandling().accessDeniedPage("/Access_Denied");
further I need to work on the flow of the existing implementation along with spring security.

Your config do not mention any authenticated uri pattern.
You need to add
anyRequest().authenticated()

Related

spring security login always redirect to failure url

I'm trying to use Spring Security in my application, But after hitting the login processing url defined in configure method of WebSecurityConfig Class, from login page, its always redirecting to the failurUrl even if the correct username and password is provided. I have seen a lot of similar problem like this but all of the solutions that were given did not work for me.
There's the code with the security config:
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests().
antMatchers(PUBLIC_MATCHERS).
permitAll().anyRequest().authenticated();
http
.formLogin().loginPage("/index").defaultSuccessUrl("/userFront",true).failureUrl("/index?error").permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/index?logout").deleteCookies("remember-me").permitAll()
.and()
.csrf().disable().cors().disable()
.rememberMe();
}
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userSecurityService).passwordEncoder(passwordEncoder());
}
And the service responsible for signing in (UserSecurityService.java)
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findByUsername(username);
if (user==null) {
LOG.warn("Username {} not found",username);
throw new UsernameNotFoundException("Username "+username+"not found");
}
return user;
}
finally the login form (index.html)
<form class="form-signin" th:action="#{/index}" method="post">
<h2 class="text-center">Sign In</h2>
<div class="form-group">
<input type="text" class="form-control" placeholder="Username"
required="required" roleId="username" name="username"
id="username " autofocus="autofocus">
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Password"
id="password" name="password" required="required"
roleId="inputPassword">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">Sign
In</button>
</div>
<div class="clearfix">
<label class="float-left form-check-label"><input
type="checkbox" name="remember-me" id="remember-me">
Remember me</label>
</div>
</form>
What i am missing here please im tired of searching everywhere ?
Do you have a method in your controller to handle POST to /login? If not, I suggest you change your GET controller method from /index to /login, change the form to POST to /login, and update the configure() method accordingly (change "/index" to "/login").
[Update]
Make sure your login method is only serving GET and let the Spring default handle the POST:
#RequestMapping(method = { RequestMethod.GET }, value = { "/login" })
public String index() {
return "login";
}

SpringBoot : where is the login form processed?

I need to do an action (namely updating a field in the user table) upon successful login. Yet I can't find where the login's data get processed.
The login view part regarding this form looks like :
<form th:action="#{/login}" th:object="${user}" method="post" role="login">
<h2 class="text-center" th:text="${companyName}"></h2>
<input type="email" id="username" name="username" autocomplete="username" th:placeholder="|Email#${clientEmailDomain}|" required class="form-control input-lg" />
<input type="password" class="form-control input-lg" id="password" name="password" autocomplete="current-password" placeholder="Password" required="" />
<button type="submit" class="btn btn-lg btn-primary btn-block">Log in</button>
</form>
The WebSecurityConfigAdapter includes :
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/",
"/css/**",
"/fonts/**",
"/img/**",
"/js/**",
"/register",
"/resetPassword",
).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/search/" + clientOsVersion)
.permitAll()
.and()
.logout()
.permitAll();
// THIS IS ONLY DURING DEV to access to the database
http.csrf().disable();
http.headers().frameOptions().disable();
// END OF DEV ONLY
}
In the login controller the following method is never called (although its counterpart "get" method is called) :
#PostMapping("/login")
public ModelAndView processLoginForm(ModelAndView modelAndView,
#Valid User user
) {
System.err.println("Processing login data"); // This line is NEVER printed!!!
// Here I need to update a user's attribute.
modelAndView.addObject("clientEmailDomain",
clientEmailDomain);
modelAndView.addObject("companyName",
companyName);
return modelaAndView;
}
What should I do to make my processLoginForm method used, or where should I put my piece of code to get some job done upon successful login before reaching the /search route because I only want the job to be done once per session (not every time the user makes a search) ?
Any help appreciated,

Spring Security - 405 Request Method 'POST' Not Supported

I have implemented Spring Security to my project, but I am getting status 405 when I try to log in. I have already added csrf token in the form.
This is the error I am getting when I send username and password:
HTTP Status 405 - Request method 'POST' not supported
Spring version: 4.0.2.RELEASED
<div class="login-form">
<c:url var="loginUrl" value="/login" />
<form action="${loginUrl}" method="post" class="form-horizontal">
<c:if test="${param.error != null}">
<div class="alert alert-danger">
<p>Invalid username and password.</p>
</div>
</c:if>
<c:if test="${param.logout != null}">
<div class="alert alert-success">
<p>You have been logged out successfully.</p>
</div>
</c:if>
<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="clientusername" placeholder="Enter Username" required>
</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="clientpassword" placeholder="Enter Password" required>
</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>
Security Configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("G2BUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.and().formLogin().loginPage("/login")
.usernameParameter("clientusername").passwordParameter("clientpassword")
.and().csrf()
.and().exceptionHandling().accessDeniedPage("/Access_Denied");
// .and().csrf().disable();
}
Controller:
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView loginPage() {
return new ModelAndView("login");
}
#RequestMapping(value="/logout", method = RequestMethod.GET)
public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/login?logout";
}
#RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
public ModelAndView accessDeniedPage(ModelMap model) {
model.addAttribute("user", getPrincipal());
return new ModelAndView("accessDenied");
}
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public ModelAndView adminPage(ModelMap model) {
model.addAttribute("user", getPrincipal());
return new ModelAndView("admin");
}
private String getPrincipal(){
String userName = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
userName = ((UserDetails)principal).getUsername();
} else {
userName = principal.toString();
}
return userName;
}
Almost every topic about this issue says that we need to add csrf token, but I already added. Am I missing something?
First of all csrf is enabled by default in Spring as of Spring 4.0 so there no need to explicitly enable it yourself.
Secondly, there is no endpoint for you to authenticate your login. What you're doing is sending a request to /login which only takes a GET request. You could create another controller method to receive that POST request and authenticate or you could use a UserDetailsService.
SecurityConfiguration
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login-form")
.anonymous()
.and()
.formLogin()
.loginPage("/user-login")
.defaultSuccessUrl("/admin", true) // the second parameter is for enforcing this url always
.loginProcessingUrl("/login")
.failureUrl("/user-login")
.permitAll();
}
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder pe = new BCryptPasswordEncoder();
auth.userDetailsService(userDetailsService).passwordEncoder(pe);
}
Here our view page is /user-login and the processing url is /login this means in your controller you need remove the mapping for /login and add the following:
Controller
#RequestMapping(value="/user-login", method=RequestMethod.GET)
public ModelAndView loginForm() {
return new ModelAndView("login-form");
}
And change your view.
View (login-form.jsp)
<c:url value="/login" var="loginUrl"/>
<form action="${loginUrl}" method="post" modelAttribute="user">
Username: <input type="text" id="username" name="username" placeholder=""><br>
Password: <input type="password" id="password" name="password" placeholder=""><br>
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
<button type="submit">Login</button>
</form>
I started getting the same thing when I added a successForwardUrl and found that the response on sucessful login is a POST to that endpoint or to "/" if not set. Once I enabled POST on the defined endpoint as well as GET all was fine.
You can set two endpoints for one url. But you cannot set any request parameter as required. As I saw your request map for login, you can set your request method like this:
#RequestMapping(value = "/login", method = { RequestMethod.GET, RequestMethod.POST })
public ModelAndView loginPage() {
return new ModelAndView("login");
}
Check your web.xml file you might forgot to keep "securityFilterChain"
Use this code in web.xml file
<!-- Security configuration goes here -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
You are calling for a POST yet have only defined GET methods. Change your endpoint to RequestMethod.POST
If you are using JSP/JSTL
Change
<form action="${loginUrl}" method="post"></form>
to
<form:form action="${loginUrl}" method="post" </form:form>
with tag declaration
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
solve my problem
Ensure that the Spring Security filter chain is registered.
With Java configuration, this can be done by creating a class that extends AbstractSecurityWebApplicationInitializer.
public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer {
}
Alternatively, edit web.xml and add the following code. (See the documentation.)
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Spring Boot custom login page displays 404

Hi I'm currently trying to set up a simple login page using Spring Boot Security but whenever I try to access the login view I get a 404 "page not found" error.
Security Config:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
}
}
Login view, using freemarker (located at main/resources/templates/login.ftl):
<body class="login">
<div>
<div class="login_wrapper">
<div class="animate form login_form">
<section class="login_content">
<form>
<h1>Login Form</h1>
<div>
<input type="text" class="form-control" placeholder="Username" required="" />
</div>
<div>
<input type="password" class="form-control" placeholder="Password" required="" />
</div>
<div>
<a class="btn btn-default submit" href="/units">Log in</a>
</div>
<div class="clearfix"></div>
</form>
</section>
</div>
</div>
</div>
</body>
Anyone know what I'm doing wrong? Thanks for the help!
You need to have a view controller for /login. either write a controller for that or following will do.
#EnableWebMvc
#ComponentScan("package_name")
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
// ...
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
To setup view rosolver:
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".ftl");
return resolver;
}
Now put your ftl files inside webapp/WEB-INF/pages directory. You're all set.

Spring Security 3 - always return error 302

I use Spring 4 to create a simple application. Recently, I'm adding Spring Security 3 to the project but always get the Error Code 302 ( so it redirect to home page always ).
Here is my SecurityConfig:
#Configuration
#EnableWebMvcSecurity
#ComponentScan(basePackages = { "com.moon.repository" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("hello").password("world").roles("USER");
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring().antMatchers("/resources/**", "/views/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/home")
.loginProcessingUrl("/acct/signin")
.and()
.logout()
.permitAll();
}
}
I have a Controller called AccountController:
#Controller
#RequestMapping(value = "/acct")
public class AccountController {
private final Logger logger = LoggerFactory.getLogger(AccountController.class);
#RequestMapping(value = "/signin", method = RequestMethod.POST)
public String signin(#RequestParam("username") String username,
#RequestParam("password") String password) {
logger.info("======== [username:{0}][password:{1}] ========", username, password);
if ("error#1.1".equalsIgnoreCase(username)) {
return "error";
} else {
return "demo";
}
}
}
My WEB-INF structure:
WEB-INF
----views
--------home.jsp
--------demo.jsp
--------error.jsp
The flow is like:
User access the web site with http://mylocal:8080/moon => it shows home.jsp
User press the button SignIn and it pops a sub-window asked for username and password => still in home.jsp
User press Submit button => I assume it will go /acct/signin and return to /demo, but I see Error 302 in Google Chrome and then it goes to /home again
Any ideas ? I'm stuck in 2 full days and now i'm almost in despair...
thank you very much every one to take a look at my problem
=================================== 1st Update ===================================
Update: The form in home.jsp
<form:form role="form" method="POST" action="acct/signin"
class="form-signin">
<div class="row">
<div class="col-lg-5">
<input name="username" size="20" type="email"
class="form-control" placeholder="Email address" required
autofocus>
<input name="password" type="password"
class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</div>
</div>
</form:form>
=================================== 2nd Update ===================================
I tried to implement UserDetailsService(not to use in-memory auth) but still... the same problem - Error 302
AppUserDetailsServiceImpl.java
#Component
public class AppUserDetailsServiceImpl implements UserDetailsService {
private final Logger logger = LoggerFactory.getLogger(AppUserDetailsServiceImpl.class);
#Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
logger.info("loadUserByUsername username=" + username);
logger.info("======== {} ========",SecurityContextHolder.getContext().getAuthentication());
if (!username.equals("hello")) {
throw new UsernameNotFoundException(username + " not found");
}
// creating dummy user details
return new UserDetails() {
private static final long serialVersionUID = 2059202961588104658L;
#Override
public boolean isEnabled() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public String getUsername() {
return username;
}
#Override
public String getPassword() {
return "world";
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> auths = new java.util.ArrayList<SimpleGrantedAuthority>();
auths.add(new SimpleGrantedAuthority("USER"));
return auths;
}
};
}
The log shows:
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](24) loadUserByUsername username=hello
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](25) ======== org.springframework.security.authentication.UsernamePasswordAuthenticationToken#f1e4f742: Principal: com.moon.repository.AppUserDetailsServiceImpl$1#e3dc1b1; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#12afc: RemoteIpAddress: 127.0.0.1; SessionId: 023BC9A8B997ECBD826DD7C33AF55FC7; Granted Authorities: USER ========
I believe Spring is redirecting you to /home because you didn't actually authenticated a User through the login process.
You access your web-app through http://mylocal:8080/moon returning the home.jsp view
You click the SignIn button, submitting your login form since no form login is explicitly declared, Spring Security will display the username and password prompt box for the end-user to enter its credentials
These credentials are then POSTed to the login processing URL (/acct/signin) for which you happen to have a mapping with the signin method in the AccountController
Such controller fails to authenticate a User the Spring way, but still redirect the request to /demo by returning a String
The /demo path is protected (.anyRequest().authenticated()) to any unauthenticated user, since the current user is indeed unauthenticated, Spring Security will automatically redirect the request to the login page
You end up on /home (.loginPage("/home"))
Using a InMemoryUserDetailsManagerConfigurer (see inMemoryAuthentication javadoc), you can only successfully login through the configured credentials. If you want a fully-fledged Authentication system, you must provide an UserDetailsService implementation to your Spring Security configuration (through the userDetailsService method).
EDIT : Following the conversation with chialin.lin, it seems the missing configuration was a defaultSuccessfulUrl for Spring Security to know where to redirect the user once authenticated.
To avoid having to create a new trivial SuccessHandler, override the successfulAuthentication method in your filter and just call the chain.doFilter() method after having set the Authentication object in the security context.
For me I came from a little different use-case but 'suddenly' had the same problem before it perfectly worked.
My Setup Spring with a ExtJs frontend where I now build in a rest interface.
It all worked super nice and then suddenly I started having http status 302 responses (WTH?)
Since I implemented by code by following this example: https://octoperf.com/blog/2018/03/08/securing-rest-api-spring-security/
there is a declaration of a SimpleUrlAuthenticationSuccessHandler.
See 4.4 SecurityConfig where the TokenAuthenticationFilter is constructed with a class NoRedirectStrategy; see 4.1 Redirect Strategy
In turn not having this NoRedirectStrategy set up in my extension of the AbstractAuthenticationProcessingFilter it would show me http 302 responses.
I had a problem with the following:
In my html that I set in the login settings
I didn't put /
In the end I was able to
<form class="form-signin" method="post" action="auth/login">
but it should have been
<form class="form-signin" method="post" action="/auth/login">
As a result, i could not login > got a 302 redirect error > and redirected again to a broken login page.
This is what the full working page looks like.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login customer</title>
</head>
<body>
<div class="container">
<form class="form-signin" method="post" action="/auth/login">
<h2 class="form-signin-heading">Login</h2>
<p>
<label for="username">Username</label>
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required>
</p>
<p>
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
</p>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
</body>
</html>

Categories