Spring Data Cassandra enable ssl hostname verification

华瀚漠
2023-12-01

现在spring data cassandra是不能通过一个开关直接开启ssl的hostname verification的,也就是所谓的verify-full,所以得自己改下代码.

方案1:

implements CqlSessionBuilderCustomizer

import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
import org.springframework.boot.autoconfigure.cassandra.CqlSessionBuilderCustomizer;
import org.springframework.stereotype.Component;

@Component
public class CqlSessionBuilderSSLCustomizer implements CqlSessionBuilderCustomizer {

    @Autowired
    CassandraProperties cassandraProperties;

    @Override
    public void customize(CqlSessionBuilder cqlSessionBuilder) {
        if(cassandraProperties.isSsl()){
            CustomSslEngineFactory customSslEngineFactory = new CustomSslEngineFactory("TLS");
            cqlSessionBuilder.withSslEngineFactory(customSslEngineFactory);
        }
    }
}

方案2:

implements BeanPostProcessor

import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
import org.springframework.stereotype.Component;

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Autowired
    CassandraProperties cassandraProperties;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if("cassandraSessionBuilder".endsWith(beanName)&&cassandraProperties.isSsl()){
            CqlSessionBuilder cassandraSessionBuilder = (CqlSessionBuilder) bean;
            CustomSslEngineFactory customSslEngineFactory = new CustomSslEngineFactory("TLS");
            cassandraSessionBuilder.withSslEngineFactory(customSslEngineFactory);
        }
        return bean;
    }
}
CustomSslEngineFactory 的代码
import com.datastax.oss.driver.api.core.metadata.EndPoint;
import com.datastax.oss.driver.api.core.ssl.SslEngineFactory;
import edu.umd.cs.findbugs.annotations.NonNull;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManagerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.KeyStore;
import java.security.SecureRandom;

public class CustomSslEngineFactory implements SslEngineFactory {

    private final SSLContext sslContext;

    private final String[] cipherSuites;

    private final boolean requireHostnameValidation;

    private final String TRUST_STORE_PROPERTY = "javax.net.ssl.trustStore";
    private final String TRUST_STORE_PASSWORD_PROPERTY = "javax.net.ssl.trustStorePassword";
    private final String TRUST_STORE_TYPE_PROPERTY = "javax.net.ssl.trustStoreType";

    private final String SSL_HOSTNAMEVERIFIER = "javax.net.ssl.hostnameverifier";

    final String DEFAULT_TRUST_STORE = System.getProperty("java.home") + File.separator + "lib"
            + File.separator + "security" + File.separator + "cacerts";
    private final String DEFAULT_TRUST_STORE_PASSWORD = "changeit";


    public CustomSslEngineFactory(String encryptionMode){
        try {
            this.sslContext = buildContext(encryptionMode);
        } catch (Exception e){
            throw new IllegalStateException("Cannot initialize SSL Context",e);
        }

        this.cipherSuites = null;

        String hostnameverifier = System.getProperty(SSL_HOSTNAMEVERIFIER);
        if("false".equals(hostnameverifier)){
            this.requireHostnameValidation = false;
        }else {
            this.requireHostnameValidation = true;
        }

    }
    @NonNull
    @Override
    public SSLEngine newSslEngine(@NonNull EndPoint remoteEndpoint) {
        SSLEngine engine;
        SocketAddress remoteAddress = remoteEndpoint.resolve();
        if (remoteAddress instanceof InetSocketAddress) {
            InetSocketAddress socketAddress = (InetSocketAddress) remoteAddress;
            engine = sslContext.createSSLEngine(socketAddress.getHostName(),socketAddress.getPort());
        } else {
            engine = sslContext.createSSLEngine();
        }
        engine.setUseClientMode(true);
        if (cipherSuites != null) {
            engine.setEnabledCipherSuites(cipherSuites);
        }
        if (requireHostnameValidation) {
            SSLParameters parameters = engine.getSSLParameters();
            parameters.setEndpointIdentificationAlgorithm("HTTPS");
            engine.setSSLParameters(parameters);
        }
        return engine;
    }

    protected SSLContext buildContext(String encryptionMode) throws Exception {
        String trustStore = System.getProperty(TRUST_STORE_PROPERTY);
        String trustStorePassword = System.getProperty(TRUST_STORE_PASSWORD_PROPERTY);

        if (null == trustStore || "".equals(trustStore)) {
            trustStore = DEFAULT_TRUST_STORE;
        }
        if (null == trustStorePassword || "".equals(trustStorePassword)) {
            trustStorePassword = DEFAULT_TRUST_STORE_PASSWORD;
        }
        String storePropType = System.getProperty(TRUST_STORE_TYPE_PROPERTY,
                KeyStore.getDefaultType());
        KeyStore ks = KeyStore.getInstance(storePropType);
        InputStream trustStoreStream = new FileInputStream(trustStore);
        ks.load(trustStoreStream, trustStorePassword.toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);

        SSLContext sslContext = SSLContext.getInstance(encryptionMode.trim().toUpperCase());
        sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
        return sslContext;

    }

    @Override
    public void close() throws Exception {
        // noting to do
    }
}

 类似资料:

相关阅读

相关文章

相关问答