Skip to content

Named HTTP client ignores SSL settings #12244

@martina-radilova-flowpay

Description

Hi,
after upgrading to Micronaut 4.10.3, I tried to configure a custom JdkHttpClient with an SSL context using application configuration like this:

micronaut:
  http:
    services:
      clientname:
        url: ${MFS_API}
        read-timeout: 300s
        ssl:
          enabled: true
          key-store:
            path: base64:${MFS-CERT}
            password: "password"
            type: PKCS12

However, this configuration does not work.
While investigating, I noticed that SSL is only applied when the configuration is an instance of ClientSslConfiguration, but named HTTP client configurations are wrapped inside ServiceHttpClientConfiguration.

In io.micronaut.http.client.jdk.AbstractJdkHttpClient, the constructor contains:

if (configuration.getSslConfiguration() instanceof ClientSslConfiguration clientSslConfiguration) {
    configureSsl(builder, clientSslConfiguration);
}

To make it work, I had to configure the client programmatically:

@Factory
public class XYHttpClientFactory {

    private static final String BASE_64_PREFIX = "base64:";
    private static final String KEY_TYPE_PKCS12 = "PKCS12";

    @Bean(preDestroy = "close")
    @Singleton
    @Named("xy")
    JdkHttpClient xyHttpClient(
            @Value("${app.xy.api}") String baseUrl,
            @Value("${app.xy.cert-file}") String certBase64,
            @Value("${app.xy.cert-pwd}") String certPassword
    ) {
        return createJdkHttpClientWithSsl(baseUrl, certBase64, certPassword);
    }

    public static JdkHttpClient createJdkHttpClientWithSsl(String baseUrl, String certBase64, String certPassword) {
        try {
            var httpClientConfiguration = getDefaultHttpClientConfiguration(certBase64, certPassword);

            var conversionService = ConversionService.SHARED;

            return new DefaultJdkHttpClient(
                    LoadBalancer.fixed(URI.create(baseUrl)),
                    null,
                    httpClientConfiguration,
                    null,
                    null,
                    null,
                    null,
                    JdkHttpClientFactory.createDefaultMessageBodyHandlerRegistry(),
                    null,
                    null,
                    conversionService,
                    new JdkClientSslBuilder(new ResourceResolver()),
                    new NettyCookieDecoder(conversionService));
        } catch (Exception e) {
            throw new RuntimeException("Failed to create HTTP client with SSL", e);
        }
    }

    private static DefaultHttpClientConfiguration getDefaultHttpClientConfiguration(String certBase64, String certPassword) {
        var keyStore = new ClientSslConfiguration.DefaultKeyStoreConfiguration();
        keyStore.setPath(BASE_64_PREFIX + certBase64);
        keyStore.setPassword(certPassword);
        keyStore.setType(KEY_TYPE_PKCS12);

        var sslConfiguration = new ClientSslConfiguration();
        sslConfiguration.setKeyStore(keyStore);
        var httpClientConfiguration = new DefaultHttpClientConfiguration();
        httpClientConfiguration.setClientSslConfiguration(sslConfiguration);
        return httpClientConfiguration;
    }
}

Questions

  1. Is there a better or recommended way to configure SSL for a named JDK HTTP client?
  2. Why is it not possible to configure the SSL context for named HTTP clients via the application.yml?

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions