-
Notifications
You must be signed in to change notification settings - Fork 6k
Access to accessToken in GrantedAuthoritiesMapper #14461
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi, @Xyaren, thanks for reaching out. What is making you feel like extending @Component
public class MyOidcUserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
private final OidcUserService delegate = new OidcUserService();
@Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
OidcUser user = this.delegate.loadUser(userRequest);
Collection<GrantedAuthority> authorities = new ArrayList<>(user.getAuthorities());
// ... add custom authorities
return new DefaultOidcUser(authorities, user.getIdToken(), user.getUserInfo());
}
} which doesn't seem dirty to me. I want to make sure I'm not missing something; can you clarify please? |
Hi, thanks for the quick response! It feels odd wrapping the original service, tear apart the response and stitch it together again in a new instance of the same object. I also was unsure about "reconstructing" the OidcUser due to no access to nameAttributeKey which is required for the all-arg constructor. Therefore I went for extending the default implementation and wrapping the result. import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import packages.from.my.company.that.i.dont.want.to.name.JwtToAuthorityExtractor;
import lombok.AllArgsConstructor;
import lombok.experimental.Delegate;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.jwt.SupplierJwtDecoder;
@AllArgsConstructor
public class ExtendedOidcUserService extends OidcUserService {
private SupplierJwtDecoder supplierJwtDecoder;
@Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
var oidcUser = super.loadUser(userRequest);
var accessToken = userRequest.getAccessToken();
var authorityExtractor = new JwtToAuthorityExtractor(
userRequest.getClientRegistration().getClientId(),
Set.of(),
false);
var jwt = supplierJwtDecoder.decode(accessToken.getTokenValue());
Set<GrantedAuthority> additionalAuthorities = authorityExtractor.authorities(jwt).collect(Collectors.toSet());
return new ExtendedOidcUser(oidcUser, additionalAuthorities);
}
static class ExtendedOidcUser implements OidcUser {
@Delegate
private final OidcUser oidcUser;
private final Collection<? extends GrantedAuthority> authorities;
public ExtendedOidcUser(OidcUser oidcUser, Collection<? extends GrantedAuthority> additionalAuthorities) {
this.oidcUser = oidcUser;
this.authorities = joinAuthorities(oidcUser, additionalAuthorities);
}
@SuppressWarnings({"LombokGetterMayBeUsed", "RedundantSuppression"})
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@NotNull
private static HashSet<GrantedAuthority> joinAuthorities(
OidcUser oidcUser,
Collection<? extends GrantedAuthority> additionalAuthorities) {
HashSet<GrantedAuthority> totalAuthorities = new HashSet<>(
oidcUser.getAuthorities().size() + additionalAuthorities.size());
totalAuthorities.addAll(oidcUser.getAuthorities());
totalAuthorities.addAll(additionalAuthorities);
return totalAuthorities;
}
}
} |
Thanks for reporting this, @Xyaren, and sorry for the delay. You should now instead be able to do the following: @Bean
OidcUserService oidcUserService() {
OidcUserService service = new OidcUserService();
service.setOidcUserMapper((request, userInfo) -> {
OAuth2AccessToken accessToken = userRequest.getAccessToken();
Collection<GrantedAuthority> authorities = authorityExtractor.authorities().collect(Collectors.toSet());
String userNameAttributeName = "preferred_username";
return new DefaultOidcUser(authorities, userRequest.getIdToken(),
userInfo, userNameAttributeName);
});
return service;
} Does this allow you to remove your wrapper class and service extension? If so, I think we'll close this issue and guide people to use that method to get the access token. |
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed. |
I got it working using the mapper, thank you very much :) |
Superceded by #14672, which added |
Expected Behavior
When using oauth2login it is should be possible to use the access token in GrantedAuthoritiesMapper in order to map access token claims to authorities for use in hasRole/hasAuthority.
This is espacially usefull when some claims do only appear in the access token.
Current Behavior
GrantedAuthoritiesMapper has currently no access to the accessToken.
Context
https://docs.spring.io/spring-security/reference/reactive/oauth2/login/advanced.html#webflux-oauth2-login-advanced-map-authorities-grantedauthoritiesmapper
My (dirty) workaround involves extending the OidcUserService and returning a new OidcUser Object.
The text was updated successfully, but these errors were encountered: