Providing the best user experience with a Single-Sign-On (SSO) capability without compromising security is key of successful implementations of federation services. I personally like the ADFS model and SAML (Security Assertion Markup Language) because is robust, effective and suitable from small to large organizations offering an incredible amount of features if it configured/implemented correctly.
What Does ADFS really do?
Active Directory Federation Services (AD FS) provides simplified, secured identity federation and Web single sign-on (SSO) capabilities for end users who want to access applications within an AD FS-secured enterprise, in federation partner organizations, or in the cloud.
What are the default settings that we can leverage for troubleshooting or security?
Security and Operations Teams frequently work on the same issues but on a different angle and most of the times they agree on some default values and to change others. Configure AD FS Extranet Soft Lockout Protection
is one of these and to achieve this result we need to delve into the ADFS and AD configuration and policies.
When your authentication requests come through the WAP (Web Application Proxy), by default ADFS will NOT stop trying to authenticate any attempt legitimate or malicious. In short, there is no limit.
Let me clarify why this is so important, but to look at the full picture we need to start to have a look to Active Directory where every Authentication Request against the domain get logged and update the AD User attributes if the login is successful or not.
In AD, every username has a default (and possibly a fine-grained) policy applied that after a certain number of unsuccessful authentication attempts will lead to a lockout event.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
PS U:\> Get-ADDefaultDomainPasswordPolicy ComplexityEnabled : True DistinguishedName : DC=CONTOSO,DC=COM LockoutDuration : 00:15:00 LockoutObservationWindow : 00:15:00 LockoutThreshold : 10 MaxPasswordAge : 90.00:00:00 MinPasswordAge : 00:00:00 MinPasswordLength : 8 objectClass : {domainDNS} objectGuid : 48591777-8edf-4334-9e98-0838eefcb45e PasswordHistoryCount : 15 ReversibleEncryptionEnabled : False |
Check also if there is a specific FineGrained Policy applied:
1 |
Get-ADFineGrainedPasswordPolicy -filter * |
Last week article was on this topic (Powershell: Monitoring AD Account Lock-Out Events).
Lockout Events are an effective protection against brute force attacks and monitor them can be crucial to identify risks and troubleshoot authentication issues.
ADFS is authenticating against AD a username and password on behalf of a trusted external application, but without leaving any trace of that attempt in AD. In other words, by default is not locking out your account will be triggered by ADFS to let the AD account block. This is not completely a bad thing, otherwise will expose AD to a big DDOS risk, but the fact that there is no audit for successful or failed requests will be basically potentially exposed to brute-force attacks.
So what can we do to mitigate that risk and be more aware of what is going on on ADFS?
The answer is turning on Security Auditing and enable AD FS Extranet Soft Lockout Protection.
Let’s first check our ADFS settings
Let’s start with checking if ADFS is installed (repeat these steps for all ADFS servers)
1 2 3 4 5 6 |
#Check if ADFS is installed Get-WindowsFeature adfs-federation Display Name Name Install State ------------ ---- ------------- [X] Active Directory Federation Services ADFS-Federation Installed |
And for your information let’s list all the available cmd-lets for this powershell module:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
get-command -module adfs CommandType Name ModuleName ----------- ---- ---------- Cmdlet Add-AdfsAttributeStore adfs Cmdlet Add-AdfsCertificate adfs Cmdlet Add-AdfsClaimDescription adfs Cmdlet Add-AdfsClaimsProviderTrust adfs Cmdlet Add-AdfsClient adfs Cmdlet Add-AdfsDeviceRegistrationUpnSuffix adfs Cmdlet Add-AdfsFarmNode adfs Cmdlet Add-AdfsNonClaimsAwareRelyingPartyTrust adfs Cmdlet Add-AdfsRelyingPartyTrust adfs Cmdlet Add-AdfsWebApplicationProxyRelyingPartyTrust adfs Cmdlet Disable-AdfsClaimsProviderTrust adfs Cmdlet Disable-AdfsClient adfs Cmdlet Disable-AdfsDeviceRegistration adfs Cmdlet Disable-AdfsEndpoint adfs Cmdlet Disable-AdfsNonClaimsAwareRelyingPartyTrust adfs Cmdlet Disable-AdfsRelyingPartyTrust adfs Cmdlet Disable-AdfsWebApplicationProxyRelyingPartyTrust adfs Cmdlet Enable-AdfsClaimsProviderTrust adfs Cmdlet Enable-AdfsClient adfs Cmdlet Enable-AdfsDeviceRegistration adfs Cmdlet Enable-AdfsEndpoint adfs Cmdlet Enable-AdfsNonClaimsAwareRelyingPartyTrust adfs Cmdlet Enable-AdfsRelyingPartyTrust adfs Cmdlet Enable-AdfsWebApplicationProxyRelyingPartyTrust adfs Cmdlet Export-AdfsAuthenticationProviderConfigurationData adfs Cmdlet Export-AdfsDeploymentSQLScript adfs Cmdlet Export-AdfsWebContent adfs Cmdlet Export-AdfsWebTheme adfs Cmdlet Get-AdfsAdditionalAuthenticationRule adfs Cmdlet Get-AdfsAttributeStore adfs Cmdlet Get-AdfsAuthenticationProvider adfs Cmdlet Get-AdfsAuthenticationProviderWebContent adfs Cmdlet Get-AdfsCertificate adfs Cmdlet Get-AdfsClaimDescription adfs Cmdlet Get-AdfsClaimsProviderTrust adfs Cmdlet Get-AdfsClient adfs Cmdlet Get-AdfsDeviceRegistration adfs Cmdlet Get-AdfsDeviceRegistrationUpnSuffix adfs Cmdlet Get-AdfsEndpoint adfs Cmdlet Get-AdfsGlobalAuthenticationPolicy adfs Cmdlet Get-AdfsGlobalWebContent adfs Cmdlet Get-AdfsNonClaimsAwareRelyingPartyTrust adfs Cmdlet Get-AdfsProperties adfs Cmdlet Get-AdfsRegistrationHosts adfs Cmdlet Get-AdfsRelyingPartyTrust adfs Cmdlet Get-AdfsRelyingPartyWebContent adfs Cmdlet Get-AdfsSslCertificate adfs Cmdlet Get-AdfsSyncProperties adfs Cmdlet Get-AdfsWebApplicationProxyRelyingPartyTrust adfs Cmdlet Get-AdfsWebConfig adfs Cmdlet Get-AdfsWebTheme adfs Cmdlet Import-AdfsAuthenticationProviderConfigurationData adfs Cmdlet Import-AdfsWebContent adfs Cmdlet Initialize-ADDeviceRegistration adfs Cmdlet Install-AdfsFarm adfs Cmdlet New-AdfsClaimRuleSet adfs Cmdlet New-AdfsContactPerson adfs Cmdlet New-AdfsOrganization adfs Cmdlet New-AdfsSamlEndpoint adfs Cmdlet New-AdfsWebTheme adfs Cmdlet Publish-SslCertificate adfs Cmdlet Register-AdfsAuthenticationProvider adfs Cmdlet Remove-AdfsAttributeStore adfs Cmdlet Remove-AdfsAuthenticationProviderWebContent adfs Cmdlet Remove-AdfsCertificate adfs Cmdlet Remove-AdfsClaimDescription adfs Cmdlet Remove-AdfsClaimsProviderTrust adfs Cmdlet Remove-AdfsClient adfs Cmdlet Remove-AdfsDeviceRegistrationUpnSuffix adfs Cmdlet Remove-AdfsFarmNode adfs Cmdlet Remove-AdfsGlobalWebContent adfs Cmdlet Remove-AdfsNonClaimsAwareRelyingPartyTrust adfs Cmdlet Remove-AdfsRelyingPartyTrust adfs Cmdlet Remove-AdfsRelyingPartyWebContent adfs Cmdlet Remove-AdfsWebApplicationProxyRelyingPartyTrust adfs Cmdlet Remove-AdfsWebTheme adfs Cmdlet Revoke-AdfsProxyTrust adfs Cmdlet Set-AdfsAdditionalAuthenticationRule adfs Cmdlet Set-AdfsAttributeStore adfs Cmdlet Set-AdfsAuthenticationProviderWebContent adfs Cmdlet Set-AdfsCertificate adfs Cmdlet Set-AdfsCertSharingContainer adfs Cmdlet Set-AdfsClaimDescription adfs Cmdlet Set-AdfsClaimsProviderTrust adfs Cmdlet Set-AdfsClient adfs Cmdlet Set-AdfsDeviceRegistration adfs Cmdlet Set-AdfsDeviceRegistrationUpnSuffix adfs Cmdlet Set-AdfsEndpoint adfs Cmdlet Set-AdfsGlobalAuthenticationPolicy adfs Cmdlet Set-AdfsGlobalWebContent adfs Cmdlet Set-AdfsNonClaimsAwareRelyingPartyTrust adfs Cmdlet Set-AdfsProperties adfs Cmdlet Set-AdfsRegistrationHosts adfs Cmdlet Set-AdfsRelyingPartyTrust adfs Cmdlet Set-AdfsRelyingPartyWebContent adfs Cmdlet Set-AdfsSslCertificate adfs Cmdlet Set-AdfsSyncProperties adfs Cmdlet Set-AdfsWebApplicationProxyRelyingPartyTrust adfs Cmdlet Set-AdfsWebConfig adfs Cmdlet Set-AdfsWebTheme adfs Cmdlet Test-AdfsFarmInstallation adfs Cmdlet Test-AdfsFarmJoin adfs Cmdlet Unregister-AdfsAuthenticationProvider adfs Cmdlet Update-AdfsCertificate adfs Cmdlet Update-AdfsClaimsProviderTrust adfs Cmdlet Update-AdfsRelyingPartyTrust adfs |
Let’s focus of checking if the extranet lockout is enabled or not if Get-ADFSProperties:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Get-AdfsProperties | select ExtranetLockOutThreshold, ExtranetLockoutEnabled,ExtranetObservationWindow |Fl ExtranetLockoutThreshold : 2147483647 ExtranetLockoutEnabled : False ExtranetObservationWindow : 00:30:00 #Or with this more elegant cmd-let Get-AdfsProperties | fl *extranet* ExtranetLockoutThreshold : 2147483647 ExtranetLockoutEnabled : False ExtranetObservationWindow : 00:30:00 |
Checking the ADFS log level:
1 2 3 4 |
Get-AdfsProperties | fl *log* LogLevel : {Errors, Information, Verbose, Warnings} |
No Failure or Success Audits are turned on by default, so I need to change it to :
1 |
Set-ADFSProperties –LogLevel Information,Errors,Verbose,Warnings,FailureAudits,SuccessAudits |
Turn On Loggin with Group Policy:
1 |
auditpol.exe /set /subcategory:"Application Generated" /failure:enable /success:enable |
Let’s turn on the Extranet Lockout
1 |
Set-AdfsProperties -EnableExtranetLockout $true -ExtranetLockoutThreshold 8 -ExtranetObservationWindow (new-timespan -Minutes 15) |
Note that is recommended that ADFS Lockout Threshold is smaller than the AD Lockout event.
AD FS extranet lockout functions independently from the AD lockout policies. However, we strongly recommend that you set the ExtranetLockoutThreshold parameter value to a value that is less than the AD account lockout threshold. Failing to do so would result in AD FS being unable to protect accounts from being locked out in Active Directory.
When AD FS Extranet lockout on Server 2012 R2 is enabled all authentication requests through the WAP are validated by AD FS on the PDC. When the PDC is unavailable, users will be unable to authenticate from the extranet.
There is also a new addition for Server 2016 where you can allow AFDS to fallback to another DC if a Primary Domain Controller (PDC) is not available. This Parameter is called ExtranetLockoutRequirePDC and the Type is Boolean.
Checking the Security Events from the Event Log of ADFS
1 2 3 4 |
Get-EventLog -LogName Security -computername "adfs.contoso.com" -source "AD FS Auditing" -newest 10} #if You have more than one ADFS "adfs01.contoso.com","adfs02.contoso.com","adfs03.contoso.com" |%{Get-EventLog -LogName Security -computername $_ -source "AD FS Auditing" -newest 10} |
This is a summary from microsoft doc:
1 2 3 4 5 6 7 8 9 10 |
Key points to remember ------------------------------ The Extranet Lockout feature only works for the extranet scenario where the authentication requests come through the Web Application Proxy The Extranet Lockout feature only applies to username & password authentication AD FS does not keep any track of badPwdCount or users that are soft-locked out. AD FS uses AD for all state tracking AD FS performs a lookup for the badPwdCount attribute through LDAP call for the user on the PDC for every authentication attempt AD FS older than 2016 will fail if it cannot access the PDC. AD FS 2016 introduced improvements that will allow AD FS to fall back to other domain controllers in case of the PDC is not available. AD FS will allow authentication requests from extranet if badPwdCount < ExtranetLockoutThreshold If badPwdCount >= ExtranetLockoutThreshold AND badPasswordTime + ExtranetObservationWindow < Current time, AD FS will reject authentication requests from extranet To avoid malicious account lockout, you should make sure ExtranetLockoutThreshold < Account Lockout Threshold AND ExtranetObservationWindow > Reset Account Lockout Counter |
Troubleshooting
Once the security auditing is turned on ADFS and on the Local Security Policy the troubleshooting options available to engineers and sysadmin are a lot more. This article offers some good idea on how to troubleshoot ADFS Authentication issues.
More about ADFS
Since the introduction of Active Directory Federation Services, authorization policies have been available to restrict or allow users access to resources based on attributes of the request and the resource. As AD FS has moved from version to version, how these policies are implemented has changed.
(2016) ADFS and Banned IP address (and subnets)
On Windows Server 2016 (since June ADFS 2018 update)
This update enables you to configure a set of IP addresses globally in AD FS, so that requests coming from those IP addresses, or that have those IP addresses in the x-forwarded-for or x-ms-forwarded-client-ip headers, will be blocked by AD FS.
1 |
Set-AdfsProperties -AddBannedIps "1.2.3.4", "::3", "1.2.3.4/16" |
ADFS Conditional Access /MFA
(2019) ADFS Additional authentication methods:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Scenario 1: protect the password Protect password-based login from brute-force attacks and lockouts by prompting for an additional, external factor first. Only if the external authentication is successfully completed does the user then see a password prompt. This eliminates a convenient way attackers have been trying to compromise or disable accounts. This scenario consists of two components: Prompting for Azure MFA or an external authentication factor as primary authentication Username and password as additional authentication in AD FS Scenario 2: password-free! Eliminate passwords entirely but completing a strong, multi-factor authentication using entirely non password based methods in AD FS Azure MFA with Authenticator app Windows 10 Hello for Business Certificate authentication External authentication providers |
Extranet Soft LockOut vs (ADFS 2019 ) Smart lockout
Extranet Smart Lockout in AD FS 2019 adds the following advantages compared to AD FS 2016:
-
Set independent lockout thresholds for familiar and unfamiliar locations so that users in known good locations can have more room for error than requests from suspect locations
-
Enable audit mode for smart lockout while continuing to enforce previous soft lockout behavior
Wrap Up
Turning on Audits for ADFS is essential to work with lockout events, but audits are essential for overall security and troubleshooting purposes. The next step will be turning on Windows Events Forwarding (WEF) to collect and analyze all attempts. Last year I read this nice article about WEF and I definitely recommend it in case you missed it.
how can I control the level of auditting on the adfs web proxy server (verbose vs. basic) ???
Hi Morten,
Thanks for your question. Have you tried the Set-AdfsProperties cmdlet that has the argument called audit level:
-AuditLevel
Specifies an array of audit levels. The acceptable values for this parameter are:
None
Basic
Verbose
Have a look at the official doc:
https://docs.microsoft.com/en-us/powershell/module/adfs/set-adfsproperties?view=win10-ps
Regards
That conmand does NOT exist on web proxy. Only on main Adfs server