Spring WS 客户端 - 使用服务器和客户端证书进行身份验证

x80*_*486 4 ssl soap web-services spring-ws keystore

我需要能够对 SOAP 服务进行“客户端证书”身份验证。

\n\n

我正在使用 Spring WS。我有: a my.key、 amyCA.pem和 a myClient.crt

\n\n

这是我的相关 Java 代码(我知道它仍然很混乱,但我只是想让它先工作):

\n\n
public TheResponse doIt(TheRequest request) {\n  log.info("Sending request...");\n  try {\n    InputStream is = new FileInputStream(new File("src/main/resources/keystore.jks"));\n    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());\n    keyStore.load(is, "keystore!passwd".toCharArray());\n    is.close();\n    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n    keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());\n\n    InputStream is1 = new FileInputStream(new File("src/main/resources/truststore.jks"));\n    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());\n    trustStore.load(is1, "truststore!passwd".toCharArray());\n    is1.close();\n    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n    trustManagerFactory.init(trustStore);\n\n    HttpsUrlConnectionMessageSender messageSender = new HttpsUrlConnectionMessageSender();\n    messageSender.setKeyManagers(keyManagerFactory.getKeyManagers());\n    messageSender.setTrustManagers(trustManagerFactory.getTrustManagers());\n    setMessageSender(messageSender);\n\n    return (TheResponse) getWebServiceTemplate().marshalSendAndReceive(request,\n        new SoapActionCallback("https://domain/tld/icc/SomePathDownTheLine"));\n  } catch (Throwable e) {\n    log.error("Sh*t didn\'t work due to:", e);\n    throw new GatewayConnectionException(String.format("Unexpected error while sending request [%s]", e.getMessage()));\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这就是我构建信任库和密钥库的方式:

\n\n
# KeyStore\n$ openssl pkcs12 -export -in myClient.crt -inkey my.key -out keystore.p12 -name my_key -CAfile myCA.pem -caname root\n\n$ keytool -importkeystore -deststorepass keystore!passwd -destkeypass keystore!passwd -destkeystore keystore.jks \\\n  -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass keystore!passwd -alias my_key\n\n# Trustore (using truststore!passwd)\n$ keytool -import -trustcacerts -alias my_ca -file myCA.pem -keystore truststore.jks\n\n$ keytool -import -trustcacerts -alias my_cc -file myClient.crt -keystore truststore.jks\n
Run Code Online (Sandbox Code Playgroud)\n\n

...这些是验证步骤:

\n\n
$ keytool -list -keystore keystore.jks -storepass ********\n\nKeystore type: JKS\nKeystore provider: SUN\n\nYour keystore contains 1 entry\n\nmy_key, Oct 17, 2017, PrivateKeyEntry,\nCertificate fingerprint (SHA1): 1A:9D:6A:65:. . .:E6:C1:90\n\n$ keytool -list -keystore truststore.jks -storepass ********\n\nKeystore type: JKS\nKeystore provider: SUN\n\nYour keystore contains 2 entries\n\nmy_cc, Oct 17, 2017, trustedCertEntry,\nCertificate fingerprint (SHA1): 1A:9D:6A:65:. . .:E6:C1:90\nmy_ca, Oct 17, 2017, trustedCertEntry,\nCertificate fingerprint (SHA1): 36:82:F7:AB:. . .:70:B2:6C\n
Run Code Online (Sandbox Code Playgroud)\n\n

...但是,每当我请求 SOAP 操作时,我都会返回 HTTP 401 (Unauthorized) \xe2\x80\x94 org.springframework.ws.client.WebServiceTransportException: Unauthorized [401]

\n\n

有什么线索吗?顺便说一句,我基本上遵循指南。我对 SSL 证书和所有这些东西不是很熟悉。

\n\n
\n\n

更新

\n\n

SSL 握手工作正常。我可以通过设置-Djavax.net.debug=allVM 选项来了解它是如何工作的。现在发生的情况是,无论所有这些安全性如何,服务器也需要用户名和密码。

\n

x80*_*486 5

这一切都很好。最终,原因HTTP 401 (Unauthorized)是因为需要服务Basic auth而我没有发送。

\n\n

所有密钥库和信任库生成都是完美的。这是“最终”解决方案(使用 Spring Web 服务):

\n\n
  //\n  // Spring Config\n\n  // Inject messageSender() into a WebServiceTemplate or,\n  // Have a class that extends from WebServiceGatewaySupport\n\n  @Bean\n  public HttpsUrlConnectionMessageSender messageSender() throws Exception {\n    HttpsUrlConnectionMessageSender messageSender = new BasicAuthHttpsConnectionMessageSender(username, password);\n    messageSender.setTrustManagers(trustManagersFactoryBean().getObject());\n    messageSender.setKeyManagers(keyManagersFactoryBean().getObject());\n    return messageSender;\n  }\n\n  @Bean\n  public TrustManagersFactoryBean trustManagersFactoryBean() {\n    TrustManagersFactoryBean trustManagersFactoryBean = new TrustManagersFactoryBean();\n    trustManagersFactoryBean.setKeyStore(trustStore().getObject());\n    return trustManagersFactoryBean;\n  }\n\n  @Bean\n  public KeyManagersFactoryBean keyManagersFactoryBean() {\n    KeyManagersFactoryBean keyManagersFactoryBean = new KeyManagersFactoryBean();\n    keyManagersFactoryBean.setKeyStore(keyStore().getObject());\n    keyManagersFactoryBean.setPassword(keyStorePassword);\n    return keyManagersFactoryBean;\n  }\n\n  @Bean\n  public KeyStoreFactoryBean trustStore() {\n    KeyStoreFactoryBean keyStoreFactoryBean = new KeyStoreFactoryBean();\n    keyStoreFactoryBean.setLocation(new ClassPathResource("truststore.jks")); // Located in src/main/resources\n    keyStoreFactoryBean.setPassword(trustStorePassword);\n    return keyStoreFactoryBean;\n  }\n\n  @Bean\n  public KeyStoreFactoryBean keyStore() {\n    KeyStoreFactoryBean keyStoreFactoryBean = new KeyStoreFactoryBean();\n    keyStoreFactoryBean.setLocation(new ClassPathResource("keystore.jks"));\n    keyStoreFactoryBean.setPassword(keyStorePassword);\n    return keyStoreFactoryBean;\n  }\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n
// You might need org.springframework.ws:spring-ws-support in order to\n// have HttpsUrlConnectionMessageSender\npublic final class BasicAuthHttpsConnectionMessageSender extends HttpsUrlConnectionMessageSender {\n  private String b64Creds;\n\n  public BasicAuthHttpsConnectionMessageSender(String username, String password) {\n    b64Creds = Base64.getUrlEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));\n  }\n\n  @Override\n  protected void prepareConnection(HttpURLConnection connection) throws IOException {\n    connection.setRequestProperty(HttpHeaders.AUTHORIZATION, String.format("Basic %s", b64Creds));\n    super.prepareConnection(connection);\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

另请参考这个\ xe2\x80\x94 也是我自己问的O:)

\n\n

希望这可以帮助将来的人。我花了一段时间才把所有东西都整理好。

\n