microsoftgraph / msgraph-sdk-dotnet

Microsoft Graph Client Library for .NET!
https://graph.microsoft.com
Other
672 stars 242 forks source link

Why isn't my code failing with unauthorized error? #1033

Closed gmantri closed 3 years ago

gmantri commented 3 years ago

Please provide the following (and please check them off the list with [x]) before submitting this issue:

Expected behavior

Once an assigned role/permission (e.g. Users.ReadAll) is revoked for an application, any operation performed that requires that role/permission should fail.

Actual behavior

The operations are running without any error despite the role/permission being revoked.

Steps to reproduce the behavior

I have the following code that I am expecting to fail when listing users/groups in my Azure AD, however to my surprise it works.

using System;
using System.Threading.Tasks;
using Azure.Core;
using Microsoft.Graph;
using Microsoft.Identity.Client;
using Azure.Identity;

namespace GraphApiSamples
{
    class Program
    {
        private const string tenantId = "tenant-id";
        private const string clientId = "client-id";
        private const string clientSecret = "client-secret";
        static async Task Main(string[] args)
        {
            var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
            var authProvider = new TokenCredentialAuthProvider(credential);
            var graphServiceClient =
                new GraphServiceClient("https://graph.microsoft.com/v1.0", authProvider);
            IGraphServiceUsersCollectionPage result = await graphServiceClient.Users.Request().GetAsync();
            IGraphServiceGroupsCollectionPage groups = await graphServiceClient.Groups.Request().GetAsync();

            Console.WriteLine("Hello World!");
        }
    }
}

Created an application in my Azure AD. Initially only User.Read delegate permission was assigned and the code failed with unauthorized error as expected.

Next, I granted the application Users.ReadAll and GroupMembers.ReadAll permissions. I also had to provide admin consent. Once I did that, the code worked perfectly fine and gave me the list of users and groups (again, as expected).

Then I discovered that there's another permission called Directory.ReadAll which kind of suited my needs at the moment (I only need to list users and groups in my application). So I removed Users.ReadAll and GroupMembers.ReadAll permissions (but I did not add Directory.ReadAll permission just yet.

Now when I run the code, my expectation is that the code should fail as I don't have the required permissions to list users and/or groups however the code ran successfully. At first I thought that it could be related to some caching so I waited for about an hour and tried running the application again and it ran successfully.

I am wondering why this is happening? Any insights into this will be highly appreciated.

P.S. Please let me know if I should be posting this on Stack Overflow and I will do the same.

AB#9891

pschaeflein commented 3 years ago

My guess is that you have a cached access token that has the removed scopes. Flush the cache (or wait ~60 minutes) and see if the results are the same.

In the future, Continuous Access Evaluation is designed to address this issue.

Shameless plug: CAE was discussed recently on the M365 Dev Podcast with Christos Mastkas: https://m365dev.link/e244

gmantri commented 3 years ago

@pschaeflein - Thanks. Caching was my initial guess however two things there:

  1. I am running a console application so my guess is that token is cached in the memory when I run the application and should be flushed once the application is terminated.
  2. It's been over an hour now already since I revoked the permission.

Can you tell me how to flush the cache manually?

I will try again after a few hours to ensure this is indeed related to caching. I will revert with my findings.

pschaeflein commented 3 years ago

Caching is dictated by the Confidential Client Application you've configured. I don't see that in your code snippet, so I'm guessing the app setup is done in the ClientSecretCredential class.

Also, I assume you are using the preview version of the SDK, so maybe it is a bug. 🤷‍♀️

gmantri commented 3 years ago

@pschaeflein - So I tried after a few hours and I am still able to run my code successfully.

Indeed I was using the preview version of the SDK (version 4.0.0.0-preview.6) so I uninstalled it and installed version 3.34.0. I also had to install Microsoft.Graph.Auth (v1.0.0-preview.7) as the code complained about ClientCredentialProvider not being found.

Even with all these changes, I am not getting unauthorized error back.

Here's my latest code:

using System;
using System.Threading.Tasks;
using Azure.Core;
using Microsoft.Graph;
using Microsoft.Identity.Client;
using Azure.Identity;
using Microsoft.Graph.Auth;

namespace GraphApiSamples
{
    class Program
    {
        private const string tenantId = "tenant-id";
        private const string clientId = "client-id";
        private const string clientSecret = "client-secret";
        static async Task Main(string[] args)
        {
            IConfidentialClientApplication clientApplication = ConfidentialClientApplicationBuilder
                .Create(clientId)
                .WithTenantId(tenantId)
                .WithClientSecret(clientSecret)
                .Build();
            IAuthenticationProvider provider = new ClientCredentialProvider(clientApplication); 
            var graphServiceClient = new GraphServiceClient(provider);

            IGraphServiceUsersCollectionPage result = await graphServiceClient.Users.Request().GetAsync();
            IGraphServiceGroupsCollectionPage groups = await graphServiceClient.Groups.Request().GetAsync();

            Console.WriteLine("Hello World!");
        }
    }
}

Any ideas as to why this is happening?

gmantri commented 3 years ago

Sorry...my bad! I did not scroll enough in Azure Portal to see the permissions were in 2 places and I only removed it from one place only. Once I removed it from the other place, I started getting error again.

Thank you @pschaeflein for your help. I really appreciate it. Please accept my most sincere apologies if I wasted your time with this.

pschaeflein commented 3 years ago

Glad you are back in business!!!

BTW, the Graph.Community library has samples that include diagnostic logging and caching.