3

I'm trying to configure Spring Security in the Spring Boot application. On the other side, Angular is running. When contacting the address

POST
localhost:15001/auth/api/v1/user/register

I get error 403 I reread a bunch of similar questions. The answer is the same everywhere. The error is treated by adding

http.csrf().disable()

csrf is disabled in my configuration, it is written in the SecurityConfig class.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
         securedEnabled = true,
         jsr250Enabled = true,
        prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final JwtTokenProvider jwtTokenProvider;

    @Autowired
    public SecurityConfig(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers(
                        "/authentication/api/v1/**",
                        "/auth/api/v1/user/register",
                        "/swagger-ui/**",
                        "/swagger-ui.html");
    }


    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers", "Access-Control-Allow-Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", "Origin", "Cache-Control", "Content-Type", "Authorization"));
        configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT"));

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().disable()
                .cors().and().csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/auth/api/v1/user/register").permitAll()
                .anyRequest().authenticated()
                .and()
                .apply(new JwtConfigurer(jwtTokenProvider));
    }
}

What else could be the problem? Link to the repository here project

The log file is very large, so I throw a link to it logs

chrome log - 1

chrome log - 2

chrome log - 3

log Spring SECURITY

08-03-2022 18:13:00.323 [http-nio-15001-exec-1] DEBUG org.springframework.security.web.FilterChainProxy.doFilterInternal - Securing OPTIONS /api/v1/user/register
08-03-2022 18:13:00.328 [http-nio-15001-exec-1] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter - Set SecurityContextHolder to empty SecurityContext
08-03-2022 18:13:00.373 [http-nio-15001-exec-1] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter - Cleared SecurityContextHolder to complete request
08-03-2022 18:13:00.373 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.FilterChainProxy.doFilterInternal - Securing POST /api/v1/user/register
08-03-2022 18:13:00.373 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter - Set SecurityContextHolder to empty SecurityContext
08-03-2022 18:13:00.389 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter - Set SecurityContextHolder to anonymous SecurityContext
08-03-2022 18:13:00.389 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.access.intercept.FilterSecurityInterceptor.attemptAuthorization - Failed to authorize filter invocation [POST /api/v1/user/register] with attributes [authenticated]
08-03-2022 18:13:00.404 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.authentication.Http403ForbiddenEntryPoint.commence - Pre-authenticated entry point called. Rejecting access
08-03-2022 18:13:00.404 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter - Cleared SecurityContextHolder to complete request
08-03-2022 18:13:00.404 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.FilterChainProxy.doFilterInternal - Securing POST /error
08-03-2022 18:13:00.404 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter - Set SecurityContextHolder to empty SecurityContext
08-03-2022 18:13:00.404 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter - Set SecurityContextHolder to anonymous SecurityContext
08-03-2022 18:13:00.404 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.FilterChainProxy.doFilter - Secured POST /error
08-03-2022 18:13:00.498 [http-nio-15001-exec-2] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter - Cleared SecurityContextHolder to complete request

If I change in the corsConfigurationSource method

// configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
   configuration.setAllowedOrigins(Arrays.asList("http://localhost:15001"));

Then an error appears:

Access to XMLHttpRequest at 'http://localhost:15001/auth/api/v1/user/register' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This is the mistake that I dealt with in this question has been blocked by CORS policy

alex
  • 324
  • 1
  • 8
  • 28
  • Enable debug logs and post them here – Toerktumlare Mar 05 '22 at 01:03
  • the log file you have posted, is not the server log. Enable spring debug logs and post the server logs in full. – Toerktumlare Mar 07 '22 at 11:27
  • this is most likely CORS, your request goes to localhost:15001 while in your CORS settings you have localhost:4200 – Toerktumlare Mar 07 '22 at 11:28
  • I don't understand, I prescribe this port everywhere in the examples. This is the port on which Angular is running – alex Mar 08 '22 at 06:08
  • Are you going to enable the server debug logs and post them? – Toerktumlare Mar 08 '22 at 07:21
  • i have no idea what kind of logs you posted, and where they are from. They are not the spring security server debug logs. If you dont know how to enable debug logs i suggest you read the spring official documentation or do a basic google search for instance here https://stackoverflow.com/a/47729991/1840146 before you ask on stack overflow. – Toerktumlare Mar 08 '22 at 14:15
  • learn how to debug your application. This https://pastein.ru/t/KWv is not spring security debug logs, i have no idea where you found these logs – Toerktumlare Mar 08 '22 at 14:16
  • I added logs spring security – alex Mar 08 '22 at 15:18
  • As i said most likely your CORS configurations is faulty, you are making requests from localhost:15001 but you have set CORS to localhost:4200 – Toerktumlare Mar 08 '22 at 20:11
  • Does this answer your question? [How to configure CORS in a Spring Boot + Spring Security application?](https://stackoverflow.com/questions/36968963/how-to-configure-cors-in-a-spring-boot-spring-security-application) – Toerktumlare Mar 08 '22 at 20:12
  • I read this topic, it didn't help me – alex Mar 10 '22 at 05:32
  • I have tried many options from the answers on this link, but the 403 error still crashes. I don't understand what the problem is. – alex Mar 10 '22 at 15:07
  • What says the error message in the console when you get the 403? What happens if you disable the `JwtConfigurer` and the `ignoring` part of `WebSecurity`? – fast-reflexes Mar 16 '22 at 18:43

4 Answers4

3

The problem is not cors or csrf. It has already been disabled. It's your antMatchers bypass config for register api. It should have been just /api/v1/user/register instead of /auth/api/v1/user/register. We should not add the servlet.context-path which is set as auth in application.yml within the web security config. Update your SecurityConfig as follows:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().disable()
                .cors().and().csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/api/v1/user/register").permitAll() // update this
                .anyRequest().authenticated()
                .and()
                .apply(new JwtConfigurer(jwtTokenProvider));
    }
deepakchethan
  • 5,240
  • 1
  • 23
  • 33
2

What you can do to solve the CORS problem without the annotation in Controller is using a filter and managing the requests there. Try this:

    package br.com.rss.generico.filter;

import java.io.IOException;
import java.util.Arrays;

import javax.annotation.PostConstruct;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.CorsProcessor;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.DefaultCorsProcessor;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
 * 
 * @author Thiago Rodrigues
 * @since 30 de nov de 2021
 */
@Component
public class CorsFilter extends org.springframework.web.filter.CorsFilter {

    private UrlBasedCorsConfigurationSource corsConfigurationSource;
    private CorsProcessor processor = new DefaultCorsProcessor();
    
    public CorsFilter(CorsConfigurationSource configSource) {
        super(configSource);
    }
    
    @PostConstruct
    private void configureCorsPolicies() {
        CorsConfiguration corsConfig = new CorsConfiguration();
        corsConfig.setAllowCredentials(false);
        corsConfig.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
        corsConfig.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type", "app-id", "platform", "sentry-trace"));
        corsConfig.setAllowedMethods(Arrays.asList("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH", "OPTION"));

        corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", corsConfig);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        CorsConfiguration corsConfiguration = corsConfigurationSource.getCorsConfiguration(request);
        Boolean isValid = this.processor.processRequest(corsConfiguration, request, response);

        if (!isValid || CorsUtils.isPreFlightRequest(request)) {
            if (response.getStatus() == 200) {
                response.setHeader(HttpHeaders.ALLOW, "HEAD, GET, PUT, POST, DELETE, PATCH, OPTION");
            }
            
            return;
        }

        filterChain.doFilter(request, response);
    }
}
thiagotrss
  • 129
  • 4
2

I think your 403 comes from something else than CORS!

My guess is that the error message in the console when you get the 403 is NOT related to CORS, right?

Spring Security

Spring Security is installed as a single filter (containing many internal filters) in the middle of the filter chain that processes a request before it is handed over to the servlet container. Spring security can terminate the request (both by means of rejection or approval) and return a response or it can hand it to the next filter coming after Spring security.

Web security

I do not know that much about Web security other than that it comes after Spring security in the filter chain and that it also has some security mechanisms governing CORS and other things. Web security is not part of Spring security, but instead resides in the web part of the main Spring framework. In order for Web security to ignore paths, use WebSecurity.ignoring() like you have done. These paths will be entirely ignored by Web security as a consequence.

CORS

There is a ton of things to say about CORS, but for some requests, a preflight OPTIONS request is mandated. In a preflight request, credentials are never passed along, as credentials are not necessarily allowed in CORS requests. If your endpoint requires authentication, Spring security will turn down the OPTIONS request before it reaches your CORS configuration in Web security, therefore the CorsFilter was introduced. The CorsFilter is enabled with HttpSecurity.cors() and it is configured using the CorsConfigurationSource that also Web security uses.

Three important classes should be taken into account here which are all used given that no particular custom beans have been added:

CorsFilter: source code

DefaultCorsProcessor: source code

CorsUtils: source code

The following applies at the time of writing (the code may obviously change in the future):

CorsUtils.isCorsRequest() considers all requests which have an Origin header with different scheme and / or host and / or port than the request it comes with as CORS requests. CorsUtils.isPreflightRequest() considers all requests which are OPTIONS, which have Origin headers and which contains a AccessControlRequestMethod header as preflight requests.

The CorsFilter, which is the only of these three that is only used by Spring security, and not Web security, will terminate the request and respond immediately either if the request is considered a preflight request, OR if the DefaultCorsProcessor considers it to be invalid. The latter only happens if the DefaultCorsProcessor considers the request to be a CORS request (by means of CorsUtils.isCorsRequest()) and, given that a configuration exists, when the request is not accepted according to the configured rules. This means that the CorsFilter will only terminate requests that are considered either invalid CORS requests or preflight requests. The interesting part here is that when the CorsFilter uses the DefaultCorsProcessor for handling, it will, given that the request is a CORS request and validates, attach CORS headers ALREADY AT THIS STAGE to the response. Therefore, a valid CORS request will already have its CORS headers set once it passes the Spring security CorsFilter.

The DefaultCorsProcessor will deal with the request AFTER Spring security has approved it, given that Web security should deal with the request (e.g. it has not been disabled with WebSecurity.ignoring()).

What is going on here?

In your case, the CorsFilter terminates processing successfully with the OPTIONS request which makes the browser send the actual request. In the actual POST request, the CorsFilter adds CORS headers but since it is a valid CORS request and it is not a preflight request, the request is not terminated by the CorsFilter.

All we KNOW is that the request makes it past this point, otherwise there shouldn't be CORS headers in the response. Spring security should not further care about this request since you have set it to permitAll() for the path in question, but I don't know too much about this JwtConfigurer and whether it does something to prevent this.

If the request makes it past Spring security, the Web security takes over but will ignore the request since you have set WebSecurity.ignore() for the path in question. This means that the request is approved by Web security even without consulting the CORS rules via the DefaultCorsProcessor. Therefore, if the request makes it to this point, there has t be something else than Web security that causes the 403, which ends up with CORS headers due to that it has been processed by the CorsFilter

Solution

  • Remove the JwtConfigurer and CorsFilter and the WebSecurity.ignoring() part and verify that CORS is working as expected.
  • Engage the JwtConfigurer again and troubleshoot if there is a problem.
  • Add the CORS filter only if the request would be turned down by Spring security (e.g. it has some restrictions connected to it which cannot be honored in the OPTIONS request).

Conclusion

Your method of doing this is correct and can be used at the time of Spring 2.6.0. Let me know if you want me to supply a proof-of-concept repo.

fast-reflexes
  • 4,891
  • 4
  • 31
  • 44
1

Please refer to the ticked answer for a similar problem. Spring security CORS Filter

I think you need to add the cors configuration to the main method of spring boot application and it should work. I am using in a similar way in my project

Aditya Akella
  • 479
  • 1
  • 7