PrincipalContext LDAPS自签名证书

时间:2017-10-13 21:49:50

标签: c# ssl ldap

我们有一个应用程序,使用LDAP,IP地址,通过VPN隧道,使用以下代码对远程AD进行身份验证:

using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, ldap.Host, ldap.Path.Replace("/", ""), ContextOptions.Negotiate, UserName, Password))
{
    using (UserPrincipal user = UserPrincipal.FindByIdentity(pc, domainAndUsername))
    {
        if (user != null)
        {
            SAMAccountName = user.SamAccountName;
            retVal = true;
        }
    }
}

这适用于普通的非SSL LDAP。但是,我们遇到过需要通过SSL连接到LDAPS的情况,并且它不起作用。我在PrincipalContext构造函数上尝试了大量的变体,但是我们所做的一切都会导致连接失败,并出现此错误:

System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contacted. ---> System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
   at System.DirectoryServices.Protocols.LdapConnection.Connect()
   at System.DirectoryServices.Protocols.LdapConnection.SendRequestHelper(DirectoryRequest request, Int32& messageID)
   at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)
   at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)
   --- End of inner exception stack trace ---
   at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)
   at System.DirectoryServices.AccountManagement.PrincipalContext.DoServerVerifyAndPropRetrieval()
   at System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String container, ContextOptions options, String userName, String password)

我们知道它不是LDAP服务器本身,因为尝试通过所讨论的方法here连接没有错误。我对使用try ... catch逻辑流程并不是很满意,而且我已经读过这个方法的其他一些问题(比如没有正确地尊重证书等),所以我尝试了使用PrincipalContext使这个工作。

有人可以在这里给我一些指导吗?我在这个上发疯了。

编辑:经过一些进一步的研究,看起来这可能是自签名证书的问题。

编辑2 :将其分解为X509连锁电话后,我收到了以下特定错误:

  

PartialChain无法将证书链构建到受信任的根颁发机构。

考虑到这一点,您认为只需将CA添加为受信任的根,但这似乎无法解决问题。

2 个答案:

答案 0 :(得分:2)

我想知道这个CodeProject article是否有帮助:

“最近,我遇到了使用System.DirectoryServices.DirectoryEntry连接到Novell eDirectory服务器的问题,因为证书是自签名的。当在ASP.NET应用程序中运行时,未检查机器级证书存储。因此,即使自签名证书位于受信任存储中,DirectoryEntry仍然拒绝建立连接。

对于这种情况,LdapConnection类是更好的选择,因为它允许用户手动验证证书。请注意,在Windows窗体应用程序中运行时,DirectoryEntry方法可以使用受信任的自签名证书。“

使用LdapConnection,您可以使用自己的证书身份验证,如下所示:

LdapConnection con = new LdapConnection(new LdapDirectoryIdentifier("EDIRECTORYSERVER:636"));
con.SessionOptions.SecureSocketLayer = true;
con.SessionOptions.VerifyServerCertificate = 
   new VerifyServerCertificateCallback(ServerCallback);
con.Credential = new NetworkCredential(String.Empty, String.Empty);
con.AuthType = AuthType.Basic;

这样的验证回调:

public static bool ServerCallback(LdapConnection connection, X509Certificate certificate)
{
  try
  {
    X509Certificate expectedCert = 
         X509Certificate.CreateFromCertFile("C:\\certificates\\certificate.cer");

    if (expectedCert.Equals(certificate))
    {
        return true;
    }
    else
    {
        return false;
    }
  }
  catch (Exception ex)
  {
      return false;
  }
}

答案 1 :(得分:0)

由Gabriel Luci检查this answer

您确定它支持SSL并且防火墙已打开以允许该连接吗?

LDAP使用端口389.LDAPS使用端口636。

如果安装了telnet客户端,则可以使用它来检查连接:

telnet yourdomain.com 636 如果你得到一个空白的屏幕,它是有效的。如果它无法连接,它会告诉你。

如果它已打开但仍然无效,则可能是使用自签名SSL证书。检查Windows事件日志中是否存在与证书相关的错误。

我还使用Chrome查看证书。你必须像这样运行chrome:

chrome.exe --explicitly-allowed-ports = 636 然后浏览到https://yourdomain.com:636并查看它是否为您提供任何证书错误。然后你就可以看到证书了。如果出现问题,您可以导入证书并明确信任它。