Thursday, October 17, 2013

Configure Sharepoint 2013 and provider-hosted app for Single Sign On via ThinkTecture Identity Server v2

The purpose of this exercise is to achieve web Single Sign On (web SSO) through the use of a third party authentication agent that issues a security token to be shared between Sharepoint and its provider-hosted apps. Therefore, both Sharepoint and its provider-hosted app will delegate user authentication to a common identity server. Upon authentication, the security token issued by the identity server is stored as browser cookie and is shared among various apps including Sharepoint that use the same identity service for user authentication. These apps sharing the same identity service are referred to as relying parties.

1.       On-premise Sharepoint 2013 configured to accept high trust provider-hosted app with a Sharepoint web application configured for claim-based authentication (This is the default OOTB authentication mode). More details here.

2.       A high trust provider-hosted app (low trust with Azure ACS will not work) configured to work with Sharepoint. More details here.

3.       Latest version of Thinktecture Identity Server v2 installed on an instance of IIS as an IIS web site. More details on its setup here.

Some abbreviations and conventions
·         “Identity Provider” and “Identity Server” are used interchangeably.
·         IP-STS: Token Issuer/Service from Identity Provider
·         RP-STS: Token Issuer/Service from Relying Party; namely, Sharepoint.
·         PH-App: Provider-hosted Sharepoint App of high trust variety.
·         WS-Fed: WS-Federation Passive Protocol.

A.      Create SSL certificate. This is to be used by the IP-STS and RP-STS, and will be the “glue” for establishing trust between these token services.

D.      Make PH-App claimed-aware. This will allow the app to delegate its user authentication to the identity server, and share its security token with Sharepoint. 

E.       Test the web SSO between the relying parties; namely, Sharepoint and the provider-hosted app.

F.       Online resources.

A. Create SSL Certificate
For the purpose of this exercise, since we’re targeting a development environment, we’re going to create a self-signed certificate. For production setup, it’s recommended that a commercial SSL certificate be used.

A1. Configure a certificate management console.
1.       From the machine that hosts the Identity Server, navigate to the Run… applet by pressing the [WinKey]+R key combination. Type in mmc to bring up the Windows Management Console. We’re going to create a custom console to show certificates for later use.

2.       From the Console window, navigate to the top menu item “Add/Remove Snap-in…”.

3.       From the Add or Remove Snap-ins dialog box, select the Certificates item from the left pane and click “Add”.

4.       On the Certificate snap-in dialog, select the Computer account radio button and click “Finish”.

5.       On the Select Computer dialog, click “Finish” to accept the default values.

6.       You’re back on the Add or Remove Snap-ins dialog box. Click “OK”.

7.       Expand the Personal certificate store from the tree view on the left of the Console window as shown.

8.       Save this instance of the Console to desktop from the File menu -> “Save” as Certificates.msc for easy access at a later time. Do not close the console window at this time as we’re coming back to modify the new certificate we’re creating in the next steps.

A2. Create a certificate
IIS 7 and above has built-in facilities to create self-signed certificates but it’s not flexible enough for us to create a certificate with a subject (common name) of our choice. So for this, we’ll use a command line tool detailed below.

1.       Open Visual Studio 2012 Command Prompt from Start menu -> All programs -> Microsoft Visual Studio 2012 -> Visual Studio Tools -> Developer Command Prompt for VS2012. Note if you don’t have Visual Studio installed on the same machine as the Identity Server, you can use SelfSSL from IIS 6 Resource Kit to create a self-signed certificate.

2.       From the Visual Studio command prompt, run the following command to create a certificate. This command will create a certificate in the personal certificate store we saw earlier on the console window. It will also generate a .cer file that we will use later on for hooking up PH-App and RP-STS for Sharepoint. Note that the common name (CN) will be different on every machine and the CN can either be an IP address or a domain name.
makecert -r -pe -n CN= -ss my -sr localmachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 "c:\stscert.cer"

3.       Switch back to the Management Console window, refresh the window view and you should see the newly-created certificate under the personal certificate store. Right-click on the new certificate item on the right pane and select Properties.

4.       On the Properties dialog box under the General tab, specify a Friendly name (i.e. STS Cert), and Click “OK” to apply the change.

A3. Export the certificate
1.       Open IIS Manager by typing in InetMgr from the Run… applet (pressing [WinKey]+R key combinations).

2.       Select the local server node from the connections pane on the left side of the screen, and double click the Server Certificates icon on the main Feature View.

3.       Select the new certificate you created earlier on the certificates list, right-click, and choose “Export…”.

4.       On the Export certificate dialog that appears, choose a location for file export, specify a password, and click OK. Note you will need this exported pfx file for your provider-hosted app configuration later.

B. Configure Sharepoint for trust between its RP-STS and IP-STS.
In order to establish trust between RP-STS and IP-STS, a trusted identity token issuer needs to be created on Sharepoint. This trusted token issuer will act on-behalf of Sharepoint to establish a trusted authenticated connection, via the same certificate shared between RP-STS and IP-STS.

B1. Create a Trusted Identity Token Issuer
1.       Using Notepad or other text editor, save the following powershell script in a file named createSTS.ps1 on Desktop.
## Sharepoint incoming WS-Fed endpoint ##
$realm = ""
## Thinktecture Identity Server sign-in URI ##
$providerUri = ""
## Create certificate object. Note the .cer file we saved earlier. ##
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\stscert.cer")
## Create a new Root Certificate Authority (optional if a root authority with the same cert exists) ##
New-SPTrustedRootAuthority -Name "IP STS Auth" -Certificate $cert
## Create claims mappings ##
$map1 = New-SPClaimTypeMapping -IncomingClaimType "" -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming
$map2 = New-SPClaimTypeMapping -IncomingClaimType "" -IncomingClaimTypeDisplayName "Role" -SameAsIncoming
$map3 = New-SPClaimTypeMapping -IncomingClaimType "" -IncomingClaimTypeDisplayName "Webpage" -SameAsIncoming
## Putting it all together as a Token Issuer ##
$ap = New-SPTrustedIdentityTokenIssuer -Name "Identity Provider STS" -Description "Identity Provider STS" -Realm $realm -ImportTrustCertificate $cert -SignInUrl $providerUri -IdentifierClaim $map1.InputClaimType -ClaimsMappings $map1,$map2,$map3

2.       Launch Sharepoint 2013 Management Shell as an administrator, execute the following commands line by line to run the script above:
cd Desktop

3.       Ensure that the Identity Token Issuer was created properly by running following command, and examine the output which should look as follows.
Get-SPTrustedIdentityTokenIssuer | where {$_.Name -eq "Identity Provider STS"}

B2. Configure a trusted identity provider for a Sharepoint web application
For the purpose of this exercise, we’re going to add the new STS (Identity Token Issuer) we created earlier to the default Sharepoint web application we have on our test environment. However, this can just as well be done on any web application within your Sharepoint farm.

1.       Browse to your Sharepoint Central Admin Application Management section -> Manage web applications, select the web application displayed on the list.

2.       Click on the “Authentication Providers” menu bar item on top, select the default zone on the dialog screen.

3.       Check the “Trusted Identity Provider” checkbox and the checkbox displayed for the identity provider. In this case it is the “Identity Provider STS” we created earlier.

4.       Scroll down the dialog screen and click the Save button to apply the changes. Note this normally will take a while to complete. If everything goes well, it will take you back to the Authentication Provider dialog screen we saw earlier.

5.       Close all instances of the browser, then try logging into a Sharepoint site, you should see a Sign In screen that asks to choose an authentication provider.

C. Configure the identity server for Sharepoint and PH-App as relying parties
This part of exercise requires an existing Thinktecture Identity Server already installed on a computer accessible on your network with at least one non-administrator user set up. For installation instructions, please refer to this guide.

C1. Add Sharepoint as a relying party on the Identity Server
1.       Log in to the identity server with an administrator account, click on the administration tab, expand the “Relying Parties & Resources” node from the Configuration area on the left of the screen, and click on the New button to create a relying party.

2.       On the New Relying Party form that appears, fill out the fields as shown, and Click the “Create” button.

3.       At this point, Sharepoint is configured as a relying party on the Identity Server. We now need to assign permission to an IP-STS user from Sharepoint.

C2. Assign Sharepoint permission to an IP-STS user
1.       Log into a sharepoint site with a user with admin privileges. For this exercise, we’ll use the developer site at /sites/dev.

2.       Navigate to Site Settings -> Users and Permissions section -> Site permissions.

3.       On the Permissions screen, click on the "Grant Permissions" menu bar item on the top.

4.       On the “Share” dialog screen, type the email of the IP-STS user in the "Invite people to 'Edit'" box as it appears on the identity server admin web page. If the trust is established correctly between the IP-STS and RP-STS, the user entry should appear on the autocomplete drop-down list. Select the user entry from the drop-down list when it appears.

5.       On the "Share" screen, click on "SHOW OPTIONS" to select a group in which to assign user permission to. In this case, we’re going to assign to the user site owner permission.

6.       Click the “Share” button to assign user permission.

7.       To test out the claims-based authentication via the identity server, log out the current user from Sharepoint, close all instances of the browser, and log in to the Sharepoint developer site as the IP-STS user for which the permission was just assigned.

C3. Add PH-App as a relying party on the Identity Server
1.       The steps involved in adding a relying party entry for a PH-App on the IP-STS is similar to section C1. Follow the steps provided on section C1 and complete the fields as shown, and click the “Create” button.

D. Making a provider-hosted Sharepoint app claims-aware  
For this part of the exercise, we’re going to use an existing Visual Studio 2012 PH-App project already configured to hook up with Sharepoint. If you do not have such a project, please follow the instructions from here to create one or download a sample from here.  You will also need to update your Visual Studio 2012 to Update 3 and install the Identity and Access Tool to allow easy configuration.

D1. Configure the PH-App to be claims-aware
1.       Open the existing PH-App project with Visual Studio 2012. From the Solution Explorer, right-click on the web project node (not the Sharepoint App project node) as shown and choose Identity and Access… from the context menu.

2.       On the Identity and Access dialog that appears, from the Providers tab, choose the radio button “Use a business identity provider”, fill out the remaining fields for the federation metadata URI from the IP-STS, and your app ID URI (realm).

3.       Switch to the Configuration tab, fill in values for App ID URI and Audience URI as shown. In this case, these values are the same as the application realm field value on the Providers tab.

4.       Accept the default values for the remaining fields and click OK. At this point, the tool will make some changes to the web.config file, which will look similar to the following:
<?xml version="1.0" encoding="utf-8"?>
    <add key="ClientId" value="a91915ef-96b2-48e5-a033-bbdba8b8a164" />
    <add key="ClientSecret" value="+RseWjNOUIFtFPyDZtr6yb5cNJ2ymMNy8xXhlPMSt8I=" />
    <add key="ClientSigningCertificatePath" value="C:\stscert.pfx" />
    <add key="ClientSigningCertificatePassword" value="password" />
    <add key="IssuerId" value="177cdf87-bb07-4360-a431-5fc2cad5d34e" />
    <add key="ida:FederationMetadataLocation" value="" />
    <add key="ida:Issuer" value="" />
    <add key="ida:ProviderSelection" value="productionSTS" /> 
  <location path="FederationMetadata">
        <allow users="*" />
        <add value="http://MyLocalComputer/" />
      <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
        <authority name="STS Identity Provider">
            <add thumbprint="8F385746D36C1F885A41647AD2BCB5D77E075C9A" />
            <add name="STS Identity Provider" />
      <!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
      <certificateValidation certificateValidationMode="None" />
      <cookieHandler requireSsl="false" />
      <wsFederation passiveRedirectEnabled="true" issuer="" realm="http://MyLocalComputer/" requireHttps="false" />

5.       Note the highlighted parts of the markup that correspond to the values filled from the Identity and Access Tool earlier. The ClientSigningCertificatePath value from the appSettings section should also be changed to point to the stscert.pfx file we exported earlier. The path of this pfx file should point to a physical location on the machine that hosts the app web site.

D2. Obtaining Sharepoint Client Context from the Claims-Aware PH-App
The OOTB Sharepoint App project template comes with a TokenHelper class (TokenHelper.cs) . However, it does not provide facilities to get Sharepoint client context from claims-based identity. For this, we’re going to use a custom implementation that extends the TokenHelper class. For this exercise, it is helpful to get a sample project here.

1.       Download the custom TokenHelper implementation from here, extract the ClaimsTokenHelper.cs file from the zip package, and add it to the project root of the web app project as shown.

2.       Wrap the TokenHelper class on the ClaimsTokenHelper.cs file with the same namespace as that on the TokenHelper.cs file, and add the static keyword from the TokenHelper declaration to make the class static.

3.       Add the partial keyword to the TokenHelper class declaration on the TokenHelper.cs file to also make the class partial.

4.       To get the Sharepoint client context, use the following snippet anywhere on the server side of the application code. In our sample project, we placed this code in a controller method of the MVC web application. Note we’re using the TokenHelper.GetS2SClientContextWithClaimsIdentity method to get an instance of ClientContext object.
        public ActionResult Index() {
            Uri hostWeb = new Uri(Request["SPHostUrl"]);
            using (ClientContext clientContext = TokenHelper.GetS2SClientContextWithClaimsIdentity(hostWeb, User, TokenHelper.IdentityClaimType.SMTP, TokenHelper.ClaimProviderType.SAML, true)) {
                //Get the current user.
                Web web = clientContext.Web;
                var currentUser = clientContext.Web.CurrentUser.LoginName;
            return View();

5.       Add a new TrustedProviderName key from the appSettings section as shown on the web.config file. Note this is the same name we created earlier for the Trusted Identity Token Issuer for Sharepoint.
    <add key="ida:FederationMetadataLocation" value="" />
    <add key="ida:Issuer" value="" />
    <add key="ida:ProviderSelection" value="productionSTS" />
<add key="TrustedProviderName" value="Identity Provider STS" />

6.       Inspect the Sharepoint App project from Solution Explorer. If Features, Packages, and app.config items have been generated, remove these items as they may prevent the published .app package from being installed to the desired Sharepoint site. The Features and Packages folders cannot be removed with Solution Explorer within Visual Studio. To do this, close Visual Studio, open the project file (.csproj) with a text editor and delete the xml content as shown.

The items to be removed from Solution Explorer are as shown:
The highlighted parts are to be deleted from the .csproj file. Note the values from your file may vary.
    <Content Include="AppIcon.png">
    <Content Include="Elements.xml" />
    <Content Include="Features\Feature1\Feature1.Template.xml">
    <Content Include="Package\Package.Template.xml">
    <None Include="app.config" />
    <None Include="Features\Feature1\Feature1.feature">
    <None Include="Package\Package.package">
    <None Include="SharePointProjectItem.spdata">

7.       Once the app project items have been removed from the project, also delete the corresponding physical files and folders from Windows Explorer.

8.       Now publish the configured app project, deploy the app to a target IIS web site, and add the high trust app to a Sharepoint site, in this exercise we’re using the developer site at /sites/dev. Follow this guide for more information on how this is done.

D3. Configure the IIS application pool of the deployed PH-App site
By default, every IIS application pool is created with the built-in ApplicationPoolIdentity account. If this account is used for the application pool associated with the PH-App site, a data protection operation error will be raised with impersonation failure once the user is authenticated through the IP-STS. To get around this issue, we need to use a local or a domain user account to replace the ApplicationPoolIdentity account.  

1.       Launch the IIS Manager on the computer hosting the PH-App, expand the server/host node from the Connections treeview, select the Application Pools node, and with a list of application pools displayed on the list, select the app pool, and click on the “Advanced Settings…” on the Actions pane as shown.

2.       On the Advanced Settings dialog box that appears, under the Process Model section, click on the ellipsis button on the Identity field.

3.       On the Application Pool Identity dialog that follows, select the Custom account radio button and click the Set button to specify a local or domain account. When a user is set, click OK to apply the change.

4.       With the app pool identity account changed, we now need to assign read permission to the certificate we created earlier for the Sharepoint Identity Token Issuer. For this, we turn to the certificate management console we created earlier. Open the certificates.mmc located on Desktop.

5.       Expand the Personal node on the left pane, and select the certificate on the list.

6.       Right-click on the certificate, choose All Tasks -> Manage Private Keys…

7.       From the Permission for <certificate> private keys dialog that opens, add a read only permission for the user as shown:

8.       Click OK to apply the changes.

E. Test the web SSO between the relying parties
By default, Sharepoint caches user session in persistent cookies. So when the browser restarts with a Sharepoint site, it automatically logs in the previously authenticated user. This presents an inconvenience in development scenarios where user authentication testing needs to be done by closing and reopening the browser in quick successions. For this, we can disable the persistent session cookie by running the following powershell command from Sharepoint server.
$serviceConfig = Get-SPSecurityTokenServiceConfig
$serviceConfig.UseSessionCookies = $true

1.       Once the app is added to a Sharepoint site, launch it, and copy the URL displayed on the browser’s address bar. We’re going to use this URL to test out the SSO functionalities.

2.       Close all instances of the browser, launch the PH-App using the URL copied previously. It should direct you to the Thinktecture log in screen for authentication. Once logged in, it should redirect you back to the app authenticated with the home page and the user name displayed on the top-right corner.

3.       With the app window still open, now try launching a Sharepoint site with the same browser from a different browser tab. Sharepoint will display the Sign In screen asking to choose an authentication provider. In this case, we’ll choose the Identity Provider STS option we created earlier.

4.       If all goes well, Sharepoint should not redirect you to the Thinktecture identity server for authentication and should allow you into the site right away with your logged-in user name, previously authenticated from the PH-App side, displayed on the top right corner of the screen.

5.       The reverse should also work; that is, if we’re logged in from Sharepoint first through Thinktecture IP-STS, and then try to launch the PH-App, the app should not redirect us to the IP-STS for authentication for the second time. Instead, it should take us to the home page right away with the authenticated user context loaded.

Note: if you’re getting the following security token error after launching the PH-App from an authenticated Sharepoint site, you may have placed Sharepoint and the PH-App under the same domain (i.e. using the same IP address for both Sharepoint and PH-App with different port numbers assigned for both). By assigning the PH-App to a different domain than the Sharepoint web application, this error will simply disappear. For development scenario where Sharepoint and PH-App are hosted on the same machine, one can simply assign a unique host name for the PH-App site from IIS site binding. This will allow for Sharepoint and  PH-App using the same IP address to coexist as relying parties sharing the same identity provider.

Server Error in '/' Application.

ID4230: The SecurityToken was not well formed. Expecting element name 'SecurityContextToken', found 'SP'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.IdentityModel.Tokens.SecurityTokenException: ID4230: The SecurityToken was not well formed. Expecting element name 'SecurityContextToken', found 'SP'.

Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:
[SecurityTokenException: ID4230: The SecurityToken was not well formed. Expecting element name 'SecurityContextToken', found 'SP'.]
   System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) +1081888
   System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) +100
   System.IdentityModel.Services.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) +623
   System.IdentityModel.Services.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) +164
   System.IdentityModel.Services.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) +173
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165

Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18055

Assigning a host name (Host Header) to an IIS site

F. Online resources used for this guide