getforobject - Acceda al servicio de descanso Https usando Spring RestTemplate
resttemplate getforobject headers (5)
Aquí está lo que terminé con el problema similar. La idea es la misma que en la respuesta de @ Avi, pero también quería evitar la estática "System.setProperty (" https.protocols "," TLSv1 ");", para que los ajustes no afecten al sistema. Inspirado por una respuesta de aquí 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;
}
}
}
¿Alguien puede proporcionarme un ejemplo de código para acceder a la URL del servicio de descanso asegurada con https usando la plantilla de descanso de primavera?
Tengo el certificado, nombre de usuario y contraseña. La autenticación básica se utiliza en el lado del servidor y quiero crear un cliente que pueda conectarse a ese servidor utilizando el certificado, el nombre de usuario y la contraseña proporcionados (si es necesario).
Aquí hay un código que le dará la idea general.
ClientHttpRequestFactory
crear un ClientHttpRequestFactory
personalizado para poder confiar en el certificado. Se parece a esto:
final ClientHttpRequestFactory clientHttpRequestFactory =
new MyCustomClientHttpRequestFactory(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER, serverInfo);
restTemplate.setRequestFactory(clientHttpRequestFactory);
Esta es la implementación 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;
}
}
En este caso, mi objeto serverInfo
contiene la huella digital del servidor. TrustManager
implementar la interfaz de TrustManager
para obtener el SslThumbprintVerifier
o cualquier otro método que desee para verificar su certificado (también puede decidir devolver siempre el valor true
).
El valor org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
permite todos los nombres de host. Si necesita verificar el nombre del host, deberá implementarlo de manera diferente.
No estoy seguro sobre el usuario y la contraseña y cómo lo implementó. A menudo, es necesario agregar un encabezado a la restTemplate
denominada Authorization
con un valor similar al siguiente: Base: <encoded user+password>
. El user+password
debe estar codificado en Base64
.
Esta es una solución sin clase ni método en desuso: (Java 8 aprobado)
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
Un punto de mi parte. Utilicé una autenticación cert mutua con microservicios de arranque por resorte. Lo siguiente está funcionando para mí, los puntos clave aquí son keyManagerFactory.init (...) y sslcontext.init (keyManagerFactory.getKeyManagers (), null, nuevas líneas de código SecureRandom ()) sin ellas, al menos para mí, las cosas no funcionaron. Los certificados son empaquetados por 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();
}
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());