5

典型的なSystem.DirectoryServices.DirectoryEntryコードを使用してディレクトリサービスからデータを複製するアプリケーションがあります。自己署名証明書を使用してSSLを使用してNovelleDirectoryから複製する必要があります。既存のコードは、検証可能な有効な証明書で機能するか、または自己署名証明書がローカルマシンのキーストアに追加された場合に機能すると思われます。ただし、自己署名証明書で確実に機能させるために、私が見つけることができる唯一の解決策は、System.DirectoryServices.Protocols名前空間とLdapConnectionクラスを使用することです。これにより、VerifyServerCertificateコールバックを接続できます。同じ概念をDirectoryEntryインスタンスに適用する方法、またはLdapConnectionインスタンスに接続して、それをDirectoryEntryインスタンスに「変換」する方法が見つかりません。多分それはそうではありません」可能であれば、それを本当に確認したいと思います。他の考えは大歓迎です。

私が見つけた唯一の適切なリンクは次の場所にあります:http://www.codeproject.com/Articles/19097/eDirectory-Authentication-using-LdapConnection-and

4

3 に答える 3

10

これは驚異的な質問です。

私はこの同じ問題と数日間戦ってきましたが、このシナリオでDirectoryEntryオブジェクトが機能しない理由についての決定的な証拠がついに得られました。

この特定のLdapサーバー(LDAPS 636で実行)も、独自の自己署名証明書を発行します。LdapConnectionを使用して(およびWiresharkを介してトラフィックを監視して)、DirectoryEntryを使用しているときに発生しないハンドシェイクが発生していることに気付きました。

ここに画像の説明を入力してください

最初のシーケンスはセキュリティで保護されたLDAPサーバーからのもので、2番目のシーケンスは私のマシンからのものです。2番目のシーケンスを促すコードは次のとおりです。

ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };

コールバックを「偽造」する方法は他にもありますが、これは私が使用している方法です。

残念ながら、DirectoryEntryには自己署名証明書を検証するオプションまたは方法がないため、証明書の受け入れは行われず(2番目のシーケンス)、接続の初期化に失敗します。

これを実現する唯一の実行可能な方法は、LdapConnectionをSearchRequestおよびSearchResponseと組み合わせて使用​​することです。これは私がこれまでに持っているものです:

LdapConnection ldapConnection = new LdapConnection("xxx.xxx.xxx:636");

var networkCredential = new NetworkCredential("Hey", "There", "Guy");
ldapConnection.SessionOptions.SecureSocketLayer = true;
ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };
ldapConnection.AuthType = AuthType.Negotiate;
ldapConnection.Bind(networkCredential);

SearchRequest request = new SearchRequest("DC=xxx,DC=xxx,DC=xxx", "(sAMAccountName=3074861)", SearchScope.Subtree);
SearchResponse response = (SearchResponse)ldapConnection.SendRequest(request);

if(response.Entries.Count == 1)
{SearchResultEntry entry = response.Entries[0];
 string DN = entry.DistinguishedName;}

そこから、SearchResponseからADプロパティを収集し、それに応じて処理できます。SearchRequestはDirectoryEntryを使用するよりもはるかに遅いように思われるため、これは非常に残念です。

お役に立てれば!

于 2012-10-25T16:47:07.753 に答える
3

私は約束します、これはこの特定の質問に対する私の最後の投稿になります。:)

さらに1週間の研究開発の後、私はこれに対する素晴らしい解決策を手に入れました。これまでのところ、それは私にとって非常にうまく機能しています。

アプローチは私の最初の答えとは多少異なりますが、一般的には同じ概念です。LdapConnectionを使用して、証明書の検証を強制します。

//I set my Domain, Filter, and Root-AutoDiscovery variables from the config file
string Domain = config.LdapAuth.LdapDomain;
string Filter = config.LdapAuth.LdapFilter;
bool AutoRootDiscovery = Convert.ToBoolean(config.LdapAuth.LdapAutoRootDiscovery);

//I start off by defining a string array for the attributes I want 
//to retrieve for the user, this is also defined in a config file.
string[] AttributeList = config.LdapAuth.LdapPropertyList.Split('|');

//Delcare your Network Credential with Username, Password, and the Domain
var credentials = new NetworkCredential(Username, Password, Domain);

//Here I create my directory identifier and connection, since I'm working 
//with a host address, I set the 3rd parameter (IsFQDNS) to false
var ldapidentifier = new LdapDirectoryIdentifier(ServerName, Port, false, false);
var ldapconn = new LdapConnection(ldapidentifier, credentials);

//This is still very important if the server has a self signed cert, a certificate 
//that has an invalid cert path, or hasn't been issued by a root certificate authority. 
ldapconn.SessionOptions.VerifyServerCertificate += delegate { return true; };

//I use a boolean to toggle weather or not I want to automatically find and query the absolute root. 
//If not, I'll just use the Domain value we already have from the config.
if (AutoRootDiscovery)
{
    var getRootRequest = new SearchRequest(string.Empty, "objectClass=*", SearchScope.Base, "rootDomainNamingContext");
    var rootResponse = (SearchResponse)ldapconn.SendRequest(getRootRequest);
    Domain = rootResponse.Entries[0].Attributes["rootDomainNamingContext"][0].ToString();
}

//This is the filter I've been using : (&(objectCategory=person)(objectClass=user)(&(sAMAccountName={{UserName}})))
string ldapFilter = Filter.Replace("{{UserName}}", UserName);

//Now we can start building our search request
var getUserRequest = new SearchRequest(Domain, ldapFilter, SearchScope.Subtree, AttributeList);

//I only want one entry, so I set the size limit to one
getUserRequest.SizeLimit = 1;

//This is absolutely crucial in getting the request speed we need (milliseconds), as
//setting the DomainScope will suppress any refferal creation from happening during the search
SearchOptionsControl SearchControl = new SearchOptionsControl(SearchOption.DomainScope);
getUserRequest.Controls.Add(SearchControl);

//This happens incredibly fast, even with massive Active Directory structures
var userResponse = (SearchResponse)ldapconn.SendRequest(getUserRequest);

//Now, I have an object that operates very similarly to DirectoryEntry, mission accomplished  
SearchResultEntry ResultEntry = userResponse.Entries[0];

ここで注意したいもう1つの点は、SearchResultEntryが「プロパティ」ではなくユーザーの「属性」を返すことです。

属性はバイト配列として返されるため、文字列表現を取得するには、属性をエンコードする必要があります。ありがたいことに、System.Text.Encodingには、これを非常に簡単に処理できるネイティブASCIIEncodingクラスが含まれています。

string PropValue = ASCIIEncoding.ASCII.GetString(PropertyValueByteArray);

そしてそれはそれについてです!ついにこれを理解できてとてもうれしいです。

乾杯!

于 2012-11-09T16:58:03.090 に答える
0

DirectoryEntryを使用してLDAPに接続するために、以下のコードを使用しました。

私のシーンリオで理解したのは、サーバーパスでldapsが指定されているか、認証タイプが「AuthenticationTypes.SecureSocketsLayer」と記載されている場合、directoryEntryは機能しませんが、サーバー名の最後にldapsポートのみが記載されている場合は機能します。Wiresharkのログを確認した後、上記の投稿で説明したようにハンドシェイクが行われていることがわかります。

ハンドシェーク: ここに画像の説明を入力してください

コード:

public static SearchResultCollection GetADUsers()
    {
        try
        {
            List<Users> lstADUsers = new List<Users>();
            DirectoryEntry searchRoot = new DirectoryEntry("LDAP://adserver.local:636", "username", "password");
            DirectorySearcher search = new DirectorySearcher(searchRoot);
            search.PropertiesToLoad.Add("samaccountname");
            SearchResult result;
            SearchResultCollection resultCol = search.FindAll();
            Console.WriteLine("Record count " + resultCol.Count);
            return resultCol;
        }
        catch (Exception ex)
        {
            Console.WriteLine("exception" + ex.Message);
            return null;
        }
    }
于 2015-11-03T11:36:31.937 に答える