You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2017/08/14 16:39:33 UTC

[4/4] airavata git commit: AIRAVATA-2500 SSHAccountManager: install SSH key and verify

AIRAVATA-2500 SSHAccountManager: install SSH key and verify


Project: http://git-wip-us.apache.org/repos/asf/airavata/repo
Commit: http://git-wip-us.apache.org/repos/asf/airavata/commit/a79d4c6d
Tree: http://git-wip-us.apache.org/repos/asf/airavata/tree/a79d4c6d
Diff: http://git-wip-us.apache.org/repos/asf/airavata/diff/a79d4c6d

Branch: refs/heads/AIRAVATA-2500
Commit: a79d4c6d760aad1aaeb0cfaeda455743897990af
Parents: e1560d0
Author: Marcus Christie <ma...@apache.org>
Authored: Mon Aug 14 12:38:53 2017 -0400
Committer: Marcus Christie <ma...@apache.org>
Committed: Mon Aug 14 12:38:53 2017 -0400

----------------------------------------------------------------------
 .../accountprovisioning/SSHAccountManager.java  | 104 ++++++++++++++-----
 .../airavata/accountprovisioning/SSHUtil.java   |  83 +++++++++++++++
 2 files changed, 162 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/airavata/blob/a79d4c6d/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountManager.java
----------------------------------------------------------------------
diff --git a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountManager.java b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountManager.java
index dcb819b..d565fe9 100644
--- a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountManager.java
+++ b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountManager.java
@@ -25,43 +25,48 @@ import org.apache.airavata.common.utils.ServerSettings;
 import org.apache.airavata.credential.store.client.CredentialStoreClientFactory;
 import org.apache.airavata.credential.store.cpi.CredentialStoreService;
 import org.apache.airavata.credential.store.exception.CredentialStoreException;
+import org.apache.airavata.model.appcatalog.accountprovisioning.SSHAccountProvisionerConfigParam;
+import org.apache.airavata.model.appcatalog.computeresource.ComputeResourceDescription;
+import org.apache.airavata.model.appcatalog.gatewayprofile.ComputeResourcePreference;
 import org.apache.airavata.model.credential.store.PasswordCredential;
+import org.apache.airavata.model.credential.store.SSHCredential;
 import org.apache.airavata.registry.api.RegistryService;
 import org.apache.airavata.registry.api.client.RegistryServiceClientFactory;
 import org.apache.airavata.registry.api.exception.RegistryServiceException;
 import org.apache.thrift.TException;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 public class SSHAccountManager {
 
-    // TODO: need private key too to verify
-    public static void setupSSHAccount(String gatewayId, String hostname, String username, String sshPublicKey) {
-
-        // TODO: finish implementing
+    // TODO: change return type to one that returns some details of the SSH account setup, for example the scratch location
+    public static void setupSSHAccount(String gatewayId, String computeResourceId, String username, SSHCredential sshCredential) {
 
         // get compute resource preferences for the gateway and hostname
+        // TODO: close the registry service client transport when done with it
+        RegistryService.Client registryServiceClient = getRegistryServiceClient();
+        ComputeResourcePreference computeResourcePreference = null;
+        ComputeResourceDescription computeResourceDescription = null;
+        try {
+            computeResourcePreference = registryServiceClient.getGatewayComputeResourcePreference(gatewayId, computeResourceId);
+            computeResourceDescription = registryServiceClient.getComputeResource(computeResourceId);
+        } catch(TException e) {
+            throw new RuntimeException(e);
+        }
 
         // get the account provisioner and config values for the preferences
-        String provisionerName = null;
-        Map<ConfigParam,String> provisionerConfig = null;
-
-        CredentialStoreService.Client credentialStoreServiceClient = getCredentialStoreClient();
-        // Resolve any CRED_STORE_PASSWORD_TOKEN config parameters to passwords
-        Map<ConfigParam,String> resolvedConfig = new HashMap<>();
-        for (Map.Entry<ConfigParam,String> configEntry : provisionerConfig.entrySet() ) {
-            if (configEntry.getKey().getType() == ConfigParam.ConfigParamType.CRED_STORE_PASSWORD_TOKEN) {
-                try {
-                    PasswordCredential password = credentialStoreServiceClient.getPasswordCredential(configEntry.getValue(), gatewayId);
-                    resolvedConfig.put(configEntry.getKey(), password.getPassword());
-                } catch (TException e) {
-                    throw new RuntimeException("Failed to get password needed to configure " + provisionerName);
-                }
-            } else {
-                resolvedConfig.put(configEntry.getKey(), configEntry.getValue());
-            }
+        if (!computeResourcePreference.isSetSshAccountProvisioner()) {
+            // TODO: provide better exception?
+            throw new RuntimeException("Compute resource [" + computeResourceId + "] does not have an SSH Account Provisioner configured for it.");
         }
+        String provisionerName = computeResourcePreference.getSshAccountProvisioner();
+        Map<ConfigParam,String> provisionerConfig = convertConfigParams(provisionerName, computeResourcePreference.getSshAccountProvisionerConfig());
+
+        Map<ConfigParam, String> resolvedConfig = resolveProvisionerConfig(gatewayId, provisionerName, provisionerConfig);
 
         // instantiate and init the account provisioner
         SSHAccountProvisioner sshAccountProvisioner = SSHAccountProvisionerFactory.createSSHAccountProvisioner(provisionerName, resolvedConfig);
@@ -70,23 +75,72 @@ public class SSHAccountManager {
         boolean hasAccount = sshAccountProvisioner.hasAccount(username);
 
         if (!hasAccount && !sshAccountProvisioner.canCreateAccount()) {
-            // TODO: throw an exception
+            // TODO: provide better exception
+            throw new RuntimeException("User [" + username + "] doesn't have account and [" + provisionerName + "] doesn't support creating account.");
         }
 
         // TODO: first check if SSH key is already installed, or do we care?
 
         // Install SSH key
+        sshAccountProvisioner.installSSHKey(username, sshCredential.getPublicKey());
 
         // Verify can authenticate to host
+        boolean validated = SSHUtil.validate(username, computeResourceDescription.getHostName(), 22, sshCredential);
+        if (!validated) {
+            throw new RuntimeException("Failed to validate installation of key for [" + username
+                    + "] on [" + computeResourceDescription.getHostName() + "] using SSH Account Provisioner ["
+                    + computeResourcePreference.getSshAccountProvisioner() + "]");
+        }
 
         // create the scratch location on the host
+        // TODO: create the scratch location
         String scratchLocation = sshAccountProvisioner.getScratchLocation(username);
     }
 
-    private static RegistryService.Client getRegistryServiceClient() throws RegistryServiceException {
+    private static Map<ConfigParam, String> resolveProvisionerConfig(String gatewayId, String provisionerName, Map<ConfigParam, String> provisionerConfig) {
+        CredentialStoreService.Client credentialStoreServiceClient = null;
+        try {
+            credentialStoreServiceClient = getCredentialStoreClient();
+            // Resolve any CRED_STORE_PASSWORD_TOKEN config parameters to passwords
+            Map<ConfigParam, String> resolvedConfig = new HashMap<>();
+            for (Map.Entry<ConfigParam, String> configEntry : provisionerConfig.entrySet()) {
+                if (configEntry.getKey().getType() == ConfigParam.ConfigParamType.CRED_STORE_PASSWORD_TOKEN) {
+                    try {
+                        PasswordCredential password = credentialStoreServiceClient.getPasswordCredential(configEntry.getValue(), gatewayId);
+                        resolvedConfig.put(configEntry.getKey(), password.getPassword());
+                    } catch (TException e) {
+                        throw new RuntimeException("Failed to get password needed to configure " + provisionerName);
+                    }
+                } else {
+                    resolvedConfig.put(configEntry.getKey(), configEntry.getValue());
+                }
+            }
+            return resolvedConfig;
+        } finally {
+            if (credentialStoreServiceClient != null) {
+                if (credentialStoreServiceClient.getInputProtocol().getTransport().isOpen()) {
+                    credentialStoreServiceClient.getInputProtocol().getTransport().close();
+                }
+            }
+        }
+    }
+
+    private static Map<ConfigParam, String> convertConfigParams(String provisionerName, Map<SSHAccountProvisionerConfigParam, String> thriftConfigParams) {
+        List<ConfigParam> configParams = SSHAccountProvisionerFactory.getSSHAccountProvisionerConfigParams(provisionerName);
+        Map<String, ConfigParam> configParamMap = configParams.stream().collect(Collectors.toMap(ConfigParam::getName, Function.identity()));
 
-        // TODO: finish implementing
-        return RegistryServiceClientFactory.createRegistryClient(null, 0);
+        return thriftConfigParams.entrySet().stream().collect(Collectors.toMap(entry -> configParamMap.get(entry.getKey().getName()), entry -> entry.getValue()));
+    }
+
+    private static RegistryService.Client getRegistryServiceClient() {
+
+        try {
+            String registryServerHost = ServerSettings.getRegistryServerHost();
+            int registryServerPort = Integer.valueOf(ServerSettings.getRegistryServerPort());
+            return RegistryServiceClientFactory.createRegistryClient(registryServerHost, registryServerPort);
+        } catch (ApplicationSettingsException|RegistryServiceException e) {
+            throw new RuntimeException("Failed to create registry service client", e);
+        }
     }
 
     private static CredentialStoreService.Client getCredentialStoreClient() {

http://git-wip-us.apache.org/repos/asf/airavata/blob/a79d4c6d/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHUtil.java
----------------------------------------------------------------------
diff --git a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHUtil.java b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHUtil.java
new file mode 100644
index 0000000..4b5452a
--- /dev/null
+++ b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHUtil.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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.apache.airavata.accountprovisioning;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import org.apache.airavata.model.credential.store.SSHCredential;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.UUID;
+
+/**
+ * Created by machrist on 2/10/17.
+ */
+public class SSHUtil {
+
+    public static boolean validate(String username, String hostname, int port, SSHCredential sshCredential) {
+
+        JSch jSch = new JSch();
+        Session session = null;
+        try {
+            jSch.addIdentity(UUID.randomUUID().toString(), sshCredential.getPrivateKey().getBytes(), sshCredential.getPublicKey().getBytes(), sshCredential.getPassphrase().getBytes());
+            session = jSch.getSession(username, hostname, port);
+            java.util.Properties config = new java.util.Properties();
+            config.put("StrictHostKeyChecking", "no");
+            session.setConfig(config);
+            session.connect();
+            return true;
+        } catch (JSchException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } finally {
+            if (session != null && session.isConnected()) {
+                session.disconnect();
+            }
+        }
+    }
+
+    public static void main(String[] args) throws JSchException {
+
+        // Test the validate method
+        String username = System.getProperty("user.name");
+        String privateKeyFilepath = System.getProperty("user.home") + "/.ssh/id_rsa";
+        String publicKeyFilepath = privateKeyFilepath + ".pub";
+        String passphrase = "changeme";
+        String hostname = "changeme";
+
+        Path privateKeyPath = Paths.get(privateKeyFilepath);
+        Path publicKeyPath = Paths.get(publicKeyFilepath);
+
+        SSHCredential sshCredential = new SSHCredential();
+        sshCredential.setPassphrase(passphrase);
+        try {
+            sshCredential.setPublicKey(new String(Files.readAllBytes(publicKeyPath), "UTF-8"));
+            sshCredential.setPrivateKey(new String(Files.readAllBytes(privateKeyPath), "UTF-8"));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        boolean result = validate(username, hostname, 22, sshCredential);
+        System.out.println(result);
+    }
+}