SharePoint App-only Policy Apps

SharePoint App-only Policy Apps

In the new world of Apps for SharePoint 2013 there is an app-only policy available to allow SharePoint Apps to make requests to SharePoint sites, on premise or SharePoint Online, without user intervention if necessary. So why is this so important in the Cloud App Model (CAM)?

Well, one case is where you may have a middle tier of web services which return SharePoint information that is accessible by a specific set of web clients that do not necessarily need the access to the SharePoint repositories directly or may be external systems making updates or retrieving data from SharePoint that may have no authenticated way of calling the SharePoint without that middle tier. In this case the SharePoint App would have the necessary permissions to retrieve or write data back to the SharePoint repositories without the calling application requiring access. The calling application would only need access to the middle tier web services in order to retrieve the underlying repository data. The middle tier could be secured differently, via certificates or Active Directory.

Another instance could be something like a re-occurring timer job that may need to perform some actions on the SharePoint repository on a regular basis e.g. a timer job or possibly a newsletter flyer being emailed based on information held in a SharePoint repository.

So how do we get this app-only policy and SharePoint App bolted together in order to make use of this new feature in the CAM world? It’s actually very simple and in this blog post I aim to provide you with a sample to work with to get you going.

First we need a scenario….

Scenario

A timer job is required to log how many items there are currently in a SharePoint list which require pending actions. An administrator reviews a list which the SharePoint App writes to on a regular basis to inform them of the number of items that are pending actions.

A simple scenario but something to work from to demonstrate the SharePoint App-only policy. For the purposes of making it really simple, I have created a console app sample that uses the app-only policy.

Important Notes

In order to install an App which uses the app-only policy, the user must be a site collection administrator to grant the app-only policy.

Apps that do not make OAuth authenticated calls cannot use the app-only policy. The app-only policy is only available in apps that run out side of SharePoint, provider-hosted or auto-hosted (SharePoint Online) app, basically not apps which are SharePoint-hosted and using the JSOM library.

Steps..

Pre-Requisites

Ensure you include the tokenhelper.cs file in your solution.

Include references to Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Runtime

1)     Register the console app in the site collection (Office 365 or SharePoint On Premise)

https://tenantdomain.sharepoint.com/sites/sitecollection/_layouts/15/appregnew.aspx

Register the details below and ensure you generate the ClientId and Client Secret, also add the app title and app domain as required. There is no re-direct URL required.

SPORegisterAppOnlyPolkicyApp

SPORegisterAppOnlyPolkicyAppConfirm

2)      Browse to the site collection (Office 365 or SharePoint On Premise)

https://tenantdomain.sharepoint.com/sites/sitecollection/_layouts/15/appinv.aspx

3)      Enter the app id (ClientId) generated in the appregnew.aspx page

SPORegisterAppOnlyPolkicyAppPermissions

4)      Enter the permissions xml, references to permission polices can be found here: http://msdn.microsoft.com/en-us/library/office/fp142383(v=office.15).aspx

I allowed the app to have Full Control rights at the web level with the “AllowAppOnlyPolicy” set to “true”.


<AppPermissionRequests AllowAppOnlyPolicy="true" >

<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />

</AppPermissionRequests>The app is now registered.

6)      After you click Create you should trust the app that was registered.

SPORegisterAppOnlyPolkicyAppTrustApp

5)      Update your app.config file with the following section and apply the appropriate ClientId and ClientSecret Note that, getting any of these incorrect may cause a 400 bad request. If you debug the error, the tokenhelper.cs will fail at the following code:

<appSettings>

<addkey="ClientId"value="generated ClientId"/>

<addkey="ClientSecret"value="generated ClientSecret"/>

</appSettings>

Bad Request Error: If you debug the error, the tokenhelper.cs will fail at the following code when the tokenhelper class tries to receive a valid OAuth response.


OAuth2AccessTokenResponse oauth2Response;

try

{

oauth2Response =

client.Issue(AcsMetadataParser.GetStsUrl(targetRealm), oauth2Request) asOAuth2AccessTokenResponse;

}

6)  You can also generate the permission request XML by adding a SharePoint App and updating the permission to allow the app to make app-only calls to SharePoint and generate the appropriate scoped permissions. Then you could view the code in the appmanifest.xml file and copy the relevant generated code. If you are new to this I would recommend following this described step.
7)      Add the appropriate code to get a app-only token.


privatestaticvoid Main(string[] args)

{

ServicePointManager.ServerCertificateValidationCallback =

newRemoteCertificateValidationCallback(delegate { returntrue; });

var siteURL = "https://tenantdomain.sharepoint.com/sites/sitecollection";

Uri siteUri = newUri(siteURL);

// Get the realm for the URL

string realm = TokenHelper.GetRealmFromTargetUrl(siteUri);

//Get the access token for the URL

string accessToken = TokenHelper.GetAppOnlyAccessToken(

TokenHelper.SharePointPrincipal,

siteUri.Authority, realm).AccessToken;

// Get client context with access token

using (var clientContext =

TokenHelper.GetClientContextWithAccessToken(

siteUri.ToString(), accessToken))

{

Web web = clientContext.Web;

clientContext.Load(web, w => w.Title);

clientContext.ExecuteQuery();

var title = web.Title;

Console.WriteLine(title);

}

Console.ReadKey();

}

The sample code above displays the web title in the console application.

Getting our pending action items from the documents list

Now lets add the code for the sample to return items from a document library to query pending items.

In the site collection the default document library has 3 items which have a different pending status. The pending column is our flag that an item requires actions. The library items are shown below.

SPORegisterAppOnlyPolkicyAppDocuments

The code required to query the list appropriately can be added in the section where a client context has been generated (clientContent). We use the clientContext with the app-only access token to retrieve the information from the list based on the app permissions specified earlier.

The code has been documented below.

// Get client context with access token

using (var clientContext =

TokenHelper.GetClientContextWithAccessToken(

siteUri.ToString(), accessToken))

{

Web web = clientContext.Web;

// Retrieve the List from the web

List documents = clientContext.Web.Lists.GetByTitle("Documents");

var pendingItemsQuery = @"<View><Query><Where><Eq><FieldRef Name='Pending'/><Value Type='Integer'>1</Value></Eq></Where></Query></View>";

CamlQuery listQuery = newCamlQuery();

listQuery.ViewXml = pendingItemsQuery;

ListItemCollection documentListItems = documents.GetItems(listQuery);

clientContext.Load(documentListItems);

clientContext.ExecuteQuery();

if (documentListItems.Count > 0)

{

Console.WriteLine("Items that have pending actions are listed below");

foreach (ListItem li in documentListItems)

{

Console.WriteLine(li.FieldValues["Title"].ToString());

}

}

else

{

Console.WriteLine("No pending items in documents list.");

}

}

Console.WriteLine("Press any key to exit");

Console.ReadKey();

Returned Console Output

The output of the query is listed below.

SPORegisterAppOnlyPolkicyAppConsoleOutput

The executable can be scheduled using the Windows task scheduler to perform the required functions on a provider hosted server. The app is trusted via OAuth (ClientId and ClientSecret), which registered at the site collection level. To make the deployment easier, you could include a SharePoint app project in the solution and register the app to be deployed to any site collection via the app catalog. Should you need to query more site collections, you could change the scoped permissions to the tenant or deploy the app at each site collection.

A simple solution to have an application query SharePoint sites in Office 365 or SharePoint 2013. The solution can be extended to update a logging list for the administrator to log pending actionable items.The Client side Object Model (CSOM) could be utilized to perform whatever functions are required for any app of this nature.

 

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

%d bloggers like this: