Skip to content
This repository has been archived by the owner on Sep 4, 2020. It is now read-only.

MSA or commercial/home account ? #26

Closed
nycodes9 opened this issue Aug 13, 2016 · 5 comments
Closed

MSA or commercial/home account ? #26

nycodes9 opened this issue Aug 13, 2016 · 5 comments

Comments

@nycodes9
Copy link

nycodes9 commented Aug 13, 2016

Is there a way to know if the signing in a/c is a MSA or home/commercial a/c before making any graph api calls ?

Logging in with a MSA account (e.g., john_doe@outlook.com) and trying to retrieve user profile along with user image graphClient .getMe() .getPhoto() .getContent() .buildRequest() .get()
yields the following :

com.microsoft.graph.http.GraphFatalServiceException: [This is an unexpected error from Graph, please report this at https://github.com/microsoftgraph/msgraph-sdk-android/issues]
   Error code: GetUserPhoto
   Error message: The operation is not supported.

   GET https://graph.microsoft.com/v1.0/me/photo/$value
   SdkVersion : graph-android-v0.9.4
   Authorization : bearer ...


   501 : Not Implemented
   Duration : 591.1586
   Cache-Control : private
   X-Android-Sent-Millis : 1471111328187
   Content-Type : application/json
   x-ms-ags-diagnostic : {"ServerInfo":{"DataCenter":"West US","Slice":"SliceB","ScaleUnit":"001","Host":"AGSFE_IN_5","ADSiteName":"WST"}}
   request-id : 45d08191-64a2-4a91-ae6c-5d9267d1421f
   X-Powered-By : ASP.NET
   Date : Sat, 13 Aug 2016 18:02:02 GMT
   Server : Microsoft-IIS/8.5
   Transfer-Encoding : chunked
   X-Android-Response-Source : NETWORK 501
   client-request-id : 45d08191-64a2-4a91-ae6c-5d9267d1421f
   X-Android-Received-Millis : 1471111328825
   {
      "error": {
         "code": "GetUserPhoto",
         "message": "The operation is not supported.",
         "innerError": {
            "request-id": "45d08191-64a2-4a91-ae6c-5d9267d1421f",
            "date": "2016-08-13T18:02:03"
         }
      }
   }
@iambmelt
Copy link
Contributor

If you have access to the id_token field of the OAuth 2 request, it is an RFC 7519 JSON Web Token

Decoding these tokens yields 3 pieces of data: the header, the payload, and a signature verification field - these values are separated by a .

A sample jwt payload might take the following form:

{
  "ver": "2.0",
  "iss": "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0",
  "aud": "32613fc5-e7ac-4894-ac94-fbc39c9f3e4a",
  "exp": 1471367710,
  "iat": 1471281310,
  "at_hash": "obWC_Q1qhqvOek-NUy9m1A",
  "name": "John Doe",
  "preferred_username": "john.doe@outlook.com",
  "sub": "AAAAAAAAAAAAAAAAAAAAALTk-6hzK4IfrxLrVKO01Vs",
  "tid": "9188040d-6c67-4c5b-b112-36a304b66dad"
}

The tid field corresponds to a tenant id - per this article, if the tid is equal to 9188040d-6c67-4c5b-b112-36a304b66dad then the account is considered MSA (AKA non business).

Extra useful tools:
Online jwt decoder
Asp.NET code sample that does this kind of MSA/Business acct check

If you're using MSGraph SDK Android MSA Auth for Android Adapter I'll have to look into how we can get access to these tokens - if need be, we can loop in @peternied

@nycodes9
Copy link
Author

@iambmelt thanks for the response and I'm using MSGraph SDK Android MSA Auth for Android Adapter, it would be great if the auth adapter had a callback for identifying MSA vs commercial account before we can proceed to make graph service calls.
cc @peternied
But I believe we do not get the bearer token for msa a/c (I checked with POSTMAN online)? How do we decide to proceed with graph calls thereafter ?

@iambmelt
Copy link
Contributor

@nycodes9 agree with this sentiment - long term, providing users with a simple way to determine their account type and what sort of functionality they can expect once authenticated would be ideal: sadly, this likely isn't on the docket for [MSGraph SDK Android MSA Auth for Android Adapter](MSGraph SDK Android MSA Auth for Android Adapter) - per the documentation

This authentication provider is limited in scope and is provided to facilitate development with the v2.0 authentication endpoint while development of MSAL for each platform progresses to general availability. You can learn more about what is currently supported on the v2.0 authentication endpoint here.

Note: This project is intended to help developers get off the ground quickly with the MSGraph SDK for Android and not to serve as an all-inclusive authentication library.

The standard 'feel free to fork/PR' language applies here - I unfortunately can't give any forecasts as to when the identity team will release the mentioned MSAL for Android.


If you're looking for more comprehensive OAuth 2 support, there are a handful of general purpose libraries out there:


The bearer token should be returned to you as the access_token in the jwt. Because you're using MSGraph SDK Android MSA Auth for Android Adapter, the parsing, storage, retrieval, and binding of these tokens should be taken care of for you by MSAAuthAndroidAdapter#authenticateRequest(final IHttpRequest request)

The IGraphServiceClient implementation should take care of binding the Authorization headers to requests for you: this relationship gets established through the follow constructions:

public IGraphServiceClient buildServiceClientExample() {
        // Create the authentication adapter
        IAuthenticationAdapter authenticationAdapter =
                new MSAAuthAndroidAdapter(mApplication) {

                    @Override
                    public String getClientId() {
                        return "YOUR CLIENT GUID";
                    }

                    @Override
                    public String[] getScopes() {
                        return new String[]{
                                // some example scopes
                                "User.Read.All",
                                "User.ReadBasic.All",
                                "User.ReadWrite",
                                "offline_access",
                                "openid"
                        };
                    }
                };

        // Create the client config using the previously initialized authentication adapter
        IClientConfig clientConfig =
                DefaultClientConfig
                        .createWithAuthenticationProvider(
                                authenticationAdapter
                        );

        // Finally, construct the client to handle requests
        return new GraphServiceClient
                .Builder()
                .fromConfig(
                        clientConfig
                ).buildClient();
    }

You'll want to make your AuthenticationAdapter instance accessible from a Fragment or Activity such that you can call

authenticationAdapter.login(this, new ICallback<Void>() {
                    @Override
                    public void success(Void aVoid) {
                        // now you can make service calls
                    }

                    @Override
                    public void failure(ClientException ex) {
                        // something went wrong
                    }
                }
        );

@iambmelt
Copy link
Contributor

As a quick hack to get access to the Authorization header - you could make a call to the Graph service using a special MSAAuthAndroidAdapter with an @Override for authenticateRequest that does something like the following:

@Override
public void authenticateRequest(IHttpRequest request) {
    super.authenticateRequest(request);
    for (HeaderOption option : request.getHeaders()) {
        // iterate over the headers to find the Authorization header
        // decode the token to grab whatever you need, set a flag somewhere
        // to store the user-type
    }
}

This is not an elegant solution, however - and requires initiating a call before you really know the user type

@morphine9
Copy link

Thanks for all the help here, I really appreciate that.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants