2012-01-11 13 views
0

のドメインコントローラに対してユーザー資格情報を検証します.Windowsユーザー、ローカルユーザー、およびドメインユーザーに対してユーザー名とパスワードによってユーザーを認証しようとしています。 I already tried this solution。 PrincipalContextを得るために、私のコードは次のようになります:ローカルWindowsユーザーのユーザーとのActiveDirectoryでのリモートユーザのために正常に動作します.NETアプリケーションで

protected static PrincipalContext TryCreatePrincipalContext(String domain) 
{ 
    var computerDomain = TryGetComputerDomain(); 

    if (String.IsNullOrEmpty(domain) && String.IsNullOrEmpty(computerDomain)) 
     return new PrincipalContext(ContextType.Machine); 
    else if (String.IsNullOrEmpty(domain)) 
     return new PrincipalContext(ContextType.Domain, computerDomain); 
    else 
     return new PrincipalContext(ContextType.Domain, domain); 
} 

protected static String TryGetComputerDomain() 
{ 
    try 
    { 
     var domain = Domain.GetComputerDomain(); 
     return domain.Name; 
    } catch 
    { 
     return null; 
    } 
} 

。しかし、マシン上で認証を実行しようとすると、それはActiveDirectory以外のドメインマスターに結合されます。 Sambaサーバは、私は次の例外を取得:

System.DirectoryServices.AccountManagement.PrincipalServerDownException: Mit dem Server konnte keine Verbindung hergestellt werden. ---> 
System.DirectoryServices.Protocols.LdapException: Der LDAP-Server ist nicht verfügbar. 
bei System.DirectoryServices.Protocols.LdapConnection.Connect() 
bei System.DirectoryServices.Protocols.LdapConnection.SendRequestHelper(DirectoryRequest request, Int32& messageID) 
bei System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout) 
bei System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request) 
bei System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties) 
--- Ende der internen Ausnahmestapelüberwachung --- 
bei System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties) 
bei System.DirectoryServices.AccountManagement.PrincipalContext.DoServerVerifyAndPropRetrieval() 
bei System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String container, ContextOptions options, String userName, String password) 
bei System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name) 
bei DomainAuthTest.DomainAuthenticator.TryCreatePrincipalContext(String domain) 
bei DomainAuthTest.DomainAuthenticator.Authenticate(String domainUser, String password) 
bei DomainAuthTest.Program.Main(String[] args) 

だから、PrincipalContextがContextType.Domainの場合にLDAPを使用しようとしているようです。 ContextType.Machineを使用しようとすると、PrincipalContextがマシンに直接接続しようとするため、ワークグループ/ドメイン名を使用できません。そのマシンに同じマシンからのウィンドウがすでに接続されていると、それは失敗します。

だから私の質問は次のとおりです。

  • 必然のActiveDirectoryに基づいていないドメインのマスター、に対して資格情報のドメイン、ユーザー名とパスワードでユーザーを認証するためにどのように?
  • 上記のタスクを実行するための管理APIがありますか?
  • 管理された基礎クラスがない場合、それを行う正しい方向は何ですか?

ありがとうございます。完全を期すために

答えて

3

、私がしたい正確に何やっているようだここに私の解決策:

public class WinApiDomainAuthenticator 
{ 
    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool LogonUser(string lpszUsername, 
             string lpszDomain, 
             string lpszPassword, 
             int dwLogonType, 
             int dwLogonProvider, 
             out IntPtr phToken); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
    public extern static bool CloseHandle(IntPtr handle); 

    public static IPrincipal Authenticate(String domainUser, String password) 
    { 
     var userToken = IntPtr.Zero; 
     var creds = new DomainAuthCredentials(domainUser, password); 

     if (! LogonUser(creds.Username, 
         creds.Domain, 
         creds.Password, 
         (int)LogonType.LOGON32_LOGON_BATCH, 
         (int)LogonProvider.LOGON32_PROVIDER_DEFAULT, out userToken)) 
     { 
      var error = new Win32Exception(Marshal.GetLastWin32Error()); 
      throw new SecurityException("Error while authenticating user", error); 
     } 

     var identity = new WindowsIdentity(userToken); 

     if (userToken != IntPtr.Zero) 
      CloseHandle(userToken); 

     return ConvertWindowsIdentityToGenericPrincipal(identity); 
    } 

    protected static IPrincipal ConvertWindowsIdentityToGenericPrincipal(WindowsIdentity windowsIdentity) 
    { 
     if (windowsIdentity == null) 
      return null; 

     // Identity in format DOMAIN\Username 
     var identity = new GenericIdentity(windowsIdentity.Name); 

     var groupNames = new string[0]; 
     if (windowsIdentity.Groups != null) 
     { 
      // Array of Group-Names in format DOMAIN\Group 
      groupNames = windowsIdentity.Groups 
             .Select(gId => gId.Translate(typeof(NTAccount))) 
             .Select(gNt => gNt.ToString()) 
             .ToArray(); 
     } 

     var genericPrincipal = new GenericPrincipal(identity, groupNames); 
     return genericPrincipal; 
    } 

    protected class DomainAuthCredentials 
    { 
     public DomainAuthCredentials(String domainUser, String password) 
     { 
      Username = domainUser; 
      Password = password; 
      Domain = "."; 

      if (!domainUser.Contains(@"\")) 
       return; 

      var tokens = domainUser.Split(new char[] { '\\' }, 2); 
      Domain = tokens[0]; 
      Username = tokens[1]; 
     } 

     public DomainAuthCredentials() 
     { 
      Domain = String.Empty; 
     } 

     #region Properties 

     public String Domain { get; set; } 
     public String Username { get; set; } 
     public String Password { get; set; } 

     #endregion 
    } 
} 

LogonTypeとLogonProvider列挙型は「Winbase.h」の定義を反映しています。私はLogonType.LOGON32_LOGON_NETWORKの代わりにLogonType.LOGON32_LOGON_BATCHで解決しました。なぜなら、samba 3.4.Xはこのタイプに問題があるようです。ここで

2

は、私はちょうど私が自分で働いているアプリのためにしたものです - ....フレームワークV3.5以上が必要です

public static bool Authenticate(string user, string password) 
{ 
    // Split the user name in case a domain name was specified as DOMAIN\USER 
    string[] NamesArray = user.Split(new char[] { '\\' }, 2); 

    // Default vars for names & principal context type 
    string DomainName = string.Empty; 
    string UserName = string.Empty; 
    ContextType TypeValue = ContextType.Domain; 

    // Domain name was supplied 
    if (NamesArray.Length > 1) 
    { 
     DomainName = NamesArray[0]; 
     UserName = NamesArray[1]; 
    } 
    else 
    { 
     // Pull domain name from environment 
     DomainName = Environment.UserDomainName; 
     UserName = user; 

     // Check this against the machine name to pick up on a workgroup 
     if (string.Compare(DomainName, System.Environment.MachineName, StringComparison.InvariantCultureIgnoreCase) == 0) 
     { 
      // Use the domain name as machine name (local user) 
      TypeValue = ContextType.Machine; 
     } 
    } 

    // Create the temp context 
    using (PrincipalContext ContextObject = new PrincipalContext(TypeValue, DomainName)) 
    { 
     // Validate the credentials 
     return ContextObject.ValidateCredentials(UserName, password); 
    } 
} 
+0

お返事をあなたに天使をありがとうございました。残念ながら、それは問題の問題を解決しません。現在のディレクトリ - サーバーに対して認証を行います。 IMHO System.DirectoryServices.AccountManagement.PrincipalContextクラスは、マシンがActive-DirectoryのないWIN2000/Sambaドメインに参加している場合、またはドメインに参加していなくても機能しません。 「advapi32.dll」の「LogonUser」メソッドは、これらのケースごとに透過的です。 –

関連する問題