Understanding SharePoint security groups, permission levels, and permissions through browser and CSOM

11 Mar 2015

Security groups, permission levels, and permissions are core concepts of SharePoint's role-based security model which can be hard to grasp. Especially since the browser interface and the object model use different terminology for the same concepts and the object model adds additional concepts to record inter-object relationships. Thus, through screenshots and code, in this post, I'll attempt to correlate security information from the user interface with that of the object model.

Setup

All code snippets in this post assume the SharePoint context object has already been initialized. For completeness sake, here's the code to setup the context:

class Program {
    static void Main() {
        var siteCollection = new Uri("https://bugfree.sharepoint.com/teams/AcmeCorpTeamSiteCollection");
        var user = "rh@bugfree.onmicrosoft.com";
        var password = "password";
        var securePassword = new SecureString();
        password.ToCharArray().ToList().ForEach(securePassword.AppendChar);
        var credentials = new SharePointOnlineCredentials(user, securePassword);
        var ctx = new ClientContext(siteCollection) { Credentials = credentials };
        var rootWeb = ctx.Site.RootWeb;

        // code below goes here.
    }
}

Site permissions and security groups

Starting from the top of the security hierarchy, the Site permissions menu item under Site settings shows the site collection's SharePoint security groups, including their permission levels.

To list the same set of security groups using the object model, the following code is required:

ctx.Load(rootWeb, w => w.SiteGroups);
ctx.ExecuteQuery();

// AcmeCorpTeamSiteCollection Members
// AcmeCorpTeamSiteCollection Owners
// AcmeCorpTeamSiteCollection Visitors
// Excel Services Viewers
foreach (var group in rootWeb.SiteGroups) {
    System.Console.WriteLine(group.Title);
}

When SharePoint created this site collection, the fixed set of security groups got created with it. Afterwards, we may create additional security groups and reference those from any web within the site collection.

Note the use of the ambiguous term site in the user interface and in the CSOM API. In general, site can refer to either site collection or web depending on the context. Here it refers to site collection because security groups exist at the site collection level and only at the site collection level.

This implies that creating a new web and breaking role inheritance (through the browser interface), even though SharePoint creates additional members, owners, and visitors groups and associates those with the new web, the security groups themselves are created at the site collection level and hence are visible and usable from any web within the site collection.

Conversely, creating a security group isn't useful in itself -- it's nothing but a container for SharePoint users (typically Active Directory users) and Active Directory groups. The security group must be associated with a securable object, such as a web, list, or list item for it to be of actual use.

Role assignments relating site groups with role definitions

The term role assignment refers to an object which tracks the many-to-many relationship between site groups on one hand and role definitions on the other. One site group, such as Members, may be associated with any number of role definitions, such as Read or Edit or custom ones. Each role definition in turn may be associated with any number of site groups. In other words, the role assignment construct is an indirection mechanism to decouple site groups from role definitions, furthering the reuse of both.

What's displayed in the browser under Site Settings and Site Permissions are the security groups with their associated (or bound) role definitions. What the user interface calls permission levels, the object model calls role definition bindings.

Given a securable object such as a web, we can iterate its role assignments and role definition bindings using the code below:

// Excel Services Viewers
//   View Only
// AcmeCorpTeamSiteCollection Owners
//   Full Control
// AcmeCorpTeamSiteCollection Visitors
//   Read
// AcmeCorpTeamSiteCollection Members
//   Edit
ctx.Load(rootWeb, w => w.RoleAssignments);
ctx.ExecuteQuery();

foreach (var ra in rootWeb.RoleAssignments) {
    ctx.Load(ra.Member);
    ctx.Load(ra.RoleDefinitionBindings);
    ctx.ExecuteQuery();

    System.Console.WriteLine(ra.Member.Title);
    foreach (var binding in ra.RoleDefinitionBindings) {
        System.Console.WriteLine("  " + binding.Name);
    }
}

These are the standard role definitions created by SharePoint during site collection creation. Like with security groups, we can create our own role definition and associate those with groups. For instance, we may deviate from the out of the box behavior and create a role definition for when contributors should only be allowed to add items to lists and not delete. Or when visitors should be able to create and save personal views on lists, which they aren't by default.

In any event, never modify an out of the box role definition. Instead, create a new one and reset the binding where applicable. This'll make long-term maintenance and upgrading easier.

Role definitions and base permissions

From the ribbon in Site permissions, the Permission levels button list all permission levels. Note how more levels are listed under permission levels than Site permissions, implying that not all permission levels are in use by default:

Clicking a permission level displays a list of permissions, each of which can be turned on or off. The screenshot only includes the first couple of permissions:

Like with security groups and role definitions, a similar many-to-many relationship exists between RoleDefinitions and BasePermissions (and for the same reason of decoupling). Note also how it's slightly confusing that both the name of the property on the RoleDefinition class and the property's underlying type is BasePermissions.

In the object model, base permissions are represented by the PermissionKind enumeration. For each role definition, we may iterate this enumeration to get the base permissions which are turned on:

// Full Control
//   EmptyMask
//   ViewListItems
//   AddListItems
//   EditListItems
//   DeleteListItems
//   ...
// Design
//   ...
// Edit
//   ...
// Contribute
//   ...
// Read
//   ...
// Limited Access
//   ...
// View Only 
//   ...
var kinds = Enum.GetValues(typeof(PermissionKind));
ctx.Load(rootWeb, w => w.RoleDefinitions);
ctx.ExecuteQuery();

foreach (var roleDefinition in rootWeb.RoleDefinitions) {
    System.Console.WriteLine(roleDefinition.Name);
    foreach (PermissionKind kind in kinds) {
        if (roleDefinition.BasePermissions.Has(kind)) {
            System.Console.WriteLine("  " + kind);
        }
    }
}

The set of base permissions is hardcoded into SharePoint and thus can only be modified by Microsoft. In principle though, the set of base permissions could've been made extensible. Then we would've been able to create domain specific base permissions and test on those in code. But given the already complex security model, the SharePoint team seems to have decided against it.

Example: modifying web associated owner, visitor, and member groups

The owners, visitors, and members groups -- or more specifically the role assignments related to each group -- are intrinsic to the web object. It has distinct properties for associating an owner, visitor, and member group with a web object. This seems odd, compared to simply adding role assignments to the web object and having their role definitions and base permissions define what a user can do. For some reason, the SharePoint team decided to add an extra discriminator to the security equation so that inside a web, we can assert the user has a specific permission and has as a special group association.

Let's list the associations (don't believe there's a page displaying the same information):

ctx.Load(rootWeb,
    w => w.AssociatedOwnerGroup,
    w => w.AssociatedVisitorGroup,
    w => w.AssociatedMemberGroup);
ctx.ExecuteQuery();

// AcmeCorpTeamSiteCollection Owners
// AcmeCorpTeamSiteCollection Visitors
// AcmeCorpTeamSiteCollection Members
System.Console.WriteLine(web.AssociatedOwnerGroup.Title);
System.Console.WriteLine(web.AssociatedVisitorGroup.Title);
System.Console.WriteLine(web.AssociatedMemberGroup.Title);

Any security group may be designated the web's owner, visitor, or member group by assigning it to the corresponding property on the web. It just so happened that during site collection creation, SharePoint created groups with names of owners, visitors, and members prefixed by site collection title and setup the associations on our behalf.

Now, let's redefine the default visitors group associated with the root web. First we locate the associated security group (it can be any custom created security groups previously assigned). Then we load the group's role assignments and modify its bindings to include Full Control.

ctx.Load(rootWeb.AssociatedVisitorGroup);
var availableRoleDefinitions = rootWeb.RoleDefinitions;
ctx.Load(availableRoleDefinitions);
ctx.ExecuteQuery();

var roleAssignmentsForVisitorGroup = rootWeb.RoleAssignments.GetByPrincipal(rootWeb.AssociatedVisitorGroup);
ctx.Load(roleAssignmentsForVisitorGroup, ra => ra.RoleDefinitionBindings);
ctx.ExecuteQuery();

// the Read permission level is added by SharePoint by default
//roleAssignmentsForVisitorGroup.RoleDefinitionBindings.RemoveAll();
roleAssignmentsForVisitorGroup.RoleDefinitionBindings.Add(availableRoleDefinitions.GetByName("Full Control"));
roleAssignmentsForVisitorGroup.Update();
ctx.ExecuteQuery();

With the above change, every SharePoint user and Active Directory group added to the visitors security group operate have Full control permissions within the site collection.

Conclusion

In order to keep track of the concepts and their relationships, think of the SharePoint security model in terms of the following layering:

Securable object (Web, list, list item)
  Role assignments
    Member (AcmeCorpTeamSiteCollection Visitors, custom security groups)
    RoleDefinitionBindings
      RoleDefinitions
        RoleDefinition (Read, Contribute, custom role definitions)
          BasePermissions (ViewListItem, EditListItem)

When SharePoint has to determine if a user is authorized to perform a certain action, such as editing a list item, SharePoint computes the user's effective set of base permissions for the securable object in question (in this case a list item). The computation involves taking into account all role assignments of the securable object and logically OR'ing together their indirectly related base permissions. Only if the resulting set includes EditListItem is the user allowed to edit the list item.

Have comments or questions? Please drop me an email or tweet to @ronnieholm.