I'm trying to get permissions on a SharePoint sub-site using Graph, but not having much joy. So far, I've tried:
var perms = await client.Sites[subSiteId].Permissions.GetAsync();
But this returns an "Operation not supported" error.
Trying to access the sub-site via the parent as below just returns an empty collection (no error):
var perms = client.Sites[parentSiteId].Sites[subSiteId].GetAsync().GetAwaiter().GetResult().Permissions;
Expanding on that to try and use Select or Expand similarly gives an empty collection:
var perms = client.Sites[parentSiteId].Sites[subSiteId].GetAsync((config) =>
{
config.QueryParameters.Select = new string[] { "permissions" };
}).GetAwaiter().GetResult().Permissions;
I know there are permissions set on the sub-sites because I can see them in SharePoint. Am I doing something wrong here? Does anyone know if it is possible to get the permissions of a sub-site using Graph?
OK, after checking with a Microsoft rep, it seems this behaviour is by design, despite being reported as a bug. The /sites/{siteId}/permissions
endpoint only returns permissions for Apps that have been granted permissions to the site, not the actual permissions that users or groups may have within SharePoint.
I have found a solution to the problem that uses PnP and SharePoint CSOM, to make it work you need to register your App in SharePoint:
Next, invite the App into the SharePoint tenant so it can be assigned permissions:
In the App Permission field, you will need to enter some XML. If you want your app to have full control of all SharePoint sites, enter the following:
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/tenant"
Right="FullControl" />
</AppPermissionRequests>
A useful cheat-sheet for other scenarios can be found here: https://medium.com/ng-sp/sharepoint-add-in-permission-xml-cheat-sheet-64b87d8d7600
As a proof-of-concept I knocked up a simple WinForms app with a button to connect and a rich text box to contain the output of the request. The app will need the following packages from NuGet:
My Code:
using System;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using PnP.Framework;
using sp = Microsoft.SharePoint.Client;
namespace CSOM_Perms2
{
public partial class Form1 : Form
{
private string siteUrl = "https://tenant.sharepoint.com/sites/SiteName";
private string username = "<Your Client ID>";
private string password = "<Your Client Secret>";
public Form1()
{
InitializeComponent();
}
private void buttonGetPerms_Click(object sender, EventArgs e)
{
new Thread(() =>
{
_ = Invoke(new Action(() => buttonGetPerms.Enabled = false));
using (var context = new AuthenticationManager().GetACSAppOnlyContext(siteUrl, username, password))
{
context.Load(context.Web);
context.ExecuteQuery();
sp.RoleAssignmentCollection roleAssignments = context.Web.RoleAssignments;
context.Load(roleAssignments);
context.ExecuteQuery();
StringBuilder sb = new StringBuilder();
foreach (sp.RoleAssignment roleAssignment in roleAssignments)
{
sp.Principal principal = roleAssignment.Member;
context.Load(principal);
context.ExecuteQuery();
sb.AppendLine($"Principal: {principal.LoginName}");
sb.AppendLine($"Type: {principal.PrincipalType}");
sp.RoleDefinitionBindingCollection roleDefinitions = roleAssignment.RoleDefinitionBindings;
context.Load(roleDefinitions);
context.ExecuteQuery();
foreach (sp.RoleDefinition roleDefinition in roleDefinitions)
{
sb.AppendLine($"Role Definition: {roleDefinition.Name}");
}
sb.AppendLine(new string('=', 80));
}
_ = Invoke(new Action(() =>
{
richTextBoxPerms.Text = sb.ToString();
buttonGetPerms.Enabled = true;
}));
}
}).Start();
}
}
}
Hope this helps anyone having the same/similar issues as me!