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.