How to Configure SAML SSO with AD FS 3.0 on Windows Server 2012 R2
Active Directory Federation Services 3.0 (AD FS 3.0), included with Windows Server 2012 R2, enables SAML 2.0 and WS-Federation based Single Sign-On for web applications and cloud services. Organizations use AD FS to federate their on-premises Active Directory identity to external relying parties — SaaS applications, partner organizations, and cloud platforms — without exposing their AD credentials to those services. This guide covers deploying AD FS 3.0, configuring a SAML 2.0 relying party trust, customizing claims, and testing SSO end-to-end.
Prerequisites
– Windows Server 2012 R2 domain member server for the AD FS role
– Active Directory domain with at least one Domain Controller accessible
– A valid SSL certificate for the AD FS service name (e.g., adfs.corp.com) from a trusted CA
– A service account (regular domain user account or Group Managed Service Account)
– DNS entry pointing the AD FS service name to the AD FS server
– Port 443 open inbound to the AD FS server for external access
– A SQL Server instance for the AD FS configuration database (or Windows Internal Database for small deployments)
Step 1: Install the AD FS Role
# Install AD FS role and management tools
Install-WindowsFeature -Name ADFS-Federation -IncludeManagementTools
# Verify installation
Get-WindowsFeature ADFS-Federation
# Import the AD FS module
Import-Module ADFS
Step 2: Prepare the SSL Certificate and Service Account
# Request and import SSL certificate for adfs.corp.com
# Import from PFX (assuming you have the cert file)
$certPwd = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
$cert = Import-PfxCertificate -FilePath "C:Certsadfs_corp_com.pfx" `
-CertStoreLocation "Cert:LocalMachineMy" `
-Password $certPwd
Write-Host "Certificate Thumbprint: $($cert.Thumbprint)"
# Create a Group Managed Service Account for AD FS
Import-Module ActiveDirectory
New-ADServiceAccount -Name "svc_ADFS" `
-Description "AD FS Service Account" `
-DNSHostName "adfs.corp.com" `
-PrincipalsAllowedToRetrieveManagedPassword "ADFS-Servers"
# Install on the AD FS server
Install-ADServiceAccount -Identity "svc_ADFS"
Test-ADServiceAccount -Identity "svc_ADFS"
Step 3: Configure the AD FS Farm
Import-Module ADFS
# Get the certificate
$cert = Get-ChildItem Cert:LocalMachineMy |
Where-Object { $_.Subject -like "*adfs.corp.com*" } |
Select-Object -First 1
# Install AD FS with Windows Internal Database (for single-server deployment)
Install-AdfsFarm `
-CertificateThumbprint $cert.Thumbprint `
-FederationServiceDisplayName "Contoso Identity Service" `
-FederationServiceName "adfs.corp.com" `
-GroupServiceAccountIdentifier "CORPsvc_ADFS$" `
-OverwriteConfiguration
# For SQL Server backend (recommended for HA):
# Install-AdfsFarm `
# -CertificateThumbprint $cert.Thumbprint `
# -FederationServiceName "adfs.corp.com" `
# -GroupServiceAccountIdentifier "CORPsvc_ADFS$" `
# -SQLConnectionString "Data Source=sql01.corp.local;Integrated Security=True"
# Verify AD FS service is running
Get-Service adfssrv | Select-Object Status, StartType
Get-AdfsSslCertificate
Get-AdfsProperties | Select-Object HostName, HttpsPort
Step 4: Configure AD FS for SAML 2.0 Relying Party Trust
A Relying Party Trust defines the relationship between AD FS (the Identity Provider) and a service provider (SP) that accepts SAML assertions. Most SaaS applications provide a SAML metadata XML file:
Import-Module ADFS
# Method 1: Import from SAML metadata URL (most SaaS apps provide this)
$metadataUrl = "https://app.example.com/saml/metadata"
Add-AdfsRelyingPartyTrust `
-Name "ExampleSaaSApp" `
-MetadataUrl $metadataUrl `
-AutoUpdateEnabled $true `
-MonitoringEnabled $true `
-Enabled $true
# Method 2: Import from local metadata file
Add-AdfsRelyingPartyTrust `
-Name "InternalWebApp" `
-MetadataFile "C:ADFSwebapp_metadata.xml" `
-Enabled $true
# Method 3: Manual SAML configuration
Add-AdfsRelyingPartyTrust `
-Name "CustomSamlApp" `
-Identifier "https://webapp.corp.com/saml" `
-WsFedEndpoint "https://webapp.corp.com/saml/acs" `
-SamlEndpoint (New-AdfsSamlEndpoint -Protocol SAMLAssertionConsumer `
-Uri "https://webapp.corp.com/saml/acs" `
-Binding POST -Index 0 -IsDefault $true) `
-EncryptionCertificate (Get-ChildItem Cert:LocalMachineMy |
Where-Object { $_.Subject -like "*webapp.corp.com*" } |
Select-Object -First 1) `
-SignatureAlgorithm "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" `
-Enabled $true
Write-Host "Relying Party Trust created successfully"
Get-AdfsRelyingPartyTrust -Name "ExampleSaaSApp" | Format-List Name, Enabled, Identifier
Step 5: Configure Claims Rules
Claims rules define what information AD FS sends in the SAML assertion. Configure rules to pass the appropriate user attributes to the service provider:
# Rule 1: Send UPN as NameID (required by most SAML SPs)
$rule1 = @"
@RuleTemplate = "MapClaims"
@RuleName = "Send UPN as NameID"
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
Issuer = c.Issuer,
OriginalIssuer = c.OriginalIssuer,
Value = c.Value,
ValueType = c.ValueType,
Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] =
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress");
"@
# Rule 2: Send email address
$rule2 = @"
@RuleTemplate = "LdapClaims"
@RuleName = "Send Email"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory",
types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
"http://schemas.xmlsoap.org/claims/Group"),
query = ";mail,givenName,sn,tokenGroups;{0}", param = c.Value);
"@
# Rule 3: Send department from AD
$rule3 = @"
@RuleName = "Send Department"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory",
types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/department"),
query = ";department;{0}", param = c.Value);
"@
# Apply all rules to the Relying Party
Set-AdfsRelyingPartyTrust -TargetName "ExampleSaaSApp" `
-IssuanceTransformRules ($rule1 + $rule2 + $rule3)
# Verify rules
Get-AdfsRelyingPartyTrust -Name "ExampleSaaSApp" |
Select-Object -ExpandProperty IssuanceTransformRules
Step 6: Configure Issuance Authorization Rules
Control which users and groups can access the relying party through AD FS:
# Permit only members of a specific AD group
$authRule = @"
@RuleName = "Permit ExampleApp Users"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid",
Value == "S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX",
Issuer == "AD AUTHORITY"]
=> issue(Type = "http://schemas.microsoft.com/authorization/claims/permit", Value = "true");
"@
# Get the SID of the authorized group
$group = Get-ADGroup "ExampleApp-Users"
$groupSID = $group.SID.Value
$authRule = @"
@RuleName = "Permit ExampleApp-Users group"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid",
Value == "$groupSID"]
=> issue(Type = "http://schemas.microsoft.com/authorization/claims/permit", Value = "true");
"@
Set-AdfsRelyingPartyTrust -TargetName "ExampleSaaSApp" `
-IssuanceAuthorizationRules $authRule
# To permit all authenticated users (less restrictive):
Set-AdfsRelyingPartyTrust -TargetName "ExampleSaaSApp" `
-IssuanceAuthorizationRules '=> issue(Type = "http://schemas.microsoft.com/authorization/claims/permit", Value = "true");'
Step 7: Deploy Web Application Proxy (AD FS Proxy)
For external access, deploy a Web Application Proxy server in the DMZ. This server pre-authenticates requests before they reach internal servers:
# On the WAP server (in DMZ), install Web Application Proxy role
Install-WindowsFeature -Name Web-Application-Proxy -IncludeManagementTools
# Configure WAP to trust the AD FS farm
# Requires AD FS admin credentials and the federation service trust certificate
Install-WebApplicationProxy `
-CertificateThumbprint $cert.Thumbprint `
-FederationServiceName "adfs.corp.com" `
-FederationServiceTrustCredential (Get-Credential)
# Publish AD FS through WAP
Add-WebApplicationProxyApplication `
-BackendServerUrl "https://adfs.corp.com/adfs" `
-ExternalCertificateThumbprint $cert.Thumbprint `
-ExternalUrl "https://adfs.corp.com/adfs" `
-Name "ADFS External" `
-ExternalPreAuthentication PassThrough `
-BackendServerAuthenticationMode NoAuthentication
Verification
# Test AD FS federation metadata is accessible
Invoke-WebRequest -Uri "https://adfs.corp.com/FederationMetadata/2007-06/FederationMetadata.xml" `
-UseBasicParsing | Select-Object StatusCode
# Verify service is running
Get-Service adfssrv | Select-Object Status
# Check AD FS event logs for authentication events
Get-WinEvent -LogName "AD FS/Admin" -MaxEvents 20 |
Where-Object { $_.Level -le 3 } |
Format-Table TimeCreated, LevelDisplayName, Message -Wrap
# Test SAML endpoint
$adfsBase = "https://adfs.corp.com/adfs/ls"
$idpMetadata = Invoke-WebRequest -Uri "https://adfs.corp.com/FederationMetadata/2007-06/FederationMetadata.xml" -UseBasicParsing
[xml]$xml = $idpMetadata.Content
Write-Host "Entity ID: $($xml.EntityDescriptor.entityID)"
# Verify relying party trusts
Get-AdfsRelyingPartyTrust | Select-Object Name, Enabled, Identifier | Format-Table -AutoSize
Summary
AD FS 3.0 on Windows Server 2012 R2 provides enterprise-grade SAML 2.0 SSO capabilities, enabling your on-premises Active Directory to serve as the identity provider for cloud and partner applications. The deployment process involves installing the AD FS role with a valid SSL certificate, creating relying party trusts from SAML metadata, configuring claims rules to pass the right user attributes, restricting access through authorization rules, and optionally deploying Web Application Proxy for external access. Combined with Azure AD Connect, AD FS creates a complete hybrid identity fabric that spans on-premises and cloud resources.