0

EDIT: Thank you @RbMm for your clarification questions!

I am implementing MFA in a credential provider (not a wrapper provider). One of the options I must support is to verify the same UPN is used for logging in to the computer and validating with the MFA provider. I use LsaLogonUser, ImpersonateLoggedOnUser and GetUserNameEx(UserNamePrincipal) to obtain this information. This works in most environments; however, on a computer connected to a hybrid Azure AD domain, LsaLogonUser fails. This lead to an investigation the results of which are elaborated below:

I have a computer belonging to an AzureAD hybrid domain, but I have no way of getting the SAM-compatible domain name from the AzureAD domain name. For example, I can log in with a user whose AzureAD upn is, for example's sake user@domain.com. The SAM-compatible name is localdomain\localuser. GetUserNameEx(NameUserPrincipal) reutrns user@domain.com GetUserNameEx(NameSamCompatible) returns localdomain\localuser HOWEVER in the following code, TranslateName fails with GetLastError() returning ERROR_NO_SUCH_DOMAIN.

TCHAR validBuffer[MAX_PATH+1];
ULONG nValidSize = MAX_PATH;
TranslateName("user@domain.com", NameUserPrincipal, NameSamCompatible, validBuffer, &nValidSize);

I have also tried the following APIs without success, they all fail with different return values:

  • GetComputerObjectName fails with any value passed to NameFormat

  • GetCompterNameEx fails with ERROR_CANT_ACCESS_DOMAIN_INFO for any relevant value of NameType

  • NetWkstaGetInfo does not return any useful information in any field

  • Also, if you look at the computer's join information in This PC > Properties > Advanced System Properties, u see it as part of a workgroup, not a domain. -if you run the dsregcmd /status command:

    • executed within the aforementioned user's logon session: the 'Diagnostic' part lists the localdomain in the output
    • executed from a command prompt running with the LocalSystem account, the output does not list the localdomain anywhere.

An important point (thanks @RbMm) - the code services a Windows Credential Provider, when using the 'Other User' tile. I am trying to pre-verify the entered credentials using LsaLogonUser, before serializing them successfully in my implementation of ICredentialProviderCredential2::GetSerialization. Using 'user@domain.com' fails, while using 'localdomain\user@domain.com' or 'localdomain\localuser' succeeds. When logging in with Windows' built in password provider, using 'user@domain.com' of course works. Maybe I should be using a different authentication package for LsaLogonUser?

I am STUMPED.

thanks for anyone's help..

  • Uriel
Uriel G
  • 23
  • 6
  • 1
    *I can log in with a user* - so you have user token. query *TokenUser* for get user *Sid* and call *LsaLookupSids* for this. you get exactly what you want. – RbMm May 27 '21 at 19:07
  • Have to try `DsEnumerateDomainTrusts` call. – Alexander May 28 '21 at 10:15
  • @RbMm Thanks for the suggestion; I forgot to mention that this is done in the context of a Windows credential provider, when logging in from the 'Other User' tile. The problem is, I cannot login using the user's credentials - using LsaLogonUser with user@domain.com fails with 'no such domain' error and only using localdomain\localuser ot localdomain\user@domain.com works. I will edit my question to include this information. – Uriel G May 30 '21 at 05:57
  • @UrielG - unclear context - from where, for what, in what situation you call `LsaLogonUser`. are you wrap built-in credential provider or not. what really credential enter user, etc.. – RbMm May 30 '21 at 17:57
  • @RbMm I have edited the question to include additional information. THANK you for the clarification questions :) – Uriel G Jun 02 '21 at 14:35
  • *I am trying to pre-verify the entered credentials* - in this case you need wrap some built-in credential provider and use already formatted `CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION` for call `LsaLogonUser`. exist different providers and different input is used. say password, pin(*NgcPinProvider*), wlid. – RbMm Jun 02 '21 at 14:57
  • @RbMm, yes that's what I thought, that's why I asked if maybe I should be using a different authentication package for LsaLogonUser in my question... BUT- which authentication package should I use and what is the format of the serialization? From this article (https://learn.microsoft.com/en-us/azure/active-directory/devices/concept-primary-refresh-token) I surmise the provider is CloudAP. But what is the format of the input data? It's undocumented... :( – Uriel G Jun 03 '21 at 06:06
  • you need use `NEGOSSP_NAME_A` Negotiate authentication package Id. and usually [`CredPackAuthenticationBufferW`](https://docs.microsoft.com/en-us/windows/win32/api/wincred/nf-wincred-credpackauthenticationbufferw) used. for instance WLID provider use `CRED_PACK_ID_PROVIDER_CREDENTIALS` flag in call. and then [`SspiEncryptAuthIdentityEx`](https://docs.microsoft.com/ru-ru/windows/win32/api/sspi/nf-sspi-sspiencryptauthidentityex). in lsass - the *LiveSsp* process buffer. in your case this may be *CloudAP*. unfortunately i dont know how join to azure for test. if can do this - can research how – RbMm Jun 03 '21 at 09:05
  • so when you use Negotiate authentication package Id - *negoexts.LsaApLogonUserEx2* is invoked, which in case `SEC_WINNT_AUTH_IDENTITY_EX[2]` call wst packages - LiveSsp, pku2u, CloudAP. until value other than `SEC_E_NO_AUTHENTICATING_AUTHORITY` returned – RbMm Jun 03 '21 at 09:21
  • *which authentication package should I use* - 100% Negotiate authentication package (*NEGOSSP_NAME_A*), *what is the format of the serialization?* - think *CredPackAuthenticationBufferW* with *CRED_PACK_ID_PROVIDER_CREDENTIALS* in case online identity – RbMm Jun 03 '21 at 09:23
  • this plugins is registered under `LOCAL_MACHINE\SOFTWARE\Microsoft\IdentityStore\Providers` – RbMm Jun 03 '21 at 09:36
  • *MicrosoftAccountCloudAP* (*livessp*) use user mail in place User and *MicrosoftAccount* in place Domain. how accept *CloudAP* need look. i however use only wrapper solution - here not important format of data. i can pass it as is to *LsaLogonUser* - because i receive it ready from wrapper – RbMm Jun 03 '21 at 10:03

0 Answers0