Beside the Point

A discussion of SharePoint-related concepts from multiple perspectives.

SharePoint Low-Trust Apps for On-Premises Deployments

SharePoint Low-Trust Apps for On-Premises Deployments

Rate This
  • Comments 23

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 `
  
-Verbose

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

Connect-SPFarmToAAD `
  
-AADDomain 'joshgav1.onmicrosoft.com' `
  
-SharePointWebUrl https://intranet.joshgav.com `
  
-RemoveExistingACS `
  
-RemoveExistingSTS `
  
-RemoveExistingAADCredentials `
  
-Verbose

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 `
  
-RemoveExistingWithSameDisplayName

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

$ClientInfo

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.

  • Hello,

    I successfully created a low trust app following your post, but now I cannot deploy any high trust apps anymore.

    Acording to SharePoint logs, SharePoint tries to validate them against ACS.

    Is there a way to prevent this?

    cheers,

    Yvan

  • Hi Josh,

    How can I see that the configuration of this Low Trust Szenario is successfull ?

    Can I see this without an App?  I have read that I can see an ACS configuration in the Authentication Provider view in the Central Administration, but I see nothing after I used the scriptes.

    Can you or someone else help me here ?

    Best regards

     Toni

  • Yvan, I encountered exactly the same error: "ACS65003: The clientId ... is not a valid service identity". Can you explain how did you manage to make it finally work? I'm fighting with it for a veery long time by now and I almost lost the rest of my hair. Any help will be more than apriciated.

  • Yvan why would you only post that you solved the problem without going into details? I have been struggling with this problem myself and your post is literally the only hit on google.

  • I am building a Provider Hosted app for a client of mine that is targeted to be put in the Dutch App Store.

    My question is, can this app also be used in on premise installations by following these steps:

    1. Register custom X.509 Certificate as STS certificate

    2. Configure SharePoint 2013 Server to use ACS

    3. Register Service Principal Name's of Local Web Application

    4. Enable Feature on Local Web Applications: " Apps that require accessible internet facing endpoints "

    5. Create Reversed Proxy with Access to WebApplication (On Premise)

    6.     Deploy Remote Web to the Cloud

    7. Publish App via Seller Dashboard

    8. Install App via App Store

  • Thanks a lot Josh....Awesome Article.

  • this is from 2012. the new implementation of low trust apps requires Azure ACS. I would like to see if there are any updated articles that implement low trust with azure ACS..

  • Josh, thanks for blazing this trail for us!

    Similar to @prasad above, I'm wondering about where things stand with using Azure Active Directory as the token broker *without* having an O365 tenancy. From this article, and everything else I've seen on MSDN, it looks like an O365 tenancy is currently required. Could you confirm that? And if it is required, are their plans to remove that requirement in the future?

Page 2 of 2 (23 items) 12
Leave a Comment
  • Please add 2 and 1 and type the answer here:
  • Post