Issue
I am trying to restrict specific endpoints on a Spring boot service depending on what role they have set in the OAuth2 credentials.
This is the endpoint
@RestController
@RequestMapping("/api/admin")
public class AdminController {
@GetMapping(produces = "application/json")
public TestResponse get() {
return new TestResponse("Admin API Response");
}
}
This is then secured using SecurityConfiguration bean
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.and()
.authorizeRequests()
.antMatchers("/login", "/", "/home", "/logout", "/ping").permitAll()
.antMatchers("/api/admin").hasRole("arn:aws:iam::xxxxxx:role/spring-sso-test-ADMIN")
.antMatchers("/api/user").hasRole("arn:aws:iam::xxxxxx:role/spring-sso-test-USER")
.and()
.oauth2Login()
.and()
.logout()
.logoutSuccessUrl("/logout");
}
}
I debugged the Principal and can see the correct IAM role in the list of attributes cognito:roles
list
However when I hit the endpoint I get a HTTP 403 Unauthorized. Meaning that the user has authenticated successfully, but Spring does not recognize or understand the attributes or how to map them?
I tried using the @Secured annotation but that didn't change anything.
@Secured("arn:aws:iam::xxxxxx:role/spring-sso-test-ADMIN")
@GetMapping(produces = "application/json")
public TestResponse get() {
return new TestResponse("Admin API Response");
}
How do I allow this to work using an IAM role defined in AWS Cognito?
Solution
When you use the hasRole
DSL method, Spring Security adds the ROLE_
prefix to your authority. So, the authority arn:aws:iam::xxxxxx:role/spring-sso-test-ADMIN
will become ROLE_arn:aws:iam::xxxxxx:role/spring-sso-test-ADMIN
.
You should use the hasAuthority
method instead.
Additionally, you should take the cognito:roles
from the attributes
and add in the authorities
, since it's the property that Spring Security will query to get the authorities.
To map the authorities you can use a OAuth2UserService
:
@Bean
SecurityFilterChain app(HttpSecurity http) throws Exception {
http
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo
.oidcUserService(this.oidcUserService())
...
)
);
return http.build();
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
// your custom implementation
}
More details in the documentation.
Answered By - Marcus Hert da Coregio