microsoftgraph / msgraph-sdk-java-auth

Authentication Providers for Microsoft Graph Java SDK
34 stars 21 forks source link

Error authenticating with UsernamePasswordProvider #64

Closed parttimer777 closed 3 years ago

parttimer777 commented 3 years ago

Hi - I have an app reg setup in azure and c# code that works and now i'm trying to do the same thing in java with issues.

The app reg is setup with delegate permissions. Might someone have any recommendations as to what is causing this? Is it possible to have it display the auth token in order to troubleshoot better?

        String CLIENT_ID = "--------";
        List<String> SCOPES = Arrays.asList("https://graph.microsoft.com/.default");
        String USERNAME = "--------";
        String PASSWORD = "--------";
        NationalCloud NATIONAL_CLOUD = NationalCloud.Global;
        String TENANT = "--------";
        String CLIENT_SECRET = "--------";

        UsernamePasswordProvider authProvider = new UsernamePasswordProvider(CLIENT_ID, SCOPES, USERNAME, PASSWORD,
                NATIONAL_CLOUD, TENANT, CLIENT_SECRET);

        IGraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider)
                .buildClient();
        graphClient.getLogger().setLoggingLevel(LoggerLevel.DEBUG);

        System.out.println(graphClient.me().buildRequest().get());
OAuthProblemException{error='invalid_grant', description='AADSTS50126: Error validating credentials due to invalid username or password.
Trace ID: -----------
Correlation ID: ----------
Timestamp: 2020-12-07 23:55:35Z', uri='https://login.microsoftonline.com/error?code=50126', state='null', scope='null', redirectUri='null', responseStatus=400, parameters={}}
    at org.apache.oltu.oauth2.common.exception.OAuthProblemException.error(OAuthProblemException.java:59)
    at org.apache.oltu.oauth2.client.validator.OAuthClientValidator.validateErrorResponse(OAuthClientValidator.java:63)
    at org.apache.oltu.oauth2.client.validator.OAuthClientValidator.validate(OAuthClientValidator.java:48)
    at org.apache.oltu.oauth2.client.response.OAuthClientResponse.validate(OAuthClientResponse.java:127)
    at org.apache.oltu.oauth2.client.response.OAuthClientResponse.init(OAuthClientResponse.java:96)
    at org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse.init(OAuthAccessTokenResponse.java:65)
    at org.apache.oltu.oauth2.client.response.OAuthClientResponse.init(OAuthClientResponse.java:101)
    at org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse.init(OAuthAccessTokenResponse.java:60)
    at org.apache.oltu.oauth2.client.response.OAuthClientResponse.init(OAuthClientResponse.java:120)
    at org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory.createCustomResponse(OAuthClientResponseFactory.java:82)
    at org.apache.oltu.oauth2.client.URLConnectionClient.execute(URLConnectionClient.java:111)
    at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:65)
    at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:55)
    at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:71)
    at com.microsoft.graph.auth.publicClient.UsernamePasswordProvider.getAccessTokenNewRequest(UsernamePasswordProvider.java:98)
    at com.microsoft.graph.auth.publicClient.UsernamePasswordProvider.getAccessToken(UsernamePasswordProvider.java:71)
    at com.microsoft.graph.auth.publicClient.UsernamePasswordProvider.authenticateRequest(UsernamePasswordProvider.java:62)
    at com.microsoft.graph.http.CoreHttpProvider.sendRequestInternal(CoreHttpProvider.java:395)
.
.
.
.
.

com.microsoft.graph.http.GraphServiceException: Error code: InvalidAuthenticationToken
Error message: CompactToken parsing failed with error code: 80049217

GET https://graph.microsoft.com/v1.0/me
SdkVersion : graph-java/v2.4.1
Authorization : [PII_REDACTED]

401 : Unauthorized
Cache-Control : private
client-request-id : ------------
Content-Length : 333
Content-Type : application/json
Date : Mon, 07 Dec 2020 23:55:35 GMT
request-id : 534f835e-309d-484e-b6c3-5410d5029e68
Strict-Transport-Security : max-age=31536000
WWW-Authenticate : Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", client_id="-------------"
x-ms-ags-diagnostic : {"ServerInfo":{"DataCenter":"North Central US","Slice":"SliceC","Ring":"2","ScaleUnit":"000","RoleInstance":"AGSFE_IN_51"}}
{
  "error": {
    "code": "InvalidAuthenticationToken",
    "message": "CompactToken parsing failed with error code: 80049217",
    "innerError": {
      "date": "--------",
      "request-id": "-------",
      "client-request-id": "-------------"
    }
  }
}
MIchaelMainer commented 3 years ago

Take a look at the documentation for the ROPC workflow. Have you triple checked the username and password? (have to ask)

https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc#error-response

Are you you using the same user and client application as the one you're using in C#? Are you using the same auth flow in C#? I'm curious, why do you have a C# app and a Java app?

Is MFA enabled for the user? Is this a hybrid environment where the user is in an on-premise AD? If so, this flow won't work.

parttimer777 commented 3 years ago

Correct, this is a hybrid environment and the user is in an on-prem AD. The 2 apps (java and c#) are both on-prem. The app-reg is setup as a desktop "platform" with "urn:ietf:wg:oauth:2.0:oob" as the redirect URI. I'm inclined to believe it won't work; I'm just confused as to why the c# one works. Does the msgraph c# lib behave differently? Like does it hook into the IIS integrated auth...? (wild guess)

MIchaelMainer commented 3 years ago

I'm confused on why the c# one works too. . Have you captured and compared the requests/response between both clients? What do you see?

parttimer777 commented 3 years ago

Are you suggesting to wireshark and compare? i guess it's coming to that... im not sure how to do that with encrypted traffic but i will try...

Just verified the app-reg settings: Platform: "Mobile and desktop applications" Redirect uris: "urn:ietf:wg:oauth:2.0:oob" Implicit grant: "ID Tokens" Allow public client flows: "Yes"

Here's the c# code that absolutely works:

            var ClientId= "-----------------";
            var Scopes = new string[] { "https://graph.microsoft.com/User.Read" };
            var UserName = "-----------";
            var Password = "-----------------";

            var TenantId = "-------------";

            IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
                       .Create(ClientId)
                       .WithTenantId(TenantId)
                       .Build();

            // Create an authentication provider by passing in a client application and graph scopes.
            IEnumerable<string> scopes = Scopes;
            SecureString pwd = new SecureString();
            foreach (var ch in Password)
                pwd.AppendChar(ch);
            Task<AuthenticationResult> task1 = publicClientApplication.AcquireTokenByUsernamePassword(scopes, UserName, pwd).ExecuteAsync();
            task1.Wait();
            IAuthenticationProvider authProvider = new UsernamePasswordProvider(publicClientApplication, scopes);

            GraphServiceClient graphClient = new GraphServiceClient(authProvider);

            User me = await graphClient.Me.Request()
                            .GetAsync();
            Console.WriteLine(me.DisplayName);
MIchaelMainer commented 3 years ago

Yeah, its what I'd have to do at this point as I'm not well enough versed with identity scenarios. Hey, I wonder if identity has issue with you setting CLIENT_SECRET in the UsernamePasswordProvider. Can you leave those out?

MIchaelMainer commented 3 years ago

Are you using the same clientId for both C# and Java?

parttimer777 commented 3 years ago

Correct, same clientId/appReg. Nulling the client_secret and trying the 4 param constructor version of UsernamePasswordProvider has no effect.

parttimer777 commented 3 years ago

Just fiddler'ed the c# app a second ago. It does a discovery request on the provided username and gets the internal network saml auth service url. Then it makes a request to the saml auth service to get the bearer assertion token. Then finally it requests the MS Graph oauth url with the saml bearer assertion token to get the graph access token.

keywords for this is "MSAL" "SAML Bearer assertion flow" does this sound familiar? any chance this lib supports that?

MIchaelMainer commented 3 years ago

This library likely does not support it. It was created before MSAL for Java was available. I assume that MSAL for Java supports this.

We need to use MSAL within an implementation of IAuthenticationProvider and ICoreAuthenticationProvider.

parttimer777 commented 3 years ago

Ok thanks. For people who will see this thread, a possible solution is to create a C# webapp where you specify the username/pass and it will return you the graph access token. I'll close this issue.

baywet commented 3 years ago

FYI the work Michael is mentioning is ongoing here https://github.com/microsoftgraph/msgraph-sdk-java-core/pull/42