/* * Copyright 2013 EMC Corporation. 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. * A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * or in the "license" file accompanying this file. This file 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.emc.vipr.services.s3; import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.internal.StaticCredentialsProvider; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.AmazonS3EncryptionClient; import com.amazonaws.services.s3.model.EncryptionMaterials; import com.emc.vipr.services.lib.ViprConfig; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.IOException; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Properties; /** * This class looks on the classpath for a file named viprs3.properties and uses it to * configure a connection to ViPR. The supported properties are: * <dt> * <dl>vipr.s3.access_key_id</dl><dd>(Required) The access key (user ID)</dd> * <dl>vipr.s3.secret_key</dl><dd>(Required) The shared secret key</dd> * <dl>vipr.s3.endpoint</dl><dd>(Required) The endpoint hostname or IP address of the ViPR * data service server to use</dd> * <dl>vipr.s3.endpoints</dl><dd>(Optional) The endpoints (plural) to use in the smart client</dd> * <dl>vipr.namespace</dl><dd>(Optional) The ViPR namespace to connect to. Generally * this is required if your endpoint is an IP or not in the format of {namespace}.company.com</dd> * <dl>vipr.s3.virtual_host</dl><dd>(Optional) The root virtual host used for vhost requests (also used by the smart * client as the load-balanced address.</dd> * </dt> * * @author cwikj */ public class S3ClientFactory { private static Log log = LogFactory.getLog(S3ClientFactory.class); public static ViPRS3Client getS3Client() { return getS3Client(false); } public static ViPRS3Client getS3Client(boolean setNamespace) { return getS3Client(false, setNamespace); } public static ViPRS3Client getSmartS3Client(boolean setNamespace) { return getS3Client(true, setNamespace); } private static ViPRS3Client getS3Client(boolean smart, boolean setNamespace) { try { Properties props = ViprConfig.getProperties(); String accessKey = ViprConfig.getPropertyNotEmpty(props, ViprConfig.PROP_S3_ACCESS_KEY_ID); String secretKey = ViprConfig.getPropertyNotEmpty(props, ViprConfig.PROP_S3_SECRET_KEY); String endpoint = ViprConfig.getPropertyNotEmpty(props, ViprConfig.PROP_S3_ENDPOINT); String endpoints = props.getProperty(ViprConfig.PROP_S3_ENDPOINTS); BasicAWSCredentials creds = new BasicAWSCredentials(accessKey, secretKey); ViPRS3Config viprConfig = new ViPRS3Config().withCredentialsProvider(new StaticCredentialsProvider(creds)); if (endpoints != null) viprConfig.withS3Endpoints(endpoints); else viprConfig.withS3Endpoints(endpoint); ViPRS3Client client = smart ? new ViPRS3Client(viprConfig) : new ViPRS3Client(endpoint, creds); String namespace = props.getProperty(ViprConfig.PROP_NAMESPACE); if (namespace != null && setNamespace) { client.setNamespace(namespace); } checkProxyConfig(client, props); return client; } catch (IOException e) { log.info("Failed to load properties: " + e); return null; } } /** * Creates an EncryptionClient for testing. Loads the public and private keys from * the properties file (not suitable for production). * * @return * @throws IOException */ public static AmazonS3EncryptionClient getEncryptionClient() throws IOException { try { Properties props = ViprConfig.getProperties(); String accessKey = ViprConfig.getPropertyNotEmpty(props, ViprConfig.PROP_S3_ACCESS_KEY_ID); String secretKey = ViprConfig.getPropertyNotEmpty(props, ViprConfig.PROP_S3_SECRET_KEY); String endpoint = ViprConfig.getPropertyNotEmpty(props, ViprConfig.PROP_S3_ENDPOINT); String publicKey = ViprConfig.getPropertyNotEmpty(props, ViprConfig.PROP_PUBLIC_KEY); String privateKey = ViprConfig.getPropertyNotEmpty(props, ViprConfig.PROP_PRIVATE_KEY); byte[] pubKeyBytes = Base64.decodeBase64(publicKey.getBytes("US-ASCII")); byte[] privKeyBytes = Base64.decodeBase64(privateKey.getBytes("US-ASCII")); X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pubKeyBytes); PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privKeyBytes); PublicKey pubKey; PrivateKey privKey; try { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); pubKey = keyFactory.generatePublic(pubKeySpec); privKey = keyFactory.generatePrivate(privKeySpec); } catch (GeneralSecurityException e) { throw new RuntimeException("Could not load key pair: " + e, e); } EncryptionMaterials keys = new EncryptionMaterials(new KeyPair(pubKey, privKey)); BasicAWSCredentials creds = new BasicAWSCredentials(accessKey, secretKey); AmazonS3EncryptionClient client = new AmazonS3EncryptionClient(creds, keys); client.setEndpoint(endpoint); checkProxyConfig(client, props); return client; } catch (Exception e) { log.info("Could not load configuration: " + e); return null; } } private static void checkProxyConfig(AmazonS3Client client, Properties props) { String proxyHost = props.getProperty(ViprConfig.PROP_PROXY_HOST); if (proxyHost != null && !proxyHost.isEmpty()) { int proxyPort = Integer.parseInt(props.getProperty(ViprConfig.PROP_PROXY_PORT)); ClientConfiguration config = new ClientConfiguration(); config.setProxyHost(proxyHost); config.setProxyPort(proxyPort); client.setConfiguration(config); } } // Generates a RSA key pair for testing. public static void main(String[] args) { try { KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA"); keyGenerator.initialize(1024, new SecureRandom()); KeyPair myKeyPair = keyGenerator.generateKeyPair(); // Serialize. byte[] pubKeyBytes = myKeyPair.getPublic().getEncoded(); byte[] privKeyBytes = myKeyPair.getPrivate().getEncoded(); String pubKeyStr = new String(Base64.encodeBase64(pubKeyBytes, false), "US-ASCII"); String privKeyStr = new String(Base64.encodeBase64(privKeyBytes, false), "US-ASCII"); System.out.println("Public Key: " + pubKeyStr); System.out.println("Private Key: " + privKeyStr); } catch (Exception e) { e.printStackTrace(); } } }