代码之家  ›  专栏  ›  技术社区  ›  Kannan Ramamoorthy

使外部客户端从自定义属性获取truststore

  •  3
  • Kannan Ramamoorthy  · 技术社区  · 6 年前

    我们应用程序中的外部客户端正在与自签名服务器通信。我们可以使用属性使外部客户端使用自定义信任库 javax.net.ssl.trustStore 系统属性。 但由于我的应用程序还与标准的CA认证站点通信,因此不应覆盖默认的truststore。

    如果不使用 javax。网ssl。信任库 系统属性?或者,我如何让我的外国客户从标准以外的属性使用truststore javax。网ssl。信任库 系统属性?

    3 回复  |  直到 2 年前
        1
  •  2
  •   Kannan Ramamoorthy    6 年前

    我最终手工制作了自己的 SSLSocketFactory 我用下面的代码传递给我的外国客户,

    /**
     * Gets the {@link SSLSocketFactory} instance for the client communication
     * using the given truststore file and password.
     * 
     * Since the instance is used as client, this is instantiated with empty
     * keystore and the truststore represented by the given truststore file.
     * 
     * 
     * @param theTrustStoreFile
     *            The complete file path of the truststore.
     * @return {@link SSLSocketFactory} instance that internally uses the given
     *         truststore.
     * @throws Exception
     *             When there is an error in the creating the
     *             {@link SSLSocketFactory} instance.
     */
    public static SSLSocketFactory getClientSSLSocketFactory(File theTrustStoreFile)
            throws Exception
    {
        // This supports TLSv1.2
        SSLContext sslContext = SSLContext.getInstance("TLS");
    
        KeyStore kStore = KeyStore.getInstance(KeyStore.getDefaultType());
    
        FileInputStream file = getFileInputStream(theTrustStoreFile);
        kStore.load(file, null);
    
        TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(kStore);
    
        sslContext.init(new KeyManager[] {}, tmf.getTrustManagers(), null);
    
        return sslContext.getSocketFactory();
    }
    
    /**
     * Reads the file into {@link FileInputStream} instance.
     * 
     * @param file
     *            The file to be read.
     * @return {@link FileInputStream} that represents the file content/
     * @throws Exception
     *             When there is any error in reading the file.
     */
    private static FileInputStream getFileInputStream(final File file) throws Exception
    {
        return AccessController.doPrivileged(new PrivilegedExceptionAction<FileInputStream>()
        {
            @Override
            public FileInputStream run() throws Exception
            {
                try
                {
                    if (file.exists())
                    {
                        return new FileInputStream(file);
                    } else
                    {
                        return null;
                    }
                } catch (FileNotFoundException e)
                {
                    // couldn't find it, oh well.
                    return null;
                }
            }
        });
    }
    

    当我实例化我的客户机时,我会这样做,

    Feign.builder().client(getClientSSLSocketFactory(trustFile),null)...
    

    gist contains 示例代码及其用法。

        2
  •  2
  •   Niraj Sonawane    5 年前

    这就是我在 keystore truststore

    假装客户端配置

    @Configuration
    public class TestClientConfig {
    
        @Bean
        public Client feignClient() {
            Client trustSSLSockets = new Client.Default(getSSLSocketFactory(), new NoopHostnameVerifier());
            return trustSSLSockets;
        }
    
        private SSLSocketFactory getSSLSocketFactory() {
            try {
                TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        //Do your validations
                        return true;
                    }
                };
                String allPassword = "123456";
                SSLContext sslContext = SSLContextBuilder
                        .create()
                        // .loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.p12"), allPassword.toCharArray(), allPassword.toCharArray())
                        .loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.jks"), allPassword.toCharArray(), allPassword.toCharArray())
                        .loadTrustMaterial(ResourceUtils.getFile("classpath:truststore.jks"), allPassword.toCharArray())
                        .build();
                return sslContext.getSocketFactory();
            } catch (Exception exception) {
                throw new RuntimeException(exception);
            }
        }
    }
    

    界面

    @FeignClient(name = "Test", url = "https://localhost:8443",configuration=TestClientConfig.class)
    public interface TestClient {
    
        @RequestMapping(method = RequestMethod.GET,value = "/hello")
        String getHello();
    }
    
        3
  •  1
  •   Zoe - Save the data dump    2 年前

    多亏了Kannan和Niraj的回答,我成功地将我的外国客户机配置为使用CustomsSocketFactory。

    我的用例:我有一个API,它要求将SSL证书添加到JAVA cacerts上的本地机器上,以便获取它。但是,在云服务器上部署后,我无法添加此证书。因此,我需要配置我的外部客户端,以便从我的应用程序本身接收自定义信任存储。

    这是我的版本

    1. 使用添加的证书创建您自己的信任库 keytool -import -file <filepath-of-certificate> -alias <certificate-alias-name> -keystore <truststore-alias-name> 系统将提示输入密码,设置您自己的密码并记住它 Truststore不需要对此案例进行任何扩展

    2. 将此truststore文件复制到spring boot应用程序的资源文件夹

    3. 正在应用中。属性或应用程序。yml文件为您的信任库设置类路径和密码。我正在使用应用程序。yml因此示例如下

    e、 g。

    example-service:
      server: https://example.api.com
      trustStore: classpath:<Your truststore name>
      trustStorePassword: yourpassword
    

    您也可以跳过步骤3,直接传入下面的信任库和密码

    1. 在CustomFeignConfig类中,您可以直接将truststore作为资源传入,并直接将truststore inputstream传入sslsocketfactory。请注意,Bean表示法对于覆盖默认的外部配置至关重要。 对于我的案例,我只需要一个信任库,所以我在sslContext上传入一个空的新KeyManager[]{}。初始化()
    public class CustomFeignConfig {
    
        @Bean
        public Client feignClient(@Value("${example-service.trustStore}") Resource trustStoreResource,
                                  @Value("${example-service.trustStorePassword}") String trustStorePassword) throws Exception {
            try {
                return new Client.Default(
                        sslSocketFactory(trustStoreResource.getInputStream(), trustStorePassword),
                        null);
            } catch (Exception e) {
                throw new Exception("Error in initializing feign client", e);
            }
        }
    
        private static SSLSocketFactory sslSocketFactory(InputStream trustStoreStream, String trustStorePassword)
                throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, KeyManagementException {
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            TrustManagerFactory tmf = createTrustManager(trustStoreStream, trustStorePassword);
            sslContext.init(new KeyManager[]{}, tmf.getTrustManagers(), null);
            return sslContext.getSocketFactory();
        }
    
        private static TrustManagerFactory createTrustManager(InputStream trustStoreStream, String trustStorePassword)
                throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(trustStoreStream, trustStorePassword.toCharArray());
            TrustManagerFactory tmf = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);
            return tmf;
        }
    }    
    
    1. 仅将此自定义外部配置应用于需要它的api
    @FeignClient(name = "example-service", url = "${example-service.server}", configuration = CustomFeignConfig.class)
    public interface MyFeignClient {}