Access Request inconvenience: approval form does not list SharePoint groups

When granting permissions to a user in SharePoint, it is almost always best to add them to a group rather than granting them permissions directly.

The Access Request feature in SharePoint 2013 does a good job of promoting this for access requests to a site. As shown below, the Permission drop down list on the approval form in this scenario contains the site’s SharePoint groups at the top.

1. Site Request

When the access request is for a page however, SharePoint behaves differently. The Permission drop down list on the approval form in this scenario only contains the individual permissions and no SharePoint groups.

2. Page Request

If you have a mixture of public and private pages in your site, then this behaviour can become a problem, as the approval form does not allow administrators to assign the user to an appropriate group on the Access Request approval form.

This post describes an approach for fixing this behaviour.

Disclaimer: Some might view this approach as a hack. Consider whether this approach is suitable for your situation.

Root cause

The root cause is in an OOTB JavaScript file, namely accessrequestsviewtemplate.js under the LAYOUTS folder. This script is included via the JSLink property of the view of the Access Requests list. This script is responsible for creating the approval form.

There is a function in this script that populates the Permission drop down list, namely GetAllPermissionStringsForSelectCtrl, as shown below (ULS logging code removed for brevity):

function GetAllPermissionStringsForSelectCtrl(iid, listItem, baseViewId, calloutActionMenuId) {
            var strId = iid + _permSelectIdSuffix;
            var str = "";
            var arrGroupIds;

            if (listItem["RequestedListItemId"] != (SP.Guid.get_empty()).toString("B")) {
                str = GetAllPermissionStringsForSelectCtrlCore(iid, listItem, baseViewId, calloutActionMenuId, null);
            }
            else if (listItem["RequestedListId"] != (SP.Guid.get_empty()).toString("B")) {
                str = GetAllPermissionStringsForSelectCtrlCore(iid, listItem, baseViewId, calloutActionMenuId, null);
            }
            else {
                arrGroupIds = g_accReqCSRBridgeSPSecToGrps[listItem["RequestedWebId"]];
                str = GetAllPermissionStringsForSelectCtrlCore(iid, listItem, baseViewId, calloutActionMenuId, arrGroupIds);
            }
            return str;
        }

This function is not complicated: it essentially is a wrapper around the GetAllPermissionStringsForSelectCtrlCore function, which does the actual job. The last parameter passed in to the Core function is an array of SharePoint groups, and determines whether the drop down list will contain groups. If this parameter is null, then groups will not appear on the drop down list.

As you can see, this parameter is only populated and passed in the final else, which is when the RequestedListItemId and RequestedListId fields of the request item are both Guid.Empty – i.e. when the request is for a site (as oppose to a page or a list).

Approach

I investigated a number of approaches:

  1. Attach an event handler to the Access Request list and clear out the RequestedListItemId and RequestedListId fields for each incoming request. I could not get this to work however. Whenever I clear out these fields, they’d just come back when I update the item in code.
  2. Override the GetAllPermissionStringsForSelectCtrl function in the least intrusive way possible (i.e. without modifying the source JS file). In the end this was not possible because this function is defined within an anonymous function.

In the end the approach I went with was to:

  • Deploy a clone of the JS file
  • Update the function in this clone
  • Update the JSLink property of the views of the Access Requests list to use this clone rather than the OOTB JS file

My updated GetAllPermissionStringsForSelectCtrl function is as below.

function GetAllPermissionStringsForSelectCtrl(iid, listItem, baseViewId, calloutActionMenuId) {
        ULSaQO:
            ;
            var strId = iid + _permSelectIdSuffix;
            var str = "";
            var arrGroupIds = g_accReqCSRBridgeSPSecToGrps[listItem["RequestedWebId"]];

			return GetAllPermissionStringsForSelectCtrlCore(iid, listItem, baseViewId, calloutActionMenuId, arrGroupIds);
        }

Here is my code to update the views. Please review the comments.

using (var site = new SPSite("http://myServer"))
			{
				using (var web = site.OpenWeb())
				{
					var list = web.Lists["Access Requests"];

					//The Access Requests list has several views with the same URL (i.e. pendingreq.aspx). We should
					//update all of them.
					var viewsToUpdate = list.Views.Cast<SPView>().Where(
						v => v.Url.EndsWith("Access Requests/pendingreq.aspx", StringComparison.InvariantCultureIgnoreCase)).ToList();

					foreach (var view in viewsToUpdate)
					{
						var jsLinks = view.JSLink.Split('|').ToList();
						var jsToReplaceIndex = jsLinks.FindIndex(js => js.Equals("accessrequestsviewtemplate.js", StringComparison.InvariantCultureIgnoreCase));

						//In this example I'm deploying my custom script to the LAYOUTS folder, but you can deploy
						//it to anywhere - just update this reference.
						jsLinks[jsToReplaceIndex] = "MyProject/accessrequestsviewtemplate-custom.js";
						view.JSLink = String.Join("|", jsLinks);
						view.Update();
					}
				}
			}

As each site/sub-site has its own Access Requests list, the above code to update the views will need to be executed on each site/sub-site where you want to change the OOTB behaviour. This also means that you could package it up and deploy/activate it as a feature (rather than running in a console test harness like I have done above).

So what does the end-state user permission look like?

I have tested several scenarios and the findings are as below.

With the OOTB behaviour:

  • Permission inheritance is broken on the page (if not already broken)
  • The selected individual permission is granted to the user for the page

With the updated behaviour, when a group is selected for the user:

  • The user is added to the selected group
  • Permission inheritance is broken on the page (if not already broken)
  • The group is not automatically granted permissions to the page if it doesn’t already have permissions to this page

Conclusion

The Access Request is a nice feature in SharePoint 2013, but if you have a mixture of public and private pages in one site then the OOTB behaviour may make it less than ideal or even unsuitable. With this relatively minor workaround you can overcome this hurdle and promote better practices in managing user permissions. Assess whether this workaround is suitable for your situation.

Advertisements

About Bernado

Based in Australia, I am a freelance SharePoint and Dynamics CRM developer. I love developing innovative solutions that address business and everyday problems. Feel free to contact me if you think I can help you with your SharePoint or CRM implementation.
This entry was posted in Access Request, Permission, SharePoint 2013. Bookmark the permalink.

4 Responses to Access Request inconvenience: approval form does not list SharePoint groups

  1. Chiranth says:

    Hello Benado,

    Is there a workaround to push a user to a particular group from an excel file?

  2. Venkat says:

    Hi,

    Is there any other solution for above issue (apart from modifying JS files in _layouts folder)

    please help me here

  3. snehal says:

    is this for 2013 as i cannot find GetAllPermissionStringsForSelectCtrl in accessrequestsviewtemplate.js file

    • Bernado says:

      Yes this is for SP 2013. I can see it on my system, and my patch version is August 2016 CU. Make sure you look in the accessrequestsviewtemplate.debug.js file and not the minified one.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s