3

C#でAD属性(今のところ単一値の文字列属性のみ)を更新するユーティリティメソッドを作成しようとしています。これは、IISに依存しないスタンドアロンユーティリティです。この方法は、HRシステムからADにデータをロードするために使用されます。

System.DirectoryServices.Protocolsを使用して、オブジェクトと属性を効果的に読み取ることができます。しかし、ModifyRequestメソッドを呼び出すと、「サーバーはディレクトリ要求を処理できません」というメッセージとともにDirectoryOperationExceptionが発生します。

別のStackOverflowの質問に基づく: .Netのディレクトリサービスは奇妙な例外をスローします

SSL LDAPにポート636を使用しようとしましたが、動作は変わりません。

私はIISを使用しておらず、.NET 4.5を使用しているため、.NET/IIS用のMicrosoftパッチを適用しないでください。

これをグーグルで検索しても効果はありません。

このエラーが発生する理由とその修正方法を知っていれば、非常にありがたいです。

以下のコード..Connには、囲んでいるユーティリティクラスからの有効で認証されたLDAP接続が含まれていると想定してください。必要に応じて、囲んでいるユーティリティクラスの完全なソースを提供できます。

例外は次のSendRequest行で発生しますModifyStringAttributeValues

using System;
using System.Collections.Generic;
using System.DirectoryServices.Protocols;
using System.Net;

namespace MyOrganization.Common.Ldap
{
    public class LdapSession
    {
        public bool UseKerberos { set; get; }
        public String Host { set; get; }
        public String UserId { set; get; }
        public String Password { set; get; }
        public String Tag { set; get; }
        public int Port { set; get; }

        public const int DefaultLdapPort = 389;

        protected LdapConnection Conn;

        public void EstablishV2()
        {

        }

        public void Establish()
        {

            var effectivePort = Port == 0 ? DefaultLdapPort : Port;

            Console.WriteLine("EffectivePort={0}", effectivePort);

            var identifier = new LdapDirectoryIdentifier(Host, effectivePort);

            if (UseKerberos)
            {
                Conn = new LdapConnection(identifier)
                {
                    AuthType = AuthType.Kerberos,
                    Timeout = new TimeSpan(0, 10, 0, 0),
                    SessionOptions =
                    {
                        ProtocolVersion = 3,
                        VerifyServerCertificate =
                            new VerifyServerCertificateCallback((con, cer) => true),
                        SecureSocketLayer = true
                    }
                };
            }
            else
            {
                Conn = new LdapConnection(identifier)
                {
                    AuthType = AuthType.Basic,
                    Timeout = new TimeSpan(0, 10, 0, 0)
                };

                // Console.WriteLine("LPA:  Binding with {0}, {1}", UserId, Password); // QUARTZ

                Conn.Bind(new NetworkCredential(UserId, Password));
            }


        }

        public IEnumerable<SearchResultEntry> Search(string cx, string filter, SearchScope searchScope, params string[] attrib)
        {
            var s = new SearchRequest(cx, filter, searchScope, attrib)
            {
                SizeLimit = 0,
                TimeLimit = new TimeSpan(1, 0, 0) // One hour, zero minutes, zero seconds
            };

            var raw = Conn.SendRequest(s);

            if (raw == null)
            {
                throw new Exception("null response");
            }

            var r = raw as SearchResponse;

            if (r != null)
            {
                // Console.WriteLine(Tag + "Search response entries: {0}", r.Entries.Count); // QUARTZ

                foreach (SearchResultEntry e in r.Entries)
                {
                    yield return e;
                }
            }
            else
            {
                // Console.WriteLine(Tag + "Search response was null" ); // QUARTZ
            }

            yield break;
        }


        public ResultCode ModifyStringAttributeValues(string dn, IDictionary<string, string> modifications)
        {
            // declare the request and response objects here
            // they are used in two blocks
            ModifyRequest modRequest;
            ModifyResponse modResponse;

            try
            {
                // initialize the modRequest object 
                modRequest =
                    new ModifyRequest(dn);

                modRequest.Controls.Add(new PermissiveModifyControl());

                var mods = new DirectoryAttributeModification[modifications.Count];

                int z = 0;
                foreach (var pair in modifications)
                {
                    var mod = new DirectoryAttributeModification();
                    mod.Operation = DirectoryAttributeOperation.Replace;
                    mod.Name = pair.Key;
                    mod.Add(pair.Value);

                    mods[z] = mod;

                    z += 1;
                }

                // cast the returned directory response into a ModifyResponse type 
                // named modResponse
                modResponse =
                    (ModifyResponse)Conn.SendRequest(modRequest);

                return modResponse.ResultCode;
            }

            catch (Exception e)
            {
                Console.WriteLine("\nUnexpected exception occured:\n\t{0}: {1}",
                                  e.GetType().Name, e.Message);

                return ResultCode.Unavailable;
            }
        }
    }
}

コードが少し不格好で、奇妙なコメントでいっぱいであることを私は知っています-私がそれを動作させている間、それはマイクロソフトのサイトのサンプルコードから切り取られ、貼り付けられ、そして修正されます。

4

4 に答える 4

3

誰かがこの問題に再び遭遇した場合、これが私の解決策です。私にとってそれを解決したのは、重複したユーザー証明書を削除するアクションでした。手順は次のとおりです

  1. 実行 >certmgr.msc
  2. personalフォルダーに移動し、関連する証明書を見つけます
  3. 最後に、重複した証明書をすべて削除します
于 2013-09-16T11:43:13.827 に答える
1

私もこの問題を抱えていました。おそらくドメインの強化が原因でした。

解決策は、シンプルではなくドメインのネゴシエーション設定で呼び出すことでした。LdapException のみがチェックされるため、これはおそらく ValidateCredentials のバグです。内部クラスの関数でhttps://github.com/dotnet/runtime/blob/main/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Context.csを参照してください。ValidateCredentialValidator

動作するはずのコード: ctx.ValidateCredentials(username, password, ContextOptions.Negotiate | ContextOptions.Sealing | ContextOptions.Signing);

追加の、おそらく正しい情報:

https://living-sun.com/143080-how-do-i-validate-active-directory-creds-over-ldap-ssl-c-net-active-directory-ldap-directoryservices.html

編集: .NET 6.0 で修正する必要があります

于 2021-04-15T04:03:59.257 に答える
0

サーバー証明書のチェックの問題である可能性があります(たとえば、サーバーが自動署名されている場合)

サーバー証明書チェックをバイパスして SSL 接続を確立するためのテストコードを次に示します。

    public static LdapConnection GetLdapConnection(string login, string password)
    {
        var serverName = /*myServerNameFromConfig*/;
        var port = /*myPortFromConfig*/;
        LdapDirectoryIdentifier ldi = new LdapDirectoryIdentifier(string.Format("{0}:{1}", serverName, port));

        NetworkCredential nc = new NetworkCredential(login, password);

        LdapConnection connection = new LdapConnection(ldi, nc, System.DirectoryServices.Protocols.AuthType.Basic);
        connection.SessionOptions.ProtocolVersion = 3;
        connection.SessionOptions.VerifyServerCertificate =
                new VerifyServerCertificateCallback((con, cer) => true);
        connection.SessionOptions.SecureSocketLayer = true;
        return connection;
    }
于 2012-11-22T16:49:17.620 に答える