Permission System¶
Home → Documentation → Features → Permissions
Overview¶
Cesivi Server implements a comprehensive permission system that mirrors real SharePoint behavior, including role-based access control (RBAC), Active Directory integration, and permission inheritance.
Features: - ✅ Role Definitions - Full Control, Contribute, Read, etc. - ✅ Role Assignments - Assign roles to users and groups - ✅ Permission Inheritance - Web → List → Item hierarchy - ✅ Active Directory Integration - Users, groups, nested membership - ✅ SharePoint Groups - Native group support - ✅ Effective Permissions - Calculate combined permissions from all roles
SharePoint Permission Model¶
Permission Hierarchy¶
Web Application (root)
└─ Site Collection
└─ Web (Site)
└─ List/Library
└─ List Item/File
Inheritance Flow: - By default, objects inherit permissions from their parent - Inheritance can be broken at any level - Objects with unique permissions maintain their own role assignments
Role Definitions (Permission Levels)¶
SharePoint uses predefined role definitions (permission levels):
| Role Definition | Permission Mask | Description |
|---|---|---|
| Full Control | 0xFFFFFFFFFFFFFFFF | All permissions |
| Design | 0x8F3FFF3F | Create lists/libraries, edit pages |
| Contribute | 0x10000BF | Add, edit, delete items |
| Read | 0x1030021 | View items and pages |
| Limited Access | 0x20000 | Access specific resources |
| View Only | 0x1030020 | View items (no download) |
Base Permissions (Individual Rights)¶
Common SPBasePermissions flags:
| Permission | Value | Description |
|---|---|---|
ViewListItems |
0x01 | View items in lists, documents in libraries |
AddListItems |
0x02 | Add items to lists, documents to libraries |
EditListItems |
0x04 | Edit items in lists, documents in libraries |
DeleteListItems |
0x08 | Delete items from lists, documents from libraries |
OpenItems |
0x10 | View the source of items with file handlers |
ViewPages |
0x20000 | View pages in a site |
Open |
0x10000 | Allow users to open a site |
ManageLists |
0x800 | Create and delete lists, add or remove columns |
FullMask |
0xFFFFFFFFFFFFFFFF | Full control |
Active Directory Integration¶
AD Users and Groups¶
The server can load AD identities from a JSON file to support realistic permission scenarios.
File Location: MockData/ActiveDirectory/identities.json
Example Structure:
{
"Users": [
{
"DistinguishedName": "CN=John Doe,OU=Users,DC=contoso,DC=com",
"SamAccountName": "jdoe",
"UserPrincipalName": "jdoe@contoso.com",
"DisplayName": "John Doe",
"GivenName": "John",
"Surname": "Doe",
"Email": "jdoe@contoso.com",
"Department": "IT",
"Title": "System Administrator",
"MemberOf": [
"CN=IT Admins,OU=Groups,DC=contoso,DC=com",
"CN=Domain Users,OU=Groups,DC=contoso,DC=com"
]
}
],
"Groups": [
{
"DistinguishedName": "CN=IT Admins,OU=Groups,DC=contoso,DC=com",
"SamAccountName": "IT Admins",
"DisplayName": "IT Administrators",
"Description": "IT department administrators",
"GroupType": 0,
"Members": [
"CN=John Doe,OU=Users,DC=contoso,DC=com"
],
"MemberOf": [
"CN=All Admins,OU=Groups,DC=contoso,DC=com"
]
}
]
}
Nested Group Membership¶
The server supports nested groups (groups containing other groups):
All Admins (has Full Control permission)
└─ IT Admins (nested group)
└─ John Doe (user)
When calculating permissions, the server resolves all transitive group memberships using breadth-first search (BFS).
Permission Operations¶
Breaking Permission Inheritance¶
REST API:
// Break inheritance on a list
fetch('http://localhost:5000/_api/web/lists/getbytitle(\'Documents\')/breakroleinheritance(copyRoleAssignments=true,clearSubscopes=true)', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('user:password'),
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(r => r.json())
.then(data => console.log('Inheritance broken'));
C# CSOM:
using Microsoft.SharePoint.Client;
var ctx = new ClientContext("http://localhost:5000");
ctx.Credentials = new System.Net.NetworkCredential("user", "password");
var list = ctx.Web.Lists.GetByTitle("Documents");
list.BreakRoleInheritance(copyRoleAssignments: true, clearSubscopes: true);
ctx.ExecuteQuery();
Console.WriteLine("Inheritance broken on list");
PowerShell PnP:
Connect-PnPOnline -Url "http://localhost:5000" -Credentials (Get-Credential)
# Break inheritance on a list
Set-PnPList -Identity "Documents" -BreakRoleInheritance -CopyRoleAssignments
# OR use REST API for better reliability
Invoke-PnPSPRestMethod -Method POST `
-Url "/_api/web/lists/getbytitle('Documents')/breakroleinheritance(copyRoleAssignments=true,clearSubscopes=true)"
Resetting Permission Inheritance¶
REST API:
// Reset inheritance on a list
fetch('http://localhost:5000/_api/web/lists/getbytitle(\'Documents\')/resetroleinheritance()', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('user:password'),
'Accept': 'application/json'
}
})
.then(r => r.json())
.then(data => console.log('Inheritance reset'));
C# CSOM:
var list = ctx.Web.Lists.GetByTitle("Documents");
list.ResetRoleInheritance();
ctx.ExecuteQuery();
Console.WriteLine("Inheritance reset on list");
Granting Permissions¶
REST API:
// Grant Read permission to a user on a list
const data = {
__metadata: { type: 'SP.RoleAssignment' },
PrincipalId: 5, // User ID
RoleDefId: 1073741826 // Read role definition ID
};
fetch('http://localhost:5000/_api/web/lists/getbytitle(\'Documents\')/roleassignments/addroleassignment(principalid=5,roledefid=1073741826)', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('user:password'),
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(r => r.json())
.then(data => console.log('Permission granted'));
C# CSOM:
var list = ctx.Web.Lists.GetByTitle("Documents");
var user = ctx.Web.EnsureUser("jdoe@contoso.com");
var roleDefinition = ctx.Web.RoleDefinitions.GetByName("Read");
ctx.Load(user);
ctx.Load(roleDefinition);
ctx.ExecuteQuery();
var roleAssignment = new RoleDefinitionBindingCollection(ctx);
roleAssignment.Add(roleDefinition);
list.RoleAssignments.Add(user, roleAssignment);
ctx.ExecuteQuery();
Console.WriteLine($"Granted Read permission to {user.Title}");
PowerShell PnP:
# Grant Read permission to a user on a list
Set-PnPListPermission -Identity "Documents" -User "jdoe@contoso.com" -AddRole "Read"
# Grant Contribute permission to a group
Set-PnPListPermission -Identity "Documents" -Group "IT Admins" -AddRole "Contribute"
Checking Permissions¶
C# CSOM:
// Check if user has specific permission
var list = ctx.Web.Lists.GetByTitle("Documents");
var user = ctx.Web.CurrentUser;
ctx.Load(list, l => l.EffectiveBasePermissions);
ctx.Load(user);
ctx.ExecuteQuery();
bool canEdit = list.EffectiveBasePermissions.Has(PermissionKind.EditListItems);
bool canDelete = list.EffectiveBasePermissions.Has(PermissionKind.DeleteListItems);
Console.WriteLine($"Can Edit: {canEdit}");
Console.WriteLine($"Can Delete: {canDelete}");
PowerShell PnP:
# Get user's effective permissions on a list
$ctx = Get-PnPContext
$list = Get-PnPList "Documents"
$user = $ctx.Web.CurrentUser
$ctx.Load($list, "EffectiveBasePermissions")
$ctx.Load($user)
$ctx.ExecuteQuery()
$canEdit = $list.EffectiveBasePermissions.Has([Microsoft.SharePoint.Client.PermissionKind]::EditListItems)
Write-Host "Can Edit: $canEdit"
REST API:
// Get user's effective permissions
fetch('http://localhost:5000/_api/web/lists/getbytitle(\'Documents\')/getusereffectivepermissions(@user)?@user=\'jdoe@contoso.com\'', {
headers: {
'Authorization': 'Basic ' + btoa('user:password'),
'Accept': 'application/json'
}
})
.then(r => r.json())
.then(data => {
const permissions = parseInt(data.d.GetUserEffectivePermissions);
const canEdit = (permissions & 0x04) === 0x04; // EditListItems
console.log('Can Edit:', canEdit);
});
User and Group Management¶
Creating SharePoint Users¶
REST API:
// Add a user to the site
const userData = {
__metadata: { type: 'SP.User' },
LoginName: 'jdoe@contoso.com'
};
fetch('http://localhost:5000/_api/web/siteusers', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('user:password'),
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
})
.then(r => r.json())
.then(data => console.log('User added:', data.d.Title));
C# CSOM:
var user = ctx.Web.EnsureUser("jdoe@contoso.com");
ctx.Load(user);
ctx.ExecuteQuery();
Console.WriteLine($"User added: {user.Title} (ID: {user.Id})");
PowerShell PnP:
# Add a user to the site
New-PnPUser -LoginName "jdoe@contoso.com"
Creating SharePoint Groups¶
REST API:
// Create a SharePoint group
const groupData = {
__metadata: { type: 'SP.Group' },
Title: 'Project Team',
Description: 'Project team members'
};
fetch('http://localhost:5000/_api/web/sitegroups', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('user:password'),
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(groupData)
})
.then(r => r.json())
.then(data => console.log('Group created:', data.d.Title));
C# CSOM:
var groupInfo = new GroupCreationInformation
{
Title = "Project Team",
Description = "Project team members"
};
var group = ctx.Web.SiteGroups.Add(groupInfo);
ctx.Load(group);
ctx.ExecuteQuery();
Console.WriteLine($"Group created: {group.Title} (ID: {group.Id})");
PowerShell PnP:
# Create a SharePoint group
New-PnPGroup -Title "Project Team" -Description "Project team members"
Adding Users to Groups¶
REST API:
// Add user to group
fetch('http://localhost:5000/_api/web/sitegroups(7)/users', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('user:password'),
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
__metadata: { type: 'SP.User' },
LoginName: 'jdoe@contoso.com'
})
})
.then(r => r.json())
.then(data => console.log('User added to group'));
C# CSOM:
var group = ctx.Web.SiteGroups.GetByName("Project Team");
var user = ctx.Web.EnsureUser("jdoe@contoso.com");
group.Users.AddUser(user);
ctx.ExecuteQuery();
Console.WriteLine($"Added {user.Title} to {group.Title}");
PowerShell PnP:
# Add user to group
Add-PnPGroupMember -Group "Project Team" -LoginName "jdoe@contoso.com"
Permission Scenarios¶
Scenario 1: Secure Document Library¶
Requirement: Create a document library with restricted access for specific team.
using Microsoft.SharePoint.Client;
var ctx = new ClientContext("http://localhost:5000");
ctx.Credentials = new System.Net.NetworkCredential("admin", "password");
// 1. Create document library
var listInfo = new ListCreationInformation
{
Title = "Confidential Documents",
TemplateType = (int)ListTemplateType.DocumentLibrary
};
var list = ctx.Web.Lists.Add(listInfo);
ctx.Load(list);
ctx.ExecuteQuery();
// 2. Break inheritance (don't copy role assignments)
list.BreakRoleInheritance(copyRoleAssignments: false, clearSubscopes: true);
ctx.ExecuteQuery();
// 3. Grant Full Control to administrators
var adminGroup = ctx.Web.SiteGroups.GetByName("Site Owners");
var fullControlRole = ctx.Web.RoleDefinitions.GetByName("Full Control");
ctx.Load(adminGroup);
ctx.Load(fullControlRole);
ctx.ExecuteQuery();
var adminRoleAssignment = new RoleDefinitionBindingCollection(ctx);
adminRoleAssignment.Add(fullControlRole);
list.RoleAssignments.Add(adminGroup, adminRoleAssignment);
ctx.ExecuteQuery();
// 4. Grant Contribute to project team
var teamGroup = ctx.Web.SiteGroups.GetByName("Project Team");
var contributeRole = ctx.Web.RoleDefinitions.GetByName("Contribute");
ctx.Load(teamGroup);
ctx.Load(contributeRole);
ctx.ExecuteQuery();
var teamRoleAssignment = new RoleDefinitionBindingCollection(ctx);
teamRoleAssignment.Add(contributeRole);
list.RoleAssignments.Add(teamGroup, teamRoleAssignment);
ctx.ExecuteQuery();
Console.WriteLine("Secure document library created");
Scenario 2: Item-Level Permissions¶
Requirement: Restrict specific document to selected users only.
// Get the document
var list = ctx.Web.Lists.GetByTitle("Confidential Documents");
var item = list.GetItemById(1);
ctx.Load(item);
ctx.ExecuteQuery();
// Break inheritance on item
item.BreakRoleInheritance(copyRoleAssignments: false, clearSubscopes: true);
ctx.ExecuteQuery();
// Grant Read to specific user
var user = ctx.Web.EnsureUser("manager@contoso.com");
var readRole = ctx.Web.RoleDefinitions.GetByName("Read");
ctx.Load(user);
ctx.Load(readRole);
ctx.ExecuteQuery();
var userRoleAssignment = new RoleDefinitionBindingCollection(ctx);
userRoleAssignment.Add(readRole);
item.RoleAssignments.Add(user, userRoleAssignment);
ctx.ExecuteQuery();
Console.WriteLine("Item-level permissions set");
Scenario 3: Nested AD Groups with Permissions¶
Requirement: Use AD group hierarchy for permission management.
Setup (identities.json):
{
"Groups": [
{
"DistinguishedName": "CN=All Employees,OU=Groups,DC=contoso,DC=com",
"SamAccountName": "All Employees",
"Members": [
"CN=IT Department,OU=Groups,DC=contoso,DC=com",
"CN=HR Department,OU=Groups,DC=contoso,DC=com"
]
},
{
"DistinguishedName": "CN=IT Department,OU=Groups,DC=contoso,DC=com",
"SamAccountName": "IT Department",
"Members": [
"CN=John Doe,OU=Users,DC=contoso,DC=com"
],
"MemberOf": [
"CN=All Employees,OU=Groups,DC=contoso,DC=com"
]
}
],
"Users": [
{
"DistinguishedName": "CN=John Doe,OU=Users,DC=contoso,DC=com",
"SamAccountName": "jdoe",
"MemberOf": [
"CN=IT Department,OU=Groups,DC=contoso,DC=com"
]
}
]
}
Grant Permission to Top-Level Group:
// Grant Read to "All Employees" AD group
var list = ctx.Web.Lists.GetByTitle("Company News");
var adGroup = ctx.Web.EnsureUser("All Employees"); // AD group
var readRole = ctx.Web.RoleDefinitions.GetByName("Read");
ctx.Load(adGroup);
ctx.Load(readRole);
ctx.ExecuteQuery();
var roleAssignment = new RoleDefinitionBindingCollection(ctx);
roleAssignment.Add(readRole);
list.RoleAssignments.Add(adGroup, roleAssignment);
ctx.ExecuteQuery();
// Now "jdoe" has Read permission (nested membership resolved):
// jdoe → IT Department → All Employees → Read permission
Effective Permissions Calculation¶
The server calculates effective permissions by:
- Resolving User Identity - Check AD storage, then SharePoint users
- Getting All Groups - Direct memberships + nested AD groups + SharePoint groups
- Collecting Role Assignments - Check all applicable role assignments for user and groups
- Combining Permissions - Union (OR) all permission masks from all roles
- Checking Inheritance - If object inherits, check parent permissions too
Example Calculation:
User: John Doe (jdoe)
├─ Direct Role: None
├─ SharePoint Group: "Site Members" → Contribute (0x10000BF)
├─ AD Group: "IT Department" → Design (0x8F3FFF3F)
└─ Nested AD Group: "All Employees" → Read (0x1030021)
Effective Permissions = 0x10000BF | 0x8F3FFF3F | 0x1030021
= 0x8F3FFFF (union of all permissions)
Best Practices¶
1. Use Groups, Not Individual Users¶
Good Practice:
// Grant permission to group
var group = ctx.Web.SiteGroups.GetByName("Project Team");
list.RoleAssignments.Add(group, roleAssignment);
Bad Practice:
// Grant permission to 50 individual users
foreach (var userEmail in emails)
{
var user = ctx.Web.EnsureUser(userEmail);
list.RoleAssignments.Add(user, roleAssignment); // Harder to manage
}
2. Minimize Broken Inheritance¶
Good Practice: - Use inheritance where possible - Only break when absolutely necessary - Document why inheritance was broken
Bad Practice: - Breaking inheritance on every item - Creates management nightmare - Performance issues with many unique permissions
3. Use Nested AD Groups¶
Good Practice:
All Employees (has Read permission)
├─ IT Department
│ └─ IT Admins (has Full Control via separate assignment)
└─ HR Department
Benefits: - Single permission assignment covers all employees - Easy to add/remove users via AD group membership - Reflects organizational structure
4. Test Permissions Before Deployment¶
// Verify user has expected permissions
var list = ctx.Web.Lists.GetByTitle("Documents");
var user = ctx.Web.CurrentUser;
ctx.Load(list, l => l.EffectiveBasePermissions);
ctx.Load(user);
ctx.ExecuteQuery();
bool hasExpectedPermission = list.EffectiveBasePermissions.Has(PermissionKind.AddListItems);
if (!hasExpectedPermission)
{
throw new Exception($"User {user.Title} missing expected permission");
}
Troubleshooting¶
User Cannot Access Content¶
Diagnosis Steps:
// 1. Verify user can be resolved
var user = ctx.Web.EnsureUser("jdoe@contoso.com");
ctx.Load(user);
ctx.ExecuteQuery();
Console.WriteLine($"User: {user.Title} (ID: {user.Id})");
// 2. Check group memberships
var groups = user.Groups;
ctx.Load(groups);
ctx.ExecuteQuery();
Console.WriteLine($"Member of {groups.Count} groups:");
foreach (var group in groups)
{
Console.WriteLine($" - {group.Title}");
}
// 3. Check effective permissions
var list = ctx.Web.Lists.GetByTitle("Documents");
ctx.Load(list, l => l.EffectiveBasePermissions);
ctx.ExecuteQuery();
bool canView = list.EffectiveBasePermissions.Has(PermissionKind.ViewListItems);
bool canEdit = list.EffectiveBasePermissions.Has(PermissionKind.EditListItems);
Console.WriteLine($"Can View: {canView}, Can Edit: {canEdit}");
// 4. Check role assignments on list
var roleAssignments = list.RoleAssignments;
ctx.Load(roleAssignments, ras => ras.Include(ra => ra.Member, ra => ra.RoleDefinitionBindings));
ctx.ExecuteQuery();
Console.WriteLine($"Role Assignments: {roleAssignments.Count}");
foreach (var ra in roleAssignments)
{
Console.WriteLine($" Principal: {ra.Member.Title}");
foreach (var roleDef in ra.RoleDefinitionBindings)
{
Console.WriteLine($" Role: {roleDef.Name}");
}
}
Permission Changes Not Taking Effect¶
Common Issues:
-
Inheritance Not Broken:
var list = ctx.Web.Lists.GetByTitle("Documents"); ctx.Load(list, l => l.HasUniqueRoleAssignments); ctx.ExecuteQuery(); if (!list.HasUniqueRoleAssignments) { Console.WriteLine("List inherits permissions from parent"); list.BreakRoleInheritance(copyRoleAssignments: false, clearSubscopes: true); ctx.ExecuteQuery(); } -
Caching Issues:
- Restart server to reload MockData
-
Clear browser cache if using web UI
-
AD Group Membership Not Updated:
- Verify
MemberOfarrays in identities.json - Restart server to reload AD data
API Reference Summary¶
ACL Service (Server-Side)¶
public interface IACLService
{
// Check specific permission
Task<bool> CheckPermissionAsync(string userLogin, string objectPath, ulong permission);
// Get combined permission mask
Task<ulong> GetEffectivePermissionsAsync(string userLogin, string objectPath);
// Get all groups (AD + SharePoint)
Task<List<string>> GetUserAllGroupsAsync(string userLogin);
// Resolve identity
Task<ResolvedIdentity?> ResolveIdentityAsync(string login);
// Get role assignments
Task<List<SPRoleAssignment>> GetRoleAssignmentsAsync(string objectPath);
}
Object Path Formats:
- Web: web:/sites/site
- List: list:/sites/site/Lists/ListName
- Item: item:/sites/site/Lists/ListName/ItemID
- File: file:/sites/site/Shared Documents/file.docx
Related Documentation¶
Features¶
- Authentication - User authentication methods
- CSOM - CSOM permission operations
- PnP PowerShell - PnP permission cmdlets
- REST API - REST permission endpoints
Reference¶
- API Reference - Complete API documentation
- Architecture - Permission system design
Setup¶
- Quick Start - Get started quickly
Last Updated: November 15, 2025 Version: 1.0.0
Navigation: Home | Documentation | Features | Permissions