Expected Behavior Use case-insensitive matching in loadUser() method
!userInfo.getSubject().equalsIgnoreCase(userRequest.getIdToken().getSubject())
Or make it configurable, or more it easier to extend instead of rewritting the whole class.
Current Behavior Use case-sensitive matching
!userInfo.getSubject().equals(userRequest.getIdToken().getSubject())
Context Some of OAuth providers in my area does not guarantee the exact case when writting the subject field. And they insist they are right. Somehow the case of letters seems not a very important factor in the context of security.
Comment From: jzheaux
Hi, @zhenchuan9r! Thanks for reaching out, and sorry that some OAuth providers are being so insistent.
Spring Security tends to prefer the most conservative interpretation of the spec, which states (emphasis mine):
NOTE: Due to the possibility of token substitution attacks (see Section 16.11), the UserInfo Response is not guaranteed to be about the End-User identified by the
sub(subject) element of the ID Token. ThesubClaim in the UserInfo Response MUST be verified to exactly match thesubClaim in the ID Token; if they do not match, the UserInfo Response values MUST NOT be used.
Further, ignoring case in a general way is more complicated than it first seems due to localization considerations, potentially widening the attack surface.
So, I think the implementation should remain as-is.
Still, let's see if I can be more helpful than that. Typically, you won't need everything that a framework class does. Considering your specific use case, would a class like this work for you:
import static org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService.*;
@Component
public class CaseInsensitiveOidcUserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
private final var claimTypeConverter = new ClaimTypeConverter(createDefaultClaimTypeConverters());
private final var oauth2UserService = new DefaultOAuth2UserService();
@Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oauth2User = this.oauth2UserService.loadUser(userRequest);
OidcUserInfo userInfo = new OidcUserInfo(this.claimTypeConverter.convert(oauth2User.getAttributes()));
if (userRequest.getIdToken().getSubject().equalsIgnoreCase(userInfo.getSubject())) {
throw new OAuth2AuthenticationException("invalid_user_info_response");
}
return new DefaultOidcUser(oauth2User.getAuthorities(), userRequest.getIdToken(), userInfo);
}
}
Comment From: spring-projects-issues
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.
Comment From: zhenchuan9r
Hi, thanks for the reply. I was doing something similar to your suggestion in a copy and modify manner.