2
votes

I was googling for a quite some time, and could not find the answer to this. Here is the question:

Is it possible to manage users permissions of the lists that are deployed to the app web?

We have many possibilities to do this on host web (parent site), where we can define permissions for any users. On the app web (SharePoint app domain), we can access all deployed lists directly, and cannot set permissions for some particular users. I have different groups of users and I want them to have different permissions on the lists deployed on the app web. How can I do that, or is it even possible?

If not, what those lists can be used for, when any app user can access them directly and change the data?

4

4 Answers

4
votes

I will use the add-ins terminology instead of apps because that's what Microsoft calls them now.

Specify permissions during development

The answer is NO. You cannot specify user or group permissions for SharePoint-hosted add-ins during development.
The reason for this is simple: add-in webs are isolated from the rest of SharePoint farm and they can be installed anywhere in the farm. Considering that users and groups are scoped to the site collection level, if you install an add-in in multiple site collections there is no way to say which users and groups are available in that site collection.
Furthermore, if you publish your add-in in the SharePoint Store, the add-in is not aware of the environment where it will be installed in, so there is no way to decide which users or groups have access to what in the add-in web.

Specify permissions after installation

The answer to this is YES. After installing an app, you can specify list permissions and item permissions in your add-in web just like you do it in the host web.
By default, all lists in the add-in web inherit permissions from the host web because the add-in web itself inherits permissions from the host web. So you need to be a site collection admin or site owner on the host web to be able to break inheritance and change permissions on the lists in the add-in web.

Some add-in permissions tips

  1. You can create groups in your host web and then use those to assign permissions to lists in your add-in web, just like you would do it to lists in the host web. SharePoint groups offer better management of permissions, namely when a new user/employee needs permissions to the list you just add that user to a group accessible anywhere in the site collection instead of going to do that directly to the list in the add-in web.

  2. You can set permissions for list items on add-in web using a SharePoint 2013 Workflow that runs with elevated permissions (see the AppOnlySequence activity) and makes RESTful web service calls to change list item permissions.

  3. When you develop and debug / install an add-in using Visual Studio, make sure you do not stop debugging after you change list permissions because if you do stop and re-start debugging your add-in will receive a new unique id (namely new instance installed in the host web) and all the list permissions you have previously set will be lost.
    Note that you will probably be forced to stop debugging at the end of the day and re-start debugging the next day which will create a new instance of your add-in. In this case, you will have to trust the add-in again on the host web, otherwise you will get Access Denied when you try to change list permissions again on the add-in web.

  4. If you want to be really smart / efficient about setting up list permissions, you can create an Admin page containing a button control inside your add-in and also write some JavaScript code using JSOM to run on that page when the button is clicked, which will automatically set up the list permissions for you.

  5. Because by default the add-in web inherits all the permissions from the host web, you may sometimes need to break that inheritance in order to give users (who would normally have read-only permissions on the host web) elevated permissions (e.g. Contribute or more) on the add-in web. A clever guy wrote an article about a clever way to do that using:

    • jQuery + REST API for breaking inheritance and setting permissions. (JSOM could be used as well as an alternative to jQuery and REST APIs)
    • and JSOM to set a custom property using the AllProperties member of the SPWeb object in order to specify that the permissions have been set for the add-in web.
2
votes

No,I don't think that is possible. If you need to manage permissions for a list you can deploy it to the host-web and access that list via the app. That way the app will inherit the permissions you defined for the list in host-web.

0
votes

Edit: The app requires Manage permission on the Web for this to work

Actually I found that it is possible.

You have to break the permissions on the list first and then change the role assignments on the list for whichever users you want:

userList is a list of login names, and roleType is an SP.RoleType (https://msdn.microsoft.com/en-us/library/office/jj246683.aspx)

    setUserListPermissionsBatch: function (listName, userList, roleType) {
                "use strict";
                Permissions.resetStored();

                var context,
                    list,
                    roleDefBindingColl,
                    i,
                    oUser,
                    deferred;

                deferred = new $.Deferred(function () {
                    if (userList && listName && roleType) {
                        // Create the role 
                        context = SP.ClientContext.get_current();
                        list = context.get_web().get_lists().getByTitle(listName);
                        roleDefBindingColl = SP.RoleDefinitionBindingCollection.newObject(context);
                        roleDefBindingColl.add(context.get_web().get_roleDefinitions().getByType(roleType));
                        // Loop the users
                        for (i = 0; i < userList.length; i++) {
                            oUser = context.get_web().get_siteUsers().getByLoginName(userList[i]);
                            list.get_roleAssignments().add(oUser, roleDefBindingColl);
                        }
                        context.load(list);
                        context.executeQueryAsync(
                            function () {
                                return deferred.resolve();
                            },
                            function (sender, args) {
                                console.log(args.get_message());
                                return deferred.reject(args);
                            }
                        );
                    }
                });
                return deferred.promise();
            },

To remove the permissions, I had to copy the current user permissions, remove the one I wanted to get rid of so you keep other permissions for that user on the same list.

Then just re-add the new roles:

    / Removes permissions for a user
            removeUserListPermissions: function (listName, userLogin, roleType) {
                "use strict";
                var context,
                    list,
                    user,
                    userRoles,
                    x,
                    rolDefs,
                    newRoleCollection,
                    deferred;

                deferred = new $.Deferred(function () {
                    if (userLogin && listName) {
                        context = SP.ClientContext.get_current();
                        list = context.get_web().get_lists().getByTitle(listName);
                        user = context.get_web().get_siteUsers().getByLoginName(userLogin);
                        userRoles = list.get_roleAssignments().getByPrincipal(user);

                        context.load(user);
                        context.load(list);
                        context.load(userRoles, 'RoleDefinitionBindings');

                        context.executeQueryAsync(Function.createDelegate(this, function () {
                            newRoleCollection = SP.RoleDefinitionBindingCollection.newObject(context);
                            for (x = 0; x < userRoles.get_roleDefinitionBindings().get_count() ; x++) {
                                rolDefs = userRoles.get_roleDefinitionBindings().itemAt(x);
                                if (rolDefs.get_roleTypeKind() !== roleType) {
                                    newRoleCollection.add(rolDefs);
                                }
                            }
                            userRoles.deleteObject();
                            list.get_roleAssignments().add(user, newRoleCollection);

                            context.load(list);
                            context.executeQueryAsync(function () {
                                return deferred.resolve();
                            }, function (sender, args) {
                                console.log("Error deleted permissions: " + args.get_message());
                                return deferred.reject();
                            });
                        }),
                            function (sender, args) {
                                console.log(args.get_message());
                                return deferred.reject();
                            });
                    } else {
                        return deferred.resolve();
                    }
                });
                return deferred.promise();
            }

To do groups I'm just using :

     // Loop the groups
     for (i = 0; i < groupList.length; i++) {
    list.get_roleAssignments().add(context.get_web().get_siteGroups().getByName(groupList[i]), roleDefBindingColl);
    }

instead of looping the users

-1
votes

Try adding this after your app name _layouts/15/user.aspx. I.e.:

https://app-12345656778.yoursite.com/sites/TestSite/TestApp/_layouts/15/user.aspx 

to get to app permission page or add ?List=[ListId] to get to a list within the app.