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 2018/10/02 18:37:40 UTC

[airavata] 01/04: IU LDAP ssh account: add user to cybergateway group

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/airavata.git

commit 18d0e4e10f27a4b189eab0a234fb02dd0edff439
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue Oct 2 12:36:59 2018 -0400

    IU LDAP ssh account: add user to cybergateway group
---
 .../accountprovisioning/SSHAccountProvisioner.java |   9 ++
 .../provisioner/IULdapSSHAccountProvisioner.java   | 165 +++++++++++++++------
 .../IULdapSSHAccountProvisionerProvider.java       |   6 +-
 .../provisioner/TestSSHAccountProvisioner.java     |   5 +
 4 files changed, 142 insertions(+), 43 deletions(-)

diff --git a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountProvisioner.java b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountProvisioner.java
index 6ad076d..fe1499f 100644
--- a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountProvisioner.java
+++ b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/SSHAccountProvisioner.java
@@ -56,6 +56,15 @@ public interface SSHAccountProvisioner {
     String createAccount(String userId, String sshPublicKey) throws InvalidUsernameException;
 
     /**
+     * Return true if this sshPublicKey has been installed for this user account and all other related setup tasks are complete.
+     * @param userId
+     * @param sshPublicKey
+     * @return
+     * @throws InvalidUsernameException
+     */
+    boolean isSSHAccountProvisioningComplete(String userId, String sshPublicKey) throws InvalidUsernameException;
+
+    /**
      * Install an SSH key for the user on the compute host.
      * @param userId the Airavata user id
      * @param sshPublicKey the public key part of an Airavata managed SSH credential
diff --git a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/provisioner/IULdapSSHAccountProvisioner.java b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/provisioner/IULdapSSHAccountProvisioner.java
index e35c118..83d7f3a 100644
--- a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/provisioner/IULdapSSHAccountProvisioner.java
+++ b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/provisioner/IULdapSSHAccountProvisioner.java
@@ -24,14 +24,12 @@ import org.apache.airavata.accountprovisioning.ConfigParam;
 import org.apache.airavata.accountprovisioning.InvalidUsernameException;
 import org.apache.airavata.accountprovisioning.SSHAccountManager;
 import org.apache.airavata.accountprovisioning.SSHAccountProvisioner;
+import org.apache.directory.api.ldap.model.cursor.EntryCursor;
 import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
 import org.apache.directory.api.ldap.model.entry.Entry;
 import org.apache.directory.api.ldap.model.entry.ModificationOperation;
 import org.apache.directory.api.ldap.model.exception.LdapException;
-import org.apache.directory.api.ldap.model.message.ModifyRequest;
-import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
-import org.apache.directory.api.ldap.model.message.ModifyResponse;
-import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.*;
 import org.apache.directory.api.ldap.model.name.Dn;
 import org.apache.directory.ldap.client.api.LdapConnection;
 import org.apache.directory.ldap.client.api.LdapNetworkConnection;
@@ -48,8 +46,9 @@ public class IULdapSSHAccountProvisioner implements SSHAccountProvisioner  {
     private final static Logger logger = LoggerFactory.getLogger(SSHAccountManager.class);
     public static final String LDAP_PUBLIC_KEY_OBJECT_CLASS = "ldapPublicKey";
     public static final String SSH_PUBLIC_KEY_ATTRIBUTE_NAME = "sshPublicKey";
+    public static final String GROUP_MEMBER_ATTRIBUTE_NAME = "memberUid";
 
-    private String ldapHost, ldapUsername, ldapPassword, ldapBaseDN, canonicalScratchLocation;
+    private String ldapHost, ldapUsername, ldapPassword, ldapBaseDN, canonicalScratchLocation, cybergatewayGroupDN;
     private int ldapPort;
     @Override
     public void init(Map<ConfigParam, String> config) {
@@ -60,6 +59,7 @@ public class IULdapSSHAccountProvisioner implements SSHAccountProvisioner  {
         ldapPassword = config.get(IULdapSSHAccountProvisionerProvider.LDAP_PASSWORD); //"secret password"
         ldapBaseDN = config.get(IULdapSSHAccountProvisionerProvider.LDAP_BASE_DN);//"dc=rt,dc=iu,dc=edu"
         canonicalScratchLocation = config.get(IULdapSSHAccountProvisionerProvider.CANONICAL_SCRATCH_LOCATION); //"/N/dc2/scratch/username/iu-gateway"
+        cybergatewayGroupDN = config.get(IULdapSSHAccountProvisionerProvider.CYBERGATEWAY_GROUP_DN); // "cn=cybergateway,ou=Group,dc=rt,dc=iu,dc=edu"
     }
 
     @Override
@@ -67,7 +67,7 @@ public class IULdapSSHAccountProvisioner implements SSHAccountProvisioner  {
         String username = getUsername(userId);
         boolean result = withLdapConnection(ldapConnection -> {
             try {
-                return ldapConnection.exists("uid=" + username + "," + ldapBaseDN);
+                return hasClusterAccount(ldapConnection, username);
             } catch (LdapException e) {
                 throw new RuntimeException(e);
             }
@@ -75,6 +75,27 @@ public class IULdapSSHAccountProvisioner implements SSHAccountProvisioner  {
         return result;
     }
 
+    private boolean hasClusterAccount(LdapConnection ldapConnection, String username) throws LdapException {
+
+        return ldapConnection.exists("uid=" + username + "," + ldapBaseDN);
+    }
+
+    private boolean isInCybergatewayGroup(LdapConnection ldapConnection, String username) throws LdapException {
+
+        final String filter = "(memberUid=" + username + ")";
+        try(EntryCursor entryCursor = ldapConnection.search(this.cybergatewayGroupDN, filter, SearchScope.OBJECT)) {
+
+            int count = 0;
+            for (Entry entry : entryCursor) {
+                count++;
+                logger.info("Found {} in cybergateway group", username);
+            }
+            return count == 1;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     @Override
     public String createAccount(String userId, String sshPublicKey) throws InvalidUsernameException {
 
@@ -82,47 +103,40 @@ public class IULdapSSHAccountProvisioner implements SSHAccountProvisioner  {
     }
 
     @Override
+    public boolean isSSHAccountProvisioningComplete(String userId, String sshPublicKey) throws InvalidUsernameException {
+        String username = getUsername(userId);
+        boolean result = withLdapConnection(ldapConnection -> {
+            try {
+                return hasClusterAccount(ldapConnection, username)
+                        && isInCybergatewayGroup(ldapConnection, username)
+                        && isSSHKeyInstalled(ldapConnection, username, sshPublicKey);
+            } catch (LdapException e) {
+                throw new RuntimeException(e);
+            }
+        });
+        return result;
+    }
+
+    public boolean isSSHKeyInstalled(LdapConnection ldapConnection, String username, String sshPublicKey) throws LdapException {
+
+        String ldapPublicKey = getLdapPublicKey(ldapConnection, username);
+        return ldapPublicKey != null && ldapPublicKey.equals(sshPublicKey.trim());
+    }
+
+    @Override
     public String installSSHKey(String userId, String sshPublicKey) throws InvalidUsernameException {
         String username = getUsername(userId);
         String finalSSHPublicKey = sshPublicKey.trim();
         boolean success = withLdapConnection(ldapConnection -> {
             try {
-                String dn = "uid=" + username + "," + ldapBaseDN;
-
-                Entry entry = ldapConnection.lookup(dn);
-                if (entry == null) {
-                    throw new RuntimeException("User [" + username + "] has no entry for " + dn);
-                }
-                boolean hasLdapPublicKey = entry.hasObjectClass(LDAP_PUBLIC_KEY_OBJECT_CLASS);
-
-                ModifyRequest modifyRequest = new ModifyRequestImpl();
-                modifyRequest.setName(new Dn(dn));
-
-                // Add or Replace, depending on whether there is already an ldapPublicKey on the entry
-                if (!hasLdapPublicKey) {
-
-                    modifyRequest.addModification(new DefaultAttribute("objectclass", LDAP_PUBLIC_KEY_OBJECT_CLASS), ModificationOperation.ADD_ATTRIBUTE);
-                    modifyRequest.addModification(new DefaultAttribute(SSH_PUBLIC_KEY_ATTRIBUTE_NAME, finalSSHPublicKey),
-                            ModificationOperation.ADD_ATTRIBUTE);
-                } else {
-
-                    String oldSshPublicKey = entry.get(SSH_PUBLIC_KEY_ATTRIBUTE_NAME).getString();
-                    if (!oldSshPublicKey.equals(finalSSHPublicKey)) {
-                        // Disallow overwriting the SSH key
-                        throw new RuntimeException("User [" + username + "] already has an SSH public key in LDAP for ["
-                                + ldapBaseDN + "] and overwriting it isn't allowed.");
-                        // modifyRequest.addModification(new DefaultAttribute(SSH_PUBLIC_KEY_ATTRIBUTE_NAME,
-                        //        sshPublicKey), ModificationOperation.REPLACE_ATTRIBUTE);
-                    } else {
-                        // SSH key is already installed so just return
-                        return true;
-                    }
+                // 1) Check to see if key is installed, and if not, install it
+                // 2) Check to see if user is in cybergateway group and if not add the user
+                // This is because the user may have the key installed but not be in the group
+                if (!isSSHKeyInstalled(ldapConnection, username, finalSSHPublicKey)) {
+                    installLdapPublicKey(ldapConnection, username, finalSSHPublicKey);
                 }
-                ModifyResponse modifyResponse = ldapConnection.modify(modifyRequest);
-                if (modifyResponse.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS) {
-                    logger.warn("installSSHKey ldap operation reported not being successful: " + modifyResponse);
-                } else {
-                    logger.debug("installSSHKey ldap operation was successful: " + modifyResponse);
+                if (!isInCybergatewayGroup(ldapConnection, username)) {
+                    addUserToCybergatewayGroup(ldapConnection, username);
                 }
                 return true;
             } catch (LdapException e) {
@@ -132,6 +146,65 @@ public class IULdapSSHAccountProvisioner implements SSHAccountProvisioner  {
         return username;
     }
 
+    private void addUserToCybergatewayGroup(LdapConnection ldapConnection, String username) throws LdapException {
+
+        ModifyRequest modifyRequest = new ModifyRequestImpl();
+        modifyRequest.setName(new Dn(cybergatewayGroupDN));
+        modifyRequest.addModification(new DefaultAttribute(GROUP_MEMBER_ATTRIBUTE_NAME, username),
+                ModificationOperation.ADD_ATTRIBUTE);
+        ModifyResponse modifyResponse = ldapConnection.modify(modifyRequest);
+        if (modifyResponse.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS) {
+            logger.warn("add member to cybergateway group ldap operation reported not being successful: " + modifyResponse);
+        } else {
+            logger.debug("add member to cybergateway group ldap operation was successful: " + modifyResponse);
+        }
+    }
+
+    private void installLdapPublicKey(LdapConnection ldapConnection, String username, String finalSSHPublicKey) throws LdapException {
+        String dn = "uid=" + username + "," + ldapBaseDN;
+
+        String ldapPublicKey = getLdapPublicKey(ldapConnection, username);
+        Entry entry = ldapConnection.lookup(dn);
+        if (entry == null) {
+            throw new RuntimeException("User [" + username + "] has no entry for " + dn);
+        }
+
+        ModifyRequest modifyRequest = new ModifyRequestImpl();
+        modifyRequest.setName(new Dn(dn));
+
+        // Add or Replace, depending on whether there is already an ldapPublicKey on the entry
+        if (ldapPublicKey == null) {
+
+            modifyRequest.addModification(new DefaultAttribute("objectclass", LDAP_PUBLIC_KEY_OBJECT_CLASS), ModificationOperation.ADD_ATTRIBUTE);
+            modifyRequest.addModification(new DefaultAttribute(SSH_PUBLIC_KEY_ATTRIBUTE_NAME, finalSSHPublicKey),
+                    ModificationOperation.ADD_ATTRIBUTE);
+        } else {
+
+            if (!ldapPublicKey.equals(finalSSHPublicKey)) {
+                 modifyRequest.addModification(new DefaultAttribute(SSH_PUBLIC_KEY_ATTRIBUTE_NAME,
+                        finalSSHPublicKey), ModificationOperation.REPLACE_ATTRIBUTE);
+            }
+        }
+        ModifyResponse modifyResponse = ldapConnection.modify(modifyRequest);
+        if (modifyResponse.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS) {
+            logger.warn("installSSHKey ldap operation reported not being successful: " + modifyResponse);
+        } else {
+            logger.debug("installSSHKey ldap operation was successful: " + modifyResponse);
+        }
+    }
+
+    private String getLdapPublicKey(LdapConnection ldapConnection, String username) throws LdapException {
+
+        String dn = "uid=" + username + "," + ldapBaseDN;
+
+        Entry entry = ldapConnection.lookup(dn);
+        if (entry == null) {
+            throw new RuntimeException("User [" + username + "] has no entry for " + dn);
+        }
+        boolean hasLdapPublicKey = entry.hasObjectClass(LDAP_PUBLIC_KEY_OBJECT_CLASS);
+        return hasLdapPublicKey ? entry.get(SSH_PUBLIC_KEY_ATTRIBUTE_NAME).getString() : null;
+    }
+
     @Override
     public String getScratchLocation(String userId) throws InvalidUsernameException {
         String username = getUsername(userId);
@@ -183,10 +256,18 @@ public class IULdapSSHAccountProvisioner implements SSHAccountProvisioner  {
         config.put(IULdapSSHAccountProvisionerProvider.LDAP_PASSWORD, ldapPassword);
         config.put(IULdapSSHAccountProvisionerProvider.LDAP_BASE_DN, "ou=bigred2-sgrc,dc=rt,dc=iu,dc=edu");
         config.put(IULdapSSHAccountProvisionerProvider.CANONICAL_SCRATCH_LOCATION, "/N/dc2/scratch/${username}/iu-gateway");
+        config.put(IULdapSSHAccountProvisionerProvider.CYBERGATEWAY_GROUP_DN, "cn=cybergateway,ou=Group,dc=rt,dc=iu,dc=edu");
         sshAccountProvisioner.init(config);
         String userId = "machrist@iu.edu";
         System.out.println("hasAccount=" + sshAccountProvisioner.hasAccount(userId));
         System.out.println("scratchLocation=" + sshAccountProvisioner.getScratchLocation(userId));
-        sshAccountProvisioner.installSSHKey(userId, "foobar1234");
+        String sshPublicKey = "foobar12345";
+        boolean sshAccountProvisioningComplete = sshAccountProvisioner.isSSHAccountProvisioningComplete(userId, sshPublicKey);
+        System.out.println("isSSHAccountProvisioningComplete=" + sshAccountProvisioningComplete);
+        if (!sshAccountProvisioningComplete) {
+            sshAccountProvisioner.installSSHKey(userId, sshPublicKey);
+            sshAccountProvisioningComplete = sshAccountProvisioner.isSSHAccountProvisioningComplete(userId, sshPublicKey);
+            System.out.println("isSSHAccountProvisioningComplete=" + sshAccountProvisioningComplete);
+        }
     }
 }
diff --git a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/provisioner/IULdapSSHAccountProvisionerProvider.java b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/provisioner/IULdapSSHAccountProvisionerProvider.java
index 9089ac3..b09334d 100644
--- a/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/provisioner/IULdapSSHAccountProvisionerProvider.java
+++ b/modules/compute-account-provisioning/src/main/java/org/apache/airavata/accountprovisioning/provisioner/IULdapSSHAccountProvisionerProvider.java
@@ -54,7 +54,11 @@ public class IULdapSSHAccountProvisionerProvider implements SSHAccountProvisione
             .setDescription("Pattern for scratch location. Use ${username} as replacement for username. For example, '/N/dc2/scratch/${username}/iu-gateway'.")
             .setOptional(false)
             .setType(ConfigParam.ConfigParamType.STRING);
-    public static final List<ConfigParam> CONFIG_PARAMS = Arrays.asList(LDAP_HOST, LDAP_PORT, LDAP_USERNAME, LDAP_PASSWORD, LDAP_BASE_DN, CANONICAL_SCRATCH_LOCATION);
+    public static final ConfigParam CYBERGATEWAY_GROUP_DN = new ConfigParam("cybergateway-group-dn")
+            .setDescription("Cybergateway group DN")
+            .setOptional(false)
+            .setType(ConfigParam.ConfigParamType.STRING);
+    public static final List<ConfigParam> CONFIG_PARAMS = Arrays.asList(LDAP_HOST, LDAP_PORT, LDAP_USERNAME, LDAP_PASSWORD, LDAP_BASE_DN, CANONICAL_SCRATCH_LOCATION, CYBERGATEWAY_GROUP_DN);
 
     @Override
     public List<ConfigParam> getConfigParams() {
diff --git a/modules/compute-account-provisioning/src/test/java/org/apache/airavata/accountprovisioning/provisioner/TestSSHAccountProvisioner.java b/modules/compute-account-provisioning/src/test/java/org/apache/airavata/accountprovisioning/provisioner/TestSSHAccountProvisioner.java
index 4cdcbd6..0df60de 100644
--- a/modules/compute-account-provisioning/src/test/java/org/apache/airavata/accountprovisioning/provisioner/TestSSHAccountProvisioner.java
+++ b/modules/compute-account-provisioning/src/test/java/org/apache/airavata/accountprovisioning/provisioner/TestSSHAccountProvisioner.java
@@ -48,6 +48,11 @@ public class TestSSHAccountProvisioner implements SSHAccountProvisioner {
     }
 
     @Override
+    public boolean isSSHAccountProvisioningComplete(String userId, String sshPublicKey) throws InvalidUsernameException {
+        return false;
+    }
+
+    @Override
     public String installSSHKey(String userId, String sshPublicKey) throws InvalidUsernameException {
 
         return userId;