Access HTTPS RESTful service using Web Client in Spring Boot 2.0 throwing exception
Asked Answered
A

1

2

I have to access one https rest web service(https://example.com) for which certificate has been provided by the client which contains 2 .cer files.

I have created keystore.jks and truststore.jks files and imported the .cer files to jks file. by using the below command

keytool -genkeypair -alias abcd -keyalg RSA -sigalg garegar -keysize 2048 -storetype jks -keystore keystore.jks -validity 365 -storepass changeit

keytool -import -alias abcd -trustcacerts -file free/ca_bundle.cer -keystore keystore.jksccessfull

I have added all properties to application.yml

   truststore-location: 
   keystore-location: 
   truststore-password: 
   keystore-password: 
   key-alias:

Created the bean in configuration class to get the webclient object.

@Data
@NoArgsConstructor
@AllArgsConstructor
@Configuration
public class WebServiceRestConfig {

    @Value(value = "${wcc.rest.endpoint}")
    private String url;

    @Value(value = "${wcc.dam.username}")
    private String username;

    @Value(value = "${wcc.dam.password}")
    private String password;

    @Value(value = "${ssl.truststore-location}")
    private String trustStore;

    @Value(value = "${ssl.keystore-location}")
    private String keyStore;

    @Value(value = "${ssl.truststore-password}")
    private String trustStorePassword;

    @Value(value = "${ssl.keystore-password}")
    private String keyStorePassword;

    @Value(value = "${ssl.key-alias}")
    private String keyAlias;




    @Bean
    WebClientCustomizer configureWebclient() {

        return (WebClient.Builder webClientBuilder) -> {
            SslContext sslContext;
            final PrivateKey privateKey;
            final X509Certificate[] certificates;
            try {
                final KeyStore trustStore;
                final KeyStore keyStore;
                trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                trustStore.load(new FileInputStream(ResourceUtils.getFile(getTrustStore())),
                        trustStorePassword.toCharArray());
                keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(new FileInputStream(ResourceUtils.getFile(getKeyStore())), keyStorePassword.toCharArray());
                List<Certificate> certificateList = Collections.list(trustStore.aliases()).stream().filter(t -> {
                    try {
                        return trustStore.isCertificateEntry(t);
                    } catch (KeyStoreException e1) {
                        throw new RuntimeException("Error reading truststore", e1);
                    }
                }).map(t -> {
                    try {
                        return trustStore.getCertificate(t);
                    } catch (KeyStoreException e2) {
                        throw new RuntimeException("Error reading truststore", e2);
                    }
                }).collect(Collectors.toList());
                certificates = certificateList.toArray(new X509Certificate[certificateList.size()]);
                privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyStorePassword.toCharArray());
                Certificate[] certChain = keyStore.getCertificateChain(keyAlias);
                X509Certificate[] x509CertificateChain = Arrays.stream(certChain)
                        .map(certificate -> (X509Certificate) certificate).collect(Collectors.toList())
                        .toArray(new X509Certificate[certChain.length]);
                sslContext = SslContextBuilder.forClient().keyManager(privateKey, keyStorePassword, x509CertificateChain)
                        .trustManager(certificates).build();

                HttpClient httpClient = HttpClient.create()
                        .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
                ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
                webClientBuilder.clientConnector(connector).baseUrl(getUrl()).build();

            } catch (KeyStoreException e) {
                throw new RuntimeException(e);
            }catch(CertificateException e) {
                throw new RuntimeException(e);
            }catch(NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }catch(IOException e) {
                throw new RuntimeException(e);
            }catch(UnrecoverableKeyException e) {
                throw new RuntimeException(e);
            }
        };
    }

}

But when i am running the application I am getting below exception

SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is reactor.core.Exceptions$ReactiveException: javax.net.ssl.SSLHandshakeException: General SSLEngine problem] with root cause
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:281)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1465)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:969)

Right now I am completely clueless what to do and how to resolve this do i need to add anything in resources folder or am i missing something here?

Alysa answered 22/4, 2020 at 20:11 Comment(0)
R
0

I had a similar problem:

@Bean("oAuth2")
public WebClient webOAuth2Client(ReactiveClientRegistrationRepository registration,
                           ServerOAuth2AuthorizedClientRepository clientRepository) {

    ServerOAuth2AuthorizedClientExchangeFilterFunction filter =
            new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                    registration,
                    clientRepository);
    filter.setDefaultClientRegistrationId("oAuth2");
   

    return WebClient
            .builder()
            .filter(filter)
            .build();
}

in property file something like:

    security:
    oauth2:
      client:
        provider:
          oAuth2:
            token-uri: url:port/auth/realms/SCRealm/protocol/openid-connect/token
        registration:
          oAuth2:
            clientId: client_id
            clientSecret: client_secret
            authorizationGrantType: client_credentials
            clientAuthenticationMethod: post

And in main application class :

System.setProperty("-Dio.netty.handler.ssl.noOpenSsl","true");
System.setProperty("javax.net.ssl.trustStore", "keyStore.jks");
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStorePassword", "any_strong_pass");
Reactionary answered 15/7, 2020 at 12:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.