Accès au service de repos Https en utilisant le temps de repos printanier

est-ce que quelqu'un peut me fournir un exemple de code pour accéder à l'url du service rest sécurisée avec https en utilisant le modèle spring rest.

j'ai le certificat, le nom d'utilisateur et mot de passe. L'authentification de base est utilisée du côté du serveur et je veux créer un client qui peut se connecter à ce serveur en utilisant le certificat fourni, le nom d'utilisateur et le mot de passe (si nécessaire).

28
demandé sur pramodc84 2013-07-12 20:44:12

5 réponses

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(new FileInputStream(new File(keyStoreFile)), keyStorePassword.toCharArray());

    SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
            new SSLContextBuilder()
                    .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                    .loadKeyMaterial(keyStore, keyStorePassword.toCharArray())
                    .build(),
            NoopHostnameVerifier.INSTANCE);

    HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();

    ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
    RestTemplate restTemplate = new RestTemplate(requestFactory);
    MyRecord record = restTemplate.getForObject(uri, MyRecord.class);
    LOG.debug(record.toString());
18
répondu Headroller 2016-07-01 15:39:37

Voici un code qui vous donnera une idée générale.

vous devez créer un custom ClientHttpRequestFactory pour faire confiance au certificat. Il ressemble à ceci:

final ClientHttpRequestFactory clientHttpRequestFactory =
        new MyCustomClientHttpRequestFactory(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER, serverInfo);
    restTemplate.setRequestFactory(clientHttpRequestFactory);

C'est la mise en œuvre de MyCustomClientHttpRequestFactory:

public class MyCustomClientHttpRequestFactory  extends SimpleClientHttpRequestFactory {

private final HostnameVerifier hostNameVerifier;
private final ServerInfo serverInfo;

public MyCustomClientHttpRequestFactory (final HostnameVerifier hostNameVerifier,
    final ServerInfo serverInfo) {
    this.hostNameVerifier = hostNameVerifier;
    this.serverInfo = serverInfo;
}

@Override
protected void prepareConnection(final HttpURLConnection connection, final String httpMethod)
    throws IOException {
    if (connection instanceof HttpsURLConnection) {
        ((HttpsURLConnection) connection).setHostnameVerifier(hostNameVerifier);
        ((HttpsURLConnection) connection).setSSLSocketFactory(initSSLContext()
            .getSocketFactory());
    }
    super.prepareConnection(connection, httpMethod);
}

private SSLContext initSSLContext() {
    try {
        System.setProperty("https.protocols", "TLSv1");

        // Set ssl trust manager. Verify against our server thumbprint
        final SSLContext ctx = SSLContext.getInstance("TLSv1");
        final SslThumbprintVerifier verifier = new SslThumbprintVerifier(serverInfo);
        final ThumbprintTrustManager thumbPrintTrustManager =
            new ThumbprintTrustManager(null, verifier);
        ctx.init(null, new TrustManager[] { thumbPrintTrustManager }, null);
        return ctx;
    } catch (final Exception ex) {
        LOGGER.error(
            "An exception was thrown while trying to initialize HTTP security manager.", ex);
        return null;
    }
}

Dans ce cas, mon serverInfo objet contient l'empreinte du serveur. Vous avez besoin de mettre en œuvre l' TrustManager interface pour obtenir SslThumbprintVerifier ou tout autre méthode que vous voulez vérifier votre certificat (vous pouvez aussi décider de aussi toujours retour true).

La valeur org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER permet tous les noms d'hôtes. Si vous avez besoin de vérifier le nom d'hôte, vous aurez besoin de mettre en œuvre différemment.

Je ne suis pas sûr de l'utilisateur et du mot de passe et de la façon dont vous l'avez implémenté. Souvent, vous devez ajouter un en-tête au restTemplateAuthorization avec une valeur qui ressemble à ceci: Base: <encoded user+password>. user+password doit être Base64 codé.

15
répondu Avi 2017-07-26 20:18:14

il s'agit d'une solution sans classe ni méthode dépréciée : (Approuvé par Java 8)

CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);

RestTemplate restTemplate = new RestTemplate(requestFactory);
7
répondu MaximeF 2018-07-11 14:59:26

voici ce que j'ai fini avec pour le problème similaire. L'idée est la même que dans la réponse de @Avi, mais je voulais aussi éviter le système statique".setroperty ("https.protocoles", "TLSv1");", de sorte que tout ajustement n'affectera pas le système. Inspiré par une réponse d'ici http://www.coderanch.com/t/637177/Security/Disabling-handshake-message-Java

public class MyCustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory {

@Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
    try {
        if (!(connection instanceof HttpsURLConnection)) {
            throw new RuntimeException("An instance of HttpsURLConnection is expected");
        }

        HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;

        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    }

                }
        };
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));

        httpsConnection.setHostnameVerifier((hostname, session) -> true);

        super.prepareConnection(httpsConnection, httpMethod);
    } catch (Exception e) {
        throw Throwables.propagate(e);
    }
}

/**
 * We need to invoke sslSocket.setEnabledProtocols(new String[] {"SSLv3"});
 * see http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html (Java 8 section)
 */
private static class MyCustomSSLSocketFactory extends SSLSocketFactory {

    private final SSLSocketFactory delegate;

    public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(final Socket socket, final String host, final int port, final boolean autoClose) throws IOException {
        final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
        return overrideProtocol(underlyingSocket);
    }

    @Override
    public Socket createSocket(final String host, final int port) throws IOException {
        final Socket underlyingSocket = delegate.createSocket(host, port);
        return overrideProtocol(underlyingSocket);
    }

    @Override
    public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort) throws IOException {
        final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
        return overrideProtocol(underlyingSocket);
    }

    @Override
    public Socket createSocket(final InetAddress host, final int port) throws IOException {
        final Socket underlyingSocket = delegate.createSocket(host, port);
        return overrideProtocol(underlyingSocket);
    }

    @Override
    public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress, final int localPort) throws IOException {
        final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
        return overrideProtocol(underlyingSocket);
    }

    private Socket overrideProtocol(final Socket socket) {
        if (!(socket instanceof SSLSocket)) {
            throw new RuntimeException("An instance of SSLSocket is expected");
        }
        ((SSLSocket) socket).setEnabledProtocols(new String[] {"SSLv3"});
        return socket;
    }
}
}
4
répondu Ruslan 2016-01-04 19:15:16

d'Un point de moi. J'ai utilisé une authentification mutuelle cert avec des microservices à amorçage. Ce qui suit fonctionne pour moi, keys point ici sont keyManagerFactory.initialisation.(..) et sslcontext.init (keyManagerFactory.getKeyManagers(), null, new SecureRandom()) lignes de code sans eux, au moins pour moi, les choses n'ont pas de travail. Les certificats sont conditionnés par PKCS12.

@Value("${server.ssl.key-store-password}")
private String keyStorePassword;
@Value("${server.ssl.key-store-type}")
private String keyStoreType;
@Value("${server.ssl.key-store}")
private Resource resource;

private RestTemplate getRestTemplate() throws Exception {
    return new RestTemplate(clientHttpRequestFactory());
}

private ClientHttpRequestFactory clientHttpRequestFactory() throws Exception {
    return new HttpComponentsClientHttpRequestFactory(httpClient());
}

private HttpClient httpClient() throws Exception {

    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
    KeyStore trustStore = KeyStore.getInstance(keyStoreType);

    if (resource.exists()) {
        InputStream inputStream = resource.getInputStream();

        try {
            if (inputStream != null) {
                trustStore.load(inputStream, keyStorePassword.toCharArray());
                keyManagerFactory.init(trustStore, keyStorePassword.toCharArray());
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    } else {
        throw new RuntimeException("Cannot find resource: " + resource.getFilename());
    }

    SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
    sslcontext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
    SSLConnectionSocketFactory sslConnectionSocketFactory =
            new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null, getDefaultHostnameVerifier());

    return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
}
2
répondu toootooo 2016-04-22 11:43:08