Exam Area: Area 1 – Product Knowledge (15%) Reference: https://docs.developers.optimizely.com/content-management-system/docs/access-rights
CMS 12 has two independent access control mechanisms:
| Level | What it controls |
|---|---|
| Role-based (UI access) | Whether a user can access Edit View, Admin View |
| ACL (content-based) | What a user can do with a specific content item |
// Defined in EPiServer.Security.AccessLevel enum
public enum AccessLevel
{
NoAccess = 0,
Read = 1, // View published content
Create = 2, // Create child content
Edit = 4, // Edit content
Delete = 8, // Delete content
Publish = 16, // Publish content
Administer = 64, // Manage access rights
FullAccess = 255 // All of the above
}
Content ACLs inherit downward through the page tree by default:
/StartPage/ [WebEditors: Read,Create,Edit,Publish]
/News/ [inherits parent]
/NewsArticle/ [inherits parent — same ACL as News]
If you change /News/ ACL:
→ Right-click → Access Rights
→ Change settings
→ Options: Apply to this item only / Apply to all descendants
Access rights can be restricted per language branch:
Admin → Languages → Swedish (sv) → Edit permissions:
→ SwedishEditors: ✅ can edit Swedish content
→ GermanEditors: ❌ cannot edit Swedish content
This is independent of content ACLs.
A user needs BOTH:
1. Content ACL (Edit level) on the content
2. Language permission to edit that language
public class AccessRightsService
{
private readonly IContentSecurityRepository _securityRepo;
public AccessRightsService(IContentSecurityRepository securityRepo)
{
_securityRepo = securityRepo;
}
public void GrantPublishToRole(ContentReference contentRef, string roleName)
{
var descriptor = (IContentSecurityDescriptor)
_securityRepo.Get(contentRef).CreateWritableClone();
descriptor.AddEntry(new AccessControlEntry(
name: roleName,
access: AccessLevel.Read | AccessLevel.Edit | AccessLevel.Publish,
entityType: SecurityEntityType.Role));
_securityRepo.Save(
contentRef,
descriptor,
SecuritySaveType.ReplaceChildPermissions); // Apply to all descendants
}
}
| Value | Description |
|---|---|
None | Apply only to this content item |
ReplaceChildPermissions | Recursively apply to all descendants |
Merge | Merge with existing ACL entries |
Replace | Replace all existing ACL entries |
// Option 1: IContentAccessEvaluator
bool canPublish = _contentAccessEvaluator.HasAccess(
content,
PrincipalInfo.CurrentPrincipal,
AccessLevel.Publish);
// Option 2: QueryDistinctRoots — get all content roots the user has access to
var roots = _contentRepository.GetChildren<IContent>(
ContentReference.StartPage,
new AccessControlFilter(PrincipalInfo.CurrentPrincipal, AccessLevel.Read));
// CreatorRole = virtual role that matches only the creator of the content
// Can be used to allow editors to publish only their own content
[Display(Name = "My Articles")]
public virtual bool AllowSelfPublish { get; set; }
Edit View → Page Tree → right-click page → "Access Rights"
→ Shows current ACL for this page
→ Add: user or role
→ Set: Read / Create / Edit / Delete / Publish / Administer
→ Apply to: this item only / this item and all descendants
SecuritySaveType.ReplaceChildPermissions do? (Recursively applies the new ACL to all descendants of the content item)