Custom Workflow Activity for Granting Permissions on a SharePoint Site

In this post I'll take a look at how to build a custom workflow activity in Visual Studio 2012 that grants permissions on a SharePoint 2013 site to a user or group.

Note: this is part of a series of posts on building workflow activities to manage sites, groups, users and permissions. For a complete list of posts, together with a more detailed walkthrough of how to build a custom workflow activity and make it available in SharePoint Designer, start at the beginning.

Fundamentals

You can use the REST API to grant permissions to a SharePoint principal (i.e. a user or group). There are two stages to the process.

Stage 1: Get the Role Definition ID
Before you can grant permissions to a principal, you need to know the ID of the role definition (i.e. the permission level) you want to assign to the principal. Built-in role definitions have a ten-digit ID value. For example:

The ID of the Full Control role definition is 1073741829.

The ID of the Contribute role definition is 1073741827.

The ID of the Read role definition is 1073741826.

However, maintaining a list of these IDs is pretty inconvenient. Also, if you want to use a non-standard role definition, you may not know the ID. When you're building a workflow, it's much easier if you can specify the name of the role definition you want rather than the integer ID. Fortunately, getting a role definition by name is straightforward with the REST API - you need to send a web request that resembles the following:

Endpoint:

{site collection URL}/_api/web/roledefinitions/getbyname('{name of role definition}')

As you can see, you can get the ID value you want by retrieving the "d/Id" property from this response.

Stage 2: Add a New Role Assignment
The REST API includes an endpoint on every securable object that enables you to add a role assignment by specifying the integer principal ID and the integer role definition ID. Unlike server-side or client-side programming, you don't need to worry about creating role definition bindings - the service will take care of this for you behind the scenes. To add a new role assignment on an SPWeb, you need to send a web request that resembles the following:

To create a workflow activity that grants permissions, I first built a utility activity (Get Role Definition ID) that retrieves the ID value of a role definition with a specified name. I then consume this utility activity within a primary activity (Grant Web Permissions) that adds a new role assignment to the specified site. I'll run through both of these activities in the rest of this post.

The "Get Role Definition ID" Activity

I'm now on post number five of this series of posts on creating workflow activities, so I'll keep this as concise as possible - please refer back to earlier posts if you want a bit more detail on the process. I'll start by defining the arguments for the Get Role Definition ID activity:

In this case, I want the consumer of the workflow activity to provide the name of the role definition. The workflow activity will return the corresponding ID of the role definition, together with the status code returned by the REST service.

Next, I'll define the variables I want to use within my activity:

Here, I've got a variable to store the URL of the current site collection, a variable to store the REST endpoint we want to use, and variables to store the headers, content and status code returned by the service call.

The complete activity looks like this:

Let's take a brief look at each of these child activities - I've covered these activity types in detail in previous posts, so I'll try to keep this concise.

Get Current Site URL
The first thing we need to do is to grab the URL of the current site and store it in our siteUrl variable. I've used a LookupWorkflowContextProperty activity to do this:

Build the REST URL
The next task is to build the URL for our REST service call, using our site URL, the site-relative REST endpoint, and the role definition name provided by the activity consumer:

HttpSend
Next, we use an HttpSend activity to make the REST API call:

Assign responseStatusCodeOut
In this activity, we convert the response status code returned by the REST service into a SharePoint Designer-friendly string format:

Get ID from Response
In this final task, we use a GetDynamicValue<T> activity to extract the ID of the role definition from the JSON response content returned by the REST service:

Build the Actions File

To finish off the Get Role Definition ID activity, we need to edit the .actions4 file. In this case, the file should resemble the following:

Now the Get Role Definition ID helper activity is complete, we can build our primary activity that makes use of it.

To use this helper activity within another activity, we need it to show up in the Visual Studio toolbox. The toolbox gets its activities from the SharePoint site you're using for debugging. As such, you'll need to deploy this activity (Start Without Debugging) and then close and reopen Visual Studio. You should then see the activity in the toolbox when you're building your next activity.

The "Grant Web Permissions" Activity

In this activity, we're going to add a role assignment to the web specified by the activity consumer. The role assignment will specify the integer ID of the principal to whom we want to grant permissions (could be a user or a SharePoint group), together with the integer ID of the permission level we want to assign. As before, let's start by defining the arguments:

In this case, we need the activity consumer to provide:

The URL of the web on which they want to grant permissions.

The login name (title or email will also work) of the principal to whom they want to grant permissions.

The name (e.g. "Full Control", "Contribute", "Read") of the permission level (aka role definition) they want to assign.

The workflow activity will return the response status code returned by the REST API call.

Next, let's define our activity variables:

Here we've got a variable to store our REST endpoint, variables to store the integer IDs for the principal and the role definition, and variables to store responses from the REST API call.

The complete activity looks like this:

Let's take a brief look at each of these child activities.

Get Principal ID
The first thing we need to do is to get the integer ID of the principal to whom we want to grant permissions, using the login name provided by the activity consumer. I've used a LookupSPPrincipalId activity to do this:

Get Role Definition ID
Next, we need to get the integer ID of the role definition we want to assign to the principal, using the permission level name provided by the activity consumer. Here, I've used the GetRoleDefinitionId helper activity that we defined in the first half of this post:

Assign (build restUrl)
We've now got all the information we need to build our REST URL. I've used an Assign activity to do this:

Here, we're sending an HTTP POST request with an empty body to the REST URL we defined in the previous step. We're also assigning the headers, content and status code returned by the service to local variables. At this stage you'll also need to configure your request headers by clicking the ellipsis button in the RequestHeaders row:

Assign responseStatusCodeOut
In this final activity, we convert the response status code returned by the REST service into a SharePoint Designer-friendly string format as before:

Build the Actions File

To finish off the Grant Web Permissions activity, we need to edit the .actions4 file. In this case, the file should resemble the following:

Once you've deployed the solution, activated the feature and cleared the SharePoint Designer cache, the Grant Web Permissions activity should be available for use in SharePoint Designer workflows. Behind the scenes, the Grant Web Permissions activity will make use of the Get Role Definition ID helper activity to get the integer ID for a specified role definition name.

Update 17/11/14: a sample Visual Studio solution containing these workflow activities is now available for download.

Followed your instructions step by step. I deployed and activated the feature. It works great in Designer. Restarted Visual Studio, started a new custom activity for the same site and the deployed activity does not show in the toolbox.

Post a Comment

Popular posts from this blog

If you use SharePoint Designer 2013 to build workflows, there's a fair chance you'll have come across the following error message:Server-side activities have been updated. You need to restart SharePoint Designer to use the updated version of activities.
Needless to say, restarting SharePoint Designer rarely makes the error go away. The usual advice is:

Approach 1: Clear the cache folders
See for example How to Clear Your SharePoint Designer 2010/2013 Cache. If you've just deployed some custom workflow activities to your site, this will probably solve your problem (and you should clear the cache folders every time you deploy custom activities). If the error occurs spontaneously, this approach often won't help.

Approach 2: Reinstall SharePoint Designer
This might work if you've got a preview version of SharePoint Designer installed. If not, it's unlikely to help. It didn't work for me, and it didn't work for countless others on the forums.

Today's problem occured after I restarted a Hyper-V based SharePoint 2013 farm (Windows Server 2012, one SharePoint 2013 machine, one SQL Server 2012 machine, one DC). I fired up Central Administration and was hit with the following error:

After checking the obvious things - testing connectivity to the DB server, checking the SQL service was running, verifying permissions, etc - I initially figured this was an issue with my Hyper-V snapshots being out of sync, so I ran the SharePoint Products Configuration Wizard. This hit me with the following error:

Failed to detect if this server is joined to a server farm. Possible reasons for this failure could be that you no longer have appropriate permissions to the server farm, the database server hosting the server farm is unresponsive, the configuration database is inaccessib…