C# 无法使用 LDAPS 连接到 AD

问题描述 投票:0回答:3

我的需求是更改AD的用户密码。因此,我按照 https://bl.ocks.org/magnetikonline/0ccdabfec58eb1929c997d22e7341e45 成功在 AD 域服务器上创建了 LDAP SSL 安全连接。

使用

ldp.exe
工具(在同一 AD 服务器上)我可以通过 SSL 连接。这意味着 AD 服务器上启用了 LDAPS。

现在我尝试使用位于客户端的库

Novell.Directory.Ldap
从 ASP.NET Core 应用程序连接它,使用以下代码:

public LdapConnection GetLDAPConnection(IOptions<ADConfiguration> _settings)
{
    LdapConnection connection = new LdapConnection { SecureSocketLayer = true };
    connection.Connect(_settings.Value.DomainIPAddress, _settings.Value.Port); //port is 636
    connection.Bind(_settings.Value.AdminDn, _settings.Value.Password);

    if (connection.Bound)
    {
        return connection;
    }

    return null;
}

Connect
方法抛出此错误:

System.Security.Authentication.AuthenticationException:“远程证书被提供的 RemoteCertificateValidationCallback 拒绝。”

客户端计算机是否也有 SSL 设置?或者我还缺少什么?请帮忙

asp.net-core active-directory ldap ssl-certificate ldapconnection
3个回答
1
投票

我怀疑您的问题是使用域控制器的IP地址:

_settings.Value.DomainIPAddress

SSL/TLS 有两个目的:加密流量,以及验证服务器实际上是您想要与之通信的服务器。为了解决第二个目的,您用于连接的域名必须与证书中的域名匹配。在您的情况下,当它验证证书时,它会看到您连接到,比方说,

10.0.0.1
,但它从服务器获取的证书显示它是
example.com
,并且验证失败,因为它不匹配。

您必须:

  1. _settings.Value.DomainIPAddress
    更改为证书中使用的域名。如果您没有该域名的 DNS 设置,您可以在
    hosts
    文件中添加一个条目。
  2. 告诉
    LdapConnection
    忽略证书错误。数据仍将被加密,但不会验证证书(域不匹配、证书过期等)。不建议在生产应用程序中这样做,但这里有一个示例:https://stackoverflow.com/a/67818854/1202807

0
投票

下面的代码可以帮助我使用 LDAPS 连接到 AD

ldapConnection = new LdapConnection(new LdapDirectoryIdentifier("your.LDAPSserver.com", 636));

var networkCredential = new NetworkCredential("UsernameWithoutDomain", "yourPassword", "AD.yourDOMAIN.com");
ldapConnection.SessionOptions.SecureSocketLayer = true;
ldapConnection.SessionOptions.ProtocolVersion = 3;
ldapConnection.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback(ServerCallback);
ldapConnection.AuthType = AuthType.Negotiate;
ldapConnection.Bind(networkCredential);
        
SearchRequest Srchrequest = new SearchRequest("CN=Users,DC=AD,DC=YOURCOMPANY,DC=COM", "[email protected]", System.DirectoryServices.Protocols.SearchScope.Subtree);
SearchResponse SrchResponse = (SearchResponse)ldapConnection.SendRequest(Srchrequest);

// 服务器回调

private static bool ServerCallback(LdapConnection connection, X509Certificate certificate)
{
    return true;
}

令人惊讶的是,当我不使用 networkCredential 而仅使用 ldapConnection.Bind(); 时它也能工作; 似乎它在本地计算机上使用我的本地凭据作为默认凭据。


0
投票

我写这个是为了在开发时可以轻松使用自签名证书。它支持纯文本、LDAPS 和 StartTLS。

using Novell.Directory.Ldap;

public class ActiveDirectory
{
    private LdapConnection LdapConn = new();

    public ActiveDirectory Connect(
        string ldapServerAddr,
        string ldapUser,
        string ldapPass,
        bool ldaps = false,
        bool startTls = false,
        bool trustAllCerts = false,
        bool fallbackToInsecure = false
    )
    {
        if (startTls && ldaps)
        {
            log.Fatal("Choose either StartTLS or LDAPS");
            throw new Exception("Choose either StartTLS or LDAPS");
        }

        LdapConnectionOptions connOptions = new();
        if (trustAllCerts)
        {
            log.Warn(
                "Trusting all certificates. This is insecure and should not be used in production."
            );
            connOptions.ConfigureRemoteCertificateValidationCallback(
                new System.Net.Security.RemoteCertificateValidationCallback(
                    (a, b, c, d) => true
                )
            );
        }
        int port = 389;
        // Set the connection timeout to 5 seconds
        // To-do: this does not seem to work. Investigate.
        LdapConn.ConnectionTimeout = 5000;
        bool performFallback = false;

        /*
        LDAPS (LDAP over SSL/TLS)
        LDAPS secures the LDAP communication by running it over SSL/TLS.
        It typically uses port 636 instead of the default LDAP port 389.
        */
        if (ldaps)
        {
            log.Debug("Using LDAPS");
            port = 636;
            connOptions.UseSsl();
        }

        /*
        LDAP with StartTLS

        StartTLS is a mechanism to upgrade an existing, plaintext connection to
        a secure TLS connection. It typically uses the default LDAP port 389
        but negotiates TLS _after_ the initial connection.
        */
        string connType = ldaps ? "LDAPS" : "LDAP";
        log.Debug($"Connecting via {connType} to {ldapServerAddr}:{port}.");
        if (startTls)
        {
            log.Debug("This connection will be upgraded to use secure transport with StartTLS");
        }

        // Connect to the LDAP server using either LDAP or LDAPS
        LdapConn = new LdapConnection(connOptions);
        try
        {
            // To-do Add multiple AD servers for failover. .Connect supports this natively.
            LdapConn.Connect(ldapServerAddr, port);
            log.Debug($"Connected to LDAP server {LdapConn.Host}:{LdapConn.Port}");
        }
        catch (System.Security.Authentication.AuthenticationException)
        {
            log.Error(
                $"Certificate error connecting to LDAP server at {ldapServerAddr}:{port}"
            );
            if (fallbackToInsecure)
            {
                performFallback = true;
            }
            else
            {
                log.Warn("Unable to connect to LDAP by any configured method. Exiting.");
                throw;
            }
        }
        catch (Exception e)
        {
            log.Error(
                $"Unable to connect to LDAP server at {ldapServerAddr}:{port}. Error: {e.Message}"
            );
            if (fallbackToInsecure)
            {
                performFallback = true;
            }
            else
            {
                log.Warn("Unable to connect to LDAP by any configured method. Exiting.");
                throw;
            }
        }

        if (startTls)
        {
            try
            {
                log.Debug("Enabling encryption with StartTLS");
                LdapConn.StartTls();
                log.Debug("StartTLS successful");
            }
            catch (LdapException e)
            {
                log.Error($"StartTLS failed. Error: {e.Message}");
                if (fallbackToInsecure)
                {
                    performFallback = true;
                }
                else
                {
                    log.Error("StartTLS required. (Insecure fallback not enabled) Exiting.");
                    throw;
                }
            }
        }

        if (performFallback)
        {
            log.Warn("Falling back to insecure LDAP connection.");
            try
            {
                Connect(
                    ldapServerAddr,
                    ldapUser,
                    ldapPass,
                    ldaps: false,
                    startTls: false,
                    fallbackToInsecure: false
                );
                return this;
            }
            catch (Exception e)
            {
                log.Error($"Fallback to insecure connection failed. Error: {e.Message}");
                throw;
            }
        }

        LdapConn.Bind(LdapConnection.LdapV3, ldapUser, ldapPass);
        log.Debug($"Bind made to LDAP server {LdapConn.Host}:{LdapConn.Port} as {ldapUser}");
        return this;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.