Skip to content
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

[BUG] AadClientRegistrationRepository#toClientRegistration did not set userInfoUri #31546

Closed
chenrujun opened this issue Oct 18, 2022 · 9 comments · Fixed by #32595
Closed

[BUG] AadClientRegistrationRepository#toClientRegistration did not set userInfoUri #31546

chenrujun opened this issue Oct 18, 2022 · 9 comments · Fixed by #32595
Assignees
Labels
azure-spring All azure-spring related issues bug This issue requires a change to an existing behavior in the product in order to be resolved. Client This issue points to a problem in the data-plane of the library.
Milestone

Comments

@chenrujun
Copy link

chenrujun commented Oct 18, 2022

Context

In current AadClientRegistrationRepository#toClientRegistration , userInfoUri is not set, which caused OidcUserService#shouldRetrieveUserInfo always returns false.

Problem

OidcUserService#shouldRetrieveUserInfo always returns false, it is unexpected behavior.

Goal

  1. Make userInfoUri configured and use it to get user information.
  2. Confirm proxy setting will work when send http request to userInfoUri. DefaultOAuth2UserService's RestTemplate. Refs: [BUG] Make sure all RestTemplate are managed by AadRestTemplateCreator #31347 (comment)

Useful links

https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo

@chenrujun chenrujun self-assigned this Oct 18, 2022
@ghost ghost added the needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. label Oct 18, 2022
@chenrujun chenrujun added question The issue doesn't require a change to the product in order to be resolved. Most issues start as that Client This issue points to a problem in the data-plane of the library. azure-spring All azure-spring related issues and removed needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. labels Oct 18, 2022
@chenrujun chenrujun added this to the 2022-11 milestone Oct 18, 2022
@chenrujun
Copy link
Author

In spring-boot-autoconfigure, userInfoUri will be got from issuerUri

image

@chenrujun chenrujun changed the title [QUERY] Why AadClientRegistrationRepository#toClientRegistration not set userInfoUri [BUG] AadClientRegistrationRepository#toClientRegistration did not set userInfoUri Oct 20, 2022
@chenrujun chenrujun added bug This issue requires a change to an existing behavior in the product in order to be resolved. and removed question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Oct 20, 2022
@chenrujun chenrujun modified the milestones: 2022-11, 2022-12 Oct 20, 2022
@chenrujun
Copy link
Author

Screenshot of quick fix:

image

Need add more unit tests.

@saragluna saragluna assigned saragluna and unassigned chenrujun Nov 6, 2022
@saragluna saragluna removed their assignment Dec 7, 2022
@backwind1233 backwind1233 modified the milestones: 2022-12, 2023-01 Dec 8, 2022
@backwind1233
Copy link
Contributor

backwind1233 commented Dec 8, 2022

The userInfoUri is used to get OidcUserInfo,

  • and then the OidcUserInfo will be used to construct OidcUser .

As the java doc of OidcUser says:

An OidcUser contains "claims" about the authentication of the End-User.  
The claims are aggregated from the OidcIdToken and the OidcUserInfo (if available).

image

So whether to set userInfoUri, it depends, we need to check whether there are different "claims" in OidcUserInfo rather than in the OidcIdToken, and then make a decision whether to set the value by default, or provide an option to user.

Also, our AadOAuth2UserService#loadUser doesn't use the oidcUser information returned by OidcUserService#loadUser.
So we need to redesign(confirm), what's the infomation we decide to return by AadOAuth2UserService#loadUser exactly.

@backwind1233
Copy link
Contributor

backwind1233 commented Dec 9, 2022

We need to make a design(decision) what is expected to return in AadOAuth2UserService#loadUser .

  • Update code logic.
  • Update java doc.

@backwind1233
Copy link
Contributor

backwind1233 commented Dec 9, 2022

Image

The javadoc does not match the implementation.

  1. UserInfo Endpoint is not set.
  2. It does not use the userInfo to build the result.

@backwind1233
Copy link
Contributor

  • The userInfoUri in the AadClientRegistrationRepository#toClientRegistration class, which means for applications using our aad starter, when the applications' users login and call AadOAuth2UserService#loadUser() to load OidcUser, the method call will never obtain the user attributes of the end-user from the UserInfo Endpoint. This means that our Java doc is not correct.
    image

  • Also in our implementation of the loadUser method, we actually did not use the userInfo to construct the return information.

    We build and return a DefaultOidcUser instance by using the below DefaultOidcUser constructor, which will always takes a null value for userInfo .
    image

    This means no matter whether the userInfoUri is set or not, we will never use or return the userInfo.

    This logic has not changed since the first commit.

I think we have two options:

  1. Keep the logic.
    • Since we are using the constructor for DefaultOidcUser that does not take userInfo explicitly, and no users have raised an issue, we can keep things as they are, but we need to refactor our code and modify our javadoc to reflect our current logic.
  2. Provide an implementation of the loadUser method that returns a DefaultOidcUser instance containing userInfo.

I prefer to the second option.

  • From the javadoc of the interface, we can infer that it is expected to obtain the UserInfo from the UserInfo Endpoint and return it.

    • image
  • The Spring official documentation also provides a sample implementation that includes setting the userInfoUri, by default it will return userInfo.

    • image

What do you think @saragluna ?

@saragluna
Copy link
Member

IMO, we should figure out the following questions before making a decision:

  • What's the API (input/output) of a OAuth2UserService#loadUser method
  • What's the difference between the API and our current implementation
  • What's the difference between the responses from the user info endpoint and what we call from the graph endpoint (our current implementation)?

@backwind1233
Copy link
Contributor

backwind1233 commented Dec 12, 2022

What's the API (input/output) of an OAuth2UserService#loadUser method

OAuth2UserService

@FunctionalInterface 
public interface OAuth2UserService<R extends OAuth2UserRequest, U extends OAuth2User> {
    U loadUser(R userRequest) throws OAuth2AuthenticationException;
}
  • Input: an OAuth2UserRequest

  • Output: an OAuth2User (it extends OAuth2AuthenticatedPrincipal), it contains below APIs

     public interface OAuth2User extends OAuth2AuthenticatedPrincipal {
     }
     public interface OAuth2AuthenticatedPrincipal extends AuthenticatedPrincipal {
         default <A> A getAttribute(String name) {
             return (A) getAttributes().get(name);
         }
         Map<String, Object> getAttributes();
         Collection<? extends GrantedAuthority> getAuthorities();
     } 
         

What's the difference between the API and our current implementation

  • our current API
    public class AadOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
        @Override
        public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
                        // construct authorities
                        // construct idToken
                        // construct userInfo
                        // construct nameAttributeKey
        }
    }
    • Input: an OidcUserRequest which extends OAuth2UserRequest
    • Output: an OidcUser which extends OAuth2User, it contains below APIs
      public interface OidcUser extends OAuth2User, IdTokenClaimAccessor {
          @Override 
          Map<String, Object> getClaims();
          OidcUserInfo getUserInfo();
          OidcIdToken getIdToken();
          
          // ... some other APIs in IdTokenClaimAccessor 
      }

What's the difference between the responses from the user info endpoint and what we call from the graph endpoint (our current implementation)?

  • This is an example of the response from the user info endpoint

Note You can't add to or customize the information returned by the UserInfo endpoint.

{
  "sub": "OLu859SGc2Sr9ZsqbkG-QbeLgJlb41KcdiPoLYNpSFA",
  "name": "Mikah Ollenburg", // all names require the “profile” scope.
  "family_name": " Ollenburg",
  "given_name": "Mikah",
  "picture": "https://graph.microsoft.com/v1.0/me/photo/$value",
  "email": "mikoll@contoso.com" // requires the “email” scope.
}
  • the graph endpoint (our current implementation) only used to get group information.
    image

Summary

The picture shows the difference between our Spring Cloud Azure implementaition and Spring security implementaition.

image

No Step name Implementaition In Spring Security Implementaition In Spring Cloud Azure
Step1 Construct Authorities Authorities from accessToken scopes + "ROLE_USER" Authorities from groupids + groupnames + roles
Step2 Construct UserInfo userInfo from userInfo endpoint uri not passed, skip constructing
Step3 Construct IdToken IdToken from input request IdToken from input request
Step4 Construct nameAttributeKey IdTokenClaimNames.SUB("sub") User passed nameAttributeKey, default == "name"
Step5 Construct Result return new
DefaultOidcUser(
authorities,
idToken,
null,
nameAttributeKey)
return new
DefaultOidcUser(
authorities,
idToken,
userInfo,
IdTokenClaimNames.SUB)

Step1 in detail

This is a sample to show implementaition logic in Spring Cloud Azure.
image

Below is a sample to show the implementaition logic in Spring Security.
image

@backwind1233
Copy link
Contributor

backwind1233 commented Dec 12, 2022

Updates relates to Step2 "Construct UserInfo"

@backwind1233 backwind1233 linked a pull request Dec 15, 2022 that will close this issue
6 tasks
@github-actions github-actions bot locked and limited conversation to collaborators Apr 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
azure-spring All azure-spring related issues bug This issue requires a change to an existing behavior in the product in order to be resolved. Client This issue points to a problem in the data-plane of the library.
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

3 participants