PREVIOUS: Security in SharePoint Apps – Part 6
In this part of the series, I’m going to shift gears a bit and talk about high trust apps and the plumbing that goes along with them. As I’ve explained somewhat earlier in this series, one of the big differences between low trust and high trust apps is that high trust apps do not get a context token. The context token contains information about the App and the user, so without that, a high trust app identifies both itself and the user to SharePoint.
The first issue to overcome is to get SharePoint to trust your App when it comes asking for content and says “hey I’m Contoso App and I’m asking for data on behalf of Steve”. Without checks in place to make sure the request is coming from a trusted source, your farm would be wide open to information leaks. In order to prevent that, just as you do with low trust Apps, high trust Apps have to use a trust broker. For a high trust scenario, that “broker” is really just an X509 certificate. I’ve been asked a few times about what kind of certificate it needs to be. In all honestly, I haven’t really found one that doesn’t work yet. My only recommendation here is that you create one specifically for this purpose – i.e. I would not try and take, for example, a wildcard SSL cert that I’m using on my web site and use it as a trust broker. You can create a self-signed certificate, you can create a domain-issued SSL certificate, etc…but I would create one specifically for this purpose.
Once you have the certificate you want to use, you need to configure SharePoint to trust it and to use it – these are two different things! The first thing you need to do is configure SharePoint to trust it. This is the same process as you go through when you create an SPTrustedIdentityTokenIssuer for SAML claims – you get the token signing certificate and you add it to the list of trusted root authorities. When you are creating a new trust broker you need to do the same thing – add your certificate to the list of trusted root authorities. Also, just like with an SPTrustedIdentityTokenIssuer, if your certificate has parent certificates in its certificate hierarchy, you need to add ALL of them to the list of trusted root authorities. I’ve explained this concept in more detail here: http://blogs.technet.com/b/speschka/archive/2010/02/13/root-of-certificate-chain-not-trusted-error-with-claims-authentication.aspx.
After you’ve done this, then you need to create your trust broker, which in SharePoint world is an SPTrustedSecurityTokenIssuer. When you create an SPTrustedSecurityTokenIssuer, you are basically saying that you are going to have Apps submitting requests to SharePoint, and those requests are going to be signed with the public key of this certificate. The only way you can sign something with the public key, is if you possess the private key. That’s how SharePoint knows if the request comes in signed by this certificate, then it could have only come from someone who possesses the keys to that certificate. In looking through some of my blog postings I realized that it doesn’t really seem like I’ve ever shared the PowerShell for creating one based on a certificate, so here goes:
#NOTE: You can use the .CER file here, i.e. without the private key
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\spapps.cer")
New-SPTrustedRootAuthority -Name "Apps Certificate" -Certificate $certificate
#NOTE: Create your own GUID and put it here, make sure
#all alpha characters are lower case
$issuerId = "e9134021-0180-4b05-9e7e-0a9e5a524965"
$spsite = Get-SPSite $spurl
$realm = Get-SPAuthenticationRealm -ServiceContext $spsite
$fullAppIdentifier = $issuerId + '@' + $realm
New-SPTrustedSecurityTokenIssuer -Name "High Trust Apps" -Certificate $certificate -RegisteredIssuerName $fullAppIdentifier -IsTrustBroker
They key to this bit of PowerShell is the -IsTrustBroker flag when you create your SPTrustedSecurityTokenIssuer. If you don’t include that flag, then that certificate can only be used with a single App, and that App would need to use the $issuerId as both the clientId and issuerId in the web.config file. That’s not to say that there aren’t scenarios where you might want to do that, but it’s certainly not the mainstream case. I’ll talk more about certificate management issues later in this post.
Once you’ve created your SPTrustedSecurityTokenIssuer, you’re ready to create your applications. That process is somewhat more complicated than when you build a low trust App. You’ll open up Visual Studio and select new SharePoint App, then in the first page of the wizard you’ll pick the site you want to deploy to during development and configure it as a provider hosted app. On the second page of the wizard though, instead of selecting a client secret you’ll need to browse and select the certificate – the .pfx version – that is configured to be the SPTrustedSecurityTokenIssuer. You’ll need to provide the password to open up the PFX file, as well as the issuerId associated with that certificate. Here’s what the second page of the wizard looks like when you create a high trust app – again, you MUST use only lower case for your alpha characters in the Issuer ID field or you will get 401 unauthorized errors when access SharePoint:
There is one thing that’s very important to note here about the location of your token signing certificate…I’m seeing this issue come up more and more frequently as folks deploy their apps so make sure you are on top of this. When you create your provider hosted app, Visual Studio will create a new web app project that uses IIS Express. When you run that App, IIS Express is effectively running in the context of your own credentials. So when IIS Express tries to load the pfx certificate to use for signing your application request, it all just works. Where the problems tend to occur is when you deploy your application to production. Now it’s running on IIS and it’s doing so in the context of an app pool. I’ve seen many times where the app pool account does NOT have rights to the directory where the pfx file is kept. As a result you will get all sorts of nasty untrapped errors (bad TokenHelper class, bad TokenHelper). Make sure you have at least Read rights to the directory for your app pool account before you deploy.
Now that all your plumbing is in place and you’re ready to write your app, you need to remember what “high trust” really means. As I’ve said before it means it’s up to YOU to tell SharePoint who the App is and who the user is to SharePoint. You tell it who the App is by the clientId value in your web.config. How you tell it the user identity is completely up to you. If you use the out of the box TokenHelper class, it’s configured to use the current user’s Windows identity. It doesn’t have to work that way though – you can modify TokenHelper and have it send an identifier for whatever user you want. I say “identifier”, because really you are just sending over a claim value – nameid, SMTP, SIP or UPN – that SharePoint will use to “rehydrate” the user when the request is received. For a more complete discussion on what rehydrate means, you can read this post: http://blogs.technet.com/b/speschka/archive/2012/08/15/oauth-and-the-rehydrated-user-in-sharepoint-2013-how-d-they-do-that-and-what-do-i-need-to-know.aspx. The net of it is you need to have an up to date User Profile Application (UPA) so when your request arrives at SharePoint, it can look in the UPA and find a profile that matches the claim type and value you sent in. As a high trust app you can tell SharePoint that you’re the Queen of England or the Mayor of Steveville and it will just take your word for it.
Since I keep pointing this fact out to people, I thought that perhaps it might help to actually dig into TokenHelper or ClaimsTokenHelper and show you exactly where and how you do that. In fact I’m going to show ClaimsTokenHelper here, because that is the class that I wrote to do this “stuff” for SharePoint sites that use SAML or FBA so I had a delightful time playing with this very fun feature. J If you open up ClaimsTokenHelper.cs, go into the IssueToken method (the TokenHelper class has this same method as well). Here’s an abbreviated version of what it looks like:
List<JsonWebTokenClaim> actorClaims = new List<JsonWebTokenClaim>();
actorClaims.Add(new JsonWebTokenClaim(samlClaimType, samlClaimValue));
In this case I’m passing some variable so I can plug in whatever claim type and value I want. However you could just as easily replace this line of code with something like this:
Congratulations – all of your users are now the Queen of England…as long as you have a user profile with an SMTP address of email@example.com.
There’s one other point worth making about the clientId, which identifies the App. Remember that when you are building your App in Visual Studio, VS will automatically generate a clientId and update the web.config, as well as configure the deployment site to ensure that everything works when you press F5. Once you’re ready to deploy your App to production you need to take care of that yourself. That means you need to go to a site and use appregnew.aspx to generate a new clientId for your application, republish your application using that clientId, deploy your App to the App Catalog, then install it in the site collection. The use of appregnew.aspx is also covered in a little more detail in this post (as well as TechNet): http://blogs.technet.com/b/speschka/archive/2013/02/18/when-do-your-apps-need-appregnew-aspx-in-sharepoint-2013.aspx.
Now that we’ve gone end-to-end on the high trust plumbing and application deployment, it’s worth taking a few minutes to come back to the topic of certificate management. Generally speaking, as I’ve said, you want to use the –IsTrustBroker flag when you create your new SPTrustedSecurityTokenIssuer. However you also need to understand the flip side of that arrangement – while every app can use that certificate as the trust broker, what happens if you want to stop trusting one particular App? The only way to really do that is to remove the SPTrustedSecurityTokenIssuer. When you do that of course, ALL of your Apps are broken. To fix it, you would need to create a new certificate, create a new SPTrustedSecurityTokenIssuer, distribute the pfx version of the new certificate to all of your Apps, and then have all of the Apps change their issuerId to match the new SPTrustedSecurityTokenIssuer. That’s potentially a lot of work. Another option would be to create separate certificates based on your organizational hierarchy. For example, you could create a separate certificate and SPTrustedSecurityTokenIssuer for each division, or each department, or however you organize your company. That will reduce the impact when or if you want to stop trusting an App, but of course it also introduces some overhead you have to plan for – how are we going to track, store, and safeguard these certificates? That’s an aspect of SharePoint Apps development that I really haven’t seen anyone address so far, which is kind of interesting in and of itself. For more discussion on managing certificates you can also take a look at this article: http://msdn.microsoft.com/en-us/library/jj945118.aspx.
That’s going to wrap up this discussion of high trust apps. The next part will be the last part in this series, and it will be kind of short. I’m going to talk briefly about developing Apps for SharePoint sites that use SAML authentication. I already have a blog post with code that covers this in some detail, so in this last post I’m really going to look at it from a higher level. The idea will be to set you up with the pieces you’ll need to put into place, what your high level plan should look like, etc. and not really the coding aspect since that’s covered in my other post.
NEXT: Security in SharePoint Apps - Part 8
your articles have helped me a lot on setting up Apps in SharePoint. But one thing is confusing about this whole thing. You are writing that the app is always responsible for telling SharePoint who the user is in high trust environment. But this seems kind of arkward, because user initially comes from SharePoint not from the App.
Actually i am writing a High Trust app(S2S) with AppParts in a FBA Scenario. User enters SharePoint Site with its credentials, and navigates to a site where an AppPart is shown. How do i know what to display to this user? Imagine its an AppPart wich just displays "Hello <Username>" (ctx.Web.CurrentUser.LoginName). That does not seem possible. So the user should first Login again in my app so that it also knows who the user is to tell SharePoint what it should already know.
Is this correct?
I think this is a big flaw. Imagine there are now 10 different Apps installed on the server, so the user has to login 10 times to be able to work properly. Single Sign On? OAuth? Where does it has gone? Provider Hosted App on O365 is working pretty well. So why is this not working OnPrem? Or am I missing something?
I have read that it should be possible to use ACS in an OnPrem Environment too, but in my (Employers) opinion that is not an option because of the need of Azure.
A response would be highly appreciated