/*******************************************************************************
* Copyright (c) 2012 GigaSpaces Technologies Ltd. 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 org.cloudifysource.esc.driver.provisioning.jclouds;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.concurrent.TimeoutException;
import org.apache.commons.io.FileUtils;
import org.cloudifysource.esc.driver.provisioning.CloudProvisioningException;
import org.jclouds.cloudstack.domain.EncryptedPasswordAndPrivateKey;
import org.jclouds.cloudstack.functions.WindowsLoginCredentialsFromEncryptedData;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.crypto.Crypto;
import org.jclouds.domain.Location;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.EC2ApiMetadata;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.domain.PasswordData;
import org.jclouds.ec2.features.WindowsApi;
import org.jclouds.encryption.internal.JCECrypto;
/************
* Handles decryption of encrypted Administrator passwords for Amazon EC2 windows instances.
*
* @author barakme
* @since 2.1.0
*
*/
public class EC2WindowsPasswordHandler {
private static final int PASSWORD_POLLING_INTERVAL_MILLIS = 5000;
private static final java.util.logging.Logger logger = java.util.logging.Logger
.getLogger(EC2WindowsPasswordHandler.class.getName());
/************
* Returns the decrypted password.
*
* @param node
* the compute node.
* @param context
* the compute context.
* @param end
* the operation end time.
* @param pemFile
* the private key file used to decrypt the password.
* @return the decrypted password.
* @throws InterruptedException .
* @throws TimeoutException .
* @throws CloudProvisioningException .
*/
public LoginCredentials getPassword(final NodeMetadata node, final ComputeServiceContext context, final long end,
final File pemFile)
throws InterruptedException, TimeoutException, CloudProvisioningException {
final Location zone = node.getLocation();
final Location region = zone.getParent();
WindowsApi winApi = EC2Client.class.cast(context.unwrap(EC2ApiMetadata.CONTEXT_TOKEN).getApi())
.getWindowsApiForRegion(region.getId()).get();
final String id = node.getId();
String key;
try {
key = FileUtils.readFileToString(pemFile);
} catch (final IOException e) {
throw new CloudProvisioningException("Failed to read key file: " + pemFile, e);
}
final String amiId = id.split("/")[1];
while (System.currentTimeMillis() < end) {
logger.fine("Reading Windows password");
final PasswordData passwordData = winApi.getPasswordDataInRegion(region.getId(), amiId);
if (passwordData == null || passwordData.getPasswordData() == null
|| passwordData.getPasswordData().isEmpty()) {
Thread.sleep(PASSWORD_POLLING_INTERVAL_MILLIS);
} else {
final String encryptedPassword = passwordData.getPasswordData();
LoginCredentials credentials;
try {
credentials = decryptPasswordData(
encryptedPassword, key);
} catch (final NoSuchAlgorithmException e) {
throw new CloudProvisioningException("Failed to decrypt windows password: " + e.getMessage(), e);
} catch (final CertificateException e) {
throw new CloudProvisioningException("Failed to decrypt windows password: " + e.getMessage(), e);
} catch (final IOException e) {
throw new CloudProvisioningException("Failed to decrypt windows password: " + e.getMessage(), e);
}
return credentials;
}
}
throw new TimeoutException("Failed to retrieve EC2 Windows password in the allocated time");
}
private LoginCredentials decryptPasswordData(final String encryptedPassword, final String key)
throws NoSuchAlgorithmException, CertificateException, IOException {
final Crypto crypto = new JCECrypto();
final WindowsLoginCredentialsFromEncryptedData f = new WindowsLoginCredentialsFromEncryptedData(crypto);
final LoginCredentials credentials = f.apply(EncryptedPasswordAndPrivateKey.builder().encryptedPassword(encryptedPassword).privateKey(key).build());
return credentials;
}
}