带有 pem 证书的 RestTemplate

RestTemplate with pem certificate

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

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

但我想将它与 java 一起使用,最好是来自 spring 的 RestTemplate。

您需要在 java 信任库中导入证书。

BTW pem 和 cer(t) 文件是相同的,只是扩展名不同

其他链接

所以关于使用 RestTemplate 的 pem 证书的知识被分散了。

必须完成的步骤:

  1. 使用 keytool 或 portecle 将服务器证书添加到 trustStore。当您想使用自定义信任库时,请使用此 script

  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。