it-swarm.dev

يمكنك الوصول إلى خدمة Https Rest Service باستخدام Spring RestTemplate

هل يمكن لأي شخص أن يزودني بنموذج رمز للوصول إلى عنوان url الخاص بالخدمة الباقي مؤمّنًا باستخدام https باستخدام نموذج spring rest.

لدي الشهادة واسم المستخدم وكلمة المرور. يتم استخدام المصادقة الأساسية على جانب الخادم وأريد إنشاء عميل يمكنه الاتصال بهذا الخادم باستخدام الشهادة المقدمة واسم المستخدم وكلمة المرور (إذا لزم الأمر).

40
zdesam
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());
27
Headroller

إليك بعض الرموز التي ستمنحك الفكرة العامة.

تحتاج إلى إنشاء مخصص ClientHttpRequestFactory لكي تثق في الشهادة. تبدو هكذا:

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

هذا هو التنفيذ لـ 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;
    }
}

في هذه الحالة ، يحتوي كائن serverInfo على بصمة الإبهام الخاصة بالخادم. تحتاج إلى تنفيذ واجهة TrustManager للحصول على SslThumbprintVerifier أو أي طريقة أخرى تريد التحقق من شهادتك (يمكنك أيضًا أن تقرر أيضًا إرجاع true) دائمًا.

القيمة org.Apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER يسمح لجميع أسماء المضيف. إذا كنت بحاجة إلى التحقق من اسم المضيف ، فستحتاج إلى تنفيذه بشكل مختلف.

لست متأكدًا من المستخدم وكلمة المرور وكيفية تنفيذها. غالبًا ما تحتاج إلى إضافة رأس إلى restTemplate المسمى Authorization بقيمة تشبه هذا: Base: <encoded user+password>. ال user+password لا بد وأن Base64 مشفرة.

16
Avi

هذا هو الحل مع لا إهمال فئة أو الطريقة: (جافا 8 المعتمدة)

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

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

RestTemplate restTemplate = new RestTemplate(requestFactory);
8
MaximeF

إليكم ما انتهيت إليه من مشكلة مماثلة. الفكرة هي نفسها كما في إجابة @ Avi ، لكنني أردت أيضًا تجنب "System.setProperty" الثابت ("https.protocols" ، "TLSv1") ؛ "، حتى لا تؤثر أي تعديلات على النظام. مستوحاة من إجابة من هنا 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;
    }
}
}
3
Ruslan

نقطة واحدة مني. لقد استخدمت مصادقة سيرت متبادلة مع microservices الربيع التمهيد. ما يلي يعمل بالنسبة لي ، والنقاط الرئيسية هنا هي keyManagerFactory.init(...) و sslcontext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom()) أسطر من الشفرة بدونها ، على الأقل بالنسبة لي ، لم تنجح الأمور. يتم حزم الشهادات بواسطة 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
toootooo