2012-11-21 94 views
2

我正在嘗試編寫實用程序方法來更新C#中的AD屬性(現在只是單值字符串屬性)。這是一個獨立的實用程序,不依賴於IIS。這種方法將用於從我們的HR系統加載數據到我們的AD中。如何防止DirectoryOperationException - 服務器無法處理目錄請求

我能夠使用System.DirectoryServices.Protocols高效地讀取對象和屬性。但是當我調用ModifyRequest方法時,我得到一個DirectoryOperationException,並顯示消息「服務器無法處理目錄請求」。

基於另一個堆棧溢出問題: .Net's Directory Services throws a strange exception

我嘗試使用端口636進行SSL LDAP,但它不會改變的行爲。

我沒有使用IIS並且在.NET 4.5上,因此Microsoft .NET/IIS補丁不適用。

在此搜索結果一直沒有結果。

如果知道你爲什麼會出現這個錯誤,以及如何解決它,我將非常感激。

下面的代碼..請假設Conn包含來自封閉實用程序類的有效和經過身份驗證的LDAP連接 - 如果需要,我可以提供封閉實用程序類的完整源代碼。

唯一的例外發生在SendRequestModifyStringAttributeValues

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; 
      } 
     } 
    } 
} 

我知道代碼是有點麻煩,而且充滿了詭異的意見 - 這是剪切,粘貼和示例代碼在微軟的網站修改而我得到它的工作。

+0

我也想知道爲什麼你需要PermissiveModifyControl。你沒有嘗試過嗎? http://stackoverflow.com/q/3450732/1236044 – jbl

+0

你有沒有找到你的問題的答案?(完成一個C# - redhat LDAP DS,我可能會有一個AD LDAP項目進來,所以我正在收集一些信息;-)有些人建議在AD服務器上儘可能提高日誌級別爲「服務器無法處理目錄請求「似乎是一個普通的AD錯誤 – jbl

回答

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; 
    } 
+1

謝謝......我的火雞現在在烤箱裏......但明天我會試試這個。 – SAJ14SAJ

+0

我更新了類的認證部分(其完整代碼現在在問題中,這不是很長),以包含您推薦的SessionOptions。這可以在'Establish'方法中找到。行爲沒有變化。 (請注意,此類專用於Microsoft和非Microsoft LDAP源 - 此用例將UseKerberos選項設置爲true,並將Port設置爲636)。 – SAJ14SAJ

+0

@ SAJ14SAJ好的,thx爲後續。我會盡力刪除我的答案,因爲它是無關緊要的。所以你的問題會顯得沒有答案,希望有人會嘗試。 – jbl

2

如果有人再次遇到這個問題,這是我的解決方案。這是刪除重複的用戶證書,爲我解決它的行爲。下面是步驟

  1. 運行>certmgr.msc
  2. 轉到personal文件夾,找到相關的證書
  3. 最後刪除任何重複的證書
0

我的問題不得不做的屬性值不滿足剋制。我試圖在沒有滿足所有要求(大寫,包括數字等等)的帳戶上設置密碼

相關問題