I have a problem with Spring Security and error pages , becaus when I am logged in the application I can show when the page is not exist.
But when I am out of the application my spring security show the login page by default.
This is my spring security configuration.
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private DataSource dataSource;
#Value("${spring.queries.users-query}")
private String usersQuery;
#Value("${spring.queries.roles-query}")
private String rolesQuery;
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.
jdbcAuthentication()
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(rolesQuery)
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/registration").permitAll()
.antMatchers("/admin/**").hasAuthority("ADMIN")
.antMatchers("/user_login").hasAuthority("USER").anyRequest()
.authenticated().and().csrf().disable().formLogin()
.loginPage("/login").failureUrl("/login?error=true")
.defaultSuccessUrl("/user_login")
.usernameParameter("email")
.passwordParameter("password")
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/")
.and().exceptionHandling()
.accessDeniedPage("/access-denied");
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
}
}
This works correctly but I don't know why when I am out of the application I redirect to login page.
Any solution for this?
Regards!
All the requests other than /, /login, /registration requires the user to be authenticated (anyRequest().authenticated()), and when you are enabling formLogin() spring's filters will redirect all the not authenticated requests to the login page even if the page doesn't exits, thats is why you are redirected to the login and not getting a 404 error.
For testing purposes you can add a test matcher without adding an actual endpoint in the controller like this:
.antMatchers("/test").permitAll() and try to access this endpoint without being authenticated and you will get the 404 error page.
p.s. make sure that the 404 response is not blocked as well (if it is a controller response then enable it as well, because your js is allowed for everyone).
Related
I have a Spring Security configuration like this:
#Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/**").hasAuthority("Business_User")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password");
http.headers().frameOptions().disable();
}
The authentication works fine. However, if an authentication failed because of either invalid user or wrong password, a standard Spring login page is returned and the return code is 200.
This is not what I expect.
How I can config Spring Security to return 401 and an empty response body if the user failed login?
You can do this if authentication failed spring security handle it by redirecting you to the login page but you can manage it by adding the following code:
http
.exceptionHandling()
.authenticationEntryPoint(new org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint("headerValue"));
or
you can also use HttpStatusEntryPoint like this
http
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
I have an application providing several REST endpoints and web pages as well.
/products -- REST endpoint
/cutomers -- REST endpoint
/ui/catalog -- Web
/ui/admin -- Web
I want to set up the security so all web starting with /ui/** are redirected to a login page and all the others (REST) are challenged with 401 and WWW-Authenticate.
With the following settings the login page is not permitted and 401 with the header is sent:
#Configuration
#Order(20)
#RequiredArgsConstructor
class RestConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.requestMatcher(AnyRequestMatcher.INSTANCE)
.authorizeRequests().anyRequest().fullyAuthenticated();
httpSecurity.
requiresChannel().
requestMatchers(AnyRequestMatcher.INSTANCE).
requiresSecure();
}
}
#Configuration
#Order(10)
#RequiredArgsConstructor
class WebUIConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.antMatcher("/ui/**")
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
Why this doesn't work? I would expect to be redirected to the login page (it works) and the login page to be 200 (it doesn't work).
Editing the WebUIConfigurationAdapter as follows solves the problem:
httpSecurity.requestMatchers()
.antMatchers("/ui/**", "/login", "/logout")
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
The URL /login is set by WebUIConfigurationAdapter so it is then excluded by RestConfigurationAdapter.
Thanks #PraveenKumarLalasangi for his comment.
I have a Spring Boot project using Spring Security and OAuth2.0 libraries.
I confirmed when I accessed http://localhost:8080/login, the default login view is displayed and I could log in.
But if I implement Config class shown below:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers( "/login**" ).permitAll()
.anyRequest()
.authenticated();
}
}
The browser returns "404 not found error".
I thought I could be authenticated directly accessing to a Github's API, so implemented this, but it Wouldn't work:
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(){
return "redirect:/oauth2/authorization/github";
}
How should I cope with that? I know I probably have some misunderstandings because of a lack of my knowledge,
but I only want to know how to allow access to only a login page when a user is not authenticated.
Thanks.
finally solved!
I need to append following parts to the end of the methods flow.
.and()
.oauth2Login()
.loginPage("/login");
so the final code is:
SecurityConfig.java
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login**")
.permitAll()
.anyRequest()
.authenticated()
//appended
.and()
.oauth2Login()
.loginPage("/login");
}
}
Controller.java
#GetMapping(value = "/login")
public String getit(Model model){
return "login";
}
login.html
<body>
<a th:href="#{/oauth2/authorization/github}">Login</a>
</body>
It worked!
Referenced URL:https://www.codeflow.site/ja/article/spring-security-5-oauth2-login
I'm trying to add a landing page to a Spring Application that I created so that when the application initially loads the landing page is the first page that is seen. The issue is, I created the landing page after I created the application and so the application loads a login/register page first and I cannot route the landing page to open first. I'm trying to research online where I could possibly complete this task yet I'm lost and would really appreciate some help.
I've included the WebSecurityConfig file below.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
//Disable csrf token as it is not needed for now and is preventing the applciation from running properly
http.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
What ever link I type in the address bar it keeps redirecting me to the login page. How can I prevent that?
For example if i add http://localhost:8080/asdasdsa > it will redirect me to
http://localhost:8080/account/login, so if i add anything after http://localhost:8080/ i will be redirected to account/login view.
My security config:
package com.example.configuration;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private DataSource dataSource;
#Value("${spring.queries.users-query}")
private String usersQuery;
#Value("${spring.queries.roles-query}")
private String rolesQuery;
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.jdbcAuthentication()
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(rolesQuery)
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/index").permitAll()
.antMatchers("/other/other").permitAll()
.antMatchers("/account/login").permitAll()
.antMatchers("/account/registration").permitAll()
.antMatchers("/account/admin/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
.and()
.csrf().disable()
.formLogin()
.loginPage("/account/login")
.failureUrl("/account/login?error=true")
.defaultSuccessUrl("/account/admin/")
.usernameParameter("email")
.passwordParameter("password")
.and()
.logout().permitAll()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/")
.and()
.exceptionHandling()
.accessDeniedPage("/access-denied");
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/img/**");
}
}
You configured that all other URLs must be authenticated, see Spring Security Reference:
Authorize Requests
Our examples have only required users to be authenticated and have done so for every URL in our application. We can specify custom requirements for our URLs by adding multiple children to our http.authorizeRequests() method. For example:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests() 1
.antMatchers("/resources/**", "/signup", "/about").permitAll() 2
.antMatchers("/admin/**").hasRole("ADMIN") 3
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") 4
.anyRequest().authenticated() 5
.and()
// ...
.formLogin();
}
1
There are multiple children to the http.authorizeRequests() method each matcher is considered in the order they were declared.
2
We specified multiple URL patterns that any user can access. Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about".
3
Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN". You will notice that since we are invoking the hasRole method we do not need to specify the "ROLE_" prefix.
4
Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA". You will notice that since we are using the hasRole expression we do not need to specify the "ROLE_" prefix.
5
Any URL that has not already been matched on only requires that the user be authenticated
Try with 127.0.0.1 instead of localhost.
Explanation
Your browser doesn't set the JSESSIONID cookie for localhost (see this SO question), so when redirecting after successful login the next request looks not authenticated to the server.
If you use idea and you open the browser clicking on the Services panel, you can add this config in your application-dev.yml to fix that:
server:
address: 127.0.0.1
Here's a workaround!
// Required to provide UserDetailsService for "remember functionality"
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("{noop}password").roles("USER");
}
Add the above snippet to your Security Config class, add the same username and password defined in pom.xml here as well. (without removing the "{noop}" part)
So next time you login, don't forget to click on "remember me" check box else the issue will keep repeating.
You may refer this article for further details.