msgraph-sdk-dotnet icon indicating copy to clipboard operation
msgraph-sdk-dotnet copied to clipboard

PageIterator seems to ignore request-options "WithAppOnly" on subsequent requests

Open Jan1503 opened this issue 11 months ago • 3 comments

I'm in the process of migrating some code from v4 to v5 and encounter the same bug while using the NextPageRequest (v4) in the PageIterator (v5).

I have to get the Access-Packages from our Azure AD using graph and this has to be done with "AppOnly" application permissions. For all other tasks, delegated permissions are needed so I don't have the Graph-Client injected with AppOnly in the first place.

So I just add the option "WithAppOnly()" to the request and all works well for the first request.

But as soon as the single-page limit is reached, in this case 100, the iterator kicks in and ignore the options from the request so the next call crashes with an unauthorized error because the request is done with the user-credentials instead.

Here's the entire function with some explanations to better understand the issue: image

The behaviour is the same in the old v4 but there was an easy workaround to add the "WithAppOnly" to the "NextPageRequest".

Please show me how add the options to any subsequent request...I tried many workarounds but haven't found a working one yet.

private async Task<List<AccessPackage>> GetAccessPackagesAsync(
        CancellationToken cancellationToken = default)
    {
        var accessPackages = new List<AccessPackage>();

        var accessPackagesResponse = await _graphServiceClient
                .IdentityGovernance
                .EntitlementManagement
                .AccessPackages
                .GetAsync(requestConfiguration =>
                {
                    requestConfiguration.QueryParameters.Expand = new[] { "assignmentPolicies" };
                    requestConfiguration.Options.WithAppOnly();
                    requestConfiguration.QueryParameters.Top = 999;
                }, cancellationToken)
            ;

        try
        {
            if (accessPackagesResponse != null)
            {
                var pageIterator = PageIterator<AccessPackage, AccessPackageCollectionResponse>.CreatePageIterator(
                    _graphServiceClient,
                    accessPackagesResponse, accessPackage =>
                    {
                        accessPackages.Add(accessPackage);
                        return true;
                    }
                    , subsequentRequest =>
                    {
                        // How to add ...WithAppOnly() to following request?
                        return subsequentRequest;
                    }
                );

                await pageIterator.IterateAsync(cancellationToken);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }

        // Working v4 code.
        //IEntitlementManagementAccessPackagesCollectionPage? entitlementAccessPackages = null;

        //while (entitlementAccessPackages is not { NextPageRequest: null })
        //{
        //    var entitlementAccessPackagesRequest = entitlementAccessPackages?.NextPageRequest.WithAppOnly() ??
        //                                           _graphServiceClient
        //                                               .IdentityGovernance
        //                                               .EntitlementManagement
        //                                               .AccessPackages
        //                                               .Request()
        //                                               .Expand("assignmentPolicies")
        //                                               .WithAppOnly()
        //                                               .Top(999);

        //    entitlementAccessPackages = await entitlementAccessPackagesRequest
        //        .GetAsync(cancellationToken);

        //    accessPackages.AddRange(entitlementAccessPackages);
        //}

        return accessPackages;
    }

Jan1503 avatar Jul 24 '23 15:07 Jan1503

Thanks for raising this @Jan1503,

Just to confirm, is WithAppOnly() a custom method you have to update the Option collection?

Any chance it works out if you have the following request configurator?

 subsequentRequest =>
                    {
                        subsequentRequest.RequestOptions.WithAppOnly(); // How to add ...WithAppOnly() to following request?
                        return subsequentRequest;
                    }

Alternatively, you can also call

subsequentRequest =>
                    {
                        subsequentRequest.AddRequestOptions( ... );// pass a list of IRequestOptions
                        return subsequentRequest;
                    }

andrueastman avatar Jul 26 '23 09:07 andrueastman

No, WithAppOnly() is an official extension method in Microsoft.Identity.Web.RequestOptionsExtension.

It instructs the graph to use application-permissions for the next request instead of delegated-permissions.

As I said, the first request without the iterator works as expected but any subsequent requests fail, because the iterator ignores the request options configured in the first request.

This is also the case when using the "old" sdk as I have mentioned here without any reply: https://github.com/AzureAD/microsoft-identity-web/issues/2272

Jan1503 avatar Jul 26 '23 11:07 Jan1503

@andrueastman Hey, any news on this or a workaround? This stops me from updating my app!

Jan1503 avatar Aug 31 '23 16:08 Jan1503