I'm getting 403 forbidden error when using Spring boot security for basic authentication. I get this error when using the POST method.
My main class code is as follows,
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder)
{
return builder.sources(MyContext.class);
}
Please suggest a solution for this. Thanks
I get this error using Post method.
Above line gives hint that the issue is due to CSRF protection. If users will not be using your application in a web browser, then it is safe to disable CSRF protection. Otherwise you should ensure to include the CSRF token in the request.
To disable CSRF protection you can use the following:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.csrf().disable();
}
Refer spring-security-csrf
Related
When I try to check my spring registration request, it should return the message "it Works," but I get nothing. Does anyone have any ideas what might be wrong?
I had missed an API link in the.antMatchers section of the WebSecurityConfig file.
If you preview your postman response you can see a login form which means you are not authenticated. If your signup request does not need any authentication you can simply exclude your registration api endpoint from spring checks. To do that permit all requests to the particular url in your configuration file
If you are using WebSecurityConfigurerAdapter, add an antMatcher entry to your configure method.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/v1/registration").permitAll()
.anyRequest().authenticated();
}
Since WebSecurityConfigurerAdapter is deprecated now if you want to use SecurityFilterChain you can do it as follows. For more info refer documentation.
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/v1/registration").permitAll()
.anyRequest().authenticated();
return http.build();
}
I have provided the cookie based authorization request repository to oauth2Login() dsl to make it as stateless. but when I add the session creation policy as STATELESS , the oauth2 login is not working and returning "too many callbacks" error in UI page.
I have used the following oauth2Login config. for login with google oauth2 provider.
#Autowired
private HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().csrfTokenRepository(new CookieCsrfTokenRepository())
.ignoringAntMatchers("/oauth2/authorization/google")
.and()
.sessionManagement(sessionMgmtConfig -> sessionMgmtConfig.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated())
.oauth2Login(oauth2Config -> oauth2Config
.authorizationEndpoint(config -> config.authorizationRequestRepository(httpCookieOAuth2AuthorizationRequestRepository))
.userInfoEndpoint(config -> config.oidcUserService(oidcUserOAuth2UserService()))
.successHandler(authenticationSuccessHandler())
)
;//.logout(logoutConfig -> logoutConfig.addLogoutHandler(logoutHandler()))
}
public AuthenticationSuccessHandler authenticationSuccessHandler() {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setRequestCache(new CookieRequestCache());
return successHandler;
}
If I comment out the session management line, it is working as expected and creating the JSESSION but when not working if I uncomment this part. Am I missing something?
It is not so easy to have oauth2Login and stateless sessionManagement.
The problem is that Spring needs to store information about OAuth 2.0 state parameter. Normally it is stored in session but when you disable it, Spring gets crazy ("too many callbacks") because it can not find it.
To solve that problem you can use your own cookie to store state parameter.
This can be done by providing a custom implementation of AuthorizationRequestRepository<OAuth2AuthorizationRequest>.
There is a nice blog post descriging everything in more details.
https://www.jessym.com/articles/stateless-oauth2-social-logins-with-spring-boot
What is the purpose of the 'state' parameter in OAuth authorization request
As spring disables CSRF token for certain methods like GET, how we can enable CSRF token validation for all requests including GET using spring security.
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().requireCsrfProtectionMatcher(AnyRequestMatcher.INSTANCE);
}
}
Note this configuration means csrf token is required for any request ,that's unnecessary and hard to achieve
I have a spring boot app which provides HTML page service via / and also rest api via /api. The former requires login via a Login form and the later requires HTTP basic auth, and hereby, I configure two HttpSecurity section as follows:
#Configuration
#Order(1)
public static class ApiSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**")
.cors().and().csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic(Customizer.withDefaults());
}
}
#Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.cors().disable()
.authorizeRequests()
.antMatchers("/login", "/js/**", "/css/**").permitAll()
.antMatchers("/**").hasRole("ADMIN")
.and().formLogin().loginPage("/login").permitAll().defaultSuccessUrl("/index")
.and().logout().invalidateHttpSession(true)
.deleteCookies("JSESSIONID").logoutSuccessUrl("/login").permitAll();
}
}
The configuration works perfectly in normal case. However, if wrong credentials are provides in rest api clients, an HTML code of login page with HTTP status code 200 returns from the app instead of an excepted json message with HTTP status code 401 or 403.
I'm afraid it is because the url pattern of /api/** both matches "/api/**" and "/**", and therefore, the request will pass both the filter chain for rest api and HTML page. Finally, because of the lower order of formLogin, a login page returns in the case.
So, How can I get the excepted result for rest api clients? Is there an only solution to separate the two url patterns which should not match each other?
Addition 1:
I think there are three cases which will raise exceptions in the security filter chain:
No credentials provided;
Wrong credentials provided;
Right credentials provided but not matched the required roles
And the results for the cases are as follows:
Return HTTP status 401 with a json error message
Return HTTP status 302 and try to redirect to login page
Return HTTP status 403 with a json error message
Therefore, it seems that only the case of wrong credentials provided will
be routed to /error endpoint (as what Eleftheria said in the answer), and the difference between 1,3 and 2 is the exception type -- org.springframework.security.access.AccessDeniedException: Access is denied for 1 and 3; org.springframework.security.authentication.BadCredentialsException: Bad credentials for 2.
In the formLogin() case, if the BadCredentialsException rises, it will be routed to the failure-url, but how to configure the failure-url in the httpbasic case? (seems no such method in HttpBasicConfigurer)
This is happening because the failed authentication is throwing an exception and the "/error" page is secured by your second filter chain.
Try permitting all requests to "/error" in your second filter chain.
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/error").permitAll()
// ....
Note that the request will only be processed by one filter chain, and that is the first filter chain that it matches.
The request to "/api/123" is only processed by the first filter chain, however the second filter chain was invoked because there was an error.
What I wanted to do is build a Rest backend application that needs the Authorization header on every request, validate and return the data or 401 Unauthorized if the user or password is wrong.
I have Spring Security in my classpath with this simple configuration:
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("user")
.password("pass")
.roles("USER");
}
}
But one thing is not working correctly: when I make a request with valid username and password with Postman, the server responds the data correctly, but if I change the password to a wrong password and keep the correct username, the server stills responds with the data and OK status, as if it is using a JSESSIONID Cookie to check the further requests.
Is that a way of using spring security only for checking the header Authorization (with no cookies, sessions nor saving user informations or login and logout pages), or is better to just use Filters for doing that instead?
Thank you for any help !
Just add the following to your configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
This will configure spring security to never create a cookie, every request must reauthenticate.