/*
* Copyright (c) 2012-2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.vasa.util;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Collections;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.log4j.Logger;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.ClientFilter;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.api.client.filter.LoggingFilter;
public class RESTClientUtil {
private static final Logger log = Logger.getLogger(RESTClientUtil.class);
private final static String AUTH_TOKEN_HEADER = "X-SDS-AUTH-TOKEN";
private String _baseURL;
// private boolean _authorizationFlag;
private ClientConfig _config;
private Client _client;
private String _username;
private String _password;
private static final int CALL_COUNT_FOR_AUTHENTICATION = 10;
public RESTClientUtil(String baseURL) {
this._baseURL = baseURL;
log.trace("base URL:" + this._baseURL);
// this._authorizationFlag = false;
_config = new DefaultClientConfig();
_client = Client.create(_config);
}
/**
*
* @param uri
* endpoint uri of REST api
* @param clazz
* the class of data object to be binded with as response
* @return the response data object
* @throws NoSuchAlgorithmException
* @throws UniformInterfaceException
*/
public <T> T queryObject(String uri, Class<T> clazz)
throws NoSuchAlgorithmException, UniformInterfaceException {
final String methodName = "queryObject(): ";
log.trace(methodName + "Entry with inputs uri[" + uri + "] class["
+ clazz.getName() + "]");
_config.getClasses().add(clazz);
/*
* if (this._authorizationFlag) { this.authenticate(_client); }
*/
WebResource resource = null;
try {
resource = _client.resource(_baseURL + uri);
return resource.get(clazz);
} catch (UniformInterfaceException e) {
if (e.getMessage().contains("401 Unauthorized")
|| e.getMessage().contains("403 Forbidden")) {
this.authenticate(_client, CALL_COUNT_FOR_AUTHENTICATION);
resource = _client.resource(_baseURL + uri);
return resource.get(clazz);
} else {
throw e;
}
}
}
public void setLoginCredentials(String username, String password)
throws NoSuchAlgorithmException {
// this._authorizationFlag = true;
this._username = username;
this._password = password;
try {
this.authenticate(_client, CALL_COUNT_FOR_AUTHENTICATION);
} catch (NoSuchAlgorithmException e) {
throw e;
}
log.trace("username and password are set");
}
private void authenticate(final Client c, final int authenticateCallCount)
throws NoSuchAlgorithmException {
final String methodName = "authenticate(): ";
log.debug(methodName + "Called");
disableCertificateValidation();
c.setFollowRedirects(false);
if (log.isTraceEnabled()) {
c.addFilter(new LoggingFilter());
}
c.addFilter(new HTTPBasicAuthFilter(this._username, this._password));
c.addFilter(new ClientFilter() {
private Object authToken;
// private int callCount = authenticateCallCount;
@Override
public ClientResponse handle(ClientRequest request)
throws ClientHandlerException {
if (authToken != null) {
request.getHeaders().put(AUTH_TOKEN_HEADER,
Collections.singletonList(authToken));
}
ClientResponse response = getNext().handle(request);
if (response.getHeaders() != null
&& response.getHeaders().containsKey(AUTH_TOKEN_HEADER)) {
authToken = (response.getHeaders()
.getFirst(AUTH_TOKEN_HEADER));
}
if (response.getStatus() == 302) {
WebResource wb = c.resource(response.getLocation());
response = wb.header(AUTH_TOKEN_HEADER, authToken).get(
ClientResponse.class);
}
return response;
}
});
}
public static void disableCertificateValidation() {
// this method is basically bypasses certificate validation.
// Bourne appliance uses expired certificate!
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(final X509Certificate[] certs,
final String authType) {
}
public void checkServerTrusted(final X509Certificate[] certs,
final String authType) {
}
} };
final HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(final String hostname,
final SSLSession session) {
return true;
}
};
// Install the all-trusting trust manager
try {
final SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (final Exception e) {
log.error("Unexpeted error occured", e);
}
}
}