INDIVIRTUAL - TECHNISCH PARTNER IN DIGITALE DIENSTVERLENING

How to set Rights and Permissions using the SDL Tridion core service API

March 21, 2014

How to set Rights and Permissions using the SDL Tridion core service API

Today I saw an interesting question on the Tridion Stack Exchange site about setting permissions on multiple categories. Of course, a slightly broader question is also interesting - how can I also set multiple permissions on folders, and rights on publications? The answer to the question as posed is that you can’t do it directly from the GUI but that the core service offers the possibility of automating the process.

This is a great example of when it makes sense to write a couple of Powershell functions, and add them to your profile. Then any time you want to set up some permissions you can either do it as a “one liner” from the shell, or write a quick script. Once you see the code, you’ll understand why… the core service API doesn’t really offer a high enough level of abstraction. Instead, it gives you a fine degree of control, but mostly, you know exactly what permissions you want a given group to have, so let’s wrap it up a bit.

Here’s the sample code that demonstrates the technique. In fact, some of the code is just for demonstration purposes. The useful part is in the three functions.

# Depends on PowerShell Reflection module (http://poshcode.org/search/Reflection)
# Depends on Tridion Powershell Modules (http://code.google.com/p/tridion-powershell-modules/)

$autoLocalize = $true

import-module Tridion-CoreService
$core = Get-TridionCoreServiceClient

import-module Reflection
import-namespace Tridion.ContentManager.CoreService.Client

$defaultReadOptions = new-object ReadOptions 
$groupsFilter = new-object GroupsFilterData
$usersFilter = new-object UsersFilterData

function addRightsAndPermissions( $trustee, $orgItem, $rights, $permissions){

    if ($autoLocalize -and $orgItem.BluePrintInfo.IsShared){
        $orgItem = $core.Localize($orgItem.Id, $defaultReadOptions)
    }
    # need to strip out any existing entries for this trustee
    $entries = $orgItem.AccessControlList.AccessControlEntries | ? {$_.Trustee.IdRef -ne $trustee.Id}
    $link = new-object LinkToTrusteeData
    $link.IdRef = $trustee.Id

    $ace = new-object AccessControlEntryData
    $ace.Trustee = $link
    if ($rights -ne $null) {$ace.AllowedRights = $rights}
    if ($permissions -ne $null) {
        $ace.AllowedPermissions = $permissions
        $orgItem.IsPermissionsInheritanceRoot = $true
    }
    $entries += $ace
    $orgItem.AccessControlList.AccessControlEntries = $entries
    "Updating $($orgItem.LocationInfo.Webdavurl) for $($trustee.Id)"
    $core.Save($orgItem, $null)
}

function addPermissions( $trustee, $orgItem, $permissions){
    addRightsAndPermissions $trustee $orgItem $null $permissions
}

function addRights( $trustee, $orgItem, $rights){
    addRightsAndPermissions $trustee $orgItem $rights $null
}

# First check to see if our group is there already and delete it
$groupTitle = "TestGroup"
$core.GetSystemWideList($groupsFilter) | ? {$_.Title -eq $groupTitle} | % {$core.Delete($_.Id)}

# First create a test group 
$group = $core.GetDefaultData([ItemType]::Group, $null, $null)
$group.Title = $groupTitle
$group.Description = "It's the test group"
$group = $core.Create($group, $defaultReadOptions)

$testUserDescription = "Test User 1"
$testUserTitle = "TRIDIONDEV\test1"
$testUser = @($core.GetSystemWideList($usersFilter) | ? {$_.Description -eq $testUserDescription})[0] 
if ($testUser -eq $null) {
  $testUser = $core.GetDefaultData([ItemType]::User, $null, $null)
  $testUser.Title = $testUserTitle
  $testUser.Description = $testUserDescription
  $testUser = $core.Create($testUser, $defaultReadOptions)
}

#Add group to test user
$groupMembership = new-object GroupMembershipData
$groupMembership.Group = new-object LinkToGroupData
$groupMembership.Group.IdRef = $group.Id
$testUser.GroupMemberships = $groupMembership
$core.Save($testUser, $null)

# And now for the project-specific stuff.

# Add read permission to the PermsTest category on the "01 Definitions" publication
$catContent = $core.Read("/webdav/01%20Definitions/PermsTest", $defaultReadOptions)
addPermissions $group $catContent Read

# and read and write permissions on the content folder in "02 Content"
$contentFolder = $core.Read("/webdav/02%20Content/Building%20Blocks/Content", $defaultReadOptions)
addPermissions $group $contentFolder Read,Write

# and some rights on the content publication
$contentPub = $core.Read("/webdav/02%20Content", $defaultReadOptions)
addRights $group $contentPub ComponentManagement,FolderManagement,VirtualFolderManagement

The first thing you can see is that I’m using the Reflection and Tridion powershell modules (links in the comment at the top).  After using these to get a core service client and import the namespace, you can see the addRightsAndPermissions function. This is what actually gets the job done. Of course, you can only set permissions on a local organizational item, so there’s support for having the script localize your organizational items if needed. It’s up to you whether you want to use this or not. You may already have a strategy for ensuring that the correct organizational items are local, so you may actually want the script to throw an error if it encounters an unexpectedly shared one. It’s your choice.

For the rest it’s a question of manipulating the access control list (ACL) for the organizational item. Each ACL is a list of Access Control Entries (ACE) representing individual Trustees. We copy the ACE’s for the other trustees, and create a new one for the trustee we are busy with - and we add the rights or permissions. If we’re dealing with permissions, we set the inheritance root flag, add our ACE back to the ACL, and save the organisational item.

I’ve also added two wrapper functions - addRights, and addPermissions. These help to make the invoking code a bit more readable, but you can also do without the wrappers if you prefer.

The next part of the code deletes/creates a group and a user. These can be useful for some applications, and not for others - as they say - your mileage may vary. If you have a group already in your system then just grab it with $core.Read() and carry on.

At the end you can see that with all this “boilerplate” code out of the way, the act of setting some permissions is very simple: you just need to call addPermissions and pass as parameters the trustee, the organisational item, and your desired permissions.

I don’t know why the original questioner on Stack Exchange wanted to do this, but it’s easy to imagine useful applications. The most obvious one is perhaps moving your tested security settings up through your DTAP street. If you create them this way from the beginning, this is just a matter of executing your existing script in a different environment.

Dominic Cronin

Dominic Cronin