web-dev-qa-db-ja.com

LDAP + SSLを介してActiveDirectoryの資格情報を検証するにはどうすればよいですか?

.NET 3.5 _System.DirectoryServices.AccountManagement_名前空間を使用して、Active Directory LDAPサーバーに対してユーザー資格情報を検証しようとしていますSSL暗号化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設定ではないことがわかります。

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

15
Nate Sauber

同僚のおかげで、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ブロックを使用して決定ロジックを制御することにワクワクしていませんが、それが機能します。 :/

14
Nate Sauber

多分これは別の方法です。資格情報の検証に異常はありません。 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);
}
3
mijail

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

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

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

回避策:可能な場合はSSLをサポートしますが、フォールバックがある場合は、最初にデフォルトのオプションを使用して(つまり、オプションなしで)ValidateCredentials(...)を呼び出します。これがDirectoryOperationExceptionで失敗した場合は、ContextOptions(ネゴシエート|シーリング|署名)を指定して再試行してください。これは、とにかく予想されるValidateCredentialsに対してLdapExceptionが内部的に行うことです。

0
Ingo

私にとって、ValidateCredentialsメソッドは問題なく機能します。私が見つけた問題は、ADをホストしているサーバーにありました(私はAD LDSを使用しています)。サーバー証明書をADインスタンスに関連付ける必要がありました。したがって、インスタンスの名前が「MyAD」(またはActiveDirectoryWebService)の場合は、MMCを開き、「証明書」モジュールにスナップインし、「サービスアカウント」を選択して、リストから「MyAD」を選択する必要があります。そこから、SSL証明書を「MyAD」パーソナルストアに追加できます。これにより、SSL処理がようやく開始されました。

LdapConnectionメソッドについて知っていることと、コールバック関数を省略したという事実から、サーバー証明書を検証していないのではないかと思います。それは厄介な仕事であり、ValidateCredentialsは無料でそれを行います。おそらく大したことではありませんが、それでもセキュリティホールです。

0
Quarkly