15

System.DirectoryServices.AccountManagement.NET 3.5名前空間を使用して、SSL 暗号化 LDAP 接続を介して Active Directory LDAP サーバーに対してユーザー資格情報を検証しようとしています。サンプルコードは次のとおりです。

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:389", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate))
{
    return pc.ValidateCredentials(_username, _password);
}

このコードは、セキュリティで保護されていない LDAP (ポート 389) では問題なく動作しますが、ユーザーとパスの組み合わせをクリア テキストで送信したくありません。しかし、LDAP + SSL (ポート 636) に変更すると、次の例外が発生します。

System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests.
  at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error)
  at System.DirectoryServices.Protocols.LdapSessionOptions.FastConcurrentBind()
  at System.DirectoryServices.AccountManagement.CredentialValidator.BindLdap(NetworkCredential creds, ContextOptions contextOptions)
  at System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password)
  at System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password)
  at (my code)

ポート 636 は、その LDAP/AD エントリのパスワード以外の情報を検索するなど、他のアクティビティにも使用できます...

UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, _username)

...だから、他のルックアップでは SSL を介して動作するため、LDAP サーバーの SSL 設定ではないことはわかっています。

ValidateCredentials(...)SSL を介して動作するように呼び出しを受けた人はいますか? 方法を説明できますか?または、AD/LDAP 資格情報を安全に検証するための別の/より良い方法はありますか?

4

4 に答える 4

15

System.DirectoryServices.Protocols同僚のおかげで、名前空間を使用して資格情報を検証できました。コードは次のとおりです。

// See http://support.microsoft.com/kb/218185 for full list of LDAP error codes
const int ldapErrorInvalidCredentials = 0x31;

const string server = "sd.example.com:636";
const string domain = "sd.example.com";

try
{
    using (var ldapConnection = new LdapConnection(server))
    {
        var networkCredential = new NetworkCredential(_username, _password, domain);
        ldapConnection.SessionOptions.SecureSocketLayer = true;
        ldapConnection.AuthType = AuthType.Negotiate;
        ldapConnection.Bind(networkCredential);
    }

    // If the bind succeeds, the credentials are valid
    return true;
}
catch (LdapException ldapException)
{
    // Invalid credentials throw an exception with a specific error code
    if (ldapException.ErrorCode.Equals(ldapErrorInvalidCredentials))
    {
        return false;
    }

    throw;
}

私は、try/catch ブロックを使用して決定ロジックを制御することに興奮していませんが、うまく機能しています。:/

于 2012-06-01T15:32:06.283 に答える
3

多分これは別の方法です。資格情報の検証に異常はありません。ContextOptions を正しく設定する必要があります。

デフォルト値:

ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing

SSL を追加します。

ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing | ContextOptions.SecureSocketLayer

ContextOptions.Negotiate または ContextOptions.SimpleBind が必要です。または、サーバーが認証を実行するために必要なもの。ContextOptions は、ビットからビットへの OR のみをサポートします。

ValidateCredentials メソッドで、この方法で ContextOptions を直接設定することもできます。

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:636", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate | ContextOptions.SecureSocketLayer))
{
    return pc.ValidateCredentials(_username, _password);
}

または

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:636", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate))
{
    return pc.ValidateCredentials(_username, _password, ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);
}
于 2014-03-12T17:44:15.667 に答える
0

私はこれが古いことを知っていますが、これに再び遭遇した人のために:

PrincipalContext.ValidateCredentials(...)は、デフォルトで SSL 接続を開こうとし ( ldap_init(NULL, 636))、続いてオプションを設定しますLDAP_OPT_FAST_CONCURRENT_BIND

ただし、 (信頼できる?)クライアント証明書が存在する場合、LDAP 接続は暗黙的にバインドされ、高速バインドを有効にすることはできなくなります。PrincipalContext はこのケースを考慮せず、予期しない で失敗しますDirectoryOperationException

回避策:可能な場合に SSL をサポートしながらフォールバックを行うには、ValidateCredentials(...)最初にデフォルト オプションを指定して呼び出します (つまり、オプションを指定しません)。これが で失敗した場合は、(Negotiate | Sealing | Signing)DirectoryOperationExceptionを指定して再試行してください。ContextOptionsValidateCredentialsLdapException

于 2018-03-15T22:24:54.263 に答える