Abhishek Bansal
Abhishek Bansal

Reputation: 99

How to get permission levels for Files/Folders/Documents in Sharepoint using rest endpoints?

I am using the following rest end point while trying to get permission levels for a particular file/document.

https://<web url>/_api/Web/GetFileByServerRelativeUrl('<path to the file>')/getlimitedwebpartmanager(scope=1 or 0)

I am able to get hold of the file successfully. But how should I get hold of the permission levels now?

Upvotes: 5

Views: 16202

Answers (4)

WantToDo
WantToDo

Reputation: 441

$.ajax({ 
    url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/getFileByServerRelativeUrl('<your file or folder url>')/ListItemAllFields/effectiveBasePermissions",
    type: "GET",
    headers: { Accept: "application/json;odata=verbose" },
    success: function(data){
        var permissions = new SP.BasePermissions();
        permissions.initPropertiesFromJson(data.d.EffectiveBasePermissions);
        var hasPermissions = permissions.has(SP.PermissionKind.<any level to check>);
        //for example: var bool_has_editListItems =  permissions.has(SP.PermissionKind.editListItems);
    }
});

to check more levels, see SP.PermissionKind list

Upvotes: 0

Thomas Doman
Thomas Doman

Reputation: 566

What I do to get the permission levels is by using the "$expand" query parameter equal to "ListItemAllFields/RoleAssignments/XXXX" where XXXX is Member, RoleDefinitionBindings, and so forth expanding out the chain as far as I need to get the user and permission level info that I need. For example,

.../GetFileByServerRelativeUrl('')?$expand=ListItemAllFields/RoleAssignments/Member,ListItemAllFields/RoleAssignments/RoleDefinitionBindings,ListItemAllFields/RoleAssignments/Member/Users

It took a lot of web searching to figure out that the "$expand" query parameter even existed but it's very useful to get all the info needed in one GET. I subsequently add a "$select" parameter to the query to filter out just the pieces that my application uses.

Edit: Also look at Radu's question and my follow-up answer below. The answer to the question depends on what you're trying to accomplish. To quote part of my answer:

If you're dredging for all permissions had by all users, use my approach. However, you'll need sufficient rights to get that information. If you want to know the base permissions of the user you're using to make the request, use his approach. I have both use cases in my work so I, in fact, do both.

Upvotes: 9

Radu Simionescu
Radu Simionescu

Reputation: 4686

The accepted solution didn't work for me. It seems that a user doesn't by default have permission to see RoleAssignments. But here's what I ended up doing.

I grabbed the effectiveBasePermissions by getting a response from /_api/web/getFileByServerRelativeUrl('my/relative/path')/ListItemAllFields/effectiveBasePermissions

I think this works for any item/folder in sharepoint by appending the /ListItemAllFields/effectiveBasePermissions to the url)

So, this returns the permission that the current user has for that file/item. The Permissions "object" is a set of 35 flags which are encoded in 64 bits (not all 64 bits are used - only 35). And these bits are provided by the endpoint as two integers (32 bits each) named:

  • Low - representing the first 32 bits
  • High - the next 32 bits in sequence, up to 64

Now, to see if the user has, for instance, editing permissions on that file, we need to look at the corresponding bit in this Low-High sequence. You can find what each bit in the sequence means, below:

    ViewListItems = 1,
    AddListItems = 2,
    EditListItems = 3,
    DeleteListItems = 4,
    ApproveItems = 5,
    OpenItems = 6,
    ViewVersions = 7,
    DeleteVersions = 8,
    CancelCheckout = 9,
    ManagePersonalViews = 10,
    ManageLists = 12,
    ViewFormPages = 13,
    AnonymousSearchAccessList = 14,
    Open = 17,
    ViewPages = 18,
    AddAndCustomizePages = 19,
    ApplyThemeAndBorder = 20,
    ApplyStyleSheets = 21,
    ViewUsageData = 22,
    CreateSSCSite = 23,
    ManageSubwebs = 24,
    CreateGroups = 25,
    ManagePermissions = 26,
    BrowseDirectories = 27,
    BrowseUserInfo = 28,
    AddDelPrivateWebParts = 29,
    UpdatePersonalWebParts = 30,
    ManageWeb = 31,
    AnonymousSearchAccessWebLists = 32,
    UseClientIntegration = 37,
    UseRemoteAPIs = 38,
    ManageAlerts = 39,
    CreateAlerts = 40,
    EditMyUserInfo = 41,
    EnumeratePermissions = 63

As you can see, some bits don't mean anything (like bit 11, 33, 34 etc) So, we need to look at bit number 3 (for editing) from the first 32 bits to tell if user can edit this file/item/folder. We can just ignore the High bits. We must make a bitwise comparison with the integer which in binary format has only the 3rd bit set to 1 (the rest being 0). In this case this is 100 (this is the binary representation of 4). There is a formula for this, actually: binaryNr = 2^(bitIndex - 1). For our example, bitIndex is 3. Now that we have the binaryNr we use it as a mask to find out if the third bit in the low sequence is 0 or 1:

hasEditingPermission = (binaryNr | LowSequence) == LowSequence

and here's a handy pseudocode function for the whole thing (^ is the power operator):

function hasPermission (low, high, bitIndex){
  var sequence = low;
  if (bitIndex >= 32){
    sequence = high;
    bit -= 32;
  }
  return ((2^(bitIndex - 1)) | sequence) == sequence
}

Upvotes: 8

Thomas Doman
Thomas Doman

Reputation: 566

Radu made a great point in his answer for a different use case than I had given in my answer. If you're dredging for all permissions had by all users, use my approach. However, you'll need sufficient rights to get that information. If you want to know the base permissions of the user you're using to make the request, use his approach. I have both use cases in my work so I, in fact, do both.

However, as I commented to Radu in his answer, I had some trouble using his hasPermission() function. I'm adding a new answer here to provide an example of why it didn't work for me:

I'm definitely not a expert bit twiddler but, in Java at least, 1 << (bitIndex-1) is not equivalent to 2 ^ (bitIndex-1) as Radu asserted in his comment. Perhaps the overall expressions were intended to accomplish the same thing so here's an example where I discovered the XOR approach didn't work for me.

Example: The permissions had by the user correspond to the permission list "Limited Access" (low = 134287360). I want to check if the user has the "Open" permission, bit 17. In binary, the low value (which becomes "sequence" in hasPermission()) is 1000000000010001000000000000. As you will see, bit 17 is set. Running the expression ((2^(bitIndex - 1)) | sequence) yields 1000000000010001000000010010 which obviously does not equal sequence as required to get a true response from hasPermission().

So, not understanding or knowing for sure exactly what was intended by Radu's XOR approach, I decided to use a more straightforward, less obtuse way for testing for the presence of a bit. Like so: return (sequence & (1 << (bitIndex - 1))) != 0; Taking 1 and shifting it bitIndex-1 spaces to the left and then doing a bitwise AND not only makes it obvious what I'm trying to accomplish but it also works in every case I've tested.

Not being a bit twiddler as I said, I briefly considered whether there might be problems with signed values etc. (I'm using ints for high and low) but I don't think my approach really would suffer from any of that since I'm not shifting the ints themselves and the remainder of my logic is simply bitwise.

Upvotes: 0

Related Questions