2011-04-05 61 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); 
} 
相關問題