Home > other >  Spring Security not allowing POST
Spring Security not allowing POST

Time:10-22

I have a requirement to lock down an existing REST API application containing many endpoints. The application receives a cognito token from the client via the Authorization header as a Bearer token. That token is verified by AWS cognito against this url in application.properties:

spring.security.oauth2.resourceserver.jwt.issuer-uri=https://cognito-idp.${aws.cognito.region}.amazonaws.com/${aws.user.pools.id}

I've imported the following jars to support this:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

And here is the SecurityConfiguration class

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests(authz -> authz
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers(HttpMethod.GET, "/**").permitAll()
            .antMatchers(HttpMethod.POST, "/**").permitAll()
            .anyRequest().authenticated())
          .oauth2ResourceServer(oauth2 -> oauth2.jwt());
    }
}

It seems to work fine for GET, but the POST calls fail with a 403 Forbidden. I have it open to everything that is authenticated for now until I can get it working. I'm thinking the answer lies somewhere in the SecurityConfiguration configure method code.

In case it's relevant to this, I also had to add "Authorization" to the "Access-Control-Allow-Headers" header to an existing old school Filter w doFilter(ServletRequest req, ServletResponse resp) used by the application like this (pasted in all the headers in case it's helpful):

    response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    response.setHeader("Access-Control-Allow-Credentials", "true");
    response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, X-Requested-With, remember-me");

CodePudding user response:

You should configure CORS for anything that can alter resources (POST, PUT, DELETE):

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // Enable and configure CORS
        http.cors().configurationSource(corsConfigurationSource());
        ...
        return http.build();
    }

    private CorsConfigurationSource corsConfigurationSource() {
        // Very permissive CORS config...
        final var configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setExposedHeaders(Arrays.asList("*"));

        // Limited to API routes (neither actuator nor Swagger-UI)
        final var source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/greet/**", configuration);

        return source;
    }

Side note, do not extend WebSecurityConfigurerAdapter which is deprecated. Instead, provide your application context with a SecurityFilterChain @Bean as done in the sample above.

CodePudding user response:

Turns out I overlooked the fact that the front end was not sending the token in the Authorization header on POST, but is for GET.

  • Related