복붙노트

[SPRING] Spring RestTemplate을 사용하여 Https Rest Service에 액세스

SPRING

Spring RestTemplate을 사용하여 Https Rest Service에 액세스

누구나 스프링 샘플 템플릿을 사용하여 https로 보호되는 휴식 서비스 URL에 액세스하는 코드 샘플을 제게 제공 할 수 있습니까?

인증서, 사용자 이름 및 암호가 있습니다. 기본 인증은 서버 측에서 사용되며 제공된 인증서, 사용자 이름 및 암호 (필요한 경우)를 사용하여 해당 서버에 연결할 수있는 클라이언트를 만들고 싶습니다.

해결법

  1. ==============================

    1.

        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());
    
  2. ==============================

    2.일반적인 아이디어를 줄 수있는 몇 가지 코드가 있습니다.

    일반적인 아이디어를 줄 수있는 몇 가지 코드가 있습니다.

    인증서를 신뢰하려면 사용자 지정 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 값은 모든 호스트 이름을 허용합니다. 호스트 이름을 확인해야하는 경우, 다르게 구현해야합니다.

    사용자와 암호 및 구현 방법에 대해 잘 모르겠습니다. 자주, Authorization이라는 restTemplate에 헤더를 추가해야합니다. 이 값은 Base : 와 같습니다. 사용자 + 암호는 Base64로 인코딩되어야합니다.

  3. ==============================

    3.이 메소드는 더 이상 사용되지 않는 클래스 또는 메소드가없는 솔루션입니다. (Java 8 승인)

    이 메소드는 더 이상 사용되지 않는 클래스 또는 메소드가없는 솔루션입니다. (Java 8 승인)

    CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
    
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);
    
    RestTemplate restTemplate = new RestTemplate(requestFactory);
    
  4. ==============================

    4.여기 내가 비슷한 문제로 끝난 것이다. 아이디어는 @ Avi의 답변과 동일하지만 정적 인 "System.setProperty ("https.protocols ","TLSv1 ");"을 피하기 위해 모든 조정이 시스템에 영향을주지 않습니다. 여기에서 응답에 의해 고무시켰다 http://www.coderanch.com/t/637177/Security/Disabling-handshake-message-Java

    여기 내가 비슷한 문제로 끝난 것이다. 아이디어는 @ 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;
        }
    }
    }
    
  5. ==============================

    5.나 한테서 요. 나는 스프링 부트 마이크로 서비스와 상호 인증서 인증을 사용했다. 다음은 나를 위해 일하고있다, 열쇠는 여기에있다. keyManagerFactory.init (...) 및 sslcontext.init (keyManagerFactory.getKeyManagers (), null, 새로운 SecureRandom ()) 코드를 사용하지 않고도 최소한의 작업만으로는 작동하지 않았습니다. 인증서는 PKCS12에 의해 패키지됩니다.

    나 한테서 요. 나는 스프링 부트 마이크로 서비스와 상호 인증서 인증을 사용했다. 다음은 나를 위해 일하고있다, 열쇠는 여기에있다. keyManagerFactory.init (...) 및 sslcontext.init (keyManagerFactory.getKeyManagers (), null, 새로운 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();
    }
    
  6. from https://stackoverflow.com/questions/17619871/access-https-rest-service-using-spring-resttemplate by cc-by-sa and MIT license