-
Notifications
You must be signed in to change notification settings - Fork 6k
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
Customize when UserInfo is called #13259
Comments
See related issues: |
Thanks for the report, @youlabi! I think the Would you be interested in submitting a PR? |
I can not promise anything :). Can you please forward me to some resources and things I need to know, on how to submit a PR ? Regarding the actual change. This seems to me like it is exactly the same logic duplicated in two places. Should this be kept this way? This seems highly inefficient, and the next fix will again have to be transferred and likely be forgotten. Another question I am unsure about: why does the reactive stack make use of a static class? Is this just legacy ? |
Hi @youlabi, thanks for the reply.
Sadly, I don't know the answer to that question. It's just however the developer chose to do it.
It is OK to duplicate logic when needed. It is not a goal of Spring Security to eliminate all such duplication as this would be an untenable goal. However, I see your point that duplication can cause issues like this. In this case, it looks like the static class can be used to reduce duplication, so if you wish, you can refactor the code so both
Thank you so much! That's completely okay, I'm here to help. Take a look at the contributing document which will walk you through most of what you need to know. I will mention that because you have correctly categorized this issue as a bug, it would be nice to base the change on the Any other questions, please let me know. |
Oh, I just remembered one more thing. If/when we make a fix on the Looking over the code in |
Thanks for all the input. I noticed that shouldRetrieveUserInfo is alwyas private and or final, or to put it differently, it is behaviour that can not be overwritten by the user. So I can not extend OidcUserService and adapt the behaviour. Is this because, this is standardized OIDC / OAuth2.0 behaviour? This might explain why it is private / static code that can not be changed. What do you think about this implementation:
|
@sjohnr , I have a question regardingyour fix fde26e0 for #12144 If https://www.rfc-editor.org/rfc/rfc6749#section-5.1 says, that "returning no scopes means all requested scopes were granted", shouldn't the AccessToken actually be populated with all of those granted scopes earlier, if the scopes in the response was not set. It seems to me, that the fix is in fact incorrect, and more of a workaround because the way I understand it, we should have probably filled the at some place earlier. What if the server returns an access token with an empty scope list. Then assuming that all scopes were granted is not right. |
Unless of course an empty scope list is not permitted, in which case the workaround is fine, however, it still seems like a workaround instead of a fix :) |
Also, I know see what you mean by
In my opinion the only way to not introduce a severe breaking change in older versions while somehow solving the bug is to:
As a result, we have no change in behaviour, however, we can set accessibleScopes to empty if we like, so that there is some alignement between the two. The accessToken scopes = empty check however needs to be introduced. This is a breaking change, in the sense that, more requests are done to the userInfo endpoint than before. |
Hi @youlabi.
Just to point this out (in case you weren't aware), this behavior was changed previously for security reasons, so we won't be following the spec here. We don't want to assume that you were granted all the scopes you requested, we have no way of getting that assumption right. I'm still working through your other comments and will follow up this week. |
Any updates on this one? |
No updates @mikelemikelo. I didn't get around to responding to questions from @youlabi. Apologies for that. Actually, as I look at this again I'm not sure there is a path forward that doesn't introduce a breaking change. While I understand that there is an expectation to call the UserInfo endpoint in certain situations, I don't see a way to harmonize that with the situations where the reactive implementation currently calls UserInfo. Also, because the reactive version's behavior is not compatible with the non-reactive one, I don't think we can/should share any code between the two right now. Before we proceed, I'd like to get feedback on whether the following outlined behavior would result in the UserInfo endpoint being called when expected. For this discussion, please ignore what either implementation currently does. -- The UserInfo Endpoint should be called if all of the following conditions are true:
-- If this would not be the correct behavior for your use case, can you provide clarification on what specific situation you're aiming to solve? @mikelemikelo @youlabi |
@youlabi do you have any feedback on the above? Does the above set of conditions describe the situation in which you're wanting to see the UserInfo endpoint called? |
Following on this as my company has started to see some significant movement to Spring Cloud Gateway and the switch to Reactive implementations have started to hit this. @sjohnr Those assumptions do not work for our use case. Scopes are simply not returned in this case from our IdP, and I'd assume enterprise users are expecting the same functionality in this circumstance between imperative and reactive implementations given how much spring security handles in this area. Additionally there is no hint provided why the userInfo endpoint isn't called when switching, given how deep and the lack of configuration options to override this check I've resorted to a hack classloading so a custom implementation is loaded before the libraries... which isn't great.
Is this documented anywhere? I am a bit shocked on not following the spec, but then not allowing configurations to revert back to spec behaviour. Happy to contribute a PR on this if there is a consensus on how. |
Is this the referenced security issue? https://spring.io/blog/2022/10/31/cve-2022-31690-privilege-escalation-in-spring-security-oauth2-client This seems to be the offending lines: https://github.com/spring-projects/spring-security/blob/main/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/userinfo/OidcUserRequestUtils.java#L63-L64 By overriding the In the case of our enterprise authorization server, I believe this comment is true: This was a wild issue to chase down. Previously, the application was running |
@DarrenForsythe, apologies as the above flow in my comment was from some time ago, so I am not fully remembering what the intent of my question to the reporter was, but I think I was describing the "normal" flow. The flow I proposed should allow for the UserInfo endpoint to be called in your case, assuming we introduce a setter for
@mrlonis that's correct.
I'm wondering if part of the (or the entire) solution here would be to introduce a way to simply override the logic of |
@sjohnr That would work well. Would the addition of a new property be considered "non-breaking"? I am imagining something like this: return CollectionUtils.containsAny(userRequest.getAccessToken().getScopes(),
userRequest.getClientRegistration().getScopes()) ||
NEW_PROPERY; where I'm sure there is a better way to do it but that's just something off the top of my head. |
@mrlonis we could add the ability to set a lambda to replace the logic of the existing method. I created a branch to illustrate my idea (see this commit).
It would not be a new property (see above), so adding a new setter would be considered a new feature but it is non-breaking. So we would need to put this in the next feature release (6.3). |
@sjohnr I would highly highly appreciate this change; I had to resort to go this route to enforce the call to user info.. setAccessibleScopes(Collections.emptySet()); // Make it empty so that ALL claims; even openid enforces a call to /userinfo.... |
Just in case if someone is looking for the version which is working and makes the call to userinfo endpoint -> Try version 5.7.0. I was facing issues in version 5.7.10 |
Thanks, but we do not recommend downgrading versions as a workaround, because older versions do not include security fixes like the one mentioned above (see blog post). If you need to work around the issue while waiting for this enhancement, please give the following configuration a try and let me know if it helps you: @Configuration
@EnableWebFluxSecurity
public class SecurityConfiguration {
private static final Set<String> ACCESSIBLE_SCOPES = Set.of(OidcScopes.OPENID, OidcScopes.PROFILE);
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// ...
}
@Bean
public ReactiveOAuth2UserService<OidcUserRequest, OidcUser> userService() {
var delegate = new OidcReactiveOAuth2UserService();
return (userRequest) -> {
var accessToken = userRequest.getAccessToken();
if (!CollectionUtils.isEmpty(accessToken.getScopes())) {
return delegate.loadUser(userRequest);
}
var modifiedAccessToken = new OAuth2AccessToken(
accessToken.getTokenType(),
accessToken.getTokenValue(),
accessToken.getIssuedAt(),
accessToken.getExpiresAt(),
ACCESSIBLE_SCOPES);
var modifiedUserRequest = new OidcUserRequest(
userRequest.getClientRegistration(),
modifiedAccessToken,
userRequest.getIdToken());
return delegate.loadUser(modifiedUserRequest);
};
}
} |
Note: I have converted this issue into an enhancement as discussed above. See workaround for a possible way to cause UserInfo to be called prior to 6.3. |
Describe the bug
org.springframework.security.oauth2.client.oidc.userinfo.OidcReactiveOAuth2UserService#getUserInfo calls OidcUserRequestUtils::shouldRetrieveUserInfo that uses the scopes in the OAuth2AccessToken to determine whether it should fetch user infos or not.
In the non-reactive OidcUserService shouldRetrieveUserInfo was extended to return true if either, the access token has no scopes or the accessibleScopes is empty:
fde26e0
This fix was not applied to the reactive version
To Reproduce
Set up OIDC server to return an Opaque Token, which automatically has no scopes.
Expected behavior
Userinfo endpoint is called
Sample
No sample present
Reports that include a sample will take priority over reports that do not.
At times, we may require a sample, so it is good to try and include a sample up front.
The text was updated successfully, but these errors were encountered: