Jorge's Quest For Knowledge!

All About Identity And Security On-Premises And In The Cloud – It's Just Like An Addiction, The More You Have, The More You Want To Have!

Archive for the ‘Active Directory Federation Services (ADFS)’ Category

(2018-11-01) Transform Rules In ADFS – Send E-Mail Address Value For E-mail, Otherwise Send UPN Value For E-Mail

Posted by Jorge on 2018-11-01


A few days ago I got the following question:

  • Some accounts have a mailbox, some do not;
  • For accounts that do have a mailbox I need to send the e-mail address value as the claim value in the e-mail address claim type;
  • For accounts that do not have a mailbox I need to send the upn value as the claim value in the e-mail address claim type;

How can I achieve that through the claims rule language in ADFS?

It is not that difficult. See below for an example as the answer to the question above:

RULENAME1: User Identity Claims – Windows Account Name
COMMENT1: if the windows account name claim exists and has a value send it through

c:[Type == "
http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
=> issue(claim = c);

RULENAME2: User Identity Claims – upn
COMMENT2: if the UPN claim exists and has a value send it through

c:[Type == "
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"]
=> issue(claim = c);

RULENAME3: User Identity Claims – E-Mail Address
COMMENT3: get mail from AD and put it in claim

c:[Type == "
http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"), query = ";mail;{0}", param = c.Value);

RULENAME4: System Claims – Check E-Mail Address Existence
COMMENT4: check if the mail address claim exist or not

NOT EXISTS([Type == "
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"])
=> add(Type = "http://temp.org/system/claims/eMailAddressExistance", Value = "False");

RULENAME5: User Identity Claims – upn To E-Mail Address (When E-Mail Address DOES NOT Exist)
COMMENT5: send the UPN value into mail address claim if no mail claim address exists

c1:[Type == "
http://temp.org/system/claims/eMailAddressExistance", Value == "False"] &&
c2:[Type == "
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", Value = c2.Value);

Make sure to test this first in a TEST environment!

Cheers,
Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Advertisements

Posted in Active Directory Federation Services (ADFS), Claims, Claims Rule Language | Leave a Comment »

(2018-10-24) Setting/Fixing The Correct Permissions On Your ADFS Certificates And/Or On The Certificate Sharing Container

Posted by Jorge on 2018-10-24


Are the permissions on any of the private keys of your certificates in use by ADFS and/or the certificate sharing container screwed up? If YES, then you can use the PowerShell code below to fix those permissions for the account the ADFS Service is running under. Make sure to test this is a test environment first!

### Function To Permission Private Key Of Custom/Non-ADFS Managed Certificates
Function permissionPrivateKey($certificate,$certType,$svcAccount) {
    $ace = $svcAccount,"Read,Synchronize","Allow"
    $machineKeysLocation = $ENV:ALLUSERSPROFILE + "\Microsoft\Crypto\RSA\MachineKeys\"
    $CertKeyFile = $certificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
    $CertKeyFileFullPath = $MachineKeysLocation + $CertKeyFile
    $CertKeyFileACL = Get-Acl $CertKeyFileFullPath
    Write-Host "+++ RESULT +++" -ForeGroundColor Magenta
    $certSubject = $null
    $certSubject = $certificate.Subject
    Write-Host "Certificate Type……..: $certType" -ForegroundColor Yellow
    Write-Host "Certificate Subject…..: $certSubject" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "Private Key Permissions (BEFORE)" -ForegroundColor Yellow
    $CertKeyFileACL.Access | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.FileSystemRights}}
    $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $ace
    $CertKeyFileACL.SetAccessRule($accessRule)
    $CertKeyFileACL | Set-Acl $CertKeyFileFullPath
    $CertKeyFileACL = $null
    $CertKeyFileACL = Get-Acl $CertKeyFileFullPath
     Write-Host ""
    Write-Host "Private Key Permissions (AFTER)" -ForegroundColor Yellow
    $CertKeyFileACL.Access | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.FileSystemRights}}
}
   
### Determining Current ADFS Service Account
$adfsService = Get-WmiObject win32_service -filter "name=’ADFSSRV’"
$currentADFSServiceAccount = $adfsService.StartName

### Determining Database Type Being Used
$adfsSTS = Get-WmiObject -namespace root/ADFS -class SecurityTokenService
$configDBConnectionString = $adfsSTS.ConfigurationDatabaseConnectionString
If ($configDBConnectionString.contains("\\.\pipe\")) {
    Write-Host ""
    Write-Host "Windows Internal Database Is Being Used" -ForegroundColor Yellow
     $dbType = "WID"
    $roleADFSServer = (Get-AdfsSyncProperties).Role
    If ($roleADFSServer -eq "SecondaryComputer") {
         Write-Host ""
        Write-Host "Running On Secondary ADFS Server" -ForegroundColor Yellow
        Function portConnectionCheck($fqdnServer,$port,$timeOut) {
            $tcpPortSocket = $null
            $portConnect = $null
            $tcpPortWait = $null
            $tcpPortSocket = New-Object System.Net.Sockets.TcpClient
            $portConnect = $tcpPortSocket.BeginConnect($fqdnServer,$port,$null,$null)
            $tcpPortWait = $portConnect.AsyncWaitHandle.WaitOne($timeOut,$false)
            If(!$tcpPortWait) {
                $tcpPortSocket.Close()
                 Return "ERROR"
            } Else {
                $ErrorActionPreference = "SilentlyContinue"
                $tcpPortSocket.EndConnect($portConnect) | Out-Null
                If (!$?) {
                    Return "ERROR"
                } Else {
                    Return "SUCCESS"
                }
                 $tcpPortSocket.Close()
                $ErrorActionPreference = "Continue"
            }
        }
        $primaryADFSServer = (Get-AdfsSyncProperties).PrimaryComputerName
        $adfsWIDIsSecondary = $true
    } Else {
        Write-Host "Running On Primary ADFS Server" -ForegroundColor Yellow
        $adfsWIDIsSecondary = $false
    }
} Else {
    Write-Host "SQL Server Is Being Used" -ForegroundColor Yellow
    $dbType = "SQL"
}

### Getting ADFS Properties And Certificates
If ($dbType -eq "WID") {
    If ($adfsWIDIsSecondary) {
        $ports = 5985,443,80 # WinRM For Remote PowerShell, ADFS HTTPS, ADFS HTTP
        $connectionCheckOK = $true
        $ports | %{
            $port = $null
            $port = $_
            $connectionResult = $null
            $connectionResult = portConnectionCheck $primaryADFSServer $port 500
            If ($connectionResult -eq "ERROR") {
                $connectionCheckOK = $false
            }
        }
        If ($connectionCheckOK) {
            $primaryADFSServerSession = New-PSSession -ComputerName $primaryADFSServer
            $fedSvcConfig = Invoke-Command -Session $primaryADFSServerSession -ScriptBlock {
                $fedSvcProperties = Get-AdfsProperties
                $fedSvcCertificates = Get-AdfsCertificate
                Return $fedSvcProperties,$fedSvcCertificates
            }
            Remove-PSSession $primaryADFSServerSession
            $fedSvcProps = $fedSvcConfig[0]
            $fedSvcCerts = $fedSvcConfig[1]
        } Else {
             Write-Host ""
            Write-Host "The Primary ADFS Server IS NOT Reachable" -ForegroundColor Red
            Write-Host "Aborting…" -ForegroundColor Red
            Write-Host ""
            EXIT
        }
    } Else {
        $fedSvcProps = Get-AdfsProperties
        $fedSvcCerts = Get-AdfsCertificate
     }
}
If ($dbType -eq "SQL") {
    $fedSvcProps = Get-AdfsProperties
    $fedSvcCerts = Get-AdfsCertificate
}

### Checking If Certificate Sharing Container Has Been Configured
If ($fedSvcProps.CertificateSharingContainer) {
    Write-Host ""
    Write-Host "Certificate Sharing Container IS Configured" -ForegroundColor Yellow
    $certSharingContainerConfigured = $true
    $certSharingContainerState = "Configured"
    $certSharingContainerDN = ($fedSvcProps.CertificateSharingContainer).ToString()
} Else {
     Write-Host ""
    Write-Host "Certificate Sharing Container IS NOT Configured" -ForegroundColor Yellow
    $certSharingContainerConfigured = $false
    $certSharingContainerState = "NOT Configured"
    $certSharingContainerDN = "N.A."
}

### Checking If Custom Certificates Are Being Used Or ADFS Managed Self-Signed Certificates For Token Signing/Encryption
If ($fedSvcProps.AutoCertificateRollover -eq $false) {
    Write-Host ""
    Write-Host "ADFS Managed Self-Signed Certs ARE NOT Being Used" -ForegroundColor Yellow
    $adfsManagedCerts = $false
    $certManagement = "NON-ADFS Managed"
} ElseIf ($fedSvcProps.AutoCertificateRollover -eq $true) {
    Write-Host ""
    Write-Host "ADFS Managed Self-Signed Certs ARE Being Used" -ForegroundColor Yellow
    $adfsManagedCerts = $true
    $certManagement = "ADFS Managed"
}

### Displaying All The Info Gathered
Invoke-Command -ScriptBlock {
    Write-Host ""
    Write-Host "Database Type………………………: $dbType" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "Certificate Sharing Container State…..: $certSharingContainerState" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "Certificate Sharing Container DN……..: $certSharingContainerDN" -ForegroundColor Yellow
    Write-Host ""
     Write-Host "Certificate Management………………: $certManagement" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "Current Service Account……………..: $currentADFSServiceAccount" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "Token-Signing Certificate(s)…" -ForegroundColor Yellow
    $fedSvcTokenSigningCert = $fedSvcCerts | ?{$_.CertificateType -eq "Token-Signing"}
    $fedSvcTokenSigningCert | FT Thumbprint,@{n=’Subject’;e={$_.Certificate.Subject}},@{n=’Not Before’;e={$_.Certificate.NotBefore}},@{n=’Not After’;e={$_.Certificate.NotAfter}}
    Write-Host "Token-Encryption Certificate(s)…" -ForegroundColor Yellow
    $fedSvcTokenEncryptCert = $fedSvcCerts | ?{$_.CertificateType -eq "Token-Decrypting"}
    $fedSvcTokenEncryptCert | FT Thumbprint,@{n=’Subject’;e={$_.Certificate.Subject}},@{n=’Not Before’;e={$_.Certificate.NotBefore}},@{n=’Not After’;e={$_.Certificate.NotAfter}}
    Write-Host "Service Communications / SSL Certificate…" -ForegroundColor Yellow
    $fedSvcSvcCommCert = $fedSvcCerts | ?{$_.CertificateType -eq "Service-Communications"}
    $fedSvcSvcCommCert | FT Thumbprint,@{n=’Subject’;e={$_.Certificate.Subject}},@{n=’Not Before’;e={$_.Certificate.NotBefore}},@{n=’Not After’;e={$_.Certificate.NotAfter}}
}

### Setting Permissions On Private Key Of Custom Token Certificates
If (!$adfsManagedCerts) {
    Write-Host ""
    Write-Host "Permissioning Custom Token Certificates" -ForegroundColor Yellow
    $certStoreLocation = "Cert:\LocalMachine\My"
    $fedSvcCerts | ?{$_.CertificateType -ne "Service-Communications"} | %{
        $certificateType = $null
        $certificateType = $_.CertificateType
        $certificateThumbprint = $null
        $certificateThumbprint = $_.Thumbprint
        $certificateInStore = $null
        $certificateInStore = Get-ChildItem $($certStoreLocation + "\" + $certificateThumbprint) -ErrorAction SilentlyContinue
        If ($certificateInStore -And $certificateInStore.HasPrivateKey) {
            permissionPrivateKey $certificateInStore $certificateType $currentADFSServiceAccount
        } Else {
             Write-Host ""
            Write-Host "The Certificate With Thumbprint ‘$certificateThumbprint’ ($certificateType) Does Not Exist" -ForegroundColor Red
            Write-Host "Or" -ForegroundColor Red
            Write-Host "The Certificate With Thumbprint ‘$certificateThumbprint’ ($certificateType) Does Not Have A Private Key" -ForegroundColor Red
            Write-Host ""
        }
    }
}

### Setting Permissions On Private Key Of SSL/Service-Communication Certificate
$fedSvcCerts | ?{$_.CertificateType -eq "Service-Communications"} | %{
    $certificateType = $null
    $certificateType = $_.CertificateType
    $certificateThumbprint = $null
    $certificateThumbprint = $_.Thumbprint
     $certificateInStore = $null
    $certificateInStore = Get-ChildItem $($certStoreLocation + "\" + $certificateThumbprint) -ErrorAction SilentlyContinue
    If ($certificateInStore -And $certificateInStore.HasPrivateKey) {
        permissionPrivateKey $certificateInStore $certificateType $currentADFSServiceAccount
    } Else {
        Write-Host ""
        Write-Host "The Certificate With Thumbprint ‘$certificateThumbprint’ ($certificateType) Does Not Exist" -ForegroundColor Red
        Write-Host "Or" -ForegroundColor Red
        Write-Host "The Certificate With Thumbprint ‘$certificateThumbprint’ ($certificateType) Does Not Have A Private Key" -ForegroundColor Red
        Write-Host ""
    }
}

### If Configured Setting Permissions On Certificate Sharing Container
### WARNING: ADDS PowerShell Module Required!!! – Will Be Installed!
If ($certSharingContainerConfigured) {
    Write-Host ""
    Write-Host "Certificate Sharing Container Is Configured Used" -ForegroundColor Yellow

    # Install RSAT PowerShell Tools And Load Module
    Install-WindowsFeature RSAT-AD-Tools -IncludeAllSubFeature
     Import-Module ActiveDirectory

    # Get The Certificate Sharing Container DN, Its ACL And Present The Results Of That
    $dnPathCertSharingContainer = ($fedSvcProps.CertificateSharingContainer).ToString()
    $dnPathCertSharingContainerPath = $(Join-Path "AD:\" $dnPathCertSharingContainer)
    Write-Host ""
    Write-Host "Certificate Sharing Container Permissions (BEFORE)" -ForegroundColor Yellow
    $aclCertSharingContainer = Get-Acl $dnPathCertSharingContainerPath
    $aclCertSharingContainer.Access | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.ActiveDirectoryRights}}
   
    # Object Class And Inheritance Scope
    $schemaIDGUIDScopedObject = [guid]"00000000-0000-0000-0000-000000000000"
    $inheritanceScope = "All"

    # Security Principal To Assign Permissions To
    $securityPrincipalAccount = $currentADFSServiceAccount
    $securityPrincipalObject = New-Object System.Security.Principal.NTAccount($securityPrincipalAccount)

    # Define ACE
    $rightsCollection = [System.DirectoryServices.ActiveDirectoryRights]::"CreateChild","Self","WriteProperty","DeleteTree","GenericRead","WriteOwner"
    $aclType = [System.Security.AccessControl.AccessControlType]::"Allow"
    $aceDefinition = $securityPrincipalObject,$rightsCollection,$aclType,$schemaIDGUIDScopedObject,$inheritanceScope
    $accessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($aceDefinition)   

    # Set The New Access Rule
    $aclCertSharingContainer.AddAccessRule($accessRule)
    $aclCertSharingContainer | Set-Acl $dnPathCertSharingContainerPath

    # Get The Certificate Sharing Container ACL And Present The Results Of That
    Write-Host ""
    Write-Host "Certificate Sharing Container Permissions (AFTER)" -ForegroundColor Yellow
    $aclCertSharingContainer = Get-Acl $dnPathCertSharingContainerPath
    $aclCertSharingContainer.Access | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.ActiveDirectoryRights}}
    $aclCertSharingContainer.Access | ?{$_.IdentityReference -eq $securityPrincipalAccount} | FT @{n='[Account]’;e={$_.IdentityReference}},@{n='[Control]’;e={$_.AccessControlType}},@{n='[Permissions]’;e={$_.ActiveDirectoryRights}}
    $aclCertSharingContainer.Access | ?{$_.IdentityReference -eq $securityPrincipalAccount}
}

Cheers,
Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Federation Services (ADFS), Certificates, PowerShell | Leave a Comment »

(2018-10-23) How Do You Know Your ADFS Server Is Lacking Permissions On Its Certificates?

Posted by Jorge on 2018-10-23


Even through the ADFS Service starts and everything “appears” to be right, NOTHING works! In the ADFS Admin Event Log you may see the following event

image

Figure 1: An Error In The ADFS Admin Event Log Referencing The Lack Of Permissions On The Private Key

There was an error in enabling endpoints of Federation Service. Fix configuration errors using PowerShell cmdlets and restart the Federation Service.

Additional Data
Exception details:
System.ArgumentNullException: Value cannot be null.
Parameter name: certificate
    at System.IdentityModel.Tokens.X509SecurityToken..ctor(X509Certificate2 certificate, String id, Boolean clone, Boolean disposable)
    at Microsoft.IdentityServer.Service.Configuration.MSISSecurityTokenServiceConfiguration.Create(Boolean forSaml, Boolean forPassive)
    at Microsoft.IdentityServer.Service.Policy.PolicyServer.Service.ProxyPolicyServiceHost.ConfigureWIF()
    at Microsoft.IdentityServer.Service.SecurityTokenService.MSISConfigurableServiceHost.Configure()
    at Microsoft.IdentityServer.Service.Policy.PolicyServer.Service.ProxyPolicyServiceHost.Create()
    at Microsoft.IdentityServer.ServiceHost.STSService.StartProxyPolicyStoreService(ServiceHostManager serviceHostManager)
    at Microsoft.IdentityServer.ServiceHost.STSService.OnStartInternal(Boolean requestAdditionalTime)

The solution? Fix the permissions on the private keys and restart the ADFS Service on every ADFS server where the permissions were fixed

When the ADFS Service is finished starting your should ALWAYS see the following informational events (may be slightly different depending on the version of Windows):

  • Event ID 397 (WinHTTP Settings)
  • Event ID 349 (Administration Service)
  • Event ID 251 (For Every Attribute Store)
  • Event ID 278 (SAML Artifact)
  • Event ID 106 (For Every Authentication Provider (Multiple Times))
  • Event ID 100 (Federation Service Started Successfully)
  • Event ID 298 (Windows Hello For Business)
  • Event ID 399 (Certificate Archiving)
  • Event ID 386 (Certificate Expiration)
  • ….And Last But Not Least

image

Figure 2: ADFS Mentioning Everything Is Correct Regarding The ADFS Certificates

AD FS detected that all the service certificates have appropriate access given to the AD FS service account.

Cheers,
Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Federation Services (ADFS), Certificates | Leave a Comment »

(2018-10-11) Configuring A New Identity Store As A Local Claims Provider In ADFS

Posted by Jorge on 2018-10-11


In ADFS v1.0 and ADFS v1.1 it was possible to use both AD and ADLDS/ADAM as an identity store. One of the very common scenarios is to use the AD identity store for internal users and use the ADLDS/ADAM identity store for external users (e.g. partners, customers, vendors, etc.). After ADFS v1.x Microsoft released ADFS v2.0 (separate download for W2K8 and W2K8R2), ADFS v2.1 in W2K12 and ADFS v3.0 in W2K12R2. All the ADFS versions starting with ADFS v2.0 and higher only supported AD as the identity store and nothing else. That could be one of the reasons why some companies remained using ADFS v1.1 and did not move one.

If you would like to support a similar scenario, where you would like to have a separate identity store for externals, you would need to:

  1. Configure a separate AD with its own ADFS infrastructure and configure federation between (also see: (2013-09-24) AD User Accounts For Which The ADFS STS Can Generate Security Tokens)
    OR
  2. Use Azure AD to store those identities and configure federation

The biggest advantage of using [2] instead of [1] is that you do not need a complete new infrastructure just to support externals. The basic Azure AD features are free, but as soon as you need something special from the Azure AD Premium list, you need to pay licensing.

With the release of the Windows Server 2016, a third option has become available as already mentioned in the blog post (2014-10-03) ADFS In vNext To Support Other Identity Stores Than AD Only. YES! YES! YES! Finally!

For the passive federation protocols (e.g. SAML, WS-Federation and Oauth) and the active federation protocols (e.g. WS-Trust), ADFS v4.0 (ADFS in Windows Server 2016) and higher will support the following identity stores:

  • Identity Stores As Claim Providers:◦Active Directory (Trusted AD forests)
  • Identity Stores As Local Claim Providers:◦Active Directory (NON-Trusted AD forests)
    • ADLDS/ADAM
    • Apache DS
    • IBM Tivoli DS
    • Novell DS
    • Open LDAP
    • Open DJ
    • Open DS
    • Radiant Logic Virtual DS
    • Sun ONE v6, v7, v11

The local claims providers can only be configured through PowerShell and authentication through ADFS against those local claims providers can only be done by using forms-based authentication. One last thing to note is that you can only configure local claims providers when the Farm Behavior/Level is higher than Win2012R2. Also see: (2014-10-12) Migrating Or Upgrading To A New ADFS Version.

For more information also see:

I have the following Identity (ID) Store:

  • Type: ADLDS (LDAP)
  • Node Server (1): R1FSRWDC1.IAMTEC.NET
    • LDAP Port: 5389
    • LDAPS Port: 5636
  • Node Server (2): R1FSRWDC2.IAMTEC.NET
    • LDAP Port: 5389
    • LDAPS Port: 5636
  • Account UserName For ADFS To Access data In The IDStore: SVC_R1_LDAPQuery@CORP

# Define The Credentials For ADFS To Use When Connecting To The ID Store

$idStoreAccountUserName = ‘SVC_R1_LDAPQuery@CORP’

$idStoreAccountPassword = ‘pwd’ | ConvertTo-SecureString -asPlainText -Force

$idStoreAccountCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $idStoreAccountUserName,$idStoreAccountPassword

# Define All The Server Instances Hosting The Identity Store

$idStoreInstance1 = New-AdfsLdapServerConnection -HostName R1FSRWDC1.IAMTEC.NET -Port 5389 -SslMode None -Credential $idStoreAccountCreds -AuthenticationMethod Basic

$idStoreInstance2 = New-AdfsLdapServerConnection -HostName R1FSRWDC2.IAMTEC.NET -Port 5389 -SslMode None -Credential $idStoreAccountCreds -AuthenticationMethod Basic

PS: If you have a load balanced ADLDS farm than you would only need to define one connection instance as the load balancer would figure out which node to use. For more information about load balancing ADLDS please see: https://www.itprotoday.com/management-mobility/load-balance-ad-lds-microsoft-nlb-6-steps. If you do not have a load balanced ADLDS farm you need to define all connection instances so that ADFS can figure out which one to use. In the connection above I’m using the custom LDAP port (5389) configured by me. I did this as I was too lazy for this post to get an SSL certificate for LDAPS. For production systems I do suggest you use LDAPS!. For more information please see: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc725767(v=ws.10)

# Define All The Attribute-To-ClaimType Mappings For Which You Want ADFS To Automatically Retrieve From The ID Store

# (These are the attributes and their values, if any, automatically retrieved from the ID store and stored in claims, whether or not these are issued later on in a security token)

$mappingGivenName = New-AdfsLdapAttributeToClaimMapping -LdapAttribute givenName -ClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"

$mappingSurname = New-AdfsLdapAttributeToClaimMapping -LdapAttribute sn -ClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"

$mappingDisplayName = New-AdfsLdapAttributeToClaimMapping -LdapAttribute displayName -ClaimType "http://temp.org/identity/claims/displayName"

$mappingEmployeeID = New-AdfsLdapAttributeToClaimMapping -LdapAttribute employeeID -ClaimType "http://temp.org/identity/claims/employeeID"

$mappingDescription = New-AdfsLdapAttributeToClaimMapping -LdapAttribute description -ClaimType "http://temp.org/identity/claims/description"

# Create The Local Claims Provider Trust To Appear In The HRD Screen Through A List Of Claims Providers

Add-AdfsLocalClaimsProviderTrust -Name "External ID Store" -Identifier "urn:adlds:external:idstore" -Type Ldap -LdapServerConnection @($idStoreInstance1,$idStoreInstance2) -UserObjectClass user -UserContainer "OU=People,O=CORP" -LdapAuthenticationMethod Basic -AnchorClaimLdapAttribute userPrincipalName -AnchorClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" -LdapAttributeToClaimMapping @($mappingGivenName, $mappingSurname, $mappingDisplayName, $mappingEmployeeID, $mappingDescription) -Enabled $true -AcceptanceTransformRules "@RuleName = `"Issue All Mapped Claims`"`nc:[] => issue(claim = c);"

OR

# Create The Local Claims Provider Trust To Appear In The HRD Screen Through UPN Suffix

Add-AdfsLocalClaimsProviderTrust -Name "External ID Store" -Identifier "urn:adlds:external:idstore" -Type Ldap -LdapServerConnection @($idStoreInstance1,$idStoreInstance2) -UserObjectClass user -UserContainer "OU=People,O=CORP" -LdapAuthenticationMethod Basic -AnchorClaimLdapAttribute userPrincipalName -AnchorClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" -LdapAttributeToClaimMapping @($mappingGivenName, $mappingSurname, $mappingDisplayName, $mappingEmployeeID, $mappingDescription) -Enabled $true -AcceptanceTransformRules "@RuleName = `"Issue All Mapped Claims`"`nc:[] => issue(claim = c);"

Now when running either of the “Add-AdfsLocalClaimsProviderTrust” CMDlets you may see the following error at the end. It is really vague and does not tell you anything about what is really wrong. At first I thought something was wrong with the database.

image

Figure 1: Creating The Local Claims Provider Trust Fails With An Error

When things go wrong, the first thing I look at is the event log of the specific application/system. In this case it was the ADFS Admin Event Log. It did not say anything about this error. Knowing that I thought it would took me hours to figure this out. Au contraire!. Looking at the ADFS Debug Event Log, I saw the following message. It was referencing the Certificate Sharing Container.

image

Figure 2: Error Message In The ADFS Debug Event Log

An error occurred while trying to add an object:
Message: MSIS0013: Encrypted property ‘AccountStoreData’ cannot be set when a certificate sharing container is not configured in AD FS properties.

It was a weird error, because my ADFS farm is NOT using automatic certificate rollover and therefore it does not need the Certificate Sharing Container. You can see in the figure below that is the case. My farm is using CA issued certificates for the Token Signing Certificate and the Token Encryption Certificate.

image

Figure 3: Certificate Rollover NOT Being Enabled And The Certificate Sharing Container Not Being Configured

The Certificate Sharing Container is related to ADFS using ADFS Managed Self-Signed Certificates for the Token Signing Certificate and the Token Encryption Certificate. When the “AutoCertificateRollover” is set to TRUE, the “CertificateSharingContainer” property MUST specify the DN of the Certificate Sharing Container in AD. The ADFS servers and the Certificate Sharing Container must be in the same AD domain. When the “AutoCertificateRollover” is set to FALSE, the “CertificateSharingContainer” property CAN have a DN specified but in that case it is not being and can be removed if needed (but only when you are not going to use it in the future!).

Well, because the error was mentioning the Certificate Sharing Container and I did not have a Certificate Sharing Container, I decided to create one. When doing so you need to specify the service account in use by ADFS. I did that by reading the account from the ADFS service. Please be aware that by configuring the Certificate Sharing Container in ADFS, it will also be created in AD. Because of that you need to have Domain Admin equivalent permissions to be able to successfully do this!

$adfsService = Get-WmiObject win32_service -filter "name=’ADFSSRV’"
$adfsServiceAccount = $adfsService.StartName
Set-AdfsCertSharingContainer -ServiceAccount $adfsServiceAccount

image

Figure 4: Configuring The Certificate Sharing Container For ADFS

Now looking at the ADFS properties you can see the Certificate Sharing Container is configured in ADFS.

image

Figure 5: The Certificate Sharing Container Being Configured For ADFS

Before the configuration in ADFS you can see AD did not have a Certificate Sharing Container.

image

Figure 6: The AD Domain The ADFS Servers Are In With NO Certificate Sharing Container

After the configuration in ADFS you can see AD now does have a Certificate Sharing Container.

image

Figure 7: The AD Domain The ADFS Servers Are In With Certificate Sharing Container

Now when running either of the “Add-AdfsLocalClaimsProviderTrust” CMDlets above succeeds!

image

Figure 8: Creating The Local Claims Provider Trust Now Succeeds

Below you can see the properties of the Local Claims Provider trust that was created.

image

Figure 9: The Configuration Of The Local Claims Provider Trust That Was Just Created

And now you also see the local Claims Provider Trust is displayed and therefore available in the HRD page in ADFS.

image

Figure 10: The HRD Page In ADFS Showing The Newly Created Local Claims Provider Trust

Choosing the IdP “External ID Store” and logging on with an account from the ADLDS based ID Store through Forms Based Authentication, show amongst others the claims as displayed in the figure below.

image

Figure 11: My Show My Claims Application Displaying The Claims That Were Retrieved From The ID Store Based Upon ADLDS

You can see the values for the following claims that were configured above:

Cheers,
Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Federation Services (ADFS), Active Directory Lightweight Directory Services (ADLDS), Identity Stores | 2 Comments »

(2018-10-09) Changing AD CP Trust Display Name And Order In ADFS 2016 Farm Level And Higher

Posted by Jorge on 2018-10-09


You are currently running ADFS 2012 R2 and you are planning on upgrading (yes, you can upgrade!) to ADFS 2016. Your Home Realm Discovery (HRD) page is looking similar to the one in figure 1, meaning that the AD CP trust is listed at the top and that it inherits the Display Name of the federation service. So far so good , right?

image

Figure 1: A Home Realm Discovery Web Page In ADFS 2012 R2 Or ADFS 2016 When At ADFS 2012 R2 Farm Level

After adding ADFS 2016 servers and removing the ADFS 2012 R2 servers, it is time to increase the farm level to the highest farm level possible.

You “throw the switch” and suddenly your HRD page looks similar to the one as displayed in figure 2. Damn!

image

Figure 2: A Home Realm Discovery Web Page In ADFS 2016 When At, At Least ADFS 2016 Farm Level

From a user perspective, that can be quite some impact as user to not expect “their default selection” to have moved to the bottom. Worse yet, the users might not even recognize it because the trust display name does not inherit the display name of the federation service anymore. It just shows as “Active Directory”, which is a technical name. You might think in changing the display name of the “Active Directory” CP trust to match whatever you need. Let me save you the trouble of trying that, because, it is not allowed to change much including the display name.

So, one simple change (farm level increase) results in an unfortunate functional impact for users.

What can you do about this? The solution to this problem is to implement some extra javascript code in the ONLOAD.JS.

To make sure your current web theme is not broken while making this change, make sure to first create a new web theme and implement the changes in that new web theme. So let’s get started!

Retrieve the name of your CURRENT web theme

Get-AdfsWebConfig

In the property called “ActiveThemeName” you will find the name of the current theme that is active and in use by everyone.

Make a copy of that theme and give the copy a new name:

New-AdfsWebTheme -Name <New WebTheme Name> -SourceName <Current Active WebTheme Name>

Export the new web theme to be able to edit it:

MD <Path To Export The Theme To>

Export-AdfsWebTheme -Name <New WebTheme Name> -DirectoryPath <Path To Export The Theme To>

Open the ONLOAD.JS file

NOTEPAD "<Path To Export The Theme To>\script\onload.js"

Edit the ONLOAD.JS file by adding a piece of javascript code at the end of it. It will put the AD CP trust at the top again and it will rename it to the display name of your choosing. It has been tested with the following browsers: IE, Edge, Chrome, Firefox, Safari.
REMARK: Make sure to follow guidelines as available in
https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/advanced-customization-of-ad-fs-sign-in-pages

The javascript code is available at: https://github.com/microsoft/adfsWebCustomization/tree/master/communityCustomizations/RenameAndReorderADCPTrust

Save the ONLOAD.JS file

Import the new ONLOAD.JS into the new web theme

Set-AdfsWebTheme -TargetName <New WebTheme Name> -AdditionalFileResource @{Uri=’/adfs/portal/script/onload.js’;path="<Path To Export The Theme To>\script\onload.js"}

Now it is time to activate the new web theme and check it has been activated

Set-AdfsWebConfig -ActiveThemeName <New WebTheme Name>

Get-AdfsWebConfig

Now make sure to clear your cookies, and navigate to an application connected to ADFS for which more than one CP trust is allowed to use. In that case, assuming you have cleared your cookies, the HRD page should appear and it should again be similar to what you see in figure 1.

If you need to revert back to your previous current web theme, you new to activate it as such and check it has been activated

Set-AdfsWebConfig -ActiveThemeName <Current Active WebTheme Name>

Get-AdfsWebConfig

PS: make sure to test this first in a test environment!

Cheers,
Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Federation Services (ADFS), Configuration, Federation Trusts, Home Realm Discovery (HRD), Migration, onload.js | Leave a Comment »

(2018-04-20) Azure AD MFA Server v8.0.0.3 Has Been Released

Posted by Jorge on 2018-04-20


Azure Multi-Factor Authentication Server provides a way to secure resources with MFA capabilities

Download "Azure Multi-Factor Authentication Server"

Azure Multi-Factor Authentication Server

8.0.0.3

Released: 4/9/2018

Microsoft has released a newer version of the Azure AD MFA server. If you start the MFA Server Console you should see a notification about a newer version being available.

Version 8.0.0.3 of the Azure Multi-Factor Authentication Server adds the following additional functionality:

  • Registration experience improvements on mobile
  • Improved interaction with AD Sync
  • Support for TLS 1.2 for LDAP, User Portal to Web Service SDK, and SChannel replication
  • Compliance with General Data Protection Regulation
  • Accessibility improvements to User Portal, MFA Server management, and installation
  • Fixed issue with fallback to security questions
  • Fixed issue with security questions appearing multiple times
  • Miscellaneous bug fixes and improvements
  • NOT MENTIONED IN RELEASE NOTES: It now DOES install on Server Core!

Known Issues:

  • Windows Authentication for Terminal Services is not supported for Windows Server 2012 R2

Upgrade Considerations:

  • Must upgrade MFA Server and Web Service SDK before upgrading User Portal And AD FS adapter
  • All other features and components are backwards-compatible with all previous versions
  • Installation of the mobile app web service is not necessary for v8.0 or higher. Complete only the steps under Configure the mobile app. After the upgrade you may want to uninstall the previous mobile app web service, remove the virtual directory and application pool from IIS. If you have published the mobile app web service, then that is not required anymore

More information about Azure AD MFA Server can be found here.

Upgrade steps can be found here, but also take the following info into account

For this version of the MFA server:

  • you need to have MS-KB2919355 installed on the MFA server before starting the installation (check with Get-HotFix KB2919355)
  • you need to have the following installed on any server with any MFA server component: The Visual C++ 2017 Redistribution packages (a.k.a. Visual C++ "14" Runtime Libraries) are also available from here
  • you need to have the at least following version installed on any server with any MFA server component: .NET Framework 4.6.2 is available from here.

Before upgrading/installing the new ADFS adapter, you need to unselect and unregister the previous ADFS adapter

  • Using WID?: Execute the commands below on primary ADFS server and wait at least 5 minutes to allow WID replication to take place and finish
  • Using SQL?: Execute the commands below on any ADFS server

# Unselecting The Use Of Azure AD MFA Adapter To Be Listed
$listOfCurrentMFAProviders = (Get-AdfsGlobalAuthenticationPolicy).AdditionalAuthenticationProvider
$listOfNewMFAProviders = $listOfCurrentMFAProviders
$listOfNewMFAProviders.Remove("WindowsAzureMultiFactorAuthentication")  # Use THIS line if the old version is v6.3.0 or lower
$listOfNewMFAProviders.Remove("AzureMfaServerAuthentication")  # Use THIS line if the old version is v7.0.0.9 or higher
Set-AdfsGlobalAuthenticationPolicy -AdditionalAuthenticationProvider $listOfNewMFAProviders

# Unregistering The Azure AD MFA Adapter Within ADFS
Unregister-AdfsAuthenticationProvider -Name WindowsAzureMultiFactorAuthentication  # Use THIS line if the old version is v6.3.0 or lower
Unregister-AdfsAuthenticationProvider -Name AzureMfaServerAuthentication  # Use THIS line if the old version is v7.0.0.9 or higher

After installing the new ADFS adapter, you need to configure it, register it and configure it within ADFS

  • Using WID?: EDIT The file “MultiFactorAuthenticationAdfsAdapter.config” on the primary ADFS server as explained below (use your previous settings where applicable), and SAVE it afterwards
  • Using SQL?: EDIT The file “MultiFactorAuthenticationAdfsAdapter.config” on any ADFS server as explained below (use your previous settings where applicable), and SAVE it afterwards

FILE: MultiFactorAuthenticationAdfsAdapter.config

<ConfigurationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <UseWebServiceSdk><true OR false></UseWebServiceSdk>

    <WebServiceSdkUrl><URL to the MFA Web Service SDK></WebServiceSdkUrl>

    <WebServiceSdkUsername><the account (DOMAIN\SAMACCOUNTNAME) the user portal is also using in its web.config></WebServiceSdkUsername>

    <WebServiceSdkPassword><the password of the account above the user portal is also using in its web.config></WebServiceSdkPassword>

    <WebServiceSdkCertificateThumbprint><thumbprint of certificate of web service sdk></WebServiceSdkCertificateThumbprint>

    <AutomaticallyTriggerUserDefaultMethod><true OR false></AutomaticallyTriggerUserDefaultMethod>

    <TestMode><true OR false></TestMode>

</ConfigurationData>

Now we need to register and configure the new ADFS adapter within ADFS

# Registering The Azure AD MFA Adapter Within ADFS

$typeName = "pfadfs.AuthenticationAdapter, MultiFactorAuthAdfsAdapter, Version=8.0.0.3, Culture=neutral, PublicKeyToken=f300afd708cefcd3"
Register-AdfsAuthenticationProvider -TypeName $typeName -Name AzureMfaServerAuthentication –ConfigurationFilePath "<Provide Path To MultiFactorAuthenticationAdfsAdapter.config>"

# Selecting The Use Of Azure AD MFA Adapter To Be Listed
$listOfCurrentMFAProviders = (Get-AdfsGlobalAuthenticationPolicy).AdditionalAuthenticationProvider
$listOfNewMFAProviders = $listOfCurrentMFAProviders + "AzureMfaServerAuthentication"
Set-AdfsGlobalAuthenticationPolicy -AdditionalAuthenticationProvider $listOfNewMFAProviders

# Configuring Custom Display Name And Custom Description
Set-AdfsAuthenticationProviderWebContent -Name "AzureMfaServerAuthentication" -DisplayName "<Provide Custom DisplayName>" -Description "<Provide Custom Description>"

I upgraded from the previous version without any issues!

Cheers,
Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Federation Services (ADFS), Azure AD MFA Adapter, Multi-Factor AuthN, Windows Azure Active Directory | 2 Comments »

(2017-09-11) Registering The Azure AD Connect Health Agent Through A Proxy

Posted by Jorge on 2017-09-11


If you need to register your Azure AD Connect Health Agent for ADFS, Sync or ADDS through a proxy, you need to first configure the proxy server and port for Azure AD Connect Health.

You have the following options:

  • Read the current proxy settings for AAD Connect Health –> Get-AzureAdConnectHealthProxySettings
  • Import from Internet Explorer (if confgured) –> Set-AzureAdConnectHealthProxySettings -ImportFromInternetSettings
  • Import from WinHTTP (if configured) –> Set-AzureAdConnectHealthProxySettings -ImportFromWinHttp
  • Specify Proxy addresses manually –> Set-AzureAdConnectHealthProxySettings -HttpsProxyAddress <fqdn>:<port>
  • Clear existing proxy configuration –> Set-AzureAdConnectHealthProxySettings -NoProxy

Now let’s assume you have used one of the options to configure the proxy settings. After that you can use the following PowerShell commands to register the Azure AD Connect Health Agent

$azureADUserName = "<replace this with a native or federated account that has the global admin role and is NOT MFA enabled/enforced>"

$azureADPassword = ‘<replace this with the password>’

$azureADSecurePassword = ConvertTo-SecureString $azureADPassword -AsPlainText –Force

$azureADCreds = New-Object System.Management.Automation.PSCredential $azureADUserName, $azureADSecurePassword

REMARK: specifying the credentials through PowerShell may be required if the server installing Azure AD Connect Health does not support cookies and/or javascript.

REMARK: Of course you can also use –> $azureADCreds = Get-Credential

For Azure AD Connect Health for ADFS –> Register-AzureADConnectHealthADFSAgent -Credential $azureADCreds

For Azure AD Connect Health for ADDS –> Register-AzureADConnectHealthADDSAgent-Credential $azureADCreds

For Azure AD Connect Health for Sync –> Register-AzureADConnectHealthSyncAgent-Credential $azureADCreds –AttributeFiltering [$false | $true] -StagingMode [$false | $true]

If the registration is succesful, you should see something similar to te following

image

Figure 1: Successful Registration Of Azure AD Connect Health (In This Case For ADFS)

However, you may see the following error:

SNAGHTML4a070dba

Figure 2: Unsuccessful Registration Of Azure AD Connect Health (In This Case For ADFS) With The Error: “user_realm_discovery_failed: User Realm Discovery Failed”

Always when receiving an error, open the specified log file to see/understand what went wrong.

In this case opening the file I saw the following:

2017-08-25 07:20:39.295 ProductName: Azure AD Connect Health AD FS Agent, FileVersion: 3.0.68.0, Current UTC Time: 2017-08-25 07:20:39Z

2017-08-25 07:20:39.295 AHealthServiceUri (ARM): https://management.azure.com/providers/Microsoft.ADHybridHealthService/

2017-08-25 07:20:39.31 AdHybridHealthServiceUri: https://s1.adhybridhealth.azure.com/

2017-08-25 07:20:39.326 AHealthServiceUri (ARM): https://management.azure.com/providers/Microsoft.ADHybridHealthService/

2017-08-25 07:20:39.326 AdHybridHealthServiceUri: https://s1.adhybridhealth.azure.com/

2017-08-25 07:20:39.373 User Context outbound connections to https://management.azure.com/providers/Microsoft.ADHybridHealthService/ will use proxy address https://management.azure.com/providers/Microsoft.ADHybridHealthService/ (if equal, no proxy is used)

2017-08-25 07:20:39.373 Service Context: Outbound connections to https://management.azure.com/providers/Microsoft.ADHybridHealthService/ will use proxy address http://proxy.iamtec.nl:3128/ (if equal, no proxy is used)

2017-08-25 07:20:39.373 UploadLogFileFromDisk: arguments LogFileLocation=C:\Users\XXX\AppData\Local\Temp\3\AdHealthAdfsAgentConfiguration.2017-08-25_09-20-39.log;ProductName=Azure AD Connect Health AD FS Agent;ProductVersion=3.0.68.0;MachineName=SERVER;ServiceUri=https://s1.adhybridhealth.azure.com/;Result=started;type=registration,activityId=432fd061-6219-498a-8a98-bf68d90a5431

2017-08-25 07:20:39.389 UploadLogFileFromDisk: TenantId: unknown

2017-08-25 07:20:39.389 UploadLogFileFromDisk: MachineId: unknown

2017-08-25 07:20:39.389 UploadLogFileFromDisk: reading file contents of C:\Users\XXX\AppData\Local\Temp\3\AdHealthAdfsAgentConfiguration.2017-08-25_09-20-39.log

2017-08-25 07:20:39.389 UploadLogFileFromDisk: log length: 1842

2017-08-25 07:20:39.389 UploadFile: start, url: https://s1.adhybridhealth.azure.com/providers/Microsoft.ADHybridHealthService/diagnostics/logs/installer/product/Azure-AD-Connect-Health-AD-FS-Agent/version/3.0.68.0/machine/SERVER?result=started&type=registration

powershell.exe Information: 0 : AdHealthWebproxy settings: HttpsProxyAddress: http://proxy.iamtec.nl:3128/, initialization status: Succeeded; Registry value did not exist; Value was not a string, No Initialization Exception

2017-08-25 07:20:40.451 UploadFile: upload successful

2017-08-25 07:20:40.451 UploadLogFileFromDisk: response: Http response code: OK

"log successfully uploaded"

2017-08-25 07:20:40.451 AHealthServiceApiVersion: 2014-01-01

2017-08-25 07:20:40.451 –> https://management.core.windows.net/

powershell.exe Information: 0 : 8/25/2017 7:20:40 AM:  – AdHealthAgentConfigurationUtility: ADAL .NET with assembly version ‘2.24.0.0’, file version ‘2.24.30411.1323’ and informational version ‘4482033c814db2fd31423c79b5027d0b5dfb7a6d’ is running…

powershell.exe Information: 0 : 8/25/2017 7:20:40 AM: 432eb23e-19c6-4c97-9bc2-ca4f7138fb3e – AcquireTokenNonInteractiveHandler: === Token Acquisition started:

                Authority: https://login.windows.net/common/

                Resource: https://management.core.windows.net/

                ClientId: cf6d7e68-f018-4e0a-a7b3-126e053fb88d

                CacheType: Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache (0 items)

                Authentication Target: User

powershell.exe Information: 0 : 8/25/2017 7:20:40 AM: 432eb23e-19c6-4c97-9bc2-ca4f7138fb3e – <RunAsync>d__0: No matching token was found in the cache

powershell.exe Information: 0 : 8/25/2017 7:20:40 AM: 432eb23e-19c6-4c97-9bc2-ca4f7138fb3e – AsyncMethodBuilderCore: Sending user realm discovery request to ‘https://login.windows.net/common/UserRealm/jorge@iamtec.nl?api-version=1.0&#8217;

powershell.exe Error: 0 : 8/25/2017 7:21:10 AM: 432eb23e-19c6-4c97-9bc2-ca4f7138fb3e – AsyncMethodBuilderCore: Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: user_realm_discovery_failed: User realm discovery failed —> System.Net.WebException: The operation has timed out

   at System.Net.HttpWebRequest.GetResponse()

   at Microsoft.IdentityModel.Clients.ActiveDirectory.HttpWebRequestWrapper.<GetResponseSyncOrAsync>d__2.MoveNext()

— End of stack trace from previous location where exception was thrown —

   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   at Microsoft.IdentityModel.Clients.ActiveDirectory.UserRealmDiscoveryResponse.<CreateByDiscoveryAsync>d__0.MoveNext()

   — End of inner exception stack trace —

   at Microsoft.IdentityModel.Clients.ActiveDirectory.UserRealmDiscoveryResponse.<CreateByDiscoveryAsync>d__0.MoveNext()

— End of stack trace from previous location where exception was thrown —

   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()

   at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenNonInteractiveHandler.<PreTokenRequest>d__4.MoveNext()

— End of stack trace from previous location where exception was thrown —

   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase.<RunAsync>d__0.MoveNext()

                ErrorCode: user_realm_discovery_failed

                StatusCode: 0

2017-08-25 07:21:10.645 Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: user_realm_discovery_failed: User realm discovery failed —> System.Net.WebException: The operation has timed out

   at System.Net.HttpWebRequest.GetResponse()

   at Microsoft.IdentityModel.Clients.ActiveDirectory.HttpWebRequestWrapper.<GetResponseSyncOrAsync>d__2.MoveNext()

— End of stack trace from previous location where exception was thrown —

   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   at Microsoft.IdentityModel.Clients.ActiveDirectory.UserRealmDiscoveryResponse.<CreateByDiscoveryAsync>d__0.MoveNext()

   — End of inner exception stack trace —

   at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.RunAsyncTask[T](Task`1 task)

   at Microsoft.Identity.Health.Common.Clients.PowerShell.ConfigurationModule.AdHealthAgentConfigurationUtility.ObtainAadAccessTokenWithExistingCredential(PSCredential psCredential)

   at Microsoft.Identity.Health.Common.Clients.PowerShell.ConfigurationModule.RegisterADHealthAgent.ProcessRecord()

                ErrorCode: user_realm_discovery_failed

                StatusCode: 0

2017-08-25 07:21:10.66 UploadLogFileFromDisk: arguments LogFileLocation=C:\Users\XXX\AppData\Local\Temp\3\AdHealthAdfsAgentConfiguration.2017-08-25_09-20-39.log;ProductName=Azure AD Connect Health AD FS Agent;ProductVersion=3.0.68.0;MachineName=SERVER;ServiceUri=https://s1.adhybridhealth.azure.com/;Result=failed;type=registration,activityId=432fd061-6219-498a-9b98-bf68d90a5431

2017-08-25 07:21:10.66 UploadLogFileFromDisk: TenantId: unknown

2017-08-25 07:21:10.66 UploadLogFileFromDisk: MachineId: unknown

2017-08-25 07:21:10.66 UploadLogFileFromDisk: reading file contents of C:\Users\XXX\AppData\Local\Temp\3\AdHealthAdfsAgentConfiguration.2017-08-25_09-20-39.log

2017-08-25 07:21:10.66 UploadLogFileFromDisk: log length: 7608

2017-08-25 07:21:10.66 UploadFile: start, url: https://s1.adhybridhealth.azure.com/providers/Microsoft.ADHybridHealthService/diagnostics/logs/installer/product/Azure-AD-Connect-Health-AD-FS-Agent/version/3.0.68.0/machine/SERVER?result=failed&type=registration

2017-08-25 07:21:11.082 UploadFile: upload successful

2017-08-25 07:21:11.082 UploadLogFileFromDisk: response: Http response code: OK

"log successfully uploaded"

The green lines above list what/where things go wrong. In this case user realm discovery is failing. However, the yellow lines are giving you a hint why things are going wrong.

Looking at the second yellow line you see the service context is using the proxy server configured for Azure AD Connect Health. However, the first yellow line tells you the user context context is not using any proxy server at all. Because of that it is failing the realm discovery

The solution for this is to configure the user context with a proxy server and port. That is done by configuring the proxy settings in Internet Explorer with the same values

image

Figure 3: Configuring The User Context With Proxy Settings

After doing this, retry registration.

If it still fails check the log file again. You might see the following:

powershell.exe Information: 0 : 9/11/2017 11:54:12 AM: 68215d80-864f-43af-9b6a-8f3f41f276af – <RunAsync>d__0: No matching token was found in the cache

powershell.exe Information: 0 : 9/11/2017 11:54:12 AM: 68215d80-864f-43af-9b6a-8f3f41f276af – AsyncMethodBuilderCore: Sending user realm discovery request to ‘https://login.windows.net/common/UserRealm/jorge@iamtec.nl?api-version=1.0&#8217;

powershell.exe Error: 0 : 9/11/2017 11:54:12 AM: 68215d80-864f-43af-9b6a-8f3f41f276af – AsyncMethodBuilderCore: Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: user_realm_discovery_failed: User realm discovery failed —> System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. —> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

   at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)

   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)

at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)

   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)

In this case, your proxy server is terminating SSL traffic for inspection. If you have not imported the root certificate of the certificate being used by the proxy server into the “Trusted Root Certificate Authority” store, you will see an error like this. Import the root certificate of the certificate being used by the proxy server into the “Trusted Root Certificate Authority” store to fix this.

Hope this helps you!

Cheers,
Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Domain Services (ADDS), Active Directory Federation Services (ADFS), Azure AD Connect Health, Azure AD Connect Health, Azure AD Connect Health, Windows Azure Active Directory | Leave a Comment »

(2017-09-07) Claims Rules Set For Your AAD/O365 RP Trust To Support User And Device Authentication

Posted by Jorge on 2017-09-07


On the page “How to configure hybrid Azure Active Directory joined devices” Microsoft explains how to setup Domain Join ++, currently a.k.a. Hybrid AAD Join. This post is about, hopefully giving additional, clarification on how to setup the claims rules in ADFS. All the scenarios listed below work, it just on your scenario. Feel free to leave any comments if unclear. The import of the rules below should replace your current rules for the AAD RP Trust, and where applicable add rules to your AD CP trust. A final note, is that these rule sets are based upon Microsoft’s rule in the previous article.

Make sure to test this first in your test environment!

You may also want to have a look at the following blog post:

(2016-12-16) Automatic Azure AD Join With ADFS v3.0 And Higher And Conditional Access – What You Really Need In Detail

[OPTION 1]

The following works if you have claims rules in place on the AD CP trust that output the following claim types. This is true if you are using the default claim rule set in ADFSv3/ADFSv4:

Assumptions here:

  • You have one ADFS environment servicing all the federated domains in AAD
  • The federation identifier being used on your federated domains in AAD is default
  • The primary group was not changed for any user or any computer
  • The objectGUID is the attribute being used for the Immutable ID for users
  • The objectGUID is the attribute being used for the Immutable ID for computers
  • On-premises UPN is also the UPN used in AAD
  • Whether or not you have multiple federated domains, the config below for the IssuerID for users works as long as the UPN of the user matches one of the federated domains in AAD
  • You will replace FEDERATED-DOMAIN with one of the federated domains in AAD. It does not matter which one
  • You will replace NAME-OF-AAD/O365-RP-TRUST with the actual name of the RP trust for AAD/O365

Remarks:

  • Leave a comment if you have any deviation of the assumptions above

Thoughts here:

  • It is making multiple LDAP calls to AD, and is therefore not that optimized. It works though!
  • Still using groupsid claim type

Link to claims rules below: https://www.dropbox.com/s/vgzvnwhku2adp39/AzureAD-RP-Trust-Issuance-Rules1.txt

$aadRPTrustIssuanceRules = @"

@RuleName = "Issue UPN And ImmutableID (Domain User Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-513$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"%5D

=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/claims/UPN&quot;, "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID&quot;), query = ";userPrincipalName,objectGUID;{0}", param = c2.Value);

@RuleName = "Issue IssuerID (Domain User Only)"

c:[Type == "http://schemas.xmlsoap.org/claims/UPN"%5D

=> issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid&quot;, Value = regexreplace(c.Value, ".+@(?<domain>.+)", http://${domain}/adfs/services/trust/));

@RuleName = "Issue ImmutableID (Domain Joined Computer Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot;, Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(store = "Active Directory", types = ("http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID&quot;), query = ";objectguid;{0}", param = c2.Value);

@RuleName = "Issue Account Type (Domain Joined Computer Only)"

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(Type = "http://schemas.microsoft.com/ws/2012/01/accounttype&quot;, Value = "DJ");

@RuleName = "Issue ObjectGUID (Domain Joined Computer Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot;, Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(store = "Active Directory", types = ("http://schemas.microsoft.com/identity/claims/onpremobjectguid&quot;), query = ";objectguid;{0}", param = c2.Value);

@RuleName = "Issue ObjectSID (Domain Joined Computer Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid&quot;, Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(claim = c2);

@RuleName = "Issue IssuerID (Domain Joined Computer Only)"

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid&quot;, Value = http://FEDERATED-DOMAIN/adfs/services/trust/);

@RuleName = "Issue NameID (Domain User and Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID"%5D

=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&quot;, Value = c.Value, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"%5D = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");

@RuleName = "Issue AuthN Methods References (Domain User and Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/claims/authnmethodsreferences"%5D

=> issue(claim = c);

"@

Set-AdfsRelyingPartyTrust -TargetName "NAME-OF-AAD/O365-RP-TRUST" -IssuanceTransformRules $aadRPTrustIssuanceRules

[OPTION 2]

The following works if you have claims rules in place on the AD CP trust that output the following claim types. This is true if you are using the default claim rule set in ADFSv3/ADFSv4:

Assumptions here:

  • You have one ADFS environment servicing all the federated domains in AAD
  • The federation identifier being used on your federated domains in AAD is default
  • The primary group was not changed for any user or any computer
  • The objectGUID is the attribute being used for the Immutable ID for users
  • The objectGUID is the attribute being used for the Immutable ID for computers
  • On-premises UPN is also the UPN used in AAD
  • Whether or not you have multiple federated domains, the config below for the IssuerID for users works as long as the UPN of the user matches one of the federated domains in AAD
  • You will replace FEDERATED-DOMAIN with one of the federated domains in AAD. It does not matter which one
  • You will replace NAME-OF-AAD/O365-RP-TRUST with the actual name of the RP trust for AAD/O365

Remarks:

  • Leave a comment if you have any deviation of the assumptions above

Thoughts here:

  • Although a few LDAP calls less, it is still making LDAP calls to AD. It works though!
  • Still using groupsid claim type

Link to claims rules below: https://www.dropbox.com/s/udn1rudm5bgv7jq/AzureAD-RP-Trust-Issuance-Rules2.txt

$aadRPTrustIssuanceRules = @"

@RuleName = "Issue UPN (Domain User Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-513$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"%5D

=> issue(Type = "http://schemas.xmlsoap.org/claims/UPN&quot;, Issuer = c2.Issuer, OriginalIssuer = c2.OriginalIssuer, Value = c2.Value, ValueType = c2.ValueType);

@RuleName = "Issue IssuerID (Domain User Only)"

c:[Type == "http://schemas.xmlsoap.org/claims/UPN"%5D

=> issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid&quot;, Value = regexreplace(c.Value, ".+@(?<domain>.+)", http://${domain}/adfs/services/trust/));

@RuleName = "Issue Account Type (Domain Joined Computer Only)"

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(Type = "http://schemas.microsoft.com/ws/2012/01/accounttype&quot;, Value = "DJ");

@RuleName = "Issue ObjectGUID (Domain Joined Computer Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot;, Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(store = "Active Directory", types = ("http://schemas.microsoft.com/identity/claims/onpremobjectguid&quot;), query = ";objectguid;{0}", param = c2.Value);

@RuleName = "Issue ObjectSID (Domain Joined Computer Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid&quot;, Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(claim = c2);

@RuleName = "Issue IssuerID (Domain Joined Computer Only)"

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid&quot;, Value = http://FEDERATED-DOMAIN/adfs/services/trust/);

@RuleName = "ImmutableID (Domain User And Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"%5D

=> issue(store = "Active Directory", types = ("http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID&quot;), query = ";objectGUID;{0}", param = c.Value);

@RuleName = "Issue NameID (Domain User and Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID"%5D

=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&quot;, Value = c.Value, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"%5D = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");

@RuleName = "Issue AuthN Methods References (Domain User and Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/claims/authnmethodsreferences"%5D

=> issue(claim = c);

"@

Set-AdfsRelyingPartyTrust -TargetName "NAME-OF-AAD/O365-RP-TRUST" -IssuanceTransformRules $aadRPTrustIssuanceRules

[OPTION 3]

The following works if you have claims rules in place on the AD CP trust that output the following claim types. This is true if you are using the default claim rule set in ADFSv3/ADFSv4:

For the last claim type you would need the following claim rule on the AD CP trust if you are not already extracting additional data from AD

$additionalADCPTrustRule = @"
@RuleTemplate = "LdapClaims"
@RuleName = "Extract Extra Data From AD"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot;, Issuer == "AD AUTHORITY"]
  => issue(store = "Active Directory", types = ("http://temp.org/identity/claims/objectGUID&quot;), query = ";objectguid;{0}", param = c.Value);
"@

$existingADCPtrustAcceptRuleSet = (Get-AdfsClaimsProviderTrust -Name "Active Directory").AcceptanceTransformRules

$newADCPtrustAcceptRuleSet = $existingADCPtrustAcceptRuleSet + $additionalADCPTrustRule

Set-AdfsClaimsProviderTrust -TargetName "Active Directory" -AcceptanceTransformRules $newADCPtrustAcceptRuleSet

If you are already extracting additional data from AD, you need to add the claim type and attribute to that existing extraction

Assumptions here:

  • You have one ADFS environment servicing all the federated domains in AAD
  • The federation identifier being used on your federated domains in AAD is default
  • The primary group was not changed for any user or any computer
  • The objectGUID is the attribute being used for the Immutable ID for users
  • The objectGUID is the attribute being used for the Immutable ID for computers
  • On-premises UPN is also the UPN used in AAD
  • Whether or not you have multiple federated domains, the config below for the IssuerID for users works as long as the UPN of the user matches one of the federated domains in AAD
  • You will replace FEDERATED-DOMAIN with one of the federated domains in AAD. It does not matter which one
  • You will replace NAME-OF-AAD/O365-RP-TRUST with the actual name of the RP trust for AAD/O365

Remarks:

  • Leave a comment if you have any deviation of the assumptions above

Thoughts here:

  • No LDAP calls!
  • Still using groupsid claim type

Link to claims rules below: https://www.dropbox.com/s/8cicjpyusapsarj/AzureAD-RP-Trust-Issuance-Rules3.txt

$aadRPTrustIssuanceRules = @"

@RuleName = "Issue UPN (Domain User Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-513$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"%5D

=> issue(Type = "http://schemas.xmlsoap.org/claims/UPN&quot;, Issuer = c2.Issuer, OriginalIssuer = c2.OriginalIssuer, Value = c2.Value, ValueType = c2.ValueType);

@RuleName = "Issue IssuerID (Domain User Only)"

c:[Type == "http://schemas.xmlsoap.org/claims/UPN"%5D

=> issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid&quot;, Value = regexreplace(c.Value, ".+@(?<domain>.+)", http://${domain}/adfs/services/trust/));

@RuleName = "Issue Account Type (Domain Joined Computer Only)"

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(Type = "http://schemas.microsoft.com/ws/2012/01/accounttype&quot;, Value = "DJ");

@RuleName = "Issue ObjectGUID (Domain Joined Computer Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://temp.org/identity/claims/objectGUID"%5D

=> issue(Type = "http://schemas.microsoft.com/identity/claims/onpremobjectguid&quot;, Issuer = c2.Issuer, OriginalIssuer = c2.OriginalIssuer, Value = c2.Value, ValueType = c2.ValueType);

@RuleName = "Issue ObjectSID (Domain Joined Computer Only)"

c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"] &&

c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid&quot;, Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(claim = c2);

@RuleName = "Issue IssuerID (Domain Joined Computer Only)"

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot;, Value =~ "-515$", Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid&quot;, Value = http://FEDERATED-DOMAIN/adfs/services/trust/);

@RuleName = "ImmutableID (Domain User And Domain Joined Computer)"

c:[Type == "http://temp.org/identity/claims/objectGUID"%5D

=> issue(Type = "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID&quot;, Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType);

@RuleName = "Issue NameID (Domain User and Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID"%5D

=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&quot;, Value = c.Value, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"%5D = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");

@RuleName = "Issue AuthN Methods References (Domain User and Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/claims/authnmethodsreferences"%5D

=> issue(claim = c);

"@

Set-AdfsRelyingPartyTrust -TargetName "NAME-OF-AAD/O365-RP-TRUST" -IssuanceTransformRules $aadRPTrustIssuanceRules

[OPTION 4]

The following works if you have claims rules in place on the AD CP trust that output the following claim types.  This is true if you are using the default claim rule set in ADFSv3/ADFSv4 for the first 2 claim types, but not for the last 2 claim types. My main reason for not using groupsid is that the amount of values can be so huge it may not fit on a cookie and the browser chokes. Because of that, when not using the groupsid claim type, you need to design a better model to extract group data from AD and use authorization based claims types from that data. If you are not using the groupsid claim type you can also not identify the difference between a user and a computer. That’s why you can then specifically extract the primaryGroupID.:

For the last 2 claim types you would need the following claim rule on the AD CP trust if you are not already extracting additional data from AD

$additionalADCPTrustRule = @"
@RuleTemplate = "LdapClaims"
@RuleName = "Extract Extra Data From AD"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot;, Issuer == "AD AUTHORITY"]
  => issue(store = "Active Directory", types = ("http://temp.org/identity/claims/objectGUID&quot;,"http://temp.org/identity/claims/primaryGroupID&quot;), query = ";objectguid,primaryGroupID;{0}", param = c.Value);
"@

$existingADCPtrustAcceptRuleSet = (Get-AdfsClaimsProviderTrust -Name "Active Directory").AcceptanceTransformRules

$newADCPtrustAcceptRuleSet = $existingADCPtrustAcceptRuleSet + $additionalADCPTrustRule

Set-AdfsClaimsProviderTrust -TargetName "Active Directory" -AcceptanceTransformRules $newADCPtrustAcceptRuleSet

If you are already extracting additional data from AD, you need to add the claim type and attribute to that existing extraction

Assumptions here:

  • You have one ADFS environment servicing all the federated domains in AAD
  • The federation identifier being used on your federated domains in AAD is default
  • The primary group was not changed for any user or any computer
  • The objectGUID is the attribute being used for the Immutable ID for users
  • The objectGUID is the attribute being used for the Immutable ID for computers
  • On-premises UPN is also the UPN used in AAD
  • Whether or not you have multiple federated domains, the config below for the IssuerID for users works as long as the UPN of the user matches one of the federated domains in AAD
  • You will replace FEDERATED-DOMAIN with one of the federated domains in AAD. It does not matter which one
  • You will replace NAME-OF-AAD/O365-RP-TRUST with the actual name of the RP trust for AAD/O365

Remarks:

  • Leave a comment if you have any deviation of the assumptions above

Thoughts here:

  • No LDAP calls!
  • No groupsid claim type!

Link to claims rules below: https://www.dropbox.com/s/6nbwuuxl677wb3p/AzureAD-RP-Trust-Issuance-Rules4.txt

$aadRPTrustIssuanceRules = @"

@RuleName = "Issue UPN (Domain User Only)"

c1:[Type == "http://temp.org/identity/claims/primaryGroupID&quot;, Value =~ "^513$"] &&

c2:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"%5D

=> issue(Type = "http://schemas.xmlsoap.org/claims/UPN&quot;, Issuer = c2.Issuer, OriginalIssuer = c2.OriginalIssuer, Value = c2.Value, ValueType = c2.ValueType);

@RuleName = "Issue IssuerID (Domain User Only)"

c:[Type == "http://schemas.xmlsoap.org/claims/UPN"%5D

=> issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid&quot;, Value = regexreplace(c.Value, ".+@(?<domain>.+)", http://${domain}/adfs/services/trust/));

@RuleName = "Issue Account Type (Domain Joined Computer Only)"

c:[Type == "http://temp.org/identity/claims/primaryGroupID&quot;, Value =~ "^515$"]

=> issue(Type = "http://schemas.microsoft.com/ws/2012/01/accounttype&quot;, Value = "DJ");

@RuleName = "Issue ObjectGUID (Domain Joined Computer Only)"

c1:[Type == "http://temp.org/identity/claims/primaryGroupID&quot;, Value =~ "^515$"] &&

c2:[Type == "http://temp.org/identity/claims/objectGUID"%5D

=> issue(Type = "http://schemas.microsoft.com/identity/claims/onpremobjectguid&quot;, Issuer = c2.Issuer, OriginalIssuer = c2.OriginalIssuer, Value = c2.Value, ValueType = c2.ValueType);

@RuleName = "Issue ObjectSID (Domain Joined Computer Only)"

c1:[Type == "http://temp.org/identity/claims/primaryGroupID&quot;, Value =~ "^515$"] &&

c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid&quot;, Issuer =~ "^(AD AUTHORITY|SELF AUTHORITY|LOCAL AUTHORITY)$"]

=> issue(claim = c2);

@RuleName = "Issue IssuerID (Domain Joined Computer Only)"

c:[Type == "http://temp.org/identity/claims/primaryGroupID&quot;, Value =~ "^515$"]

=> issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid&quot;, Value = http://FEDERATED-DOMAIN/adfs/services/trust/);

@RuleName = "ImmutableID (Domain User And Domain Joined Computer)"

c:[Type == "http://temp.org/identity/claims/objectGUID"%5D

=> issue(Type = "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID&quot;, Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType);

@RuleName = "Issue NameID (Domain User and Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID"%5D

=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&quot;, Value = c.Value, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"%5D = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");

@RuleName = "Issue AuthN Methods References (Domain User and Domain Joined Computer)"

c:[Type == "http://schemas.microsoft.com/claims/authnmethodsreferences"%5D

=> issue(claim = c);

"@

Set-AdfsRelyingPartyTrust -TargetName "NAME-OF-AAD/O365-RP-TRUST" -IssuanceTransformRules $aadRPTrustIssuanceRules

Hopefully this blog post gives you the information you need to understand what is needed

Cheers,
Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Federation Services (ADFS), Azure AD / Office 365, Azure AD Join, Claim Types, Claims, Claims Rule Language, Windows Azure Active Directory | 2 Comments »

(2017-06-23) Adding A Link To The SSPR Page In The ADFS FBA Page

Posted by Jorge on 2017-06-23


When users use Windows Integrated Authentication against ADFS through their Windows desktop/laptop the users are authenticated based upon the credentials they used to logon with onto that Windows desktop.laptop. If those users needed to reset their password or unlock their account, a link would need to be provided within the logon screen to point to the SSPR page or users would need to use some kind of kiosk PC.

However, when hitting the Forms Based Authentication page within ADFS, it would be nice if you could display a link on that same page if users needed to reset their password or unlock their account when for example on a mobile device. Something similar to the following:

image 

Figure 1: A Link To The SSPR Page On The FBA Page

If you want to do this, you can use the following steps

[Step 1]

Clone the current active ADFS web theme to a new ADFS web theme

First determine the current web theme

Get-ADFSWebConfig

Clone the current active web theme to a new web theme

New-AdfsWebTheme -Name <New Web Theme Name> -SourceName <Active Web Theme Name>

[Step 2]

Export the cloned web theme to a folder on the file system

Export-AdfsWebTheme -Name <New Web Theme Name> -DirectoryPath <Some Folder On The File System>

[Step 3]

Edit the file “onload.js” in the folder “<Some Folder On The File System>\Script” and add the following piece of code to the end of the file to show the link to the SSPR page in AAD on the FBA page (NOTE: you can use any other SSPR page if you want, such as the FIM/MIM SSPR page)

// Add link for password reset, if we find the forms authentication element in the page
var formsAuthArea = document.getElementById("formsAuthenticationArea");
if (formsAuthArea) {
    //Create the hyperlink
    var pwdResetLink = document.createElement(‘a’);
    var linkText = document.createTextNode("Click Here For Password Reset Or Account Unlock");
    pwdResetLink.appendChild(linkText);
    pwdResetLink.title = "Click Here For Password Reset Or Account Unlock";
    pwdResetLink.href = "
";’>";’>https://passwordreset.microsoftonline.com/?whr=<Your Domain In AAD>";
    pwdResetLink.target = "_blank";
    document.body.appendChild(pwdResetLink);

    //append to the authArea
    var authNArea = document.getElementById("authArea");
    authNArea.appendChild(pwdResetLink);
}

[Step 4]

Import the new edited “onload.js” file

Set-AdfsWebTheme -TargetName <New Web Theme Name> -AdditionalFileResource @{Uri=’/adfs/portal/script/onload.js’;path="<Some Folder On The File System>\script\onload.js"}

[Step 5]

Activate the new web theme

Set-AdfsWebConfig -ActiveThemeName <New Web Theme Name>

Now access an application and make sure to use the FBA page. The FBA page is used when coming from a mobile device on an external network or when not using WIA

Cheers,
Jorge

 

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Federation Services (ADFS), Forefront Identity Manager (FIM) Portal, Forms Based AuthN, Self Service Password Reset, Self-Service Password Reset, Windows Azure Active Directory | Leave a Comment »

(2017-06-15) Displaying The Welcome Message On The MFA Page In ADFS 2016

Posted by Jorge on 2017-06-15


In ADFS 2012 R2 when hitting the MFA page a welcome message was displayed with an explanation as shown in figure 1 below

image

Figure 1: MFA Page In ADFS 2012 R2 With The Default Value For The Name Claim Type

Looking at the default behavior in ADFS 2016 you will get the following instead

image

Figure 2: MFA Page In ADFS 2016 With The Default Value For The UPN Claim Type

There is no welcome message anymore and the identity value is now located in the explanation at the end.

If you want to revert back to the ADFS 2012 R2 behavior you can do the following:

[Step 1]

Clone the current active ADFS web theme to a new ADFS web theme

First determine the current web theme

Get-ADFSWebConfig

Clone the current active web theme to a new web theme

New-AdfsWebTheme -Name <New Web Theme Name> -SourceName <Active Web Theme Name>

[Step 2]

Export the cloned web theme to a folder on the file system

Export-AdfsWebTheme -Name <New Web Theme Name> -DirectoryPath <Some Folder On The File System>

[Step 3]

Edit the file “onload.js” in the folder “<Some Folder On The File System>\Script” and add the following piece of code to the end of the file to show the welcome message again

// Check if we are in the auth area
var authNArea = document.getElementById("authArea");
if (authNArea) {
    // if mfaGreeting element is present, modify its properties.
    var mfaGreeting = document.getElementById("mfaGreeting");
    if (mfaGreeting) {
        mfaGreeting.className = "fieldMargin bigText";
    }
}

[Step 4]

Import the new edited “onload.js” file

Set-AdfsWebTheme -TargetName <New Web Theme Name> -AdditionalFileResource @{Uri=’/adfs/portal/script/onload.js’;path="<Some Folder On The File System>\script\onload.js"}

[Step 5]

Activate the new web theme

Set-AdfsWebConfig -ActiveThemeName <New Web Theme Name>

[Step 6]

Reconfigure the explanation text if required

Set-AdfsGlobalWebContent -SignInPageAdditionalAuthenticationDescriptionText "For security reasons, we require additional information to verify your account"

Now access an application through ADFS for which MFA is required

If you did display the Welcome message and did not revert back to the explanation as shown in the ADFS 2012 R2 you would see something similar to

image

Figure 3: Customized MFA Page In ADFS 2016 With The Default Value For The UPN Claim Type

Cheers,
Jorge

 

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Active Directory Federation Services (ADFS), Azure AD MFA Adapter, Claim Types, onload.js | Leave a Comment »

 
%d bloggers like this: