Describe the bug Scope mapping handling changed with https://github.com/spring-projects/spring-security/issues/12112.
https://github.com/spring-projects/spring-security/commit/2915a70bf786e2bd0780d686d432b9ba85617522#diff-73bd44f873d78e3d71e6a0fa18644a304d562a4a9fd2e303e913f6ed20a0ad16R78-R83
OidcAuthorizationCodeAuthenticationProvider.authenticate()
callsOidcAuthorizationCodeAuthenticationProvider.getResponse()
)DefaultAuthorizationCodeTokenResponseClient.getTokenResponse
does NOT add the scopes anymore. If no scopes are returned by default by the IdP, the scopes list is empty.- The comment
If AccessTokenResponse.scope is empty, then we assume all requested scopes were granted.
seems to say something completely different. - Back in
OidcAuthorizationCodeAuthenticationProvider.authenticate()
the user info has to be loaded:this.userService.loadUser()
. OidcUserService.loadUser
callsthis.shouldRetrieveUserInfo(userRequest)
which returnsfalse
now, because the scopes (userRequest.getAccessToken().getScopes()
) is empty.- Because of this the userInfo is not loaded (it is
null
) and can't be used for example in theuserAuthoritiesMapper
.
To Reproduce Our scopes are configured like this:
spring.security.oauth2.client.registration.default.scope=openid,profile,entitlements
Use the userAuthoritiesMapper
with a token-uri endpoint that doesn't return a list of scopes.
http.oauth2Login()
.userInfoEndpoint().userAuthoritiesMapper(this.userAuthoritiesMapper());
In the authorities mapper try to use the oidcUserAuthority.getUserInfo()
(which is now null).
Expected behavior
oidcUserAuthority.getUserInfo()
should not be null
.
Sample No sample yet.
Ping @sjohnr
Comment From: sjohnr
Thanks @DamianFekete. Please see the blog post on cve-2022-31690 and related advisory for details about the fix and why it was applied.
The comment
If AccessTokenResponse.scope is empty, then we assume all requested scopes were granted.
seems to say something completely different.
See RFC 6749, Section 5.1 for details on why we assume that all scopes were granted. The unfortunate reality is that we cannot rely on that assumption in all cases, hence the fix.
I'll look into a fix for OidcUserService
. In the meantime, you can apply the following workaround to consume the latest version of Spring Security:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Login(Customizer.withDefaults());
return http.build();
}
@Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
OidcUserService oidcUserService = new OidcUserService();
oidcUserService.setAccessibleScopes(Collections.emptySet());
return oidcUserService;
}
}
You can apply this workaround if it is acceptable to query the User Info endpoint on every login. If that's not acceptable in your case, let me know and I'll see about a different workaround.
Comment From: tobiaskrauss
Thanks @sjohnr for your fast and helpful response. I was working with @DamianFekete on this issue. The workaround works fine for our application. As we do not have too many users on this application, it should be fine for us that the user info endpoint is queried on every login.
Comment From: shresthaujjwal
FYI, seeing same issue with 5.7.5 version too. Workaround works for me
Comment From: Clemens-E
I'm seeing the same behaviour on 5.7.8 while integrating a login with Azure B2C IDM. Spring was supposed to call the UserInfo endpoint to get the users' email/name after login, but UserInfo is always null, and I can't see any call to the endpoint in the debug logs. I can't exclude with certainty that it's not caused by some (miss-) configuration on either spring or azure b2c.
So, either way, I just wanted to put my fix here after hours of debugging in case anyone has a similar issue: add the above-mentioned workaround (I had to remove the security filter chain as it interfered with my WebSecurityConfigurerAdapter and you can't have both)
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
// see https://github.com/spring-projects/spring-security/issues/12144
@Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
OidcUserService oidcUserService = new OidcUserService();
oidcUserService.setAccessibleScopes(Collections.emptySet());
return oidcUserService;
}
}
However, spring now validates the UserInfo and will complain if you do not have a "sub" property, so make sure your UserInfo endpoint includes a sub property (mine didn't)
If you are using the Azure B2C Identity Experience Framework, you have to configure this:
https://github.com/azure-ad-b2c/samples/blob/master/policies/user-info-endpoint/policy/UserInfo_TrustFrameworkExtensions.xml#L34
and additionally add the mentioned sub claim with: <InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
This way the sub property will be included in the UserInfo Response and spring won't complain.
I apologize if this seems off-topic, but I thought it would be valuable to share my solution here for others experiencing the same problem, even if it's a niche topic.
Comment From: asinghania71
@sjohnr the issue still exists if we use reactive spring boot application I have raised a PR for same, would be great if you can take a look and help me get this fixed