Хранилище ключей в памяти с использованием API-интерфейса хранилища ключей «не удалось найти действительный путь сертификации к запрошенной цели»

Я пытаюсь создать хранилище ключей в памяти для одного запроса ldap. Соединения и сертификаты Ldap могут меняться, поэтому я не могу их нигде хранить.

Spring Ldap не очень дружелюбен к нескольким соединениям ldap

    public LdapContextSource buildLdapContext(final LdapConnection connection) {
        final LdapContextSource context = new LdapContextSource();
        context.setBase(connection.getBaseDN());
        context.setUrl(connection.getConnectionUrl());
        context.setPassword(connection.getAdminPassword());
        context.setUserDn(connection.getUserDN());

        if(connection.getProtocol() == LdapProtocol.LDAPS) {
            final DefaultTlsDirContextAuthenticationStrategy authenticationStrategy = new DefaultTlsDirContextAuthenticationStrategy();
            authenticationStrategy.setSslSocketFactory(ldapSslSocketFactoryBuilder.buildSslSocketFactory(connection));
            context.setAuthenticationStrategy(authenticationStrategy);
        }

        context.afterPropertiesSet();
        return context;
    }
    public SSLSocketFactory buildSslSocketFactory(final LdapConnection connection) {
        try {
            final KeyStore store = buildKeyStore(connection);
            final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(store);

            final SSLContext ctx = SSLContext.getInstance("SSL");
            ctx.init(null, tmf.getTrustManagers(), null);
            return ctx.getSocketFactory();

        } catch(Exception e) {
            throw new LdapException(e.getMessage(), e);
        }
    }
    private KeyStore buildKeyStore(final LdapConnection ldapConnection) {
        try {
            // Load in-memory keystore
            final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            keystore.load(null);

            // Decode certificate
            byte[] decoded = Base64.decodeBase64(ldapConnection.getSslCertificate()
                            .replaceAll(X509Factory.BEGIN_CERT, "")
                            .replaceAll(X509Factory.END_CERT, "")
                            .trim().getBytes(StandardCharsets.UTF_8));

            // Load certificate
            CertificateFactory certificateFactory = CertificateFactory.getInstance("x.509");
            Certificate cert = certificateFactory.generateCertificate(new ByteArrayInputStream(decoded));
            keystore.setCertificateEntry(ldapConnection.getConnectionUrl(), cert);

            return keystore;
        } catch(Exception e) {
            log.error(e.getMessage(), e);
            throw new LdapException(e.getMessage(), e);
        }
    }

Я ожидаю, что сохраненный открытый ключ используется для подключения к серверу ldap, но вместо этого я получаю «невозможно найти действительный путь сертификации к запрошенной цели»


person Milos Zivkovic    schedule 20.09.2019    source источник
comment
Не могли бы вы добавить -Djavax.net.debug=SSL,handshake,trustmanager в качестве опции JVM и проверить журналы?   -  person Bernhard Thalmayr    schedule 23.09.2019


Ответы (1)


Мне удалось решить эту проблему. Код работает правильно, проблема заключалась в том, что мы использовали самозаверяющий сертификат, который невозможно было проверить. Все, что нам нужно было сделать, это поместить сертификат hte в файл cacerts. Самозаверяющие сертификаты являются собственным центром сертификации и поэтому должны быть помещены в файл cacerts, который находится в папке $JAVA_HOME/jre/lib/security/cacerts.

person Milos Zivkovic    schedule 24.09.2019
comment
Что, в свою очередь, означает, что вам не нужна большая часть этого кода. - person user207421; 24.09.2019
comment
Делаем при использовании подписанных CA сертификатов - person Milos Zivkovic; 01.11.2019