LDAPS-证书不应该分配给我尝试连接的主机名吗?

LDAPS-证书不应该分配给我尝试连接的主机名吗?,ldap,certificate,Ldap,Certificate,我尝试通过LDAPS协议连接到LDAP服务器,并使用服务器的IP定义URL 我使用的密钥库包含颁发给此服务器的证书,但主题DN包含主机名 它不应该失败吗 代码如下: public class LdapConnection { private String host = "1.2.3.4"; //the correct ip... private String baseDn = "dc=x,dc=y,dc=com"; //the correct base DN priv

我尝试通过LDAPS协议连接到LDAP服务器,并使用服务器的IP定义URL

我使用的密钥库包含颁发给此服务器的证书,但主题DN包含主机名

它不应该失败吗

代码如下:

public class LdapConnection
{

    private String host = "1.2.3.4"; //the correct ip...
    private String baseDn = "dc=x,dc=y,dc=com"; //the correct base DN

    private String username = "myUsername";
    private String password = "myPassword";

    private String connectionUrl = null;

    public void connectLdaps() throws Exception
    {
        connectionUrl = "ldaps://" + host + "/" + baseDn;

        System.out.println("Trying to connect to " + connectionUrl + " using LDAPS protocol");

        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put("java.naming.ldap.derefAliases", "finding");
        env.put(Context.PROVIDER_URL, connectionUrl);
        env.put(Context.SECURITY_AUTHENTICATION, "Simple");
        env.put(Context.SECURITY_PRINCIPAL, username);
        env.put(Context.SECURITY_CREDENTIALS, password);
        env.put("java.naming.ldap.factory.socket", MySocketFactory.class.getName());

        new InitialLdapContext(env, null);

        System.out.println("Connected successfully!");
    }

    public static void main(String[] args) throws Exception
    {
        LdapConnection ldapConnection = new LdapConnection();
        ldapConnection.connectLdaps();
    }

}

public class MySocketFactory extends SocketFactory
{
    private static MySocketFactory instance = null;
    private SSLContext sslContext = null;

    private static String certFileName = "C:\\certs\\cert_by_hostname.cer";

    public static SocketFactory getDefault()
    {
        if (instance == null)
        {
            try
            {
                instance = new MySocketFactory();
                instance.initFactory();
            }
            catch (Exception e)
            {
                e.printStackTrace();
                System.out.println("Returning null socket factory");
            }
        }

        return instance;
    }

    private void initFactory() throws Exception
    {
        System.out.println("Initializing socket factory...");

        InputStream certStream = new FileInputStream(certFileName);
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Certificate certificate = certificateFactory.generateCertificate(certStream);
        System.out.println("The certificate was generated. It is issued to " + ((X509Certificate)certificate).getSubjectDN());

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, "myPassword".toCharArray());
        new KeyStore.TrustedCertificateEntry(certificate);
        keyStore.setCertificateEntry("myCert", certificate);
        System.out.println("The Keystore was initialized.");

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
        trustManagerFactory.init(keyStore);
        System.out.println("The TrustManagerFactory was initialized.");

        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
        System.out.println("The SSLContext was initialized.");

    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException
    {
        System.out.println("In create socket, host is " + host + " and port is " + port);
        return sslContext.getSocketFactory().createSocket(host, port);
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException
    {
        return sslContext.getSocketFactory().createSocket(host, port);
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException
    {
        return sslContext.getSocketFactory().createSocket(host, port, localHost, localPort);
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException
    {
        return sslContext.getSocketFactory().createSocket(address, port, localAddress, localPort);
    }

}

当您通过HTTP或LDAP绑定到SSL并使用密钥库时,需要的是签署证书的受信任根的公钥。这与主机名是什么无关

从Windows的角度来看,这意味着签署证书的受信任根应该位于Windows密钥库中,在该实例中称为证书存储

对于大多数其他应用程序来说,它是某种密钥库。基于Java的应用程序使用keytool对其进行操作

因此,只要可信根是已知的,并且隐含可信的,那么它就假定证书链是好的和可信任的

因此,除非您使用服务器证书进行相互身份验证,否则在通过SSL的普通LDAP或通过SSL的常规HTTP的情况下不太可能,否则我认为这不重要

Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: hostname of the server '1.2.3.4' does not match the hostname in the server's certificate.
    at com.sun.jndi.ldap.ext.StartTlsResponseImpl.verify(Unknown Source)
    at com.sun.jndi.ldap.ext.StartTlsResponseImpl.negotiate(Unknown Source)
    at ldapconnection.LdapConnection.connectTLS(LdapConnection.java:84)
    at ldapconnection.LdapConnection.main(LdapConnection.java:92)
Caused by: java.security.cert.CertificateException: No subject alternative names matching IP address 1.2.3.4 found
    at sun.security.util.HostnameChecker.matchIP(Unknown Source)
    at sun.security.util.HostnameChecker.match(Unknown Source)
    ... 4 more