2012-11-21 81 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连接 - 如果需要,我可以提供封闭实用程序类的完整源代码。

唯一的例外发生在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; 
      } 
     } 
    } 
} 

我知道代码是有点麻烦,而且充满了诡异的意见 - 这是剪切,粘贴和示例代码在微软的网站修改而我得到它的工作。

+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

我的问题不得不做的属性值不满足克制。我试图在没有满足所有要求(大写,包括数字等等)的帐户上设置密码

相关问题