2017-10-17 10 views
0

Je dois être en mesure d'effectuer une authentification "client cert" pour un service SOAP. J'utilise Spring WS. J'ai: un my.key, un myCA.pem, et un myClient.crt.Spring WS Client - Authentification avec des certificats serveur et client

Ceci est mon morceau de Java pertinent code (je sais qu'il est toujours compliqué, mais je suis juste essayer pour faire fonctionner en premier):

public TheResponse doIt(TheRequest request) { 
    log.info("Sending request..."); 
    try { 
    InputStream is = new FileInputStream(new File("src/main/resources/keystore.jks")); 
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
    keyStore.load(is, "keystore!passwd".toCharArray()); 
    is.close(); 
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
    keyManagerFactory.init(keyStore, keyStorePassword.toCharArray()); 

    InputStream is1 = new FileInputStream(new File("src/main/resources/truststore.jks")); 
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
    trustStore.load(is1, "truststore!passwd".toCharArray()); 
    is1.close(); 
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    trustManagerFactory.init(trustStore); 

    HttpsUrlConnectionMessageSender messageSender = new HttpsUrlConnectionMessageSender(); 
    messageSender.setKeyManagers(keyManagerFactory.getKeyManagers()); 
    messageSender.setTrustManagers(trustManagerFactory.getTrustManagers()); 
    setMessageSender(messageSender); 

    return (TheResponse) getWebServiceTemplate().marshalSendAndReceive(request, 
     new SoapActionCallback("https://domain/tld/icc/SomePathDownTheLine")); 
    } catch (Throwable e) { 
    log.error("Sh*t didn't work due to:", e); 
    throw new GatewayConnectionException(String.format("Unexpected error while sending request [%s]", e.getMessage())); 
    } 
} 

Voilà comment je vais construire la confiance - et magasins: claviers

# KeyStore 
$ openssl pkcs12 -export -in myClient.crt -inkey my.key -out keystore.p12 -name my_key -CAfile myCA.pem -caname root 

$ keytool -importkeystore -deststorepass keystore!passwd -destkeypass keystore!passwd -destkeystore keystore.jks \ 
    -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass keystore!passwd -alias my_key 

# Trustore (using truststore!passwd) 
$ keytool -import -trustcacerts -alias my_ca -file myCA.pem -keystore truststore.jks 

$ keytool -import -trustcacerts -alias my_cc -file myClient.crt -keystore truststore.jks 

... et ce sont les étapes de vérification:

$ keytool -list -keystore keystore.jks -storepass ******** 

Keystore type: JKS 
Keystore provider: SUN 

Your keystore contains 1 entry 

my_key, Oct 17, 2017, PrivateKeyEntry, 
Certificate fingerprint (SHA1): 1A:9D:6A:65:. . .:E6:C1:90 

$ keytool -list -keystore truststore.jks -storepass ******** 

Keystore type: JKS 
Keystore provider: SUN 

Your keystore contains 2 entries 

my_cc, Oct 17, 2017, trustedCertEntry, 
Certificate fingerprint (SHA1): 1A:9D:6A:65:. . .:E6:C1:90 
my_ca, Oct 17, 2017, trustedCertEntry, 
Certificate fingerprint (SHA1): 36:82:F7:AB:. . .:70:B2:6C 

... mais quand je demande l'action SOAP, je récupère un HTTP 401 (Unauthorized) - org.springframework.ws.client.WebServiceTransportException: Unauthorized [401].

Des indices? En passant, je suis à peu près suivant le guide this. Je ne connais pas très bien les certificats SSL et tout ce genre de choses.


MISE À JOUR

La poignée de main SSL fonctionne correctement. Je peux voir comment cela fonctionne en définissant l'option -Djavax.net.debug=all VM. Qu'est-ce qui se passe maintenant, c'est que, malgré toute cette sécurité, le serveur a également besoin d'un nom d'utilisateur et mot de passe.

Répondre

0

Tout était OK. Finalement, la raison pour le HTTP 401 (Unauthorized) était parce que le service requis Basic auth et je ne l'envoyais pas.

Toute la génération de keystore et de truststore est parfaite. Ceci est la solution "finale" (en utilisant les services Web Spring):

// 
    // Spring Config 

    // Inject messageSender() into a WebServiceTemplate or, 
    // Have a class that extends from WebServiceGatewaySupport 

    @Bean 
    public HttpsUrlConnectionMessageSender messageSender() throws Exception { 
    HttpsUrlConnectionMessageSender messageSender = new BasicAuthHttpsConnectionMessageSender(username, password); 
    messageSender.setTrustManagers(trustManagersFactoryBean().getObject()); 
    messageSender.setKeyManagers(keyManagersFactoryBean().getObject()); 
    return messageSender; 
    } 

    @Bean 
    public TrustManagersFactoryBean trustManagersFactoryBean() { 
    TrustManagersFactoryBean trustManagersFactoryBean = new TrustManagersFactoryBean(); 
    trustManagersFactoryBean.setKeyStore(trustStore().getObject()); 
    return trustManagersFactoryBean; 
    } 

    @Bean 
    public KeyManagersFactoryBean keyManagersFactoryBean() { 
    KeyManagersFactoryBean keyManagersFactoryBean = new KeyManagersFactoryBean(); 
    keyManagersFactoryBean.setKeyStore(keyStore().getObject()); 
    keyManagersFactoryBean.setPassword(keyStorePassword); 
    return keyManagersFactoryBean; 
    } 

    @Bean 
    public KeyStoreFactoryBean trustStore() { 
    KeyStoreFactoryBean keyStoreFactoryBean = new KeyStoreFactoryBean(); 
    keyStoreFactoryBean.setLocation(new ClassPathResource("truststore.jks")); // Located in src/main/resources 
    keyStoreFactoryBean.setPassword(trustStorePassword); 
    return keyStoreFactoryBean; 
    } 

    @Bean 
    public KeyStoreFactoryBean keyStore() { 
    KeyStoreFactoryBean keyStoreFactoryBean = new KeyStoreFactoryBean(); 
    keyStoreFactoryBean.setLocation(new ClassPathResource("keystore.jks")); 
    keyStoreFactoryBean.setPassword(keyStorePassword); 
    return keyStoreFactoryBean; 
    } 

// You might need org.springframework.ws:spring-ws-support in order to 
// have HttpsUrlConnectionMessageSender 
public final class BasicAuthHttpsConnectionMessageSender extends HttpsUrlConnectionMessageSender { 
    private String b64Creds; 

    public BasicAuthHttpsConnectionMessageSender(String username, String password) { 
    b64Creds = Base64.getUrlEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8)); 
    } 

    @Override 
    protected void prepareConnection(HttpURLConnection connection) throws IOException { 
    connection.setRequestProperty(HttpHeaders.AUTHORIZATION, String.format("Basic %s", b64Creds)); 
    super.prepareConnection(connection); 
    } 
} 

Consultez également ce one - également demandé par moi-même :) O

espère que cela peut aider quelqu'un dans le futur. Il m'a fallu du temps pour tout mettre en place.