Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GetPermissionRequestsAsync does not return request for the app where another app with the same scope was previously approved. #1406

Open
1 task done
larry-lau opened this issue Feb 22, 2024 · 10 comments
Assignees
Labels
area:admin 📜 Admin library related bug Something isn't working

Comments

@larry-lau
Copy link

Category

  • Bug

GetPermissionRequestsAsync does not return request for the app where another app with the same scope was previously approved.

Steps to reproduce

  1. Deploy a SPFx app with the following config
"webApiPermissionRequests": [
      {
        "resource": "App1",
        "scope": "access_as_user"
      }
    ]
  1. Approve the access request in SharePoint Admin center
  2. Deploy another app with the following config but don't approve it and just leave it pending request
"webApiPermissionRequests": [
      {
        "resource": "App2",
        "scope": "access_as_user"
      }
    ]

Note: App1 and App2 has the same scope name "access_as_user" which is commonly used in OAuth application.
4. Call GetPermissionRequestsAsync()

var appManager = context.GetTenantAppManager();
List<IPermissionRequest> permissionRequests = await appManager.ServicePrincipal.GetPermissionRequestsAsync();
  1. Observe that the result value permissionRequests is empty array.

Expected behavior

The expected return value should contain an request object for App2 / access_as_user

Environment details (development & target environment)

  • SDK version: [1.11.0]
  • OS: [Windows 11]
  • SDK used in: [Console App | ASP.Net Web app]
  • Framework: [.NET 8]
  • Browser(s): [Chrome latest]
  • Tooling: [Visual Studio 2022]

Additional context

Investigating further, I found that the filter logic in GetPermissionRequestsAsync in ServicePrincipal.cs is filtering out previoysly approved permission by looking at the scope only. It does not account for different resource Id with the same scope name.

Line 102 in ServicePrincipal.cs

return permissionRequests
    .Where(permissionRequest => !alreadyGranted.Contains(permissionRequest.Scope))
    .ToList();

The filter logic should check both resource id and scope.

Thanks for your contribution! Sharing is caring.

@jansenbe
Copy link
Contributor

@larry-lau : thanks for reporting this.

@mloitzl : is this something you can have a look at?

@mloitzl
Copy link
Contributor

mloitzl commented Feb 23, 2024

@jansenbe Yep, I think I will be able to fix this issue.

@larry-lau Thanks for the thorough analysis 🤜🤛

@jansenbe jansenbe added bug Something isn't working area:admin 📜 Admin library related labels Mar 1, 2024
@jansenbe
Copy link
Contributor

@mloitzl : did you manage to have some time for this?

@mloitzl
Copy link
Contributor

mloitzl commented May 24, 2024

Hi @jansenbe,
Yes, I have implemented a half baked solution, but it's a surprisingly complicated problem.

There's an edge case left I want to cover:
It can occur, that there is more than one App with the same name and the a same scope in the Directory. But they still have different ids.
I want to introduce an optional parameter (app, or object id, not sure yet) that can be used to denote the specific app that should be used in such a case.

I think I will be able to finish on one of the upcoming weekends.

@mloitzl
Copy link
Contributor

mloitzl commented Jun 9, 2024

Dear @jansenbe,

Some updates on that:
It seems that the internal CSOM way of approving Permission Requests does not work anymore.
It returns an error like this:
The service principal for permssion request <PackageName> could not be found.

I did some research and discovered that also the "API Access" page in the SharePoint Admin Portal now uses the Graph API instead of the CSOM API to grant OAuth2Permissions on the SharePoint Client Extensibility Principal.

During that I found some other GitHub issues, e.g. SharePoint/sp-dev-docs#9633, or microsoftgraph/msgraph-sample-spfx#14 which may also have the same reason.

I put together a PoC in this draft PR #1479 that mimics the behaviour of the API Access page (work in progress).

It extends the IApp with an ApprovePermissionRequestsAsync method.

Some questions on that:

  • Is the IApp interface the right place for that?
  • Should the internal CSOM methods ApprovePermissionRequest, DenyPermissionRequest and GetPermissionRequests be removed?
  • Should the Enable, Disable, ListGrants, AddGrant and RevokeGrant methods also be moved to the Graph API (if possible)?

Thanks for the feedback, Martin

@jansenbe
Copy link
Contributor

@mloitzl : interesting find on the move to Graph, let me check with the engineering side and come back to you. Thanks for helping with this one!

@mloitzl
Copy link
Contributor

mloitzl commented Jun 10, 2024 via email

@jansenbe
Copy link
Contributor

@mloitzl : moving to Graph is indeed the recommended approach, we can mark the CSOM based methods as obsolete once done and then drop them in a next major release.

The fact that CSOM fails is however not expected, I could repro this and am following up.

@mloitzl
Copy link
Contributor

mloitzl commented Jun 24, 2024

Hi @jansenbe

Some issues with that:
I have no clue how to version the API (ListGrants -> ListGrants2, AddGrant -> AddGrant2) ... I just added the postfix '2' for easier search/replace later on.
The same applies for IPermissionRequest and IOAuth2PermissionGrant

What do you think?

I am open for hints/feedback/advise/help on the changes in #1479

@jansenbe
Copy link
Contributor

@mloitzl : thanks for the great work on this! We're still investigating the issue with the existing CSOM API and will fix that, but being able to use the "modern" approach via Graph is the future.

Let's settle with a "2" suffix whenever that's needed for methods and types. When there's already an "Async" suffix then the let's go for "...2Async". Once this is in place we can mark the old classes/methods as Obsolete. In a next major release then obsolete classes/methods then will be removed from the code base. This way we give folks time to switch over without breaking their code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:admin 📜 Admin library related bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants