Troubleshoot MFA issues for the MFA Credential Provider for Windows

This topic describes troubleshooting scenarios and solutions for the MFA Credential Provider for Windows.

The Sign-In Widget (third generation) doesn't support multifactor authentication for third-party agents.

MFA Bypass dialog appears during sign in

Symptom:

The MFA Bypass dialog appears when signing in.

Solution:

Verify in Okta that the user is included in an MFA policy.

An App-SignOn Policy is the only policy that is relevant to the Microsoft RDP App.

Display Failed dialog appears during sign in

Symptom:

The Display Failed dialog appears when signing in.

Verify:

  • The client ID, the client secret, and the Okta URL are configured correctly.
  • The username entered into the Windows sign in matches the username in Okta.

Can't RDP into a server

Symptom:

End user can't use an RDP client to connect to a Okta Credential Provider for Windows supported workstation or server.

Solution:

Verify that Allow remote connections to this computer and Allow connections only from computers running Remote Desktop with Network Level Authentication are enabled as shown in the System Properties dialog.

System.Net.WebException displayed

Symptom:

An exception, similar to that shown below, is displayed, the likely case is an older version of TLS. Okta requires TLS 1.2 or later.

System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. . . . System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. . . . System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host.

Solution:

Open a PowerShell terminal as administrator and execute the following script:

Copy
$is64bit = [IntPtr]::Size * 8 -eq 64
Write-Host "Is 64-bit script: $is64bit"
#helper function to check for if 0x800 bit is set
function checkTls12Bit([Int] $regValue) {
return ($regValue -band 0x800) -ne 0x800
}

function setRegKeyToBitValue([string] $regBranch, [string] $regKey) {
$current = Get-ItemProperty -Path $regBranch -ErrorAction SilentlyContinue
if ($current -eq $null) {
Write-Host "$regBranch\$regKey does not exist. No change."
return $false
}
$regValue = $current.$regKey
if ($regValue -eq $null -or (checkTls12Bit $regValue) ) {
if ($regValue -eq $null) {
$regValue = 0x800
} else {
$regValue = $regValue -bor 0x800
}

$p = New-ItemProperty $regBranch -Name $regKey -PropertyType DWord -Value $regValue -ErrorAction Stop -Force
Write-Host "Updated $regBranch\$regKey value to $regValue"
return $true
}
Write-Host "$regBranch\$regKey value is $regValue. No change."
return $false
}

function setRegKeyToValueOfOne([string] $regBranch, [string] $regKey) {
$current = Get-ItemProperty -Path $regBranch -ErrorAction SilentlyContinue
if ($current -eq $null) {
Write-Host "$regBranch\$regKey does not exist. No change."
return $false
}
if ($current.$regKey -ne 1) {
$p = New-ItemProperty $regBranch -Name $regKey -PropertyType DWord -Value 1 -ErrorAction Stop -Force
Write-Host "Updated $regBranch\$regKey value to 1"
return $true
}
Write-Host "$regBranch\$regKey value is 1. No change."
return $false
}

#setup .net tls settings
function setupTls4NET([boolean]$is64bit, [string]$regBranch, [string]$reg32bitBranch) {
# https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls
$updated = setRegKeyToValueOfOne $regBranch "SchUseStrongCrypto"
$updated = (setRegKeyToValueOfOne $regBranch "SystemDefaultTlsVersions") -or $updated

if ($is64bit) {
$updated = (setRegKeyToValueOfOne $reg32bitBranch "SchUseStrongCrypto") -or $updated
$updated = (setRegKeyToValueOfOne $reg32bitBranch "SystemDefaultTlsVersions") -or $updated
}

return $updated
}
# https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed

$version = Get-ItemProperty -Path "HKLM:\Software\Microsoft\NET Framework Setup\NDP\v4\Full" -Name Release
# 394254 - .NET Framework 4.6.1, which is the current target of the installer
if ($version.Release -ge 394254) {
$ev = [environment]::Version
$v = "v" + $ev.Major + "." + $ev.Minor + "." + $ev.Build
$updated = setupTls4NET $is64bit "HKLM:\SOFTWARE\Microsoft\.NETFramework\$v" "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\$v"
# https://support.microsoft.com/en-ca/help/3140245/update-to-enable-tls-1-1-and-tls-1-2-as-a-default-secure-protocols-in

$updated = (setRegKeyToBitValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp" "DefaultSecureProtocols") -or $updated
$updated = (setRegKeyToBitValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings" "SecureProtocols") -or $updated

# updated the 32-bit branches if we are on 64-bit machine
if ($is64bit) {
$updated = (setRegKeyToBitValue "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp" "DefaultSecureProtocols") -or $updated
$updated = (setRegKeyToBitValue "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings" "SecureProtocols") -or $updated
}

# current user settings
$updated = (setRegKeyToBitValue "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings" "SecureProtocols") -or $updated

# local system account
$userSid = ".DEFAULT"
$updated = (setRegKeyToBitValue "Registry::HKEY_USERS\$userSid\Software\Microsoft\Windows\CurrentVersion\Internet Settings" "SecureProtocols") -or $updated

if ($updated) {
Write-Host "Done. Updated required settings."
}
else
{
Write-Host "Done. No updates are required."
}
}
else
{
Write-Host "No changes were made. Your version of .NET Framework is earlier version than 4.6.1, please upgrade."
}

Users locked out - disable credential provider using the registry editor

Symptom:

End users can no longer use MFA for Windows Credential Provider and the Remote Desktop Protocol to access a Windows host. In effect end users are locked out.

Solution:

Use the Windows Registry editor to browse the remote servers registry and disable the MFA for Windows Credential Provider.

This solution disables the MFA for Windows Credential Provider for all users and requires that an administrator have remote access to the registry of the locked server.Extreme caution should be exercised in editing the Windows registry.

  1. Log on to another computer which can reach the host server as the administrator.

  2. Open the Registry Editor.

  3. Select Connect Network Registry.

  4. Enter the hostname of the remote server where the MFA for Windows Credential Provider is installed.

  5. Click Check Names. After a moment the hostname will be validated.

  6. Click Ok. The remote registry will open.

  7. Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Provider Filters.

  8. Note the CLSID (or folder name) of the Okta Credential Provider.

  9. In HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers, locate the CLSID from the prior step.

  10. Right click and create a new DWORD with the name Disabled and a value of 1.

  11. Restart the server. On restart, the credential provider should be inactive.

Users locked out - disable credential provider using PSExec

Symptom:

End users can no longer use MFA for Windows Credential Provider and the Remote Desktop Protocol to access a Windows host. In effect end users are locked out.

Additionally other solutions, such as using the Windows Registry editor remotely, can't be used.

Solution:

Use psexec to query and modify the registry of the server running the MFA for Windows Credential Provider to disable the provider.

This solution requires the use of the System Internals PsExec application. Available for download from https://docs.microsoft.com/en-us/sysinternals/downloads/psexec.

Enter-PSSession can be used as an alternative to psexec. See Enter-PSSession.

  1. Open a command prompt as administrator. Using psexec and the Windows reg query command, list the values found in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Provider Filters. For example:
    Copy

    Query remote registry

    psexec \\ipaddress -u username -p password reg query "hklm\software\microsoft\windows\currentversion\authentication\Credential Provider Filters"
    Where: \\ipaddress - refers to the IP address of the server running the MFA for Windows Credential provider. For example: \\192.168.1.199-u username - refers to a valid user on the remote server represented by \\ipaddress. For example: -u validuser- p password - refers to the password for the user specified by the -u parameter. For example: -p pwdforValiduserWhich should return a result resembling: HKEY_LOCAL_MACHINE\software\microsoft\windows\currentversion\authentication\Credential Provider Filters\{6D269AEA-...-02AA9C14F310} HKEY_LOCAL_MACHINE\software\microsoft\windows\currentversion\authentication\Credential Provider Filters\{DDC0EED2-...-EDE16A79A0DE}.
  2. For each result shown, query to determine which is the OktaCredentialProvider:
    Copy

    Query remote registry

    psexec \\ipaddress -u username -p password reg query "hklm\software\microsoft\windows\currentversion\authentication\Credential Provider Filters\{6D269AEA-...-02AA9C14F310}"
    Which should return results similar to:HKEY_LOCAL_MACHINE\software\microsoft\windows\currentversion\authentication\Credential Provider Filters\{6D269AEA-...-02AA9C14F310} (Default) REG_SZ OktaCredentialProvider
  3. Using psexec and the reg add command and the class id for the Okta Credential Provider, create a new DWord value with name Disabled and value 1.
    Copy
    Create Disabled entry
    psexec \\ipaddress -u username -p password reg add "hklm\software\microsoft\windows\currentversion\authentication\Credential Provider Filters\{value from prior step}" /f /v Disabled /t REG_DWORD /d 1
    Where:/f - force overwriting/v {name of new entry} - Name of new entry being added, Disabled. /t {type} - Type of new entry added, REG_DWORD./d {value} - Value of new entry, 1. Which should return a result resembling:The operation completed successfully.
  4. Re-run the prior query which should now return results showing the newly added element and resembling:HKEY_LOCAL_MACHINE\software\microsoft\windows\currentversion\authentication\Credential Provider Filters\{6D269AEA-...-02AA9C14F310} (Default) REG_SZ OktaCredentialProvider REG_DWORD Disabled 1
  5. Restart the remote computer using psexec and the shutdown command:
    Copy

    Restart remote server

    psexec \\ipaddress -u username -p password shutdown -f -r -t 0
    Where: -f - Force running programs to exit without warning.-r - Full shutdown and reboot.-t 0 - Set timeout before shutdown to zero seconds.

On restart the credential provider should be inactive.

After the root cause is determined, the Disabled value can be removed with a command similar to:

Copy

Delete Disabled entry

psexec \\ipaddress -u username -p password reg delete "hklm\software\microsoft\windows\currentversion\authentication\Credential Provider Filters\{class id from prior step}" /f /v Disabled 

Credential provider cannot reach Okta

Symptom: The credential provider cannot reach Okta. This can happen with or without a proxy. An exception, similar to that shown below, is thrown.System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send.

Complete exception

exception thrown is - System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Authentication failed because the remote party has closed the transport stream. at System.Net.Security.SslState.StartReadFrame (Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ForceAuthentication (Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result) at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size) at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size) at System.Net.ConnectStream.WritHeaders (Boolean async) --- End of inner exception stack trace --- at System.Net.HttpWebRequest.GetResponse() at OktaWidget.JwtService.GetStateTokenUsingJwt(String username) at OktaWidget.OktaWidgetForm..ctor(String username, Int64 parent, Int64 widgetFlow) at OktaWidget.OktaWidgetClass.displayWidget(Int64 parent, String username, Int64 flow)

Solution:

The likely case is that TLS is not correctly enabled. Okta requires TLS 1.2 or later.

To correct the issue:

  1. If proxy is in use and TLS is terminated at the proxy disable SslPinningEnabled. See Modify additional properties in Install the Okta Credential Provider for Windows.
  2. Enable TLS 1.2 in the registry. Open a PowerShell terminal as administrator and execute the following script:
    Copy
    $is64bit = [IntPtr]::Size * 8 -eq 64
    Write-Host "Is 64-bit script: $is64bit"
    #helper function to check for if 0x800 bit is set
    function checkTls12Bit([Int] $regValue) {
    return ($regValue -band 0x800) -ne 0x800
    }

    function setRegKeyToBitValue([string] $regBranch, [string] $regKey) {
    $current = Get-ItemProperty -Path $regBranch -ErrorAction SilentlyContinue
    if ($current -eq $null) {
    Write-Host "$regBranch\$regKey does not exist. No change."
    return $false
    }
    $regValue = $current.$regKey
    if ($regValue -eq $null -or (checkTls12Bit $regValue) ) {
    if ($regValue -eq $null) {
    $regValue = 0x800
    } else {
    $regValue = $regValue -bor 0x800
    }

    $p = New-ItemProperty $regBranch -Name $regKey -PropertyType DWord -Value $regValue -ErrorAction Stop -Force
    Write-Host "Updated $regBranch\$regKey value to $regValue"
    return $true
    }
    Write-Host "$regBranch\$regKey value is $regValue. No change."
    return $false
    }

    function setRegKeyToValueOfOne([string] $regBranch, [string] $regKey) {
    $current = Get-ItemProperty -Path $regBranch -ErrorAction SilentlyContinue
    if ($current -eq $null) {
    Write-Host "$regBranch\$regKey does not exist. No change."
    return $false
    }
    if ($current.$regKey -ne 1) {
    $p = New-ItemProperty $regBranch -Name $regKey -PropertyType DWord -Value 1 -ErrorAction Stop -Force
    Write-Host "Updated $regBranch\$regKey value to 1"
    return $true
    }
    Write-Host "$regBranch\$regKey value is 1. No change."
    return $false
    }

    #setup .net tls settings
    function setupTls4NET([boolean]$is64bit, [string]$regBranch, [string]$reg32bitBranch) {
    # https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls
    $updated = setRegKeyToValueOfOne $regBranch "SchUseStrongCrypto"
    $updated = (setRegKeyToValueOfOne $regBranch "SystemDefaultTlsVersions") -or $updated

    if ($is64bit) {
    $updated = (setRegKeyToValueOfOne $reg32bitBranch "SchUseStrongCrypto") -or $updated
    $updated = (setRegKeyToValueOfOne $reg32bitBranch "SystemDefaultTlsVersions") -or $updated
    }

    return $updated
    }
    # https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed

    $version = Get-ItemProperty -Path "HKLM:\Software\Microsoft\NET Framework Setup\NDP\v4\Full" -Name Release
    # 394254 - .NET Framework 4.6.1, which is the current target of the installer
    if ($version.Release -ge 394254) {
    $ev = [environment]::Version
    $v = "v" + $ev.Major + "." + $ev.Minor + "." + $ev.Build
    $updated = setupTls4NET $is64bit "HKLM:\SOFTWARE\Microsoft\.NETFramework\$v" "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\$v"
    # https://support.microsoft.com/en-ca/help/3140245/update-to-enable-tls-1-1-and-tls-1-2-as-a-default-secure-protocols-in

    $updated = (setRegKeyToBitValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp" "DefaultSecureProtocols") -or $updated
    $updated = (setRegKeyToBitValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings" "SecureProtocols") -or $updated

    # updated the 32-bit branches if we are on 64-bit machine
    if ($is64bit) {
    $updated = (setRegKeyToBitValue "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp" "DefaultSecureProtocols") -or $updated
    $updated = (setRegKeyToBitValue "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings" "SecureProtocols") -or $updated
    }

    # current user settings
    $updated = (setRegKeyToBitValue "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings" "SecureProtocols") -or $updated

    # local system account
    $userSid = ".DEFAULT"
    $updated = (setRegKeyToBitValue "Registry::HKEY_USERS\$userSid\Software\Microsoft\Windows\CurrentVersion\Internet Settings" "SecureProtocols") -or $updated

    if ($updated) {
    Write-Host "Done. Updated required settings."
    }
    else
    {
    Write-Host "Done. No updates are required."
    }
    }
    else
    {
    Write-Host "No changes were made. Your version of .NET Framework is earlier version than 4.6.1, please upgrade."
    }