SharePoint 2013: Using Authorization Policy with Apps
Introduction
A lot of people ask questions on MSDN SharePoint 2013 forums about how they can host an application on their public site.
They want to use App Modules for Public facing site which have anonymous right or current user does not have permissions to. something like Elevate Privileges in developer`s term Elevate Privileges in App Module. Perhaps many developers start working API by checking simple tutorials, sample code, HOL and don't understand what SharePoint 2013 new API is doing.
New App Module takes away the normal impersonation confusion and makes it very clear for developers there is no impersonation capability in the SharePoint 2013 API. So, if Elevate Privileges, impersonation is not there, then how can get things to be done? The answer is the "App Only Policy".
Authentication Flow
The App Only Policy
Let's consider a scenario when application has to work when current user does not have Permissions. We will use “The App Only Policy”. When user does not provide any kind of credentials. An Oath access token is present but does not contain user information. Then we will evaluate the application based permissions instead of user.
Authorization in SharePoint 2013 is divided into two types of Entities:
- 1st Permission for Users.
- 2nd Permission for Apps.
App Authorization Policies Types
"User-only policy—This user-only policy is the authorization policy that was always applied in SharePoint 2010. When the user-only policy is used, the authorization checks take into account only the user identity. An example of when this policy is enforced is when the user is accessing resources directly without using the app.
User + app policy—When the user + app policy is used, the authorization checks take into account both the user identity and the app identity. In particular, when this policy is used, authorization checks succeed only if both the current user and the app have sufficient permissions to perform the action in question.
An example of when this policy is used is when a SharePoint site has an embedded IFRAME that links to a Office Store app, and the app calls back to SharePoint to access SharePoint resources on behalf of the user. That is, when a Office Store app, which does not run in SharePoint Server, wants to act on behalf of the user to get access to the user's resources.
App-only policy—When the app-only policy is used, the content database authorization checks take into account only the app identity. In particular, when this policy is used, an authorization check succeeds only if the current app has sufficient permissions to perform the action in question, regardless of the permissions of the current user (if any)." [MSDN]
Oath requires to generate App token. So App- Only Policy can only be used for Auto Hosted Apps or Provider Hosted Apps.
Limitations
- SharePoint hosted Apps cannot use App-only policy.
Using App Policies
To request an app to use App-only policy your app needs to add attribute called “AllowAppOnlyPolicy” in tag node of AppPermissionRequests with value = 'true". User must be Site Collection Administrator to allow use of the app-only policy.
<AppPrerequisites AllowAppOnlyPolicy="true">
</AppPrerequisites>
Code Example
string contextTokenString = TokenHelper.GetContextTokenFromRequests(Request);
if (contextTokenString != null)
{
SharePointContextToken contextToken = TokenHelper.ReadAndValidateContextToken(contextTokenString,Request.Url.Authority);
Uri sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]);
string accessToken = TokenHelper.GetAccessToken(contextToken, sharepointUrl.Authority).AccessToken;
using (ClientContext clientContext = TokenHelper.GetClientContextWithAccessToken(sharepointUrl.ToString(),accessToken))
{
List list = clientContext.Web.Lists.GetByTitle("Annoucements");
ListItemCreationInformation info = new ListItemCreationInformation();
Microsoft.SharePoint.Client.ListItem item = list.AddItem(info);
item["Title"] = "Created from CSOM App";
item["Body"] = String.Format("Created from CSOM APP, {0}", DateTime.Now.ToLongTimeString());
item.Update();
clientContext.Load(item);
clientContext.ExecuteQuery();
}
}