SharePoint 2013 introduced the concept of SharePoint apps, pushing custom code to remote servers and using the client-side object model. However, not many SharePoint developers are aware that apps come in two distinct “flavours”: low-trust and high-trust apps. In this article I will introduce the less known app model: high-trust or S2S apps.
Low-Trust SharePoint Apps
It is probable that you have never heard of low-trust SharePoint apps before. The reason for this is that a vast majority of SharePoint 2013 app examples and documentation is centered on it, so the “low trust” moniker is unnecessary. Let’s recap how SharePoint cloud apps (the low-trust ones) work.
In a SharePoint provider-hosted app, there are two separate entities involved: the SharePoint server (either on-premises or Office 365) and the remote server where the app is running. Once we have the app code running outside SharePoint, we need some way of secured communication between the remote server and SharePoint server. This is achieved with the concept of app identity.
This article is published from the DotNetCurry .NET Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months. Subscribe to this eMagazine for Free and get access to hundreds of free .NET tutorials from experts
In addition to users, in SharePoint 2013, apps also have an identity of their own. They are identified by a long GUID-like identifier. Because they have identity, they can be assigned permissions, just like the users. These permissions are the permissions that the app is going to have on the SharePoint site, site collection or tenant where the app is running. Similar to how users are checked against their permissions for every operation in SharePoint, apps are also checked for permission when they use the client-side object model (CSOM) or REST endpoint to communicate with SharePoint.
However, there is one piece missing in this puzzle. How does SharePoint know that the app request is legitimate and not some rogue code that crafts a fake request message? In low-trust apps - the kind of apps you can install from SharePoint store, this is achieved by delegating authentication to a third-party service called Access Control Service or ACS.
ACS is a service running in Microsoft cloud and its purpose is to issue and validate identity tokens. When you launch an app from SharePoint, there is a HTTP POST to the app URL. In the parameters that are posted to the server, there is a small encoded payload known as context token. Prior to redirecting to the app, SharePoint contacts ACS to get a context token for the app. The context token is a JSON token that contains information about the app identity, the SharePoint farm or tenant ID and the expiration dates. For more details about the context token contents you should refer to this post by Kirk Evans from Microsoft.
The low-trust app gets the context token from the initial request. Immediately, the app calls ACS and exchanges the context token for a new JSON token called access token. Access token is used to authenticate the app for making SharePoint API call (CSOM or REST). Access token is the only token SharePoint trusts.
So, why all the fuss with ACS? If you pay attention to all the orchestration, the app is pretty much passive about the authentication. Its only duty is to pass the context token, exchange it for an access token and to attach the access token in its API calls. It can’t do much more. The authentication (the user ID and the app ID) is baked in the context token that is passed to the app from SharePoint. This is why the app is called “low-trust”, as SharePoint doesn’t entrust the app with the authentication. The app can’t change the user information nor the permissions it has.
Why High-Trust Apps?
If low-trust apps are so good, why are there high-trust apps? A valid question. As nice and simple the low-trust apps are, they have two main drawbacks.
The first drawback is that they depend on having Internet connectivity. If you are running Office 365 this is no problem, but if you run apps on your SharePoint server in your datacentre, the SharePoint servers have to be able to communicate with ACS servers in the cloud. This involves opening the firewall for bidirectional traffic between your farm and ACS. In many organisations, this is a huge security issue.
The second drawback is that there has to be a trust relationship between ACS and your SharePoint. Again, in Office 365 this is automatically available as both services are run by Microsoft. But, if you have on-premises SharePoint, you have to manually establish this trust by adding your SharePoint as a “principal” in Azure Active Directory (AAD). This involves a custom certificate, changing your SharePoint farm token signing process and it requires some fiddling with PowerShell. The whole nitty-gritty process is well explained in this post by Josh Gavant from Microsoft.
What if you want to leverage the app model but don’t want to open your datacentre to Internet or fiddle with trust connections? What if you want the app identity and permissions but for your own code that runs inside your own servers? Well, here is where high-trust apps are coming into place.
High-Trust App Authentication
As opposed to low-trust apps, high-trust apps are entrusted by SharePoint to build their own access tokens. Instead of passively accepting their user and SharePoint context and exchanging them for an access token, they are making access tokens and signing them, just as ACS does. In high-trust apps there is no ACS and there is no context token, just the SharePoint server and the remote server where the app is running. This is why high-trust apps are also known as server-to-server apps (S2S).
When we build a high-trust app in Visual Studio, we get a TokenHelper class that has all the low-level details of how to build and sign the access token and it uses Windows identity of the current user to fill the token.
But, you might ask yourself how SharePoint can trust the access token coming from a high-trust app. Well it uses a custom SSL certificate for the trust: SharePoint knows the public key of the SSL certificate and can use it to check that the token isn’t faked. The app has the private key and uses it to sign the token.
Note that the app is fully responsible for building the access token. It means that the app is putting the user ID, the app ID and the context information such as the SharePoint realm. This is why it’s called “high-trust”, as SharePoint “trusts” the app to make the tokens in good faith. However, the app can for example make a token that corresponds to another SharePoint user instead of the one opening the app. It can impersonate another app by changing the app ID in the token. What does SharePoint do to prevent fake calls?
The first line of defense is the SSL certificate. Only the certificate that has been registered as a trusted issuer can be used to sign access tokens. It is true that apps can share the same certificate for signing their tokens, we still need the certificate to be in the list that SharePoint trusts. The second line of defense is the app permissions. Even if the app changes the ID of the user to say an administrator, if the app doesn’t have the needed permissions granted on SharePoint, the request is going to be refused with an “Access Denied” error message.
Remember, high-trust doesn’t mean full-trust. The app is still limited to what it has been given permission to upon app installation. No more, no less.
Prerequisites for High-Trust Apps
There are several prerequisites for building high-trust apps in our SharePoint farm.
The user profile service has to be running and it has to contain the user profiles for the users that will be using the app. Why is that? Remember that the app is the one that puts the user IDs in the access token. How does SharePoint know which user it should check for permissions? It matches the user ID from the access token against the user profile database. If there is a match, and there is one and only one match, the user is “impersonated” and the API request is made on his or her behalf. The user ID is usually the SID (for Windows users) but it also can be the email (for federated authentication users) or plain username (for custom or FBA users). Steve Peschka has an excellent blog post about the “user rehydration” in high-trust apps.
We will need to create a custom SSL certificate for our app. In development we can use a self-issued certificate but in production we need a certificate issued by a trusted authority such as the domain controller or a verified entity such as VeriSign. We will need the PFX certificate with the private key for the app and a CER certificate with the public key for SharePoint. We have to register a “Trusted Root Authority” in SharePoint and also register the “Trusted Issuer” that signs the tokens with the certificate. The trusted issuer is identified by a GUID, and this GUID has to be registered in SharePoint and known to the app at runtime too.
Also, SharePoint Security Token Service (STS) has to be up and running. In addition, the STS application pool identity in IIS needs read permission to the public SSL certificate location in the farm.
Lastly, the web application to which we are installing the app also needs read permission to the public SSL certificate location.
Building “Hello World” High-Trust App
To build a high-trust app, we first need to create a custom certificate. I will be using a self-signed certificate created by IIS in Server Certificates feature. The name of the certificate is ‘HighTrustCertificate’ and once created, it can be exported in CER or PFX version. For the PFX version, you have to specify a password. In this case, the password will be “password”. The certificates are placed in the C:\certificates folder and the SharePoint Secure Token Service and default web application app pool have been given read permissions to the folder.
Figure1: Creating self-issued SSL certificate
Now we have to register the certificate as a trusted root authority and to register a new issuer based on that certificate. The issuer ID for simplicity sake will be 11111111-1111-1111-1111-111111111111. Open a SharePoint 2013 PowerShell console and execute the following script.
# Create root authority
$publicCertPath = "C:\Certificates\HighTrustCertificate.cer"
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($publicCertPath)
New-SPTrustedRootAuthority -Name "CertificadoHighTrust" -Certificate $certificate
# Create trusted issuer and IISRESET
$realm = Get-SPAuthenticationRealm
$specificIssuerId = "11111111-1111-1111-1111-111111111111"
$fullIssuerIdentifier = $specificIssuerId + '@' + $realm
New-SPTrustedSecurityTokenIssuer -Name "HighTrustCertificate" -Certificate $certificate -RegisteredIssuerName $fullIssuerIdentifier –IsTrustBroker
# Disable HTTPS requirement (for development)
$serviceConfig = Get-SPSecurityTokenServiceConfig
$serviceConfig.AllowOAuthOverHttp = $true
This script creates the root authority, a trusted issuer and disables the HTTPS for development, so that we don’t get SSL errors for self-signed certificates. This must only be done in development environment and never in a production environment.
Now we can open Visual Studio and create a new SharePoint 2013 App named ‘HelloWorldHTA’.
Figure2: Creating High-Trust App Project in Visual Studio
Once the project is created, Visual Studio will ask for more details about the app we are building. First we’ll have to specify the SharePoint development URL where the app will be published when it is launched from Visual Studio. Here we’ll also specify “Provider-hosted” as the app type.
Figure3: Specifying SharePoint debug URL and app type
The next question we’ll see is Visual Studio asking us whether to create ASP.NET Web Forms or MVC project for the remote app. In this case for simplicity I will use Web Forms.
The last question to answer is how the app will be authenticated. It asks if we would like to use ACS to create a low-trust app or to use a custom certificate to create a high-trust app. Here we will specify the path to the PFX certificate, providing its password (“password”) and trusted issuer ID (11111111-1111-1111-1111-111111111111).
Figure4: High-trust app authentication information
The app itself is very basic. In the Page_Load event handler we can see the following code.
protected void Page_Load(object sender, EventArgs e)
var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
using (var clientContext = spContext.CreateUserClientContextForSPHost())
clientContext.Load(clientContext.Web, web => web.Title);
The SharePointContextProvider is a helper class contained in the SharePointContext.cs class created alongside TokenHelper. It is a static instance of a concrete class SharePointHighTrustContextProvider of the abstract SharePointContextProvider, the other implementation being SharePointAcsContextProvider (for low trust apps). The context provider class is responsible for instantiating a concrete instance of SharePointContext class. In our app, this is an instance of a SharePointHighTrustContext class.
The line in the code that is responsible for instantiating the SharePoint access token when called in the CreateUserClientContextForSPHost method, is this one.
public override string UserAccessTokenForSPHost
return GetAccessTokenString(ref this.userAccessTokenForSPHost,
() => TokenHelper.GetS2SAccessTokenWithWindowsIdentity(this.SPHostUrl, this.LogonUserIdentity));
Here GetS2SAccessTokenWithWindowsIdentity method from TokenHelper is called to fill the access token with the Windows user identity. It is also given a SharePoint host web URL to scope the token to a specific SharePoint site, the one where the app is launched from.
There is another method called CreateAppOnlyClientContextForSPHost that returns app-only access token, without user identity in it. This is used in the app when the current user has less permissions than the app, so that the app can do things in SharePoint that the current user cannot.
Let’s run the app from Visual Studio by pressing F5. It will launch the app, ask for permissions in SharePoint and after that it will show the current site title (“Home” in our example).
Figure5: App trust dialog in SharePoint
Figure6: High-trust app running
Tricks and Caveats
As high-trust apps have a simpler mechanism for authentication, we can leverage it to our advantage. The low-trust apps are launched by SharePoint, and SharePoint injects the context token in the app request. We can launch our high-trust apps outside SharePoint, as long as we change the TokenHelper slightly to inject the required parameters (SPHostUrl and similar).
We don’t have to stop here. We can provision non-web applications as high-trust apps. In essence, any process that can write JSON tokens and sign them with a SSL certificate can be exposed as high-trust apps. You could write “timer jobs” as console applications, for example. The app model allows you for simpler authentication and app permissions, as opposed to having hard-coded credentials or using Windows authentication only.
However, high-trust apps are highly dependent on the validity of its two basic pillars: user profile and signing certificate. Any missing information such as incomplete profiles, multiple profiles for any single user or untrusted certificate will give the dreaded “401 Access Denied” error. Luckily for us, the ULS diagnostics logs are particularly helpful and loaded with details for OAuth app authorization.
High-trust apps (HTA) are on-premises alternative for cloud SharePoint apps. They leverage the same overall mechanism but their authentication process is simpler. This allows for using the recommended app model for your on-premises SharePoint development but still keeping all the pieces in your datacentre.
If you are still running your own SharePoint, high-trust apps may be worth a try.
Download the entire source code from GitHub at bit.ly/dncm18-sharepoint-hightrust