2011-04-05 27 views
4

我想检查Windows域上的用户/密码组合。现在我用下面的代码做到这一点:如何在不将密码放入字符串的情况下检查ActiveDirectory上的用户/密码组合?

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

虽然它的工作原理,是错误的是,我有事情把密码在String才能使用该API;因为我使用SecureString来存储其他地方的密码,所以我真的很喜欢使用某种方式来检查用户名/密码组合,而不必将密码作为托管密码System.String传递。

实现该目标的最佳方式是什么?

回答

3

一种方法,你可以尝试可能是:

通过调用LoginUser使用P/Invoke,传递密码作为SecureString的as described in MSDN模拟用户。

连接到与模拟的用户ActiveDirectory中,没有通过用户名和密码:

AuthenticationTypes authenticationTypes = AuthenticationTypes.Secure; 

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

我还没有试过,但在我看来,它应该工作。

+1

虽然我用另一种解决方案(即在SecureStringMarshaller发现http://stackoverflow.com/questions/1800695/c-securestring-question/3567531#3567531)去了,这仍然是这样做的一个有效途径我问了什么。 (我遇到的问题是,模拟AFAIK需要提升应用程序的权限。) – 2011-05-03 14:32:18

3

使用DsBindWithCred。请注意,即使凭据在技术上是有效的,例如帐户被锁定,此功能也会因拒绝访问而失败。如果您需要该级别的详细信息,则必须使用LogonUser函数,但每次调用都会计为登录尝试。

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); 
} 
相关问题