SharePoint Low-Trust Apps for On-Premises Deployments

PowerShell Functions and Scripts Post

Note: I’ve been wanting to share the details on setting up an OnPrem SharePoint environment to support low-trust apps for a while now. I had some help from the Product Group to get things working, and there were several catches and ‘Aha!’ moments involved which many of you are I’m sure stumbling over. So I dug in today and hammered out this post and the associated post of PowerShell helper functions to get this info out there. Let me know if (and when!) you find details that need clarification or might need correction. Enjoy!

A quick summary of SharePoint apps

SharePoint apps can be hosted inside SharePoint or outside of it. Apps hosted outside of SharePoint can be manually provisioned to an IIS server, an Apache server, an Azure Compute Services role, or any other host; or can be automatically provisioned and hosted in Azure Web Sites. Externally-hosted apps can call into SharePoint to request data on behalf of the user using the App Authentication model, an implementation of OAuth. Of the several OAuth profiles available, SharePoint apps implement and extend two of them under the names “High-Trust” and “Low-Trust.” In this post, we’ll discuss the protocol flow for SharePoint low-trust apps and how to configure an On-Prem SharePoint farm to support it.

A brief history of OAuth

OAuth version 1 was prepared by some of the biggest names of Web 2.0 - Twitter, Google, Facebook, Flickr. It provides a simple means for users to delegate limited authorization to their data to applications and services without sharing master credentials (e.g. username and password). For example, by using OAuth Facebook doesn’t need to ask you to share your Google password to get your Google contacts; instead you delegate to Facebook specific authorization to read your Google contacts list. In the canonical example (from the RFC), you can grant a photo printing service authorization to read your photos from a photo storage service without sharing your password with the printing service or granting that service read/write privileges to your photos and other account data at the photo storage service provider.

OAuth version 2 has been under discussion for several years now and RFC 6749 is the first of several RFCs documenting it. Significant (and controversial) additions to OAuth 2 include the JavaScript Web Token (JWT, pronounced ‘jot’) profile and the OAuth Assertion Framework, which together have made it easier to use OAuth for authentication as well as delegated authorization. Microsoft’s implementations of OAuth make heavy use of JWTs, and you’ll find the JWT Bearer Token profile to be the foundation for Microsoft’s High-Trust, Server-to-Server authentication schemes. For low-trust authentication, SharePoint uses a version of the classic authorization code flow discussed in the previous paragraph.

OAuth in SharePoint low-trust apps

SharePoint low-trust apps rely on the OAuth authorization code flow (“grant type”) to delegate limited rights to apps to act as users. For this to work, both SharePoint and the Client application (the SharePoint app) must trust and communicate with an Authentication Provider; SharePoint relies on Azure Active Directory. Azure AD, in turn, must be aware of SharePoint and the Client app in order to grant them the necessary codes and tokens to work together.

Let’s orient ourselves by presenting the overall protocol flow:

SharePoint 2013 OAuth

In this picture, the ‘S’ icon represents SharePoint and the globe represents an externally-hosted SharePoint app. The floating blue window represents Azure Active Directory, as indicated. In step 1, a user requests a page or an app directly from SharePoint. The app could be hosted directly within a SharePoint page in an IFrame, or might be on its own page. In either case, SharePoint will need to send the user’s browser to the external host to retrieve the app page, either via the location tag of the IFrame element or a 302 Redirect HTTP status; it will do so in step 3. First, though, SharePoint gets an OAuth authorization code to share with the app; the app will use this code to ultimately communicate back with SharePoint acting as the user. In step 2, SharePoint asks Azure Active Directory Access Control Service for an authorization code for the app. Now, in step 3, SharePoint redirects the user’s browser to the app, including the authz code with the redirected request (as the SPAppToken form parameter).

The app doesn’t use the authorization code directly to authenticate to SharePoint. Instead, in step 4 it calls Azure AD ACS and exchanges the authorization code it received from SharePoint for a proper Access Token. In step 5 the app uses this access token to authenticate to and access data from SharePoint, and finally in step 6 it uses this data to present a page to the user.

Setup SharePoint for low-trust apps

There’s lots to say about the various steps in this flow, but our focus here will be on setting up an On-Premises SharePoint 2013 farm to participate in it via a connection to Azure Active Directory. Most of this post will focus on enabling step 2 above - the connection between SharePoint and Azure Active Directory. The three steps you’ll need to follow to setup a SharePoint farm for low-trust apps are as follows:

  1. General SharePoint setup for apps (e.g. App Management Service Application, app isolation).
  2. Connect SharePoint to Azure Active Directory.
  3. Create an App Principal in AAD and SharePoint.

Step 1 is already well-documented on TechNet and other Web sites, so we’ll start at step 2.

Connect SharePoint to Azure Active Directory

If you haven’t yet, follow the steps in my previous post to get the Azure Active Directory module for PowerShell set up. You’ll need an AAD tenant and AAD/MSOL PowerShell for the next steps, and you’ll follow the discussion better after you’ve experimented a bit with AAD.

To completely configure a connection between your OnPrem SharePoint farm and Azure AD, you’ll need to complete the following steps:

  1. Replace the local STS signing certificate with one Azure AD can trust. I use a self-signed certificate, though a certificate from a trusted global authority should also work.
  2. Associate this certificate with the SharePoint principal in Azure Active Directory.
  3. Create an SPN for the OnPrem SharePoint farm and add it to the SharePoint principal in Azure Active Directory.
  4. Configure the authentication realm for the local SharePoint farm to match the AAD realm.
  5. Create an Azure Access Control Service application proxy in SharePoint.
  6. Create a Trusted Security Token Service for Azure ACS in SharePoint.

Remember that in step 2 above SharePoint calls in to AAD to request an authorization code, which requires authentication. The SharePoint username for this authentication is a well-known GUID representing SharePoint in Azure AD and O365 (00000003-0000-0ff1-ce00-000000000000). The credential used is an X.509 certificate, specifically SharePoint’s local STS signing certificate. Worth stating again: the same certificate used by SharePoint’s local STS to sign security tokens is used by SharePoint to authenticate to Azure Active Directory. That’s why the first step above is to replace the local signing certificate with one that can be used for authentication to AAD

I’ve created PowerShell functions which take care of the above steps and which you can review for the technical nitty-gritty; they’re named Replace-SPSTSSigningCertificate and Connect-SPFarmToAAD. You can access them individually at this post’s sister post, or download the whole package of scripts related to this post here. For further details, refer to the sister post and to the scripts themselves.

If you’ve saved all the files to the same directory, you can navigate there and use the following commands to set up your connection, replacing the AADDomain name and SharePoint Web URL appropriately. In the zip file, a similar script is available named ‘_ConnectSharePointToAAD.ps1’.

$FolderPath = if ($psISE) {Split-Path -Path $psISE.CurrentFile.FullPath -Parent} elseif ($PSScriptRoot) {$PSScriptRoot} else {"."}
Import-Module -Name ('{0}\{1}' -f $FolderPath,'New-SelfSignedCertificate.ps1')
Import-Module -Name ('{0}\{1}' -f $FolderPath,'Grant-CertificateAccess.ps1')
Import-Module -Name ('{0}\{1}' -f $FolderPath,'Replace-SPSTSSigningCertificate.ps1')
Import-Module -Name ('{0}\{1}' -f $FolderPath,'Connect-SPFarmToAAD.ps1')

Add-PSSnapin Microsoft.SharePoint.PowerShell
Import-Module -Name MSOnline

Replace-SPSTSSigningCertificate `
   -SPSTSCertName 'CN=SharePoint Security Token Service, OU=SharePoint, O=Custom, C=US' `
   -RootAuthorityName 'Self-Signed STS Signing Certificate' `
   -CerPath 'C:\temp\SPSTS.cer' `
   -PfxPath 'C:\temp\SPSTS.pfx' `
   -CleanSTSSigningCerts `

Write-Warning 'The STS Signing Certificate has been replaced. It is recommended that you restart your system before continuing.'

Connect-SPFarmToAAD `
   -AADDomain '' `
   -SharePointWebUrl `
   -RemoveExistingACS `
   -RemoveExistingSTS `
   -RemoveExistingAADCredentials `

Create App Principals

We’ve connected SharePoint to AAD, but to actually utilize this connection, we need to create AppPrincipals in Azure Active Directory and SharePoint. These AppPrincipals represent the remote-hosted Web Applications which will connect to SharePoint acting as users. Azure AD needs to be aware of these principals to be able to issue authorization codes for them (step 2) and access tokens to them (step 4). SharePoint needs to be aware of them to allow them access on behalf of users (step 5).

As things currently stand, you must create principals separately in SharePoint and in AAD. Work is underway to allow SharePoint to create a service principal in AAD automatically. In the meantime, though, we’ll use two separate functions to create an AppPrincipal in AAD and SharePoint. Again, refer to the sister post for details on these two functions, Add-ServicePrincipalToAAD and Register-SPAppPrincipalEx. Note that you’ll need the ClientID and Client Secret you use here when you create your SharePoint app, so don’t lose them!

An example, included in the zip as ‘_NewAppPrincipal.ps1,’ follows:

$FolderPath = if ($psISE) {Split-Path -Path $psISE.CurrentFile.FullPath -Parent} elseif ($PSScriptRoot) {$PSScriptRoot} else {"."}
Import-Module -Name ('{0}\{1}' -f $FolderPath,'Register-SPAppPrincipalEx.ps1')
Import-Module -Name ('{0}\{1}' -f $FolderPath,'Add-ServicePrincipalToAAD.ps1')

$Credential = Get-Credential -Message 'O365 Credential'

Add-PSSnapin Microsoft.SharePoint.PowerShell
Import-Module MSOnline

$ClientInfo = Add-ServicePrincipalToAAD `
   -DisplayName 'OnPremApp1' `
   -RedirectUri 'https://localhost:44300' `
   -HostUri 'localhost:44300' `
-O365Credentials $Credential `

$AppPrincipal = Register-SPAppPrincipalEx `
   -Web `
   -ClientId $ClientInfo.ClientId `
   -ClientSecret $ClientInfo.ClientSecret `
   -HostUri 'localhost:44300' `
   -RedirectUri 'https://localhost:44300' `
   -DisplayName $ClientInfo.ClientDisplayName


Create a Remote-Hosted App

At this point, your environment is set. You can create a provider-hosted app in Visual Studio and specify the ClientID and ClientSecret created here in the web.config file. The MSDN samples have a Hello World app to get you started. Don’t forget to change the ClientID and ClientSecret in web.config.