blob: c86abea2ea2390d5b8cb9b173ad6aa6daa1a850b [file] [log] [blame]
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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 org.jclouds.fujitsu.fgcp.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.KeySpec;
import java.util.Calendar;
import java.util.Collection;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Singleton;
import javax.net.ssl.SSLContext;
import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.Pems;
import org.jclouds.date.TimeStamp;
import org.jclouds.fujitsu.fgcp.FGCPApi;
import org.jclouds.fujitsu.fgcp.FGCPAsyncApi;
import org.jclouds.fujitsu.fgcp.handlers.FGCPRetryIfNotProxyAuthenticationFailureHandler;
import org.jclouds.fujitsu.fgcp.http.SSLContextWithKeysSupplier;
import org.jclouds.fujitsu.fgcp.location.SystemAndNetworkSegmentToLocationSupplier;
import org.jclouds.fujitsu.fgcp.services.AdditionalDiskApi;
import org.jclouds.fujitsu.fgcp.services.AdditionalDiskAsyncApi;
import org.jclouds.fujitsu.fgcp.services.BuiltinServerApi;
import org.jclouds.fujitsu.fgcp.services.BuiltinServerAsyncApi;
import org.jclouds.fujitsu.fgcp.services.DiskImageApi;
import org.jclouds.fujitsu.fgcp.services.DiskImageAsyncApi;
import org.jclouds.fujitsu.fgcp.services.FirewallApi;
import org.jclouds.fujitsu.fgcp.services.FirewallAsyncApi;
import org.jclouds.fujitsu.fgcp.services.LoadBalancerApi;
import org.jclouds.fujitsu.fgcp.services.LoadBalancerAsyncApi;
import org.jclouds.fujitsu.fgcp.services.PublicIPAddressApi;
import org.jclouds.fujitsu.fgcp.services.PublicIPAddressAsyncApi;
import org.jclouds.fujitsu.fgcp.services.SystemTemplateApi;
import org.jclouds.fujitsu.fgcp.services.SystemTemplateAsyncApi;
import org.jclouds.fujitsu.fgcp.services.VirtualDCApi;
import org.jclouds.fujitsu.fgcp.services.VirtualDCAsyncApi;
import org.jclouds.fujitsu.fgcp.services.VirtualServerApi;
import org.jclouds.fujitsu.fgcp.services.VirtualServerAsyncApi;
import org.jclouds.fujitsu.fgcp.services.VirtualSystemApi;
import org.jclouds.fujitsu.fgcp.services.VirtualSystemAsyncApi;
import org.jclouds.fujitsu.fgcp.xml.FGCPJAXBParser;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.io.InputSuppliers;
import org.jclouds.location.suppliers.ImplicitLocationSupplier;
import org.jclouds.location.suppliers.LocationsSupplier;
import org.jclouds.location.suppliers.implicit.FirstNetwork;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.Credential;
import org.jclouds.rest.annotations.Identity;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.xml.XMLParser;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
/**
* Configures the FGCP connection. This module is added in FGCPContextBuilder.
*
* @author Dies Koper
*/
@ConfiguresRestClient
public class FGCPRestClientModule extends
RestClientModule<FGCPApi, FGCPAsyncApi> {
@Resource
Logger logger = Logger.NULL;
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap
.<Class<?>, Class<?>> builder()
//
.put(VirtualDCApi.class, VirtualDCAsyncApi.class)
.put(VirtualSystemApi.class, VirtualSystemAsyncApi.class)
.put(VirtualServerApi.class, VirtualServerAsyncApi.class)
.put(AdditionalDiskApi.class, AdditionalDiskAsyncApi.class)
.put(SystemTemplateApi.class, SystemTemplateAsyncApi.class)
.put(DiskImageApi.class, DiskImageAsyncApi.class)
.put(BuiltinServerApi.class, BuiltinServerAsyncApi.class)
.put(FirewallApi.class, FirewallAsyncApi.class)
.put(LoadBalancerApi.class, LoadBalancerAsyncApi.class)
.put(PublicIPAddressApi.class, PublicIPAddressAsyncApi.class)
.build();
public FGCPRestClientModule() {
super(DELEGATE_MAP);
}
@Override
protected void bindErrorHandlers() {
// bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseAWSErrorFromXmlContent.class);
// bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseAWSErrorFromXmlContent.class);
// bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseAWSErrorFromXmlContent.class);
}
@Override
protected void installLocations() {
super.installLocations();
bind(ImplicitLocationSupplier.class).to(FirstNetwork.class).in(
Scopes.SINGLETON);
bind(LocationsSupplier.class).to(
SystemAndNetworkSegmentToLocationSupplier.class).in(
Scopes.SINGLETON);
}
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
FGCPRetryIfNotProxyAuthenticationFailureHandler.class);
}
@Override
protected void configure() {
super.configure();
bind(XMLParser.class).to(FGCPJAXBParser.class);
bind(new TypeLiteral<Supplier<SSLContext>>() {
}).to(new TypeLiteral<SSLContextWithKeysSupplier>() {
});
}
@Provides
@TimeStamp
protected Calendar provideCalendar() {
return Calendar.getInstance();
}
/*
*
* @Provides
*
* @Singleton protected KeyStore
* provideKeyStore(@Named(Constants.PROPERTY_IDENTITY) String
* keyStoreFilename, @Named(Constants.PROPERTY_CREDENTIAL) String
* keyStorePassword) throws KeyStoreException { KeyStore keyStore =
* KeyStore.getInstance("pkcs12");
*
* try { FileInputStream is = new
* FileInputStream(checkNotNull(keyStoreFilename,
* Constants.PROPERTY_IDENTITY)); keyStore.load(is,
* checkNotNull(keyStorePassword,
* Constants.PROPERTY_CREDENTIAL).toCharArray()); } catch (Exception e) { //
* expecting IOException, NoSuchAlgorithmException, CertificateException
* logger.error(e, "Keystore could not be opened: %s", keyStoreFilename); }
* return keyStore; }
*
* @Provides
*
* @Singleton protected PrivateKey provideKey(Provider<KeyStore>
* keyStoreProvider, @Named(Constants.PROPERTY_CREDENTIAL) String
* keyPassword) throws KeyStoreException, NoSuchAlgorithmException,
* UnrecoverableKeyException { KeyStore keyStore = keyStoreProvider.get();
* if (keyStore == null) return null;
*
* // retrieving 1st alias in keystore as expecting only one String alias =
* checkNotNull(keyStore.aliases().nextElement(),
* "first alias in keystore"); return (PrivateKey) keyStore.getKey(alias,
* checkNotNull(keyPassword, Constants.PROPERTY_CREDENTIAL).toCharArray());
* }
*/
/*
* maybe we can provide two authentication methods:
*
* 1. same as DeltaCloud: User passes a folder name as identity and cert
* password as credential Note: pass relative path (e.g. cert's path:
* c:\jclouds\certs\dkoper\UserCert.p12: user passes 'dkoper': provider
* impl. finds it under e.g. $USER_DIR or $CURRENT_DIR or pass absolute path
* 2. no file access for GAE: User passes cert in PEM format (converted from
* UserCert.p12 using openssl?) as identity and cert password as credential
*/
@Provides
@Singleton
protected KeyStore provideKeyStore(Crypto crypto, @Identity String cert,
@Credential String keyStorePassword) {
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance("PKCS12");
// System.out.println("cert: " + cert);
// System.out.println("pwd : " + keyStorePassword);
File certFile = new File(checkNotNull(cert));
if (certFile.isFile()) { // cert is path to pkcs12 file
keyStore.load(new FileInputStream(certFile),
keyStorePassword.toCharArray());
} else { // cert is PEM encoded, containing private key and certs
// System.out.println("cert:\n" + cert);
// split in private key and certs
int privateKeyBeginIdx = cert.indexOf("-----BEGIN PRIVATE KEY");
int privateKeyEndIdx = cert.indexOf("-----END PRIVATE KEY");
String pemPrivateKey = cert.substring(privateKeyBeginIdx,
privateKeyEndIdx + 26);
// System.out.println("***************");
// System.out.println("pemPrivateKey:\n" + pemPrivateKey);
// System.out.println("***************");
String pemCerts = "";
int certsBeginIdx = 0;
do {
certsBeginIdx = cert.indexOf("-----BEGIN CERTIFICATE",
certsBeginIdx);
// System.out.println("begin:" + certsBeginIdx);
if (certsBeginIdx >= 0) {
int certsEndIdx = cert.indexOf("-----END CERTIFICATE",
certsBeginIdx) + 26;
// System.out.println("end :" + certsEndIdx);
pemCerts += cert.substring(certsBeginIdx, certsEndIdx);
certsBeginIdx = certsEndIdx;
}
} while (certsBeginIdx != -1);
// System.out.println("***************");
// System.out.println("pemCerts:\n" + pemCerts);
// System.out.println("***************");
/*
* String pemCerts = "-----BEGIN "; Splitter pemSplitter =
* Splitter.on("-----BEGIN ");
*
* for (String part : pemSplitter.split(cert)) {
* System.out.println("***************");
* System.out.println("Part:\n" + part);
* System.out.println("***************");
*
* if (part.startsWith("PRIVATE KEY")
*/
/* || part.startsWith("RSA PRIVATE KEY)" *//*
* ) {
*
* int certEndIdx =
* part.lastIndexOf
* ("-----END");
* pemPrivateKey +=
* part.substring(0,
* certEndIdx + 26);
* // take up to next
* "-----" (i.e.
* "-----END") //
* Splitter
* keySplitter =
* Splitter
* .on("-----").
* omitEmptyStrings
* ().trimResults();
* //
* Iterator<String>
* iter =
* keySplitter.
* split(part
* ).iterator(); //
* String keyName =
* iter.next() +
* "-----\n"; //
* pemPrivateKey +=
* keyName; ////
* System.out
* .println
* ("Skipping: '" +
* iter.next() +
* "'"); //
* pemPrivateKey +=
* iter.next(); //
* pemPrivateKey +=
* "\n-----END " +
* keyName;
* System.out.println
* (
* "/////////////////"
* );
* System.out.println
* (
* "pemPrivateKey:\n"
* + pemPrivateKey);
* System
* .out.println(
* "/////////////////"
* ); } else if
* (part.startsWith
* ("CERTIFICATE")) {
*
* // take up to next
* "-----" (i.e.
* "-----END") // or
* take up to last
* END CERTIFICATE?
* int certEndIdx =
* part.lastIndexOf (
* "----- END CERTIFICATE"
* ); // pemCerts +=
* part. // Splitter
* keySplitter =
* Splitter
* .on("-----").
* omitEmptyStrings
* (); // pemCerts +=
* keySplitter
* .split(part)
* .iterator
* ().next(); //
* pemCerts +=
* "-----BEGIN "; }
* else { // ignore
* the fluff in
* between (Bag
* Attributes, etc.)
* } }
*/
// parse private key
KeySpec keySpec = Pems.privateKeySpec(InputSuppliers
.of(pemPrivateKey));
PrivateKey privateKey = crypto.rsaKeyFactory().generatePrivate(
keySpec);
// populate keystore with private key and certs
CertificateFactory cf = CertificateFactory.getInstance("X.509");
@SuppressWarnings("unchecked")
Collection<Certificate> certs = (Collection<Certificate>) cf
.generateCertificates(new ByteArrayInputStream(pemCerts
.getBytes("UTF-8")));
keyStore.load(null);
keyStore.setKeyEntry("dummy", privateKey,
keyStorePassword.toCharArray(),
certs.toArray(new java.security.cert.Certificate[0]));
// System.out.println("private key: " + privateKey.getFormat() +
// "; "
// + privateKey.getAlgorithm() + "; class: " +
// privateKey.getClass().getName());// + "; " + new
// String(privateKey.getEncoded()));
}
} catch (Exception e) {
/*
* KeyStoreException, IOException, NoSuchAlgorithmException,
* CertificateException, InvalidKeySpecException
*/
throw new AuthorizationException("Error loading certificate", e);
}
return keyStore;
}
}