Alem Filli
Alem Filli

Reputation: 73

Connecting to MongoDB from spring boot app using ssl

im trying to connect my spring boot app to mongodb using ssl. I followed the steps described here, but they dont work for me.

https://www.compose.com/articles/how-to-connecting-to-compose-mongodb-with-java-and-ssl/

any idea?

Thanks Alem

Upvotes: 4

Views: 22194

Answers (2)

B. Stucke
B. Stucke

Reputation: 162

If you just want to connect your spring boot app with mongodb, you can use the keyStore and trustStore with java code. So you dont have to add your certificate via command line. If you are using cloud foundry you can connect your app with mongodbServices and then you have all the credentials you need in System.getEnv("VCAP_SERVICES").

@Configuration
public class MongoConfiguration extends AbstractMongoConfiguration {
    private static Log logger = LogFactory.getLog(MongoConfiguration.class);
    @Value("${spring.data.mongodb.database}")
    private String defaultDatabase; //database you want to connect
    private String host;
    private int port;
    private String authenticationDb; //usually admin
    private String username;
    private char[] password;
    private String certificateDecoded; //your CA Certifcate decoded (starts with BEGIN CERTIFICATE)

    public MongoConfiguration() {
        //method for credentials initialization
    }

    //you can't set replicaset=replset in mongooptions so if you want set replicaset, you have to use 
    // customEditorConfigurer in combintaion with class that implementsPropertyEditorRegistrar
    @Bean
    public static CustomEditorConfigurer customEditorConfigurer(){
        CustomEditorConfigurer configurer = new CustomEditorConfigurer();
        configurer.setPropertyEditorRegistrars(
                new PropertyEditorRegistrar[]{new ServerAddressPropertyEditorRegistrar()});
        return configurer;
    }

    @Override
    protected String getDatabaseName() {
        return authenticationDb;
    }

    @Override
    @Bean
    public MongoClient mongoClient() {
        MongoClient mongoClient = new MongoClient(Arrays.asList(new ServerAddress(host, port)), mongoCredentials(), mongoClientOptions());
        return mongoClient;
    }

    @Bean
    public MongoClientOptions mongoClientOptions() {
        MongoClientOptions.Builder mongoClientOptions = MongoClientOptions.builder().sslInvalidHostNameAllowed(true).sslEnabled(true);
        try {
            InputStream inputStream = new ByteArrayInputStream(certificateDecoded.getBytes(StandardCharsets.UTF_8));
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            X509Certificate caCert = (X509Certificate) certificateFactory.generateCertificate(inputStream);

            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null); // You don't need the KeyStore instance to come from a file.
            keyStore.setCertificateEntry("caCert", caCert);

            trustManagerFactory.init(keyStore);

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
            mongoClientOptions.sslContext(sslContext);
            mongoClientOptions.sslInvalidHostNameAllowed(true);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }

        return mongoClientOptions.build();
    }

    private MongoCredential mongoCredentials() {
        return MongoCredential.createCredential(username, authenticationDb, password);
    }

//With MongoTemplate you have access to db.
    @Bean
    public MongoTemplate mongoTemplate() {
        SimpleMongoDbFactory factory = new SimpleMongoDbFactory(mongoClient(), defaultDatabase);
        return new MongoClient(factory);

    }
}


public final class ServerAddressPropertyEditorRegistrar implements PropertyEditorRegistrar {
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(ServerAddress[].class, new ServerAddressPropertyEditor());
    }
}

Upvotes: 2

Wheelchair Geek
Wheelchair Geek

Reputation: 432

I would suggest that you look at Accessing Data with MongoDB available here https://spring.io/guides/gs/accessing-data-mongodb/ for basic usage examples. spring-boot-starter-data-mongodb will get you a long way, what you need to do is configure a MongoClientOptions bean like this

    @Bean
    public  MongoClientOptions mongoClientOptions(){
        System.setProperty ("javax.net.ssl.keyStore","<<PATH TO KEYSTOR >>");
        System.setProperty ("javax.net.ssl.keyStorePassword","PASSWORD");   
        MongoClientOptions.Builder builder = MongoClientOptions.builder();
        MongoClientOptions options=builder.sslEnabled(true).build();        
        return options;
    }

and pass the mongo client options to MongoClient instance as an argument as follows

public MongoClient(ServerAddress addr, MongoClientOptions options) {
        super(addr, options);
    }

Adding further, when mongo processs is started with

mongo --ssl --sslAllowInvalidCertificates --host --port

clients connecting to the mongo process dont have to set any options to support this.

I used this post Spring data mongodb, how to set SSL? and this spring.io guide as reference.

Hope that it helps

Upvotes: 3

Related Questions