/***************************************************************************
* Copyright (c) 2013 VMware, Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
/***************************************************************************
* Copyright (c) 2012 VMware, Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package com.vmware.vhadoop.adaptor.vc;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.TrustManager;
import javax.xml.ws.soap.SOAPFaultException;
import com.vmware.vhadoop.adaptor.vc.VCConnection.MoRefAndProps;
import com.vmware.vhadoop.adaptor.vc.VCConnection.WaitProperty;
import com.vmware.vim25.ManagedObjectReference;
public class VCUtils {
/* This is a utility class used for reducing SSL checking when testing */
private static class TrustAllTrustManager implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
}
private static class VerifyAllHostNames implements HostnameVerifier {
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
};
/*
* 1) Trust all server certificates -- TODO verify server cert
* 2) setup SSL to use given keystore to send client certificate.
*/
public static void trustAllHttpsCertificates(String keyStorePath, String keyStorePassword) {
SSLContext sc;
try {
sc = SSLContext.getInstance("SSL");
SSLSessionContext sslsc = sc.getServerSessionContext();
sslsc.setSessionTimeout(0);
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(keyStorePath), keyStorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword.toCharArray());
sc.init(kmf.getKeyManagers(),
new TrustManager[]{(TrustManager)new TrustAllTrustManager()}, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new VerifyAllHostNames());
} catch (Exception e) {
throw new RuntimeException("Unexpected HTTPS Exception", e);
}
}
/* Ignore SSL certificates - useful for testing */
public static void trustAllHttpsCertificates() {
SSLContext sc;
try {
sc = SSLContext.getInstance("SSL");
SSLSessionContext sslsc = sc.getServerSessionContext();
sslsc.setSessionTimeout(0);
sc.init(null, new TrustManager[]{(TrustManager)new TrustAllTrustManager()}, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new VerifyAllHostNames());
} catch (KeyManagementException e) {
throw new RuntimeException("Unexpected HTTPS Exception", e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Unexpected HTTPS Exception", e);
}
}
public static String getSoapFaultExceptionMessage(SOAPFaultException sfe) {
if (sfe.getFault().hasDetail()) {
return sfe.getFault().getDetail().getFirstChild().getLocalName();
}
if (sfe.getFault().getFaultString() != null) {
return "\n Message: " + sfe.getFault().getFaultString();
}
return sfe.getMessage();
}
/**
* Transforms the result from a VC call into an asynchronous result, allowing us to
* return from the VC call before the call has actually completed.
* This implementation integrates with the WaitProperty implementation so that you
* can define properties which should have changed before the operation is considered complete
*
*/
protected static abstract class ResultTransformer<DTOType> implements Future<DTOType> {
ManagedObjectReference _waitForPropsOnObj;
List<WaitProperty> _waitProperties;
VCConnection _connection;
public ResultTransformer(VCConnection connection) {
_connection = connection;
}
/* The object we want to wait for property changes on */
void setWaitForPropsOnObj(ManagedObjectReference waitForPropsOnObj) {
_waitForPropsOnObj = waitForPropsOnObj;
}
/* Define the properties we want to look for changes in.
* Note that Future.get() will return if any one of these properties is met */
void addWaitProperty(String filterProperty, String waitAttribute, Object[] expectedVals) {
if (_waitProperties == null) {
_waitProperties = new ArrayList<WaitProperty>();
}
_waitProperties.add(_connection.new WaitProperty(filterProperty, waitAttribute, expectedVals));
}
/* block and wait - returns success or failure */
boolean waitForProps() {
if ((_waitProperties != null) && (_waitForPropsOnObj != null)) {
/* TODO: Consider some more complex success/failure criteria? */
if (_connection.waitForPropertyChange(_waitForPropsOnObj, _waitProperties.toArray(new WaitProperty[0])) == null) {
return false;
}
}
return true;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
throw new RuntimeException("Not implemented!");
}
@Override
public DTOType get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
throw new RuntimeException("Not implemented!");
}
@Override
public boolean isCancelled() {
throw new RuntimeException("Not implemented!");
}
@Override
public boolean isDone() {
throw new RuntimeException("Not implemented!");
}
}
/**
* Simple non-waiting utility class for returning synchronous results with just a cast
*
*/
protected static class CastingResultTransformer<DTOType> extends ResultTransformer<DTOType> {
DTOType _toWrap;
public CastingResultTransformer(DTOType toWrap) {
super(null);
_toWrap = toWrap;
}
@Override
public DTOType get() {
return _toWrap;
}
}
/**
* This is used for wrapping single DTO types returned from VC calls
* The transform method should encapsulate the conversion to the particular DTO type
* Note that the get() should block if any waits have been specified
*
*/
protected static abstract class AsyncResultTransformer<DTOType> extends ResultTransformer<DTOType> {
MoRefAndProps _toWrap;
public AsyncResultTransformer(MoRefAndProps toWrap, VCConnection connection) {
super(connection);
_toWrap = toWrap;
}
public abstract DTOType transform(MoRefAndProps input);
@Override
public DTOType get() {
if (waitForProps()) {
return transform(_toWrap);
}
return null;
}
}
/**
* Same as AsyncResultTransformer for dealing with arrays of results
*
*/
protected static abstract class AsyncArrayResultTransformer<External> extends ResultTransformer<External[]> {
MoRefAndProps[] _toWrap;
public AsyncArrayResultTransformer(MoRefAndProps[] toWrap, VCConnection connection) {
super(connection);
_toWrap = toWrap;
}
/* Called once for each element of the array */
public abstract External transform(MoRefAndProps input);
public abstract External[] toArray(List<External> results);
public External[] get() {
if (waitForProps()) {
List<External> results = new ArrayList<External>();
if (_toWrap == null) {
return null;
}
for (MoRefAndProps moref : _toWrap) {
results.add(transform(moref));
}
if (results.size() > 0) {
return toArray(results);
}
}
return null;
}
}
}