web-dev-qa-db-fra.com

Client SSL Spring Boot

Je suis nouveau à Spring Boot. Jusqu'ici je l'apprécie. J'ai développé un serveur Web de repos SSL de démonstration qui gère correctement l'authentification de certificat mutuelle X.509. À l'aide d'un navigateur IE avec des certificats client et serveur auto-signés, j'ai vérifié le bon fonctionnement du serveur Web de démonstration. Le serveur et le navigateur échangent et valident les certificats l'un avec l'autre.

Je ne parviens pas à trouver un exemple de client SSL qui montre comment inclure le certificat client et émettre le https. Quelqu'un at-il un exemple de client de repos simple qui montre comment utiliser mon serveur SSL?

Cordialement, Steve Mansfield

7
skmansfield

Je ne pouvais pas faire en sorte que le client susmentionné soumis par Andy fonctionne. Je n'arrêtais pas de recevoir des erreurs disant que "localhost! = Clientname". Quoi qu'il en soit, je dois que cela fonctionne correctement.

 import Java.io.IOException;

 import org.Apache.commons.httpclient.HttpClient;
 import org.Apache.commons.httpclient.HttpException;
 import org.Apache.commons.httpclient.URI;
 import org.Apache.commons.httpclient.methods.GetMethod;

 public class SSLClient {

      static
        {
          System.setProperty("javax.net.ssl.trustStore","c:/apachekeys/client1.jks");
          System.setProperty("javax.net.ssl.trustStorePassword", "password");
          System.setProperty("javax.net.ssl.keyStore", "c:/apachekeys/client1.jks");
          System.setProperty("javax.net.ssl.keyStorePassword", "password");
       }

     public static void main(String[] args) throws HttpException, IOException {

         HttpClient client = new HttpClient();
         GetMethod method = new GetMethod();
         method.setURI(new URI("https://localhost:8443/restserver", false));
         client.executeMethod(method);

         System.out.println(method.getResponseBodyAsString());

     }

 }
7
skmansfield

Étant donné que vous utilisez Spring, voici un exemple qui montre comment utiliser la variable RestTemplate de Spring et la variable HttpClient d'Apache configurée avec un certificat client et comment faire confiance à un certificat auto-signé du serveur:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(new File("keystore.jks")),
        "secret".toCharArray());
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
        new SSLContextBuilder()
                .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                .loadKeyMaterial(keyStore, "password".toCharArray()).build());
HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
        httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
ResponseEntity<String> response = restTemplate.getForEntity(
        "https://localhost:8443", String.class);
10
Andy Wilkinson

L'exemple de user1707141 n'a pas fonctionné pour moi et skmansfield semble plutôt dépendre de fichiers spécifiques, ce qui n'est pas une convention avec Spring Boot/Maven. La réponse de Andy Wilkinson _ _ utilise également le constructeur SSLConnectionSocketFactory, obsolète dans Apache httpclient 4.4+ et qui semble également assez complexe. 

J'ai donc créé un exemple de projet qui devrait montrer tout 100% compréhensible ici: https://github.com/jonashackt/spring-boot-rest-clientcertificate }

Outre l'utilisation normale de RestTemplate avec @Autowired dans votre Testclass, assurez-vous de configurer votre RestTemplate comme suit:

package de.jonashackt.restexamples;

import org.Apache.http.client.HttpClient;
import org.Apache.http.impl.client.HttpClients;
import org.Apache.http.ssl.SSLContextBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.ResourceUtils;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;

@Configuration
public class RestClientCertTestConfiguration {

    private String allPassword = "allpassword";

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {

        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.jks"), allPassword.toCharArray(), allPassword.toCharArray())
                .loadTrustMaterial(ResourceUtils.getFile("classpath:truststore.jks"), allPassword.toCharArray())
                .build();

        HttpClient client = HttpClients.custom()
                .setSSLContext(sslContext)
                .build();

        return builder
                .requestFactory(new HttpComponentsClientHttpRequestFactory(client))
                .build();
    }
}
3
jonashackt

Je sais que c'est trop tard, mais voici le code qui fonctionne pour moi. 

@SpringBootApplication
public class Application {

	private static final Logger log = LoggerFactory.getLogger(Application.class);

	public static void main(String args[]) {

			makeWebServiceCall();

	}
	
	public static void makeWebServiceCall() {
		TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

		SSLContext sslContext;
		ResponseEntity<String> response = null;
		try {
			sslContext = org.Apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy)
					.build();

			SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);

			CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();

			HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();

			requestFactory.setHttpClient(httpClient);

			RestTemplate restTemplate = new RestTemplate(requestFactory);
			
			StringBuffer plainCreds = new StringBuffer();
			plainCreds.append("username");
			plainCreds.append(":");
			plainCreds.append("password");
			byte[] plainCredsBytes = plainCreds.toString().getBytes();
			byte[] base64CredsBytes = Base64.getEncoder().encode(plainCredsBytes);
			String userBase64Credentials = new String(base64CredsBytes);
			

			HttpHeaders headers = new HttpHeaders();
			headers.add("Authorization", "Basic " + userBase64Credentials);
			headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
			headers.setContentType(MediaType.APPLICATION_JSON);

			HttpEntity entity = new HttpEntity<>(headers);

			String url = "https:restUrl";
			
			response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
			
			if(response.getStatusCodeValue() == 200) {
				log.info("Success! Further processing based on the need");
			} else {
				log.info("****************Status code received: " + response.getStatusCodeValue() + ".************************");
			}

		} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
			log.error("Exception occured. Here are the exception details: ", e);
		} catch(HttpClientErrorException e) {
			if(e.getRawStatusCode() == 403) {
				log.info("****************Status code received: " + e.getRawStatusCode() + ". You do not have access to the requested resource.************************");
				
			} else if(e.getRawStatusCode() == 404) {
				log.info("****************Status code received: " + e.getRawStatusCode() + ". Resource does not exist(or) the service is not up.************************");

			} else if(e.getRawStatusCode() == 400) {
				log.info("****************Status code received: " + e.getRawStatusCode() + ". Bad Request.************************");

			} else {
				log.info("****************Status code received: " + e.getRawStatusCode() + ".************************");
				
			}

           log.info("****************Response body: " + e.getResponseBodyAsString() + "************************");
		}
	}
 }

Voici le maven déposé

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.Apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.springframework</groupId>
<artifactId>gs-consuming-rest</artifactId>
<version>0.1.0</version>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.2.RELEASE</version>
</parent>

<properties>
    <Java.version>1.8</Java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>

<!-- https://mvnrepository.com/artifact/org.Apache.httpcomponents/httpclient -->
<dependency>
    <groupId>org.Apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.3</version>
</dependency>


        <!-- https://mvnrepository.com/artifact/org.Apache.httpcomponents/httpcore -->
<dependency>
    <groupId>org.Apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.6</version>
</dependency>


</dependencies>


<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

0
user1707141

Une autre façon de faire ça. Injecter les valeurs pour keyStoreLocation et keyStorePassword

@Configuration
public class SampleSSLClient extends RestTemplate{







  /** The key store password. */
  private  String keyStorePassword;

  /** The key store location. */
  private  String keyStoreLocation;




    /** The rest template. */
    @Autowired
    private RestTemplate restTemplate;

     /** The http components client http request factory. */
    private  HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory;

    /**
     * Instantiates a new custom rest template.
     */
    public CustomRestTemplate() {
        super();
    }

    public CustomRestTemplate(RestTemplate restTemplate){
        this.restTemplate = getRestTemplate();
    }



    /**
     * Rest template.
     *
     * @return the rest template
     */
    public RestTemplate getRestTemplate()  {
        if (null == httpComponentsClientHttpRequestFactory) {
            httpComponentsClientHttpRequestFactory = loadCert();
            restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory);
        }
        return restTemplate;
    }

    /**
     * Load cert.
     *
     * @return the http components client http request factory
     */
    private HttpComponentsClientHttpRequestFactory loadCert()  {
        try {
            char[] keypass = keyStorePassword.toCharArray();
            SSLContext sslContext = SSLContextBuilder.create()
                    .loadKeyMaterial(getkeyStore(keyStoreLocation, keypass), keypass)
                    .loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
            HttpClient client = HttpClients.custom().setSSLContext(sslContext).build();
            httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(client);
            httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
            httpComponentsClientHttpRequestFactory.setReadTimeout(30000);
        } catch (Exception ex) {
            LOGGER.error(MessageFormat.format("Some Error", ex.getMessage()), ex);

        }
        return httpComponentsClientHttpRequestFactory;
    }

     /**
     * Key store.
     *
     * @param storePath the store path
     * @param password the password
     * @return the key store
     */
    private KeyStore getkeyStore(String storePath, char[] password) {
        KeyStore keyStore;
        try {
            keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            File key = ResourceUtils.getFile(storePath);
            try (InputStream in = new FileInputStream(key)) {
                keyStore.load(in, password);
            }
        }catch (Exception ex) {
            LOGGER.error(MessageFormat.format("Some Error", ex.getMessage()), ex);

        }
        return keyStore;
    }



    /**
     * Sets the key store password.
     *
     * @param keyStorePassword the new key store password
     */
    public void setKeyStorePassword(String keyStorePassword) {
        this.keyStorePassword = keyStorePassword;
    }


    /**
     * Sets the key store location.
     *
     * @param keyStoreLocation the new key store location
     */
    public void setKeyStoreLocation(String keyStoreLocation) {
        this.keyStoreLocation = keyStoreLocation;
    }



    /**
     * Sets the rest template.
     *
     * @param restTemplate the new rest template
     */
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
0
Sireesh Yarlagadda