How can I check the user / password combination in ActiveDirectory without putting the password in a string?

I want to check the User / Password combination in a Windows domain. Now I am doing this with the following code:

bool Login(String username, String password) { var principalContext = new PrincipalContext(ContextType.Domain); principalContext.ValidateCredentials(username, password); } 

While it works, it bothers me that I have to put the password in String in order to use this API; since I use SecureString to store the password everywhere, I would really like to use some way to verify the combination of username and password without passing the password as managed by System.String .

What would be the best way to achieve this?

+4
source share
2 answers

One way you could try might be:

Pass as a user by calling LoginUser using P / Invoke, passing the password as SecureString as described in MSDN .

Connect to ActiveDirectory with an impersonated user without passing a username and password:

 AuthenticationTypes authenticationTypes = AuthenticationTypes.Secure; using (var entry = new DirectoryEntry("LDAP://example.com", "", "", authenticationTypes)) { ... } 

I have not tried this, but it seems to me that it should work.

+3
source

Use DsBindWithCred . Please note that this feature does not work with Access Denied, even if the credentials are technically sound, such as account lockout. You will need to use the LogonUser function if you need this level of detail, but each call will be considered a login attempt.

 using System.Runtime.InteropServices; using System.ComponentModel; using System.Text; public class PInvoke { public static bool TestCreds(string usernamePossiblyWithDomain, SecureString password, string dnsDomainName) { string username, usernameDomain; ParseUserName(usernamePossiblyWithDomain, out username, out usernameDomain); IntPtr pPass = Marshal.SecureStringToGlobalAllocUnicode(password); try { IntPtr hDS = IntPtr.Zero; IntPtr authID = MakePassCreds(username, usernameDomain, pPass); //if you're really paranoid, you can uncomment the next two lines //to zero out the memory as soon as possible //Marshal.ZeroFreeGlobalAllocUnicode(pPass); //pPass = IntPtr.Zero; try { int lastErr = DsBindWithCred(null, dnsDomainName, authID, ref hDS); switch(lastErr) { case 0: return true; //ERROR_SUCCESS case 5: return false; //ERROR_ACCESS_DENIED default: throw new Win32Exception(lastErr); } } finally { if(hDS != IntPtr.Zero) DsUnBind(ref hDS); if(authID != IntPtr.Zero) DsFreePasswordCredentials(authID); } } finally { if(pPass != IntPtr.Zero) Marshal.ZeroFreeGlobalAllocUnicode(pPass); } } [DllImport("credui.dll", CharSet = CharSet.Unicode)] protected static extern int CredUIParseUserName(string pszUserName, StringBuilder pszUser, int ulUserMaxChars, StringBuilder pszDomain, int ulDomainMaxChars); public static void ParseUserName(string usernamePossiblyWithDomain, out string username, out string domain) { int MaxUserChars = 256, maxDomainChars = 256; StringBuilder sbUser = new StringBuilder(maxUserChars); StringBuilder sbDomain = new StringBuilder(maxDomainChars); int lastErr = CredUIParseUserName(usernamePossiblyWithDomain, sbUser, maxUserChars - 1, sbDomain, maxDomainChars - 1); if(lastErr != 0) throw new Win32Exception(lastErr); username = sbUser.ToString(); domain = sbDomain.ToString(); } [DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)] protected static extern int DsMakePasswordCredentials( string User, string Domain, IntPtr Password, ref IntPtr pAuthIdentity); [DllImport("ntdsapi.dll")] public static extern int DsFreePasswordCredentials(IntPtr AuthIdentity); //caller is responsible for calling DsFreePasswordCredentials on the return val public static IntPtr MakePassCreds(string username, string domain, IntPtr pPass) { IntPtr auth = IntPtr.Zero; int lastErr = DsMakePasswordCredentials(username, domain, pPass, ref auth); if(lastErr != 0) throw new Win32Exception(lastErr); return auth; } [DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)] protected static extern int DsBindWithCred(string DomainControllerName, string DnsDomainName, IntPtr AuthIdentity, ref IntPtr phDS); [DllImport("ntdsapi.dll")] public static extern int DsUnBind(ref IntPtr phDS); } 
+3
source

Source: https://habr.com/ru/post/1346674/


All Articles