package org.opendaylight.defense4all.odl.controller;
import java.io.IOException;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.List;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
//TODO: does it use the credentials and authScope at all???
public class RestTemplateFactory {
// INSTANCE;//Singleton
public RestTemplateFactory(){}
public static RestTemplateFactory INSTANCE = new RestTemplateFactory();//TODO:to be removed
// public static RestTemplateFactory getInstance(){
// return INSTANCE;
// }
private static Logger log = LoggerFactory.getLogger(RestTemplateFactory.class);
private boolean isInsecureSsl = false; //false = supports SSL by accept all (insecure), true = ssl.
private String trustStore = null;// "/home/sagii/workspace/tmp/cacerts.my3";
private boolean isWriteAcceptCharset = false;//from some reason RestTemplate tend to add "Accept" header that causes problem. I disable it by default.
public RestTemplate createRestTemplate(AuthScope authScope, UsernamePasswordCredentials credentials) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
RestTemplate restTemplate;
if(isInsecureSsl){
restTemplate = createInsecureSSLRestTemplate(authScope, credentials);
} else {
restTemplate = createSecureSSLRestTemplate(authScope, credentials);
}
return restTemplate;
}
/*
* factory with hardcoded predefined host,port,user,password. for tests only.
*/
@Deprecated
public RestTemplate createInsecureSSLRestTemplate() throws NoSuchAlgorithmException, KeyManagementException{
String host = "10.206.102.49";
int port = 8443;
AuthScope authScope = new AuthScope(host, port, AuthScope.ANY_REALM);
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("sdn","skyline");//odlOFC.username,odlOFC.password);
// return createInsecureSSLRestTemplate(authScope, credentials);
return createInsecureSSLRestTemplate(authScope,credentials);
}
/*
* factory with hardcoded predefined host,port,user,password. for tests only.
*/
@Deprecated
public RestTemplate createRestTemplate() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException{
String host = "10.206.102.49";
int port = 8443;
AuthScope authScope = new AuthScope(host, port, AuthScope.ANY_REALM);
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("sdn","skyline");//odlOFC.username,odlOFC.password);
// return createInsecureSSLRestTemplate(authScope, credentials);
return createRestTemplate(authScope,credentials);
}
public static class EnhancedHttpComponentsClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {
public EnhancedHttpComponentsClientHttpRequestFactory(HttpClient httpClient) { super(httpClient);}
@Override
protected HttpUriRequest createHttpUriRequest(
HttpMethod httpMethod, URI uri) {
if (HttpMethod.DELETE == httpMethod) {
return new HttpEntityEnclosingDeleteRequest(uri);
}
return super.createHttpUriRequest(httpMethod, uri);
}
}
//to add delete body support for restTemplate
public static class HttpEntityEnclosingDeleteRequest extends HttpEntityEnclosingRequestBase{
public HttpEntityEnclosingDeleteRequest(final URI uri) {
super();
setURI(uri);
}
@Override
public String getMethod() {
return "DELETE";
}
}
public RestTemplate createSecureSSLRestTemplate(AuthScope authScope, UsernamePasswordCredentials credentials) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
if(trustStore != null){
System.setProperty("javax.net.ssl.trustStore", trustStore);//"/home/sagii/workspace/tmp/cacerts.my3");
} else {
log.debug("trustStore is not configured in the "+ this.getClass() + " bean");
}
//This requires at installation to add certificate to the truststore TODO: add instructions.
TrustManager[] trustManagers = getDefaultTrustManagers();
RestTemplate restTemplate = createRestTemplate(authScope, credentials,
trustManagers, null);
return restTemplate;
}
private TrustManager[] getDefaultTrustManagers() throws NoSuchAlgorithmException, KeyStoreException{
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore)null);
return trustManagerFactory.getTrustManagers();
}
// insecure RestTemplate that supports SSL
public RestTemplate createInsecureSSLRestTemplate(AuthScope authScope, UsernamePasswordCredentials credentials) throws NoSuchAlgorithmException, KeyManagementException {
X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
public void verify(String host, SSLSocket ssl) throws IOException {}
public void verify(String host, X509Certificate cert) throws SSLException {}
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {}
};
TrustManager[] trustAllCerts = { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return null;}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
} };
//TODO: does this overrides credentials???
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
RestTemplate restTemplate = createRestTemplate(authScope, credentials,
trustAllCerts, hostnameVerifier);
return restTemplate;
}
public RestTemplate createRestTemplate(AuthScope authScope, UsernamePasswordCredentials credentials,
TrustManager[] trustManagers, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
authScope,// new AuthScope(null, -1),
credentials);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustManagers, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpClientBuilder httpClientBuilder = HttpClients.custom();
if (hostnameVerifier != null) {
httpClientBuilder.setHostnameVerifier(hostnameVerifier);
}
// httpClientBuilder.setDefaultCredentialsProvider(credsProvider)
httpClientBuilder.setSslcontext(sc);
HttpClient httpClient = httpClientBuilder.build();
HttpComponentsClientHttpRequestFactory fac = new EnhancedHttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(fac);
if(!isWriteAcceptCharset){
disableWriteAcceptCharset(restTemplate);
}
return restTemplate;
}
private void disableWriteAcceptCharset(RestTemplate restTemplate){
List<HttpMessageConverter<?>> c = restTemplate.getMessageConverters();
for(HttpMessageConverter<?> mc :c){
if (mc instanceof StringHttpMessageConverter) {
StringHttpMessageConverter mcc = (StringHttpMessageConverter) mc;
mcc.setWriteAcceptCharset(false);
}
}
}
public boolean isInsecureSsl() {
return isInsecureSsl;
}
public void setInsecureSsl(boolean isInsecureSsl) {
this.isInsecureSsl = isInsecureSsl;
}
public String getTrustStore() {
return trustStore;
}
public void setTrustStore(String trustStore) {
this.trustStore = trustStore;
}
public boolean isWriteAcceptCharset() {
return isWriteAcceptCharset;
}
public void setWriteAcceptCharset(boolean isWriteAcceptCharset) {
this.isWriteAcceptCharset = isWriteAcceptCharset;
}
@Override
public String toString() {
return "RestTemplateFactory.INSTANCE [isSsDisabled=" + isInsecureSsl
+ ", trustStore=" + trustStore + ", isWriteAcceptCharset="
+ isWriteAcceptCharset + "]";
}
//
public RestTemplate createInsecureSSLRestTemplateOld(AuthScope authScope, UsernamePasswordCredentials credentials) throws NoSuchAlgorithmException, KeyManagementException{
// try {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
authScope,// new AuthScope(null, -1),
credentials);
X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
public void verify(String host, SSLSocket ssl) throws IOException {}
public void verify(String host, X509Certificate cert) throws SSLException {}
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {}
};
TrustManager[] trustAllCerts = { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return null;}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
} };
SSLContext sc = SSLContext.getInstance("SSL");
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
HttpClient httpClient = HttpClients.custom()
// .setDefaultCredentialsProvider(credsProvider)
.setHostnameVerifier(hostnameVerifier)
.setSslcontext(sc)
.build();
HttpComponentsClientHttpRequestFactory fac = new HttpComponentsClientHttpRequestFactory(httpClient){
@Override
protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
if (HttpMethod.DELETE == httpMethod) {
return new HttpEntityEnclosingDeleteRequest(uri);
}
return super.createHttpUriRequest(httpMethod, uri);
}
};
RestTemplate restTemplate = new RestTemplate(fac);
List<HttpMessageConverter<?>> c = restTemplate.getMessageConverters();
for(HttpMessageConverter<?> mc :c){
if (mc instanceof StringHttpMessageConverter) {
StringHttpMessageConverter mcc = (StringHttpMessageConverter) mc;
mcc.setWriteAcceptCharset(false);
}
}
return restTemplate;
}
}