Development environment for low-trust: Configuring ADFS

ADFS, or Active Directory Federation Services, is widely used in both on-premise and hybrid SharePoint solutions. This is a technology that you need to get up to speed on and undoubtedly will use or be affected by in the future. In this article, we configure ADFS for our development environment.

This post is in the article series “Development environment for low-trust” where we aim to set up an environment that replicates a live production environment as closely as possible.

Sections:

Note: I will not go in to deeper discussions here on how ADFS works. For a decent overview of basic concepts (albeit for SP2010), see https://msdn.microsoft.com/en-us/library/hh446525.aspx.

ADFS 3.0

To use all features of SharePoint 2013, specifically apps, we need to use ADFS 3.0. This is because wildcards are not supported in ADFS 2.0. We need all SharePoint hosted apps to work so adding *.spapps.lekman.com, for example, is required. ADFS 3.0 is automatically included in Windows Server 2012 R2.

ADFS Proxy

If users are authenticating outside the network, then you need an ADFS Proxy. This is a server that you normally place in a DMZ and expose to the Internet. This is how you do it if you want a hybrid with Office 365. If you need to set this up for hybrid or for production, see http://goodworkaround.com/node/53.

Installing ADFS

To install ADFS, you need

  • access to Domain Admin credentials
  • install the service on a domain-joined machine
  • a certificate for the service using at least 2014 bit encryption (see Configuring and using SSL but create a single-name cert, such as adfs.lekman.com)
  • a service account for ADFS in AD.
  • An A record pointing to the ADFS server, for example adfs.lekman.com (note that CNAME records may cause endless lookup loops)

On a Windows Server 2012 R2 machine

  1. Start the server manager’s add roles and features wizard, select Active Directory Federation Services, then click next.
  2. On the Active Directory Federation Services splash screen, click Next (note the requirements here for ADFS)
  3. Click Next again and wait for the installation of the feature to complete
  4. From the Server Manager window, open the notification and run the ADFS configuration wizard
  5. Choose “Create the first federation server in a federation server farm” and click Next
  6. Provide the Domain Admin account and click Next
  7. On the next screen, select (or import) the SSL certificate and name the service then click Next
  8. Specify the service account for ADFS and click Next
  9. When selecting a database, choose WID or SQL based on your requirements then click Next
  10. Continue clicking Next until all done

For a visual step-through, see the following MSDN post.

After installation, be sure to run the WIndows Update wizard to add any patches to the service.

Configure ADFS

To allow ADFS and SharePoint to authenticate the user, you need to create a relying party. Think about this concept as a claims aware application. SharePoint will be claims aware as it can authenticate and identify users using claims that are issued by ADFS. To create a relying party for SharePoint:

  1. On the ADFS server, open AD FS Management
  2. Expand the treenode  AD FS/Trust Relationships/Relying arty Trusts
  3. From the right hand pane, click Add Relying Party Trust
  4. Click Start, choose “Enter a about the relaying party manually” then Next
  5. Create a display name. I normally enter the URN name that I will use later, such as “sharepoint:adfs”. Click Next.
  6. Click Next (accepting the default AD FS profile option)
  7. Click Browse and choose the certificate in .cer form that you configured earlier. Click Next.
  8. Select “Enable support for WS-Federation Passive Protocol”  and enter the name of your SharePoint server and the “/_trust/” path. This allows ADFS to know where the authentication party in SharePoint is. This must be over HTTPS. For example, my final URL would be “https://sharepoint.lekman.com/_trust/”. Click Next.
  9. Now add the URN identifier (I use the same as the display name), for example “urn:sharepoint:adfs”. This is used later as a pseudonym to find the relying party. Click Next.
  10. Click Next (choosing default “I do not want to…”), Next again (choosing default “Permit all users…”)
  11. To save the configuration, click Next then Close
  12. The Rule Control window opens automatically. First, we create the rule for passing the UPN, the user account name, to SharePoint by
    1. Click Add Rule under Issuance Transform Rules
    2. Use the Claim rule template “Pass Through or Filter an Incoming Claim” and click Next
    3. Set Claim Rule Name as “UPN”, Incoming Claim Type as “UPN” and click Finish
  13. We also pass the account identifier by
    1. Click Add Rule under Issuance Transform Rules
    2. Use the Claim rule template “Pass Through or Filter an Incoming Claim” and click Next
    3. Set Claim Rule Name as “SID”, Incoming Claim Type as “Primary SID” and click Finish
  14. We also pass the Windows account name by
    1. Click Add Rule under Issuance Transform Rules
    2. Use the Claim rule template “Transform an Incoming Claim” and click Next
    3. Set Claim Rule Name as “Windows Account”, Incoming Claim Type as “Windows acount name”, Outgoing Claim Type as “Name” and click Finish
  15. Finally, we send the email address as an identifier by
    1. Click Add Rule under Issuance Transform Rules
    2. Use the Claim rule template “Send LDAP Attributes as Claim” and click Next
    3. Set Claim Rule Name as “Email”, Select “Attribute Store” as “Active Directory”, “Mapping of LDAP attributes to outgoing claim types” select LDAP Attribute as User-Principal-Name and Outgoing Claim Type as E-Mail Address, then click Finish
  16. Click OK to save all rules
  17. Double-click the relying party, then open the Endpoints tab. I will now add the URL for SharePoint-hosted apps and My Site by
    1. Click Add WS-Federation
    2. Add the “/_trust” URL for My Site and click OK
    3. Repeat with the URL (with *) for the apps. 

Configure SharePoint

We will now set up the corresponding configuration in SharePoint so that users can be redirected to ADFS for authentication.

  1. Import the SSL certificate used for ADFS onto the SharePoint server
    1. Copy the certificate to the server
    2. Start Certificate Manager (from the Manage computer certificates link, search from the Start screen)
    3. Expand the treenode Personal/Certificates.
    4. Right-click the node. Choose All Tasks/Import.
    5. Click Next, choose the file, click Next
    6. Enter password if any, click Next until completed
  2. Copy the .cer certificate to a local folder on the SharePoint server. I use c:\cert\.
  3. Open SharePoint Management Shell and run (replacing highlighted values with your value for certificate, URN name and ADFS server address and optionally the authentication method name and description)
    1. $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("Full certificate path")
    2. New-SPTrustedRootAuthority -Name "Token Signing Cert" -Certificate $cert
    3. $emailClaimMap = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "EmailAddress" –SameAsIncoming
    4. $upnClaimMap = New-SPClaimTypeMapping -IncomingClaimType “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" -IncomingClaimTypeDisplayName “UPN” –SameAsIncoming
    5. $roleClaimMap = New-SPClaimTypeMapping -IncomingClaimType “http://schemas.microsoft.com/ws/2008/06/identity/claims/role" -IncomingClaimTypeDisplayName “Role” –SameAsIncoming
    6. $sidClaimMap = New-SPClaimTypeMapping -IncomingClaimType “http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid" -IncomingClaimTypeDisplayName “SID” –SameAsIncoming
    7. $realm = "urn:sharepoint:adfs"
    8. $signInURL = "https://adfs.lekman.com/adfs/ls"
    9. $ap = New-SPTrustedIdentityTokenIssuer -Name "ADFS" -Description “ADFS Server” -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $emailClaimMap,$upnClaimMap,$roleClaimMap,$sidClaimMap -SignInUrl $signInURL -IdentifierClaim $emailClaimmap.InputClaimType

We can now choose “ADFS” as a new authentication provider.Go to SharePoint Central Admin website and open the web application that you are using. Under Authentication Providers, select the default zone and now you can see the new provider. We can use one zone in a production system and set the login URL to “_trust”. This will allow the system, especially the search crawl, to index the site using Windows and users to be forced to logon using ADFS. However, this is not great on a development server as I need Windows authentication to deploy from inside Visual Studio. We need double authentication providers. To do this:

  1. Extend the web application if not already done
    1. Central Administration, Application Management, select the Web Application (I have set this application up as HTTP as the default zone)
    2. Click Extend and set it up with the same name except in HTTPS. As authentication, set it to use Windows Authentication and NTLM (we configure ADFS later).
    3. Set the zone as Intranet then click OK
    4. See previous article Configuring and using SSL for more details.
  2. Select the web application and click Authentication Providers
  3. Select the Default zone and set this to use Windows Authentication and NTLM
  4. Select the Intranet zone and set this to use both Windows Authentication (NTLM) as well as checking the Trusted Identity Provider that you created
  5. Open the HTTPS URL. You will be asked what method of authentication to use. Select Windows and log on. Go to the site collection settings and add your ADFS account as a site collection owner.
  6. Go back to the Intranet zone in central admin and now remove the NTLM option to make the zone pure ADFS.

Note: I have now set up the HTTP zone as Windows and HTTPS zone as ADFS. Services such as search will perfectly understand how to format the URLs when using the different zones. Visual Studio can deploy to HTTP and I normally use Internet Explorer on HTTP for development and Chrome on HTTPS for testing.

ADFS and Host Named Site Collections

If you are using host named site collections, then this gets a little messy. I use the web application above as the HNSC root and then use a script to create new site collections for different projects. The trick is to create the site using a temporary URL, add the HTTPS version of the URL then rename the original site. A bit weird, but hey, it works. Here is the complete script to use in this scenario. Replace $webapp, $owner1 and $server with your own specific values.

$ErrorActionPreference = "Continue";
#Get input from user
$name = Read-Host "Enter New Site Collection Name";
$site = Read-Host "Enter New Site Collection URL (without http or https)";
$dbname = Read-Host "Enter Content Database Name";
#Default values, change to your values
$webapp = "http://sharepoint.lekman.com" # Name of the HNSC root, default zone
$owner1 = New-SPClaimsPrincipal -Identity "domain\account" -IdentityType WindowsSamAccountName;
$server = "LEKMAN-SQL"; #This is the alias you setup to your database server

#Create content db

$xdb = Get-SPContentDatabase -Identity $dbname -ea SilentlyContinue
if ($xdb -eq $null) {
write
-host
Write
-Host "Creating Content DB"
New
-SPContentDatabase -Name $dbname -DatabaseServer $server -WebApplication $webapp
Write
-Host "Content DB Created Sucessfully"
write
-host
}
#Create the site collection
Write-Host "Creating Site Collection $site"
$tempsite = "http://temp-"+$site
$httpsite = "http://"+$site
$httpssite = "https://"+$site
New
-SPSite -URL $tempsite -OwnerAlias $owner1.ToEncodedString() -HostHeaderWebApplication $webapp -Template BLANKINTERNETCONTAINER#0 -Language 1033
Write-Host "Site collection $site created sucessfully"
#$newsite = Get-SPSite($site)
Set-SPSiteUrl (Get-SPSite $tempsite) -Url $httpssite -Zone Intranet
$s = Get-SPSite -Identity $tempsite
$s.Rename($httpsite)
Write
-Host "Alternate URLs configured successfully. Now restarting processes.."
IISReset
Net stop SPTimerv4
Net start SPTimerv4