Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
675 views
in Technique[技术] by (71.8m points)

authentication - Resource 'GUID value here' does not exist or one of its queried reference-property objects are not present

I'm trying to change an Azure AD user password.

The user is already authenticated in a SPA application using the implicit flow and the adal library.

While calling:

return await graphClient.Me.Request().UpdateAsync(new User
                {
                    PasswordProfile = new PasswordProfile
                    {
                        Password = userPasswordModel.NewPassword,
                        ForceChangePasswordNextSignIn = false
                    },
                });

I'm getting this exception:

{"Code: Request_ResourceNotFound Message: Resource '35239a3d-67e3-4560-920a-2e9ce027aeab' does not exist or one of its queried reference-property objects are not present. Inner error "}

Debugging the access token I got with Microsoft Client SDK I see that this GUID is referring to the oid and sub properties. See below:

enter image description here

This is the code I use to acquire the token:

 IConfidentialClientApplication clientApp =
     ConfidentialClientApplicationBuilder.Create(Startup.clientId)
            .WithAuthority(string.Format(AuthorityFormat, Startup.tenant))
            .WithRedirectUri(Startup.redirectUri)
            .WithClientSecret(Startup.clientSecret)
            .Build();

            var authResult = await clientApp.AcquireTokenForClient(new[] { MSGraphScope }).ExecuteAsync();

            return authResult.AccessToken;

I'm using the implicit flow in a SPA application. While doing ClaimsPrincipal.Current I see that my user is authenticated and all claims are present.

I've read a lot of docs @ GitHub and Microsoft Docs but it's still not clear in my mind how to implement this. By the way, I'm using these Microsoft Graph packages:

  <package id="Microsoft.Graph" version="1.15.0" targetFramework="net461" />
  <package id="Microsoft.Graph.Auth" version="0.1.0-preview.2" targetFramework="net461" />
  <package id="Microsoft.Graph.Core" version="1.15.0" targetFramework="net461" />

I guess I'm not approaching this correclty because instead of acquiring a token for the application I should acquire a token for the user. Should I use clientApp.AcquireTokenOnBehalfOf instead?

If so what's the recommended way of acquiring a token for the currently logged in user using Microsoft Graph API SDK?

Can you shed some light?

####### EDIT #######

I was able to make some progress using this:

var bearerToken = ClaimsPrincipal.Current.Identities.First().BootstrapContext as string;

JwtSecurityToken jwtToken = new JwtSecurityToken(bearerToken);

var userAssertion = new UserAssertion(jwtToken.RawData, "urn:ietf:params:oauth:grant-type:jwt-bearer");

IEnumerable<string> requestedScopes = jwtToken.Audiences.Select(a => $"{a}/.default");

var authResult = clientApp.AcquireTokenOnBehalfOf(new[] { MSGraphScope }, userAssertion).ExecuteAsync().GetAwaiter().GetResult();

return authResult.AccessToken;

but now I'm getting the error:

insufficient privileges to complete the operation. authorization_requestdenied

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

After a long debugging session (8 hours or so) I was finally able to get what I wanted after I saw this answer by @Michael Mainer.

This is the "right" code I put together:

public async Task<User> ChangeUserPassword(UserPasswordModel userPasswordModel)
{
    try
    {
        var graphUser = ClaimsPrincipal.Current.ToGraphUserAccount();

        var newUserInfo = new User()
        {
            PasswordProfile = new PasswordProfile
            {
                Password = userPasswordModel.NewPassword,
                ForceChangePasswordNextSignIn = false
            },
        };

        // Update the user...
        return await graphClient.Users[graphUser.ObjectId].Request().UpdateAsync(newUserInfo);
    }
    catch(Exception e)
    {
        throw e;
    }
}

Note 1: graphClient.Users[graphUser.ObjectId] is being used instead of graphClient.Me

Note 2: .ToGraphUserAccount() is from Microsoft.Graph.Auth.

I had a sample PATCH request in Postman that correctly set a new password for the user.

enter image description here

The Access Token used in Postman's Authorization request-header had the same formatproperties from the one I was acquiring with Microsoft Graph API. I just compared them using jwt.io. So I must've been calling something wrongly...

I used clientApp.AcquireTokenForClient instead:

var authResult = await clientApp.AcquireTokenForClient(new[] { MSGraphScope }).ExecuteAsync();

return authResult.AccessToken;

where:

MSGraphScope = "https://graph.microsoft.com/.default"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...