Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring data mongodb, how to set SSL?

I have so far failed to find a good explanation/doc on the topic.

I am using

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>1.9.5.RELEASE</version>
</dependency>

and my code looks like this:

   @Bean
   public MongoClientFactoryBean mongo() {
      MongoClientFactoryBean mongo = new MongoClientFactoryBean();
      mongo.setHost(host);
      mongo.setPort(port);
      mongo.setCredentials(new MongoCredential[]{MongoCredential.createCredential(username, database, password.toCharArray())});
      return mongo;
   }

   @Bean
   public MongoTemplate mongoTemplate(Mongo mongo) throws Exception {
      return new MongoTemplate(mongo, database);
   }

Do you know how I should configure SSL for this? And can I allow invalid certificate?

The equivalent mongo command line would be

mongo --ssl --sslAllowInvalidCertificates --host <host> --port <port>
like image 374
stackoverflower Avatar asked Jan 05 '17 18:01

stackoverflower


2 Answers

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());
    }
}
like image 188
B. Stucke Avatar answered Oct 24 '22 10:10

B. Stucke


Spring Boot 2.3.4 and Reactive Mongo in Eclipse:

pfx goes into src/test/resources

  @Bean @Profile("dev")
  public MongoClientSettings mongoClientSettingsDev() throws NoSuchAlgorithmException {
    System.setProperty ("javax.net.ssl.keyStore","target/test-classes/xxx.pfx");
    System.setProperty ("javax.net.ssl.keyStorePassword","xxx");  
    SSLContext sslContext = SSLContext.getDefault();
    MongoClientSettings settings = MongoClientSettings.builder()
                                                      .applyToSslSettings(builder -> {
                                                        builder.enabled(true);
                                                        builder.context(sslContext);
                                                      })
                                                      .build();
    return settings;
  }

bootstrap.yml for connection with x.509:

spring:
  data:
    mongodb:
      database: database_name
      uri: mongodb://[email protected]:62017/?authMechanism=MONGODB-X509&tls=true&authSource=$external

Update for Spring Boot 2.4.5

  @Bean @Profile("dev")
  public MongoClientSettings mongoClientSettingsDev(
    MongoProperties properties,
    Environment environment
  ) throws NoSuchAlgorithmException {
    System.setProperty ("javax.net.ssl.keyStore","target/test-classes/xxx.pfx");
    System.setProperty ("javax.net.ssl.keyStorePassword","xxx");  
    SSLContext sslContext = SSLContext.getDefault();
    MongoClientSettings.Builder builder = MongoClientSettings.builder();
    builder.applyToSslSettings(b -> {
      b.enabled(true);
      b.context(sslContext);
    });
    new MongoPropertiesClientSettingsBuilderCustomizer(properties, environment).customize(builder);
    return builder.build();
  }

Another way of setting the SSLContext:

Resource resource = new ClassPathResource("xxx.pfx");
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(resource.getInputStream(), "xxx".toCharArray());
SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(ks, "xxx".toCharArray()).build();
like image 20
emvidi Avatar answered Oct 24 '22 08:10

emvidi