Oauth2RestTemplate-不从自定义信任库读取证书

时间:2018-10-04 10:35:00

标签: spring-boot spring-security-oauth2

默认情况下,Oauth2RestTemplate正在从jre truststore读取证书。但是,当我们使用HttpComponentsClientHttpRequestFactory配置模板时,它不是从自定义信任库中读取证书。 下面是代码:

@Configuration
public class OauthConfig {

@Resource
private HttpComponentsClientHttpRequestFactory backendHttpComponentsClientHttpRequestFactory;

@Resource
private PoolingHttpClientConnectionManager backendPoolingHttpClientConnectionManager;

@Value("${keystore.path}")
private File certificatePath;

@Value("${keystore.password}")
private String certificatePassword;


@Bean("testOauthRestTemplate")
public OAuth2RestOperations oauth2RestTemplate() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException

{
    ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
    resourceDetails.setClientId("clientId");
    resourceDetails.setClientSecret("12345");
    resourceDetails.setAccessTokenUri("https://test:8080/oauth/token");
    resourceDetails.setGrantType("client_credentials");
    resourceDetails.setAuthenticationScheme(AuthenticationScheme.header);
    AccessTokenRequest request = new DefaultAccessTokenRequest();

    OAuth2RestTemplate oauth2RestTemplate = new OAuth2RestTemplate(resourceDetails, new DefaultOAuth2ClientContext(request));

    HttpClientBuilder clientBuilder = HttpClientBuilder.create();
    HttpClient httpClient = null;


    httpClient = clientBuilder.setConnectionManager(backendPoolingHttpClientConnectionManager)
            .setSSLSocketFactory(SslSettings.sslConnectionSocketFactory(certificatePath, certificatePassword))
            .disableCookieManagement().build();


    backendHttpComponentsClientHttpRequestFactory.setHttpClient(httpClient);

    oauth2RestTemplate.setRequestFactory(backendHttpComponentsClientHttpRequestFactory);

    return oauth2RestTemplate;
}

@Bean("backendHttpComponentsClientHttpRequestFactory")
public HttpComponentsClientHttpRequestFactory backendHttpComponentsClientHttpRequestFactory() {
    return new HttpComponentsClientHttpRequestFactory();
}


@Bean("backendPoolingHttpClientConnectionManager")
public PoolingHttpClientConnectionManager backendPoolingHttpClientConnectionManager() throws KeyManagementException,
        NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {

    Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("https", SslSettings.sslConnectionSocketFactory(certificatePath, certificatePassword))
            .build();


    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = 
            new PoolingHttpClientConnectionManager(
            socketFactoryRegistry);
    poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20);
    poolingHttpClientConnectionManager.setMaxTotal(200);

    return poolingHttpClientConnectionManager;
}

}

以下是例外:

Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
                at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
                at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1964)
                at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:328)
                at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:322)
                at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1614)
                at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
                at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1052)
                at sun.security.ssl.Handshaker.process_record(Handshaker.java:987)
                at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072)
                at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
                at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
                at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
                at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
                at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
                at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:162)
                at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:76)
                at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
                at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
                at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:723)
                ... 73 common frames omitted
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
                at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
                at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
                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:229)
                at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
                at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1596)
                ... 87 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
                at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
                at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
                at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
                at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
                ... 93 common frames omitted

需要一些建议/帮助。.找不到解决方案..

2 个答案:

答案 0 :(得分:1)

当前接受的答案提供了一个使用错误推理的解决方案。该错误不是因为您的OAuth2RestTemplate无法访问证书存储,而是因为OAuth2RestTemplate上的AccessTokenProvider在内部创建了自己的RestTemplate以便请求令牌。为了设置该内部RestTemplate的提供程序,您可以执行以下操作(根据您正在执行的OAuth类型更改为不同类型的AccessTokenProviders)

ClientCredentialsAccessTokenProvider provider = new ClientCredentialsAccessTokenProvider();
provider.setRequestFactory(requestFactory);
restTemplate.setAccessTokenProvider(provider);

被接受的答案通过将trustStore应用于所有请求而起作用,这并不总是您想要做的,因为具体起来几乎总是更好。

答案 1 :(得分:0)

您手动配置的HttpClient似乎无法访问TLS证书存储。给定的错误消息(javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: ...)指出,由于程序无法找到证书存储的路径,因此无法建立有效的SSL连接。

要解决此问题,您可以尝试设置Java密钥库和信任库设置,如下所示:

SSLConfig.java

@Configuration
public class SSLConfig {
    @Autowired
    private Environment env;

    @PostConstruct
    private void configureSSL() {
      //load the 'javax.net.ssl.trustStore' and
      //'javax.net.ssl.trustStorePassword' from application.properties
      System.setProperty("javax.net.ssl.trustStore", env.getProperty("server.ssl.trust-store")); 
      System.setProperty("javax.net.ssl.trustStorePassword",env.getProperty("server.ssl.trust-store-password"));
    }
}

application.properties:

server.ssl.trust-store: YOUR_TRUST_STORE_PATH
server.ssl.trust-store-password: YOUR_TRUST_STORE_PASSWORD