3

I have a SharePoint 2013 auto-hosted app. The app is really simple. It has a list with a remote event receiver on ItemUpdating and ItemUpdated. What I have been trying to do is to assign unique permissions to the item added by the user. I have added this logic in the ItemUpdated event because I run some other business logic in the ItemUpdating event. The code I used is:

        public void ProcessOneWayEvent(SPRemoteEventProperties properties) {

        if (properties.EventType == SPRemoteEventType.ItemUpdated) {

            using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties)) {
                if (clientContext != null) {

                    clientContext.Load(clientContext.Web);
                    clientContext.ExecuteQuery();

                    var documentList = ProtocolUtils.GetListById(clientContext, properties.ItemEventProperties.ListId);
                    var item = ProtocolUtils.GetItemById(clientContext, documentList, properties.ItemEventProperties.ListItemId);
                    var itemRoleAssignments = item.RoleAssignments;

                    // Get user info and the groups he belogns to.
                    var currentUser = ProtocolUtils.GetCurrentUser(clientContext, properties.ItemEventProperties.CurrentUserId);
                    GroupCollection userGroups = ProtocolUtils.GetCurrentUserGroups(clientContext, currentUser);

                    var contributorRDF = clientContext.Web.RoleDefinitions.GetByType(RoleType.Contributor);
                    var administratorRDF = clientContext.Web.RoleDefinitions.GetByType(RoleType.Administrator);
                    var AdminsGroup = clientContext.Web.SiteGroups.GetByName(Constants.Groups.Admins);
                    clientContext.ExecuteQuery();

                    item.BreakRoleInheritance(false, true);

                    // Set Admins group as the item's ADMINISTRATOR!
                    RoleDefinitionBindingCollection adminsCollRDB = new RoleDefinitionBindingCollection(clientContext);
                    adminsCollRDB.Add(administratorRDF);
                    item.RoleAssignments.Add(AdminsGroup, adminsCollRDB);

                    //lets add now the group ("departments") the user belongs  to as contributor
                    RoleDefinitionBindingCollection contributorsCollRDB = new RoleDefinitionBindingCollection(clientContext);
                    contributorsCollRDB.Add(contributorRDF);
                    foreach (var group in userGroups) {
                        if (IsGroupValidForRoleAssignment(group.LoginName)) {
                            item.RoleAssignments.Add(group, contributorsCollRDB);
                        }
                    }

                    clientContext.ExecuteQuery();
                }
            }
        }
    }

Now when I add an item to the list using my site collection administrator everything works just fine. When using a simple user with just the basic permissions the query fails with the message “Access denied. You do not have permission to perform this action or access this resource”. Obviously there is a permission issue here.

I started assigning more and more permissions to my app to make it work. Right now the app pretty much has all the major permissions. And more importantly it has the AllowAppOnlyPolicy.

  <AppPermissionRequests AllowAppOnlyPolicy="true" >
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />

So from my understanding my app can now only be installed by a tenant admin and the app calls will run under the app’s context and NOT the user’s that is using the app. Nevertheless this is not working. The query is failing for every simple member. After playing with the permissions for many hours I found out that the above code works if I give to my members the permission “Manage Permissions - Create and change permission levels on the Web site and assign permissions to users and groups.” This permission when give also automatically gives the permission “Enumerate Permissions - Enumerate permissions on the Web site, list, folder, document, or list item.”. But I do not want to use this workaround. My users should not have these permissions as long as my app can use the permissions I granted when I installed it.

So the problem is why the app does not run under the AllowAppOnlyPolicy context? I cannot use RunWithElevatedPrivileges so I need my app to do things the app user does not have permission to do.

Am I missing something?

Thank you


EDIT

Based on the answer the little snippet I needed to make this thing work was this:

SharePointContextToken contextToken = null;
Uri sharepointUrl = new Uri(properties.ItemEventProperties.WebUrl);
string appOnlyAccessToken = string.Empty;

try {
    contextToken = TokenHelper.ReadAndValidateContextToken(properties.ContextToken, OperationContext.Current.IncomingMessageHeaders.To.Host);
    appOnlyAccessToken = TokenHelper.GetAppOnlyAccessToken(contextToken.TargetPrincipalName, sharepointUrl.Authority, contextToken.Realm).AccessToken;
}
catch (Exception ex) {
    //Log something
    }

using (ClientContext clientContext = TokenHelper.GetClientContextWithAccessToken(sharepointUrl.ToString(), appOnlyAccessToken)) {
//rest of the code
}

1 Answer 1

2
+50

When your app works when used by a Site Collection admin then it has the permissions it needs and adding more permissions isn't going to change anything.

What you then need for it to work for ordinary users is what you started on by adding AllowAppOnlyPolicy.

But just adding AllowAppOnlyPolicy won't change anything except that it'll grant the app permissions to run with App Only permissions. The second step which you're missing is that the app needs at runtime to specify that if want to perform some actions regardless of the users permissions.

It does this by calling TokenHelper.GetAppOnlyAccessToken to get an access token for running with App Only permissions and finally create a client context using this access token passed to TokenHelper.GetClientContextWithAccessToken.

See App authorization policy types in SharePoint 2013

1
  • Is there any detailed guide on how to create the AppOnlyAccessToken? Is there anything I can use in my remote events properties to create it? I will try to follow this guy's guide blogs.msdn.com/b/kaevans/archive/2013/02/23/… Can't award the bounty yet. It will allow me in 24 hours to grant it.
    – Perisdr
    Dec 30, 2013 at 14:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.