One of the things you’re likely to hear a lot about in SharePoint 2013, and I may end up writing a lot about, is oAuth. In SharePoint 2013 oAuth is used to establish a trust between two applications for purposes of establishing the identity of a principal (user or application). In SharePoint you will use oAuth trusts between SharePoint and things like Exchange and Lync, with ACS or individual application developers who are using the new cloud app model, or even between two different SharePoint farms for things like the remote SharePoint index feature in Search.
What oAuth does NOT do is become an authentication provider for people; you still will use your New-SPTrustedIdentityTokenIssuer to create those trusts to your identity providers. For oAuth trusts we have a new cmdlet that is very similar in name, and it’s called the New-SPTrustedSecurityTokenIssuer. When we establish this kind of trust with a security token issuer we call it an S2S trust, which means “server to server”. Remember this acronym because you will start seeing it a lot in SharePoint 2013. In this post I’m going to talk through some of the particulars required to create this trust.
First it’s worth pointing out that many features that require an S2S trust will establish this trust themselves. They may do that via feature activation, or feature teams may provide you a PowerShell script or cmdlet to run that creates the trust as part of turning on their feature. There will be times when you need to do it yourself though, and that’s what this post is about.
One of the things you’ll need to resolve first is whether you are going to be using SSL or not. The reality is, that in most cases in SharePoint 2013, you should probably use SSL. The reason I say that is because there are so many scenarios that use oAuth in SharePoint 2013, and when you do you are passing around a cookie with an access token. That access token is like a key that unlocks the door to data. The access token is signed by a certificate so it can’t be spoofed by someone that creates their own access token, but you don’t want it flying around in clear text because in theory someone could grab that cookie and replay it for the duration of the cookie lifetime. SSL protects you from that cookie replay attack, the same way that you would use SSL with a forms based auth site for the same reason. That being said, there are still reasons why you may want to run your sites over HTTP – you’re in a test environment, you’re building out a dev environment, you’re running entirely on an internal network and don’t feel it’s a risk, etc. I’m not here to judge – I’m just here to explain. J
There are a couple of settings in the configuration of SharePoint’s security token service (STS) that you may want to tweak if you are not using SSL. You can get all of the STS configuration settings with this cmdlet: Get-SPSecurityTokenServiceConfig. There are two ways to establish a trust – one is with a certificate and one is using a new oAuth metadata endpoint that all SharePoint farms have. Using the metadata endpoint is the easiest way to go, but if that endpoint is not SSL secured then you need to set the AllowMetadataOverHttp property of the SharePoint STS to true. If you are not going to be running your web apps over SSL, then you will need to set the AllowOAuthOverHttp property to true as well. Here’s a little PowerShell that demonstrates how to set these properties:
$c = Get-SPSecurityTokenServiceConfig
$c.AllowMetadataOverHttp = $true
Once the STS is configured as required, we can look at how to establish the trust from one farm to another. As I mentioned above, all SharePoint farms have a metadata endpoint now that is used to supply information and the access token signing certificate. That metadata endpoint is at /_layouts/15/metadata/json/1. If you actually try to navigate to that in a browser you will be prompted to save it, which you can do to examine it. What you will find if you open it up in notepad is that it is just a JSON payload. It includes the name identifier for the STS (which it calls “issuer”), along with a serialized version of the token signing certificate (which it describes as the “value” for the key “x509certificate”). If you look a little further at the data, you’ll see that the issuer is actually servicename + “@” + realm values. It also matches the NameIdentifier property on the STS; this information is important, for reasons I will explain in a bit.
In this example let’s say that FARM_B needs to trust calls from FARM_A, because FARM_A is going to use FARM_B as a remote SharePoint index. Also, let’s say that FARM_A has a web application at http://FARM_A. To create the trust we would run the New-SPTrustedSecurityTokenIssuer cmdlet on a server in FARM_B like this (I’ll explain why I’m using the “$i = “ stuff later in the post):
$i = New-SPTrustedSecurityTokenIssuer -Name FARM_A -Description "FARM_A description" -IsTrustBroker:$false -MetadataEndPoint "http://FARM_A/_layouts/15/metadata/json/1"
Now, let’s say that you are setting up a trust with a services only farm. You don’t want to create a web application, site collection and SSL certificate just so you can create a trust from it. So, we have a second method that you can use to establish the trust using the New-SPTrustedSecurityTokenIssuer cmdlet. In the second form you can just provide the token signing certificate and the name identifier. You get the token signing certificate just like you did in SharePoint 2010 – go to a server in the farm, run the MMC, add the Certificates snap-in for the Local Computer, look in the SharePoint…Certificates node, and the first certificate in the list is the one you want – just save it to the local drive without the private key as a .cer file. You need the certificate and the NameIdentifier attribute of the STS that I was describing above in order to establish the trust. The cmdlet in that case looks like this (it assumes you have copied the STS certificate to a file called C:\sts.cer on a server in FARM_B):
$i = New-SPTrustedSecurityTokenIssuer -name FARM_A -Certificate "C:\sts.cer" -RegisteredIssuerName "00000003-0000-0ff1-ce00-000000000000@72da1552-085a-49de-9ecb-73ba7eca8fef " -Description "FARM_A description" -IsTrustBroker:$false
Just like you do with a SPTrustedIdentityTokenIssuer, you need add the trust used to sign oAuth tokens to the list of trusted root authorities in SharePoint. Again, you have two options for doing this: if you create your trust via the metadata endpoint, you can establish the trust like this:
New-SPTrustedRootAuthority -Name FARM_A -MetadataEndPoint http://FARM_A/_layouts/15/metadata/json/1/rootcertificate
Otherwise, you can create add it to the trusted root authority list just like you did in SharePoint 2010:
$root = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\sts.cer")
New-SPTrustedRootAuthority -Name "Token Signing Root CA Certificate" -Certificate $root
From a trust perspective, you’re done at this point – you’re trust is established and you can now create new application principals based on it. How you’ll use it is based on the application itself; in the case of a remote SharePoint index I’ll go ahead and finish out the scenario now for completeness.
There are two steps in this process – getting an app principal and granting it rights. Remember from our scenario that FARM_B needs to trust calls from FARM_A because it is going to get queries for the remote SharePoint index. So for my app principal I need to get a reference to the web app in FARM_B that FARM_A is going to use. Once I have that reference then I can grant rights for FARM_A to use it.
To get a reference to an the app principal you use the cmdlet like this:
$p = Get-SPAppPrincipal -Site http://FARM_B -NameIdentifier $i.NameId
IMPORTANT: There is one important thing to note here, that I think will be especially common especially during the SharePoint 2013 beta. You may get strange errors in PowerShell when you try and get the SPAppPrincipal. What I’ve found is that if your available memory on your server drops below 5% then all WCF calls will fail. Since this PowerShell cmdlet calls into a service application endpoint, which is hosted as a WCF, the Get-SPAppPrincipal cmdlet fails when you are low on memory. You can check in the Windows Event Viewer in the Application Log to see whether this is the cause of your problem. This has happened to me multiple times so far so chances are others will see it as well.
Note that as I described earlier in the post, I finally get to use my $i variable to grab the NameIdentifier of the STS in FARM_A. Now that I have a reference to the app principal for the FARM_B web app, I can grant it rights like so:
Set-SPAppPrincipalPermission -Site http://FARM_B -AppPrincipal $p -Scope SiteSubscription -Right FullControl
There you have it – those are your options and methodologies for creating an oAuth trust between two SharePoint farms. I’ll continue to dig into oAuth and the various uses and issues to be aware of over time on this blog.
UPDATE: There are other steps you need to do to get complete set of results back from all content sources when using Remote SharePoint Index; for more details see http://blogs.technet.com/b/speschka/archive/2013/01/24/getting-a-full-result-set-from-a-remote-sharepoint-index-in-sharepoint-2013.aspx.
Thanks for the post.
I am trying to configure remote SharePoint index for search. I configured oAuth trust between the farms but am getting "access denied. You do not have permission to perform this action or access this resource." error when I test the result source in Farm A. Both the farms are in same AD and system account for both farms is also same.
Can you please clarify on which server we need to run which PowerShell command and are there any other steps (apart from configuring result source in Farm A) to be performed on either Farms to get remote SP index working.
Hi Niskon25, unfortunately there is a bug in beta 2 that prevents this from working. You will see it fixed when the final product ships, sorry about that.
Thanks for the post Steve!
I have problem in setting trust relationship between SharePoint 2013 and Exchange 2013 (on-premise). As advised in Technet documentation I've tried following:
$exchange=New-SPTrustedSecurityTokenIssuer –MetadataEndpoint "exchange.domain.com/.../1" –IsTrustBroker –Name "Exchange"
Then I've tried to set permissions with:
https://spsite.domain.com -NameIdentifier $exchange.NameId
but this line was throwing the following error:
Get-SPAppPrincipal : Cannot validate argument on parameter 'NameIdentifier'.
The argument is null or empty. Supply an argument that is not null or empty
and then try the command again.
Some guy suggested me to omit "-IsTrustBroker" parameter when creating trusted security token issuer, and I've tried so, and Get-SPAppPrincipal succeeded! After some testing I've concluded that if I use -IsTrustedBroker or -IsTrustedBroker:$true - I'm getting
NameId is null error in Get-SPAppPrincipal. If I omit -IsTrustedBroker - Get-SPAppPrincipal succeeds.
My question: Will I get the same result if I omit IsTrustedBroker? What is default value of IsTrustedBroker if it is omitted? Maybe some comment on this behavior...
Thank you very much!
Just to correct some errors:
- "IsTrustedBroker" should be replaced with "IsTrustBroker"
- Exchange site address actually includes "autodiscover", so the correct address is "exchange.domain.com/.../1"
Helpful article. Thanks.