I have a credential provider with MFA codes, and offline MFA codes. Of course, the credential provider is a DLL and is running in a system application under NT Authority\System. I'm not trying to modify the token in any way. I figure if it's running in the logon process, it probably has all the permissions it needs...although that may not be true...
I want to pre-validate user accounts so that we don't force the user to do MFA if he entered a bad username or password. It is annoying when you go through the MFA process, serialize the creds in the interface callback ICredentialProviderCredential::GetSerializaion
and then it reports bad creds in ICredentialProverCredential::ReportResults
and you have to repeat the cycle...at least in our current flow.
I am calling LsaLogonUser
with the logon type as SECURITY_LOGON_TYPE::Interactive
and the authentication package being MSV1_0_PACKAGE_NAME
. If the computer is online it always works -- returning STATUS_NOERROR
for good creds and STATUS_LOGON_FAILURE
for a failed logon. I have even tried some of the other logon types, thinking maybe SECURITY_LOGON_TYPE::CachedInteractive
logon type would work...but that returns an unsupported error code for both correct and bad passwords.
If I go offline, Local accounts still pass the LsaLogonUser
call, however, AzureAD accounts fail. I think I have tested AD joined machines disconnected, but need to go back and test. Right now I'm just trying to solve the AzureAD issue.
I am doing a connect untrusted to populated the first argument of LsaLogonUser
... LsaConnectUntrusted
maybe could be problem???
LsaLoginUser w/ Local Account | LsaLogonUser w/AzureAD account | |
---|---|---|
Online | Success | Success |
Offline | Success | Failure |
--------------------- Edit Add Info -------------------------
From the outset I knew some of these logon types would be incorrect, but decided to test them all--in for a penny, in for a pound.
LogonType | Error Msg | NtStatus | NtSubstatus |
---|---|---|---|
Interactive | The user name or password is incorrect. (1326) | c000006d | 0 |
Network | The user name or password is incorrect. (1326) | c000006d | 0 |
Batch | The user name or password is incorrect. (1326) | c000006d | 0 |
Service | The user name or password is incorrect. (1326) | c000006d | 0 |
Proxy | A logon request contained an invalid logon type value. (1367) | c000010b) | 0 |
Unlock | The user name or password is incorrect. (1326) | c000006d | 0 |
NetworkClearText | The user name or password is incorrect. (1326) | c000006d | 0 |
NewCredentials | A logon request contained an invalid logon type value. (1367) | c000010b) | 0 |
RemoteInteractive | The user name or password is incorrect. (1326) | c000006d | 0 |
CachedInteractive | The request is not supported. (50) | c00000bb | 0 |
CachedRemoteInteractive | The user name or password is incorrect. (1326) | c000006d | 0 |
CachedUnlock | A logon request contained an invalid logon type value. (1367) | c000010b) | 0 |
This is going to seem stupid. I have code in places where if it is joined to AzureAD, checks for username, and then substitutes AzureAD for the domain if an email is detected. If the computer is not AD joined, then the default "domain" is WORKGROUP... maybe no bueno...
However, the code path did not substitute AzureAD and so it was failing when disconnected...
HOWEVER... If the machine is connected, LsaLogonUser()
can verify the creds if the domain is WORKGROUP. To me, that's even stranger...
Bottom line, ensure the domain is set to AzureAD when calling the function when using an AzureAD account.