具有pem证书的RestTemplate


问题内容

我有带私钥和服务器证书的pem证书。我可以使用curl执行它,一切正常。

curl -O -k --cert-type pem --cert mypem.pem url

但是我想将其与Java一起使用,最可取的是从Spring开始的RestTemplate。


问题答案:

因此,将有关与RestTemplate一起使用pem证书的知识分散了。

必须完成的步骤:

  1. 使用keytool或portecle将服务器证书添加到trustStore。当您要使用自定义信任关系时,请使用此脚本

  2. 接下来,将ssl配置为RestTemplate。可以像下面这样完成:

        @Configuration
    public class SSLConfiguration {

    @Value("${certificate.name}")
    private String name;

    @Bean(name = "sslContext")
    public SSLContext sslContext() throws Exception {
      Security.addProvider(new BouncyCastleProvider());
      return SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).useTLS().build();
    }

    @Bean(name = "sslSocketFactory")
    public SSLSocketFactory sslSocketFactory() throws Exception {

      return new ConnectionFactoryCreator(name, sslContext()).getSocketFactory();

    }

    @Bean(name = "httpClient")
    public HttpClient httpClient() throws Exception {
      return HttpClientBuilder.create().setSslcontext(sslContext())
            .setSSLSocketFactory(new SSLConnectionSocketFactory(sslSocketFactory(), new AllowAllHostnameVerifier()))
            .build();
    }

    @Bean
    public ClientHttpRequestFactory httpClientRequestFactory() throws Exception {
      return new HttpComponentsClientHttpRequestFactory(httpClient());
    }

    @Bean
    public RestTemplate restTemplate() throws Exception {
      return new RestTemplate(httpClientRequestFactory());
     }

    }

    public class ConnectionFactoryCreator {

       private final String pemName;

       private final SSLContext context;

       public ConnectionFactoryCreator(String pemName, SSLContext context) {
          this.pemName = pemName;
          this.context = context;
       }

       public SSLSocketFactory getSocketFactory() throws Exception {

          InputStream resourceAsStream = getClass().getResourceAsStream(pemName);
      byte[] certAndKey = ByteStreams.toByteArray(resourceAsStream);

      byte[] certBytes = parseDERFromPEM(certAndKey, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
      byte[] keyBytes = parseDERFromPEM(certAndKey, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");

      X509Certificate cert = generateCertificateFromDER(certBytes);

      PrivateKey key = generatePrivateKeyFromDER(keyBytes);

      KeyStore keystore = KeyStore.getInstance("JKS");
      keystore.load(null);
      keystore.setCertificateEntry("cert-alias", cert);
      keystore.setKeyEntry("key-alias", key, "changeit".toCharArray(), new Certificate[] { cert });

      KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
      kmf.init(keystore, "changeit".toCharArray());

      KeyManager[] km = kmf.getKeyManagers();

      context.init(km, null, null);

      return context.getSocketFactory();
       }

       private byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) {
      String data = new String(pem);
      String[] tokens = data.split(beginDelimiter);
      tokens = tokens[1].split(endDelimiter);
      return DatatypeConverter.parseBase64Binary(tokens[0]);
       }

       private PrivateKey generatePrivateKeyFromDER(byte[] keyBytes)
         throws InvalidKeySpecException, NoSuchAlgorithmException {
      PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);

      KeyFactory factory = KeyFactory.getInstance("RSA");

      return factory.generatePrivate(spec);
       }

       private X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
      CertificateFactory factory = CertificateFactory.getInstance("X.509");

      return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
     }

最后,您可以使用注入restTemplate连接到url。