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

yasith pushed a commit to branch feat/grpc-armeria-migration
in repository https://gitbox.apache.org/repos/asf/airavata.git

commit 85eabc164d6e23957796e2ef6dee450cdf407c8f
Author: yasithdev <[email protected]>
AuthorDate: Wed Apr 1 13:10:21 2026 -0400

    feat: extract credential-service as independent Maven module
    
    Move credential handler, model, repository, service, task, and util
    packages from airavata-api into a new credential-service module.
    Keep the CredentialProvider SPI and provisioning interfaces in
    airavata-api so other modules can depend on abstractions without
    pulling in the full credential implementation.
    
    - CredentialStoreServerHandler now implements CredentialProvider SPI
    - Expand SPI with addSSHCredential/deleteSSHCredential methods
    - Update execution/compute/security files to use CredentialProvider
    - Move AiravataDataMigrator to credential-service (deep credential deps)
    - Refactor SlurmTaskFactory to use reflection for EnvSetupTask
    - Simplify GFACPassiveJobSubmitter gateway resolution
---
 airavata-api/credential-service/pom.xml            | 51 +++++++++++++
 .../handler/CredentialStoreServerHandler.java      |  7 +-
 .../airavata/credential/model/AuditInfo.java       |  0
 .../credential/model/CertificateAuditInfo.java     |  0
 .../credential/model/CertificateCredential.java    |  0
 .../airavata/credential/model/CommunityUser.java   |  0
 .../airavata/credential/model/Credential.java      |  0
 .../credential/model/PasswordCredential.java       |  0
 .../airavata/credential/model/SSHCredential.java   |  0
 .../repository/CertificateCredentialWriter.java    |  0
 .../credential/repository/CredentialReader.java    |  0
 .../repository/CredentialReaderFactory.java        |  0
 .../repository/CredentialReaderImpl.java           |  0
 .../repository/CredentialStoreException.java       |  0
 .../credential/repository/CredentialWriter.java    |  0
 .../credential/repository/SSHCredentialWriter.java |  0
 .../credential/repository/db/CommunityUserDAO.java |  0
 .../credential/repository/db/CredentialsDAO.java   |  0
 .../repository/db/MigrateCredentialEncryption.java |  0
 .../credential/repository/db/ParentDAO.java        |  0
 .../util/CredentialStoreDBInitConfig.java          |  0
 .../repository/util/CredentialStoreJDBCConfig.java |  0
 .../credential/service/CredentialService.java      |  0
 .../credential/service/SSHAccountService.java      |  0
 .../service/provisioning/ConfigParam.java          | 88 ++++++++++++++++++++++
 .../provisioning/InvalidSetupException.java}       | 21 +++---
 .../provisioning/InvalidUsernameException.java}    | 21 +++---
 .../service/provisioning/SSHAccountManager.java    |  0
 .../provisioning/SSHAccountProvisioner.java        | 85 +++++++++++++++++++++
 .../provisioning/SSHAccountProvisionerFactory.java | 64 ++++++++++++++++
 .../SSHAccountProvisionerProvider.java             | 59 +++++++++++++++
 .../credential/service/provisioning/SSHUtil.java   |  0
 .../provisioner/IULdapSSHAccountProvisioner.java   |  0
 .../IULdapSSHAccountProvisionerProvider.java       |  0
 .../airavata/credential/task/EnvSetupTask.java     |  0
 .../credential/util/ConfigurationReader.java       |  0
 .../credential/util/CredentialStoreConstants.java  |  0
 .../airavata/credential/util/PrivateKeyStore.java  |  0
 .../airavata/credential/util/TokenGenerator.java   |  0
 .../apache/airavata/credential/util/Utility.java   |  0
 .../util/notifier/CredentialStoreNotifier.java     |  0
 .../util/notifier/NotificationMessage.java         |  0
 .../util/notifier/NotifierBootstrap.java           |  0
 .../notifier/impl/EmailNotificationMessage.java    |  0
 .../util/notifier/impl/EmailNotifier.java          |  0
 .../notifier/impl/EmailNotifierConfiguration.java  |  0
 .../sharing/util/AiravataDataMigrator.java         |  0
 .../repository/db/CommunityUserDAOTest.java        |  0
 .../repository/db/CredentialsDAOTest.java          |  0
 .../repository/db/SSHCredentialTest.java           |  0
 .../credential/service/CredentialServiceTest.java  |  0
 .../credential/service/SSHAccountServiceTest.java  |  0
 .../SSHAccountProvisionerFactoryTest.java          |  0
 .../provisioner/TestSSHAccountProvisioner.java     |  0
 .../TestSSHAccountProvisionerProvider.java         |  0
 .../store/cpi/SSHSummaryTest/SSHSummaryTest.java   |  0
 .../credential/util/ConfigurationReaderTest.java   |  0
 .../credential/util/TokenGeneratorTest.java        |  0
 .../util/notifier/impl/EmailNotifierTest.java      |  0
 .../compute/service/ApplicationCatalogService.java |  6 +-
 .../apache/airavata/compute/util/AgentUtils.java   | 12 ++-
 .../credential/spi/CredentialProvider.java         | 19 +++++
 .../execution/monitor/ClusterStatusMonitorJob.java | 15 ++--
 .../orchestrator/GFACPassiveJobSubmitter.java      | 36 +++------
 .../execution/orchestrator/OrchestratorUtils.java  | 16 ----
 .../execution/orchestrator/SlurmTaskFactory.java   | 11 ++-
 .../security/service/GatewayGroupsInitializer.java | 20 +++--
 .../service/ApplicationCatalogServiceTest.java     |  4 +-
 .../service/GatewayGroupsInitializerTest.java      |  4 +-
 airavata-server/pom.xml                            |  5 ++
 pom.xml                                            |  1 +
 71 files changed, 449 insertions(+), 96 deletions(-)

diff --git a/airavata-api/credential-service/pom.xml 
b/airavata-api/credential-service/pom.xml
new file mode 100644
index 0000000000..d4ab1415c8
--- /dev/null
+++ b/airavata-api/credential-service/pom.xml
@@ -0,0 +1,51 @@
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.airavata</groupId>
+        <artifactId>airavata</artifactId>
+        <version>0.21-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>credential-service</artifactId>
+    <name>Credential Service</name>
+    <description>Credential store service implementation</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.airavata</groupId>
+            <artifactId>airavata-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Spring (optional in airavata-api, needed here for 
@Component/@Service) -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/handler/CredentialStoreServerHandler.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/handler/CredentialStoreServerHandler.java
similarity index 99%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/handler/CredentialStoreServerHandler.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/handler/CredentialStoreServerHandler.java
index 091cb55f6f..a709cff253 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/credential/handler/CredentialStoreServerHandler.java
+++ 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/handler/CredentialStoreServerHandler.java
@@ -37,6 +37,7 @@ import 
org.apache.airavata.credential.repository.CredentialReaderImpl;
 import org.apache.airavata.credential.repository.CredentialStoreException;
 import org.apache.airavata.credential.repository.SSHCredentialWriter;
 import 
org.apache.airavata.credential.repository.util.CredentialStoreDBInitConfig;
+import org.apache.airavata.credential.spi.CredentialProvider;
 import org.apache.airavata.credential.util.TokenGenerator;
 import org.apache.airavata.credential.util.Utility;
 import org.apache.airavata.model.credential.store.proto.*;
@@ -47,7 +48,7 @@ import org.springframework.stereotype.Component;
 // import sun.security.provider.X509Factory;
 
 @Component
-public class CredentialStoreServerHandler {
+public class CredentialStoreServerHandler implements CredentialProvider {
     protected static Logger log = 
LoggerFactory.getLogger(CredentialStoreServerHandler.class);
     private DBUtil dbUtil;
     private SSHCredentialWriter sshCredentialWriter;
@@ -72,6 +73,7 @@ public class CredentialStoreServerHandler {
         credentialReader = new CredentialReaderImpl(dbUtil);
     }
 
+    @Override
     public String addSSHCredential(SSHCredential sshCredential)
             throws CredentialStoreException {
         try {
@@ -170,6 +172,7 @@ public class CredentialStoreServerHandler {
         }
     }
 
+    @Override
     public SSHCredential getSSHCredential(String tokenId, String gatewayId)
             throws CredentialStoreException {
         try {
@@ -359,6 +362,7 @@ public class CredentialStoreServerHandler {
         }
     }
 
+    @Override
     public PasswordCredential getPasswordCredential(String tokenId, String 
gatewayId)
             throws CredentialStoreException {
         try {
@@ -474,6 +478,7 @@ public class CredentialStoreServerHandler {
         return pwdCredMap;
     }
 
+    @Override
     public boolean deleteSSHCredential(String tokenId, String gatewayId)
             throws CredentialStoreException {
         try {
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/AuditInfo.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/AuditInfo.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/model/AuditInfo.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/AuditInfo.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/CertificateAuditInfo.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/CertificateAuditInfo.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/model/CertificateAuditInfo.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/CertificateAuditInfo.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/CertificateCredential.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/CertificateCredential.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/model/CertificateCredential.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/CertificateCredential.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/CommunityUser.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/CommunityUser.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/model/CommunityUser.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/CommunityUser.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/Credential.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/Credential.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/model/Credential.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/Credential.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/PasswordCredential.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/PasswordCredential.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/model/PasswordCredential.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/PasswordCredential.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/SSHCredential.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/SSHCredential.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/model/SSHCredential.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/model/SSHCredential.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CertificateCredentialWriter.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CertificateCredentialWriter.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/CertificateCredentialWriter.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CertificateCredentialWriter.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReader.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialReader.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReader.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialReader.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReaderFactory.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialReaderFactory.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReaderFactory.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialReaderFactory.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReaderImpl.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialReaderImpl.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReaderImpl.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialReaderImpl.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
similarity index 100%
copy from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
copy to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialWriter.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialWriter.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialWriter.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/CredentialWriter.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/SSHCredentialWriter.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/SSHCredentialWriter.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/SSHCredentialWriter.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/SSHCredentialWriter.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/db/CommunityUserDAO.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/db/CommunityUserDAO.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/db/CommunityUserDAO.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/db/CommunityUserDAO.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/db/CredentialsDAO.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/db/CredentialsDAO.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/db/CredentialsDAO.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/db/CredentialsDAO.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/db/MigrateCredentialEncryption.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/db/MigrateCredentialEncryption.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/db/MigrateCredentialEncryption.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/db/MigrateCredentialEncryption.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/db/ParentDAO.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/db/ParentDAO.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/db/ParentDAO.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/db/ParentDAO.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/util/CredentialStoreDBInitConfig.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/util/CredentialStoreDBInitConfig.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/util/CredentialStoreDBInitConfig.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/util/CredentialStoreDBInitConfig.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/util/CredentialStoreJDBCConfig.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/util/CredentialStoreJDBCConfig.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/util/CredentialStoreJDBCConfig.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/repository/util/CredentialStoreJDBCConfig.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/service/CredentialService.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/CredentialService.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/service/CredentialService.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/CredentialService.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/service/SSHAccountService.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/SSHAccountService.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/service/SSHAccountService.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/SSHAccountService.java
diff --git 
a/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/ConfigParam.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/ConfigParam.java
new file mode 100644
index 0000000000..c24564fa63
--- /dev/null
+++ 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/ConfigParam.java
@@ -0,0 +1,88 @@
+/**
+*
+* 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.credential.service.provisioning;
+
+public class ConfigParam {
+
+    public enum ConfigParamType {
+        STRING,
+        CRED_STORE_PASSWORD_TOKEN,
+    }
+
+    private boolean optional = false;
+    private String name;
+    private String description;
+    private ConfigParamType type = ConfigParamType.STRING;
+
+    public ConfigParam(String name) {
+        this.name = name;
+    }
+
+    public boolean isOptional() {
+        return optional;
+    }
+
+    public ConfigParam setOptional(boolean optional) {
+        this.optional = optional;
+        return this;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ConfigParam setName(String name) {
+        this.name = name;
+        return this;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public ConfigParam setDescription(String description) {
+        this.description = description;
+        return this;
+    }
+
+    public ConfigParamType getType() {
+        return type;
+    }
+
+    public ConfigParam setType(ConfigParamType type) {
+        this.type = type;
+        return this;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof ConfigParam)) return false;
+
+        ConfigParam that = (ConfigParam) o;
+
+        return name.equals(that.name);
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/InvalidSetupException.java
similarity index 59%
copy from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
copy to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/InvalidSetupException.java
index 9a62b0c3f2..123ebc2997 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
+++ 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/InvalidSetupException.java
@@ -17,22 +17,25 @@
 * specific language governing permissions and limitations
 * under the License.
 */
-package org.apache.airavata.credential.repository;
+package org.apache.airavata.credential.service.provisioning;
 
 /**
- * An exception class for credential store.
+ * This exception indicates that some SSHAccountProvisioner setup is missing 
or incorrect.
+ * Message should indicate what is invalid and potentially how to fix it.
  */
-public class CredentialStoreException extends Exception {
+public class InvalidSetupException extends Exception {
 
-    public CredentialStoreException() {
-        super();
+    public InvalidSetupException() {}
+
+    public InvalidSetupException(String message) {
+        super(message);
     }
 
-    public CredentialStoreException(String s) {
-        super(s);
+    public InvalidSetupException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public CredentialStoreException(String s, Throwable throwable) {
-        super(s, throwable);
+    public InvalidSetupException(Throwable cause) {
+        super(cause);
     }
 }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/InvalidUsernameException.java
similarity index 54%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/InvalidUsernameException.java
index 9a62b0c3f2..c59d63d1fe 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialStoreException.java
+++ 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/InvalidUsernameException.java
@@ -17,22 +17,25 @@
 * specific language governing permissions and limitations
 * under the License.
 */
-package org.apache.airavata.credential.repository;
+package org.apache.airavata.credential.service.provisioning;
 
 /**
- * An exception class for credential store.
+ * Thrown by {@link SSHAccountProvisioner} when provided userId doesn't map to 
a local account for any user. For
+ * example, the provided userId maps to a username that doesn't have an 
account on the cluster but that also doesn't
+ * exist at that institution.
  */
-public class CredentialStoreException extends Exception {
+public class InvalidUsernameException extends Exception {
+    public InvalidUsernameException() {}
 
-    public CredentialStoreException() {
-        super();
+    public InvalidUsernameException(String message) {
+        super(message);
     }
 
-    public CredentialStoreException(String s) {
-        super(s);
+    public InvalidUsernameException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public CredentialStoreException(String s, Throwable throwable) {
-        super(s, throwable);
+    public InvalidUsernameException(Throwable cause) {
+        super(cause);
     }
 }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountManager.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountManager.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountManager.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountManager.java
diff --git 
a/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisioner.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisioner.java
new file mode 100644
index 0000000000..be26b627d7
--- /dev/null
+++ 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisioner.java
@@ -0,0 +1,85 @@
+/**
+*
+* 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.credential.service.provisioning;
+
+import java.util.Map;
+
+/**
+ * An SSHAccountProvisioner is capable of installing an Airavata-managed SSH 
public key onto a compute host for a user.
+ * SSHAccountProvisioners may also optionally provide the capability to create 
accounts directly on the compute host
+ * for the user. An SSHAccountProvisioner's {@link 
SSHAccountProvisionerProvider} provides some methods to define the
+ * configuration params that this SSHAccountProvisioner requires as well as 
some metadata method to describe the
+ * capabilities of this SSHAccountProvisioner.
+ */
+public interface SSHAccountProvisioner {
+
+    /**
+     * Initialize this SSHAccountProvisioner.
+     * @param config
+     */
+    void init(Map<ConfigParam, String> config);
+
+    /**
+     * Return true if this user has an account on the compute host
+     * @param userId the Airavata user id
+     * @return
+     * @throws InvalidUsernameException
+     */
+    boolean hasAccount(String userId) throws InvalidUsernameException;
+
+    /**
+     * Create an account for the user if no account exists.  May throw {@link 
UnsupportedOperationException} if
+     * unimplemented for this SSHAccountProvisioner.
+     * @param userId the Airavata user id
+     * @param sshPublicKey the public key part of an Airavata managed SSH 
credential
+     * @return username
+     * @throws InvalidUsernameException
+     */
+    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
+     * @return username
+     * @throws InvalidUsernameException
+     */
+    String installSSHKey(String userId, String sshPublicKey) throws 
InvalidUsernameException;
+
+    /**
+     * Get the scratch location that should be created for the user. Note: 
this method doesn't create the scratch
+     * location on the compute host, it merely determines a path to a good 
scratch location to be used by a gateway
+     * on behalf of the user.
+     *
+     * @param userId
+     * @return a filesystem path (e.g. "/N/scratch/username/some-gateway")
+     * @throws InvalidUsernameException
+     */
+    String getScratchLocation(String userId) throws InvalidUsernameException;
+}
diff --git 
a/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerFactory.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerFactory.java
new file mode 100644
index 0000000000..614193ceac
--- /dev/null
+++ 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerFactory.java
@@ -0,0 +1,64 @@
+/**
+*
+* 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.credential.service.provisioning;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+public class SSHAccountProvisionerFactory {
+
+    private static ServiceLoader<SSHAccountProvisionerProvider> 
sshAccountProvisionerProviders =
+            ServiceLoader.load(SSHAccountProvisionerProvider.class);
+
+    public static List<SSHAccountProvisionerProvider> 
getSSHAccountProvisionerProviders() {
+        List<SSHAccountProvisionerProvider> providers = new ArrayList<>();
+        sshAccountProvisionerProviders.forEach(providers::add);
+        return providers;
+    }
+
+    public static List<ConfigParam> 
getSSHAccountProvisionerConfigParams(String provisionerName) {
+
+        return 
getSSHAccountProvisionerProvider(provisionerName).getConfigParams();
+    }
+
+    public static boolean canCreateAccount(String provisionerName) {
+        return 
getSSHAccountProvisionerProvider(provisionerName).canCreateAccount();
+    }
+
+    public static SSHAccountProvisioner createSSHAccountProvisioner(
+            String provisionerName, Map<ConfigParam, String> config) {
+
+        SSHAccountProvisionerProvider sshAccountProvisionerProvider = 
getSSHAccountProvisionerProvider(provisionerName);
+
+        return 
sshAccountProvisionerProvider.createSSHAccountProvisioner(config);
+    }
+
+    private static SSHAccountProvisionerProvider 
getSSHAccountProvisionerProvider(String provisionerName) {
+
+        for (SSHAccountProvisionerProvider sshAccountProvisionerProvider : 
sshAccountProvisionerProviders) {
+            if 
(sshAccountProvisionerProvider.getName().equals(provisionerName)) {
+                return sshAccountProvisionerProvider;
+            }
+        }
+        throw new RuntimeException("Unknown SSHAccountProvisioner named " + 
provisionerName);
+    }
+}
diff --git 
a/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerProvider.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerProvider.java
new file mode 100644
index 0000000000..8b5f539b75
--- /dev/null
+++ 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerProvider.java
@@ -0,0 +1,59 @@
+/**
+*
+* 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.credential.service.provisioning;
+
+import java.util.List;
+import java.util.Map;
+
+public interface SSHAccountProvisionerProvider {
+
+    /**
+     * An identifying name for the SSHAccountProvisioner instances created by 
this provider.
+     * This name should be unique amongst all SSHAccountProvisioner 
implementations.
+     */
+    default String getName() {
+        return this.getClass().getName();
+    }
+
+    /**
+     * Return the {@link ConfigParam}s for the associated 
SSHAccountProvisioner.
+     * @return
+     */
+    List<ConfigParam> getConfigParams();
+
+    /**
+     * Instantiate and initialize the associated SSHAccountProvisioner.
+     * @param config
+     * @return
+     */
+    SSHAccountProvisioner createSSHAccountProvisioner(Map<ConfigParam, String> 
config);
+
+    /**
+     * Return true if the associated SSHAccountProvisioner can create accounts 
for a user on a compute host.
+     * @return
+     */
+    boolean canCreateAccount();
+
+    /**
+     * Return true if the associated SSHAccountProvisioner can install an SSH 
public key on a compute host for the user.
+     * @return
+     */
+    boolean canInstallSSHKey();
+}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/service/provisioning/SSHUtil.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHUtil.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/service/provisioning/SSHUtil.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/SSHUtil.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/service/provisioning/provisioner/IULdapSSHAccountProvisioner.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/provisioner/IULdapSSHAccountProvisioner.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/service/provisioning/provisioner/IULdapSSHAccountProvisioner.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/provisioner/IULdapSSHAccountProvisioner.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/service/provisioning/provisioner/IULdapSSHAccountProvisionerProvider.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/provisioner/IULdapSSHAccountProvisionerProvider.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/service/provisioning/provisioner/IULdapSSHAccountProvisionerProvider.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/service/provisioning/provisioner/IULdapSSHAccountProvisionerProvider.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/task/EnvSetupTask.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/task/EnvSetupTask.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/task/EnvSetupTask.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/task/EnvSetupTask.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/ConfigurationReader.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/ConfigurationReader.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/ConfigurationReader.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/ConfigurationReader.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/CredentialStoreConstants.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/CredentialStoreConstants.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/CredentialStoreConstants.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/CredentialStoreConstants.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/PrivateKeyStore.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/PrivateKeyStore.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/PrivateKeyStore.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/PrivateKeyStore.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/TokenGenerator.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/TokenGenerator.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/TokenGenerator.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/TokenGenerator.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/Utility.java 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/Utility.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/Utility.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/Utility.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/CredentialStoreNotifier.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/CredentialStoreNotifier.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/CredentialStoreNotifier.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/CredentialStoreNotifier.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/NotificationMessage.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/NotificationMessage.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/NotificationMessage.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/NotificationMessage.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/NotifierBootstrap.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/NotifierBootstrap.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/NotifierBootstrap.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/NotifierBootstrap.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotificationMessage.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotificationMessage.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotificationMessage.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotificationMessage.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifier.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifier.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifier.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifier.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifierConfiguration.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifierConfiguration.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifierConfiguration.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifierConfiguration.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/sharing/util/AiravataDataMigrator.java
 
b/airavata-api/credential-service/src/main/java/org/apache/airavata/sharing/util/AiravataDataMigrator.java
similarity index 100%
rename from 
airavata-api/src/main/java/org/apache/airavata/sharing/util/AiravataDataMigrator.java
rename to 
airavata-api/credential-service/src/main/java/org/apache/airavata/sharing/util/AiravataDataMigrator.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/repository/db/CommunityUserDAOTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/repository/db/CommunityUserDAOTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/repository/db/CommunityUserDAOTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/repository/db/CommunityUserDAOTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/repository/db/CredentialsDAOTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/repository/db/CredentialsDAOTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/repository/db/CredentialsDAOTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/repository/db/CredentialsDAOTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/repository/db/SSHCredentialTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/repository/db/SSHCredentialTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/repository/db/SSHCredentialTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/repository/db/SSHCredentialTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/service/CredentialServiceTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/CredentialServiceTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/service/CredentialServiceTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/CredentialServiceTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/service/SSHAccountServiceTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/SSHAccountServiceTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/service/SSHAccountServiceTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/SSHAccountServiceTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerFactoryTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerFactoryTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerFactoryTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/provisioning/SSHAccountProvisionerFactoryTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/service/provisioning/provisioner/TestSSHAccountProvisioner.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/provisioning/provisioner/TestSSHAccountProvisioner.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/service/provisioning/provisioner/TestSSHAccountProvisioner.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/provisioning/provisioner/TestSSHAccountProvisioner.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/service/provisioning/provisioner/TestSSHAccountProvisionerProvider.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/provisioning/provisioner/TestSSHAccountProvisionerProvider.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/service/provisioning/provisioner/TestSSHAccountProvisionerProvider.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/service/provisioning/provisioner/TestSSHAccountProvisionerProvider.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/store/cpi/SSHSummaryTest/SSHSummaryTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/store/cpi/SSHSummaryTest/SSHSummaryTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/store/cpi/SSHSummaryTest/SSHSummaryTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/store/cpi/SSHSummaryTest/SSHSummaryTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/util/ConfigurationReaderTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/util/ConfigurationReaderTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/util/ConfigurationReaderTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/util/ConfigurationReaderTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/util/TokenGeneratorTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/util/TokenGeneratorTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/util/TokenGeneratorTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/util/TokenGeneratorTest.java
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifierTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifierTest.java
similarity index 100%
rename from 
airavata-api/src/test/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifierTest.java
rename to 
airavata-api/credential-service/src/test/java/org/apache/airavata/credential/util/notifier/impl/EmailNotifierTest.java
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/compute/service/ApplicationCatalogService.java
 
b/airavata-api/src/main/java/org/apache/airavata/compute/service/ApplicationCatalogService.java
index 8641d997bb..3ec333518a 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/compute/service/ApplicationCatalogService.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/compute/service/ApplicationCatalogService.java
@@ -22,7 +22,7 @@ package org.apache.airavata.compute.service;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import org.apache.airavata.credential.handler.CredentialStoreServerHandler;
+import org.apache.airavata.credential.spi.CredentialProvider;
 import org.apache.airavata.execution.handler.RegistryServerHandler;
 import org.apache.airavata.execution.service.RequestContext;
 import org.apache.airavata.execution.service.ServiceAuthorizationException;
@@ -54,12 +54,12 @@ public class ApplicationCatalogService {
 
     private final RegistryServerHandler registryHandler;
     private final SharingRegistryServerHandler sharingHandler;
-    private final CredentialStoreServerHandler credentialHandler;
+    private final CredentialProvider credentialHandler;
 
     public ApplicationCatalogService(
             RegistryServerHandler registryHandler,
             SharingRegistryServerHandler sharingHandler,
-            CredentialStoreServerHandler credentialHandler) {
+            CredentialProvider credentialHandler) {
         this.registryHandler = registryHandler;
         this.sharingHandler = sharingHandler;
         this.credentialHandler = credentialHandler;
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/compute/util/AgentUtils.java 
b/airavata-api/src/main/java/org/apache/airavata/compute/util/AgentUtils.java
index 170b778a64..7494f4a522 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/compute/util/AgentUtils.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/compute/util/AgentUtils.java
@@ -19,7 +19,7 @@
 */
 package org.apache.airavata.compute.util;
 
-import org.apache.airavata.credential.handler.CredentialStoreServerHandler;
+import org.apache.airavata.credential.spi.CredentialProvider;
 import org.apache.airavata.execution.handler.RegistryServerHandler;
 import org.apache.airavata.execution.scheduler.Utils;
 
@@ -29,11 +29,9 @@ public class AgentUtils {
         return Utils.getRegistryHandler();
     }
 
-    public static CredentialStoreServerHandler getCredentialClient() throws 
AgentException {
-        try {
-            return new CredentialStoreServerHandler();
-        } catch (Exception e) {
-            throw new AgentException("Unable to create 
CredentialStoreServerHandler...", e);
-        }
+    public static CredentialProvider getCredentialClient() throws 
AgentException {
+        return java.util.ServiceLoader.load(CredentialProvider.class)
+                .findFirst()
+                .orElseThrow(() -> new AgentException("No CredentialProvider 
implementation found on classpath"));
     }
 }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/spi/CredentialProvider.java
 
b/airavata-api/src/main/java/org/apache/airavata/credential/spi/CredentialProvider.java
index ae5aa3efec..41c7e75445 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/credential/spi/CredentialProvider.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/credential/spi/CredentialProvider.java
@@ -50,4 +50,23 @@ public interface CredentialProvider {
      * @throws Exception if a credential store error occurs
      */
     PasswordCredential getPasswordCredential(String tokenId, String gatewayId) 
throws Exception;
+
+    /**
+     * Store an SSH credential and return its generated token.
+     *
+     * @param sshCredential the SSH credential to store
+     * @return the generated credential token
+     * @throws Exception if a credential store error occurs
+     */
+    String addSSHCredential(SSHCredential sshCredential) throws Exception;
+
+    /**
+     * Delete an SSH credential by its token and gateway.
+     *
+     * @param tokenId   the credential token identifier
+     * @param gatewayId the gateway identifier
+     * @return {@code true} if the credential was deleted
+     * @throws Exception if a credential store error occurs
+     */
+    boolean deleteSSHCredential(String tokenId, String gatewayId) throws 
Exception;
 }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/execution/monitor/ClusterStatusMonitorJob.java
 
b/airavata-api/src/main/java/org/apache/airavata/execution/monitor/ClusterStatusMonitorJob.java
index 03073782d9..241759e807 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/execution/monitor/ClusterStatusMonitorJob.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/execution/monitor/ClusterStatusMonitorJob.java
@@ -27,7 +27,7 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.airavata.common.config.ServerSettings;
-import org.apache.airavata.credential.handler.CredentialStoreServerHandler;
+import org.apache.airavata.credential.spi.CredentialProvider;
 import 
org.apache.airavata.model.appcatalog.computeresource.proto.ComputeResourceDescription;
 import 
org.apache.airavata.model.appcatalog.computeresource.proto.JobSubmissionInterface;
 import 
org.apache.airavata.model.appcatalog.computeresource.proto.JobSubmissionProtocol;
@@ -121,7 +121,7 @@ public class ClusterStatusMonitorJob implements Job {
 
                 try {
                     JSch jsch = new JSch();
-                    CredentialStoreServerHandler credentialClient = 
getCredentialStoreHandler();
+                    CredentialProvider credentialClient = 
getCredentialProvider();
                     SSHCredential sshCredential = 
credentialClient.getSSHCredential(
                             computeResourceProfile.getCredentialStoreToken(), 
superTenantGatewayId);
                     jsch.addIdentity(
@@ -226,12 +226,11 @@ public class ClusterStatusMonitorJob implements Job {
         return 
org.apache.airavata.execution.scheduler.Utils.getRegistryHandler();
     }
 
-    private static CredentialStoreServerHandler getCredentialStoreHandler() {
-        try {
-            return new CredentialStoreServerHandler();
-        } catch (Exception e) {
-            throw new RuntimeException("Failed to create 
CredentialStoreServerHandler", e);
-        }
+    private static CredentialProvider getCredentialProvider() {
+        // Resolved at runtime via ServiceLoader when credential-service is on 
the classpath
+        return java.util.ServiceLoader.load(CredentialProvider.class)
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException("No CredentialProvider 
implementation found on classpath"));
     }
 
     private static class ComputeResourceProfile {
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/GFACPassiveJobSubmitter.java
 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/GFACPassiveJobSubmitter.java
index 5c976e4bcc..8427a82032 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/GFACPassiveJobSubmitter.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/GFACPassiveJobSubmitter.java
@@ -23,7 +23,6 @@ import java.util.UUID;
 import org.apache.airavata.common.config.ServerSettings;
 import org.apache.airavata.common.exception.AiravataException;
 import org.apache.airavata.common.util.AiravataUtils;
-import org.apache.airavata.credential.repository.CredentialReader;
 import org.apache.airavata.messaging.service.MessageContext;
 import org.apache.airavata.messaging.service.MessagingFactory;
 import org.apache.airavata.messaging.service.Publisher;
@@ -69,18 +68,7 @@ public class GFACPassiveJobSubmitter implements 
JobSubmitter, Watcher {
      */
     public boolean submit(String experimentId, String processId, String 
tokenId) throws OrchestratorException {
         try {
-            String gatewayId = null;
-            CredentialReader credentialReader = 
OrchestratorUtils.getCredentialReader();
-            if (credentialReader != null) {
-                try {
-                    gatewayId = credentialReader.getGatewayID(tokenId);
-                } catch (Exception e) {
-                    logger.error(e.getLocalizedMessage());
-                }
-            }
-            if (gatewayId == null || gatewayId.isEmpty()) {
-                gatewayId = ServerSettings.getDefaultUserGateway();
-            }
+            String gatewayId = resolveGatewayId();
             ProcessSubmitEvent processSubmitEvent = 
ProcessSubmitEvent.newBuilder()
                     .setProcessId(processId)
                     .setGatewayId(gatewayId)
@@ -109,20 +97,8 @@ public class GFACPassiveJobSubmitter implements 
JobSubmitter, Watcher {
      * @throws OrchestratorException
      */
     public boolean terminate(String experimentId, String processId, String 
tokenId) throws OrchestratorException {
-        String gatewayId = null;
         try {
-            CredentialReader credentialReader = 
OrchestratorUtils.getCredentialReader();
-            if (credentialReader != null) {
-                try {
-                    gatewayId = credentialReader.getGatewayID(tokenId);
-                } catch (Exception e) {
-                    logger.error(e.getLocalizedMessage());
-                }
-            }
-            if (gatewayId == null || gatewayId.isEmpty()) {
-
-                gatewayId = ServerSettings.getDefaultUserGateway();
-            }
+            String gatewayId = resolveGatewayId();
             ProcessTerminateEvent processTerminateEvent = 
ProcessTerminateEvent.newBuilder()
                     .setProcessId(processId)
                     .setGatewayId(gatewayId)
@@ -141,6 +117,14 @@ public class GFACPassiveJobSubmitter implements 
JobSubmitter, Watcher {
         }
     }
 
+    private static String resolveGatewayId() {
+        try {
+            return ServerSettings.getDefaultUserGateway();
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to resolve gateway id", e);
+        }
+    }
+
     public synchronized void process(WatchedEvent event) {
         logger.info(getClass().getName() + event.getPath());
         logger.info(getClass().getName() + event.getType());
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/OrchestratorUtils.java
 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/OrchestratorUtils.java
index 2ec7d85014..10bfdcf5d9 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/OrchestratorUtils.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/OrchestratorUtils.java
@@ -25,11 +25,8 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import org.apache.airavata.common.config.ServerSettings;
-import org.apache.airavata.common.db.DBUtil;
 import org.apache.airavata.common.exception.AiravataException;
 import org.apache.airavata.common.exception.ApplicationSettingsException;
-import org.apache.airavata.credential.repository.CredentialReader;
-import org.apache.airavata.credential.repository.CredentialReaderImpl;
 import org.apache.airavata.execution.scheduler.Utils;
 import 
org.apache.airavata.model.appcatalog.appinterface.proto.ApplicationInterfaceDescription;
 import 
org.apache.airavata.model.appcatalog.computeresource.proto.CloudJobSubmission;
@@ -350,17 +347,4 @@ public class OrchestratorUtils {
         return Utils.getRegistryHandler();
     }
 
-    public static CredentialReader getCredentialReader()
-            throws ApplicationSettingsException, IllegalAccessException, 
InstantiationException {
-        try {
-            String jdbcUrl = ServerSettings.getCredentialStoreDBURL();
-            String jdbcUsr = ServerSettings.getCredentialStoreDBUser();
-            String jdbcPass = ServerSettings.getCredentialStoreDBPassword();
-            String driver = ServerSettings.getCredentialStoreDBDriver();
-            return new CredentialReaderImpl(new DBUtil(jdbcUrl, jdbcUsr, 
jdbcPass, driver));
-        } catch (ClassNotFoundException e) {
-            logger.error("Not able to find driver: " + 
e.getLocalizedMessage());
-            return null;
-        }
-    }
 }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/SlurmTaskFactory.java
 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/SlurmTaskFactory.java
index e796b5b17b..7a7b605761 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/SlurmTaskFactory.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/SlurmTaskFactory.java
@@ -20,7 +20,6 @@
 package org.apache.airavata.execution.orchestrator;
 
 import org.apache.airavata.compute.task.DefaultJobSubmissionTask;
-import org.apache.airavata.credential.task.EnvSetupTask;
 import org.apache.airavata.execution.task.CompletingTask;
 import org.apache.airavata.execution.task.JobVerificationTask;
 import org.apache.airavata.execution.task.ParsingTriggeringTask;
@@ -34,10 +33,18 @@ public class SlurmTaskFactory implements HelixTaskFactory {
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(SlurmTaskFactory.class);
 
+    private static final String ENV_SETUP_TASK_CLASS = 
"org.apache.airavata.credential.task.EnvSetupTask";
+
     @Override
     public AiravataTask createEnvSetupTask(String processId) {
         LOGGER.info("Creating Slurm EnvSetupTask for process {}...", 
processId);
-        return new EnvSetupTask();
+        try {
+            return (AiravataTask) Class.forName(ENV_SETUP_TASK_CLASS)
+                    .getDeclaredConstructor()
+                    .newInstance();
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException("Failed to create EnvSetupTask; is 
credential-service on the classpath?", e);
+        }
     }
 
     @Override
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/security/service/GatewayGroupsInitializer.java
 
b/airavata-api/src/main/java/org/apache/airavata/security/service/GatewayGroupsInitializer.java
index 7d216499e4..b9248af79e 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/security/service/GatewayGroupsInitializer.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/security/service/GatewayGroupsInitializer.java
@@ -20,7 +20,7 @@
 package org.apache.airavata.security.service;
 
 import org.apache.airavata.common.util.AiravataUtils;
-import org.apache.airavata.credential.handler.CredentialStoreServerHandler;
+import org.apache.airavata.credential.spi.CredentialProvider;
 import org.apache.airavata.execution.handler.RegistryServerHandler;
 import org.apache.airavata.model.appcatalog.gatewaygroups.proto.GatewayGroups;
 import 
org.apache.airavata.model.appcatalog.gatewayprofile.proto.GatewayResourceProfile;
@@ -46,7 +46,7 @@ public class GatewayGroupsInitializer {
             throw new RuntimeException("Failed to create 
SharingRegistryServerHandler", e);
         }
         RegistryServerHandler registryClient = createRegistryClient();
-        CredentialStoreServerHandler credentialStoreHandler = 
createCredentialStoreHandler();
+        CredentialProvider credentialStoreHandler = 
createCredentialStoreHandler();
         try {
             GatewayGroupsInitializer gatewayGroupsInitializer =
                     new GatewayGroupsInitializer(registryClient, 
sharingRegistryHandler, credentialStoreHandler);
@@ -58,12 +58,12 @@ public class GatewayGroupsInitializer {
 
     private RegistryServerHandler registryClient;
     private SharingRegistryServerHandler sharingRegistryClient;
-    private CredentialStoreServerHandler credentialStoreClient;
+    private CredentialProvider credentialStoreClient;
 
     public GatewayGroupsInitializer(
             RegistryServerHandler registryClient,
             SharingRegistryServerHandler sharingRegistryClient,
-            CredentialStoreServerHandler credentialStoreClient) {
+            CredentialProvider credentialStoreClient) {
 
         this.registryClient = registryClient;
         this.sharingRegistryClient = sharingRegistryClient;
@@ -142,7 +142,7 @@ public class GatewayGroupsInitializer {
     }
 
     private String getAdminOwnerUsername(
-            RegistryServerHandler registryClient, CredentialStoreServerHandler 
credentialStoreClient, String gatewayId)
+            RegistryServerHandler registryClient, CredentialProvider 
credentialStoreClient, String gatewayId)
             throws Exception {
 
         GatewayResourceProfile gatewayResourceProfile = 
registryClient.getGatewayResourceProfile(gatewayId);
@@ -156,11 +156,9 @@ public class GatewayGroupsInitializer {
         return new RegistryServerHandler();
     }
 
-    private static CredentialStoreServerHandler createCredentialStoreHandler() 
{
-        try {
-            return new CredentialStoreServerHandler();
-        } catch (Exception e) {
-            throw new RuntimeException("Unable to create 
CredentialStoreServerHandler...", e);
-        }
+    private static CredentialProvider createCredentialStoreHandler() {
+        return java.util.ServiceLoader.load(CredentialProvider.class)
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException("No CredentialProvider 
implementation found on classpath"));
     }
 }
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/compute/service/ApplicationCatalogServiceTest.java
 
b/airavata-api/src/test/java/org/apache/airavata/compute/service/ApplicationCatalogServiceTest.java
index c873066a1b..233c1205bd 100644
--- 
a/airavata-api/src/test/java/org/apache/airavata/compute/service/ApplicationCatalogServiceTest.java
+++ 
b/airavata-api/src/test/java/org/apache/airavata/compute/service/ApplicationCatalogServiceTest.java
@@ -24,7 +24,7 @@ import static org.mockito.Mockito.*;
 
 import java.util.List;
 import java.util.Map;
-import org.apache.airavata.credential.handler.CredentialStoreServerHandler;
+import org.apache.airavata.credential.spi.CredentialProvider;
 import org.apache.airavata.execution.handler.RegistryServerHandler;
 import org.apache.airavata.execution.service.RequestContext;
 import org.apache.airavata.execution.service.ServiceException;
@@ -50,7 +50,7 @@ class ApplicationCatalogServiceTest {
     SharingRegistryServerHandler sharingHandler;
 
     @Mock
-    CredentialStoreServerHandler credentialHandler;
+    CredentialProvider credentialHandler;
 
     ApplicationCatalogService service;
     RequestContext ctx;
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/security/service/GatewayGroupsInitializerTest.java
 
b/airavata-api/src/test/java/org/apache/airavata/security/service/GatewayGroupsInitializerTest.java
index 9aadda3490..01522dd3d1 100644
--- 
a/airavata-api/src/test/java/org/apache/airavata/security/service/GatewayGroupsInitializerTest.java
+++ 
b/airavata-api/src/test/java/org/apache/airavata/security/service/GatewayGroupsInitializerTest.java
@@ -26,7 +26,7 @@ import java.util.List;
 import mockit.Expectations;
 import mockit.Mocked;
 import mockit.Verifications;
-import org.apache.airavata.credential.handler.CredentialStoreServerHandler;
+import org.apache.airavata.credential.spi.CredentialProvider;
 import org.apache.airavata.execution.handler.RegistryServerHandler;
 import org.apache.airavata.model.appcatalog.gatewaygroups.proto.GatewayGroups;
 import 
org.apache.airavata.model.appcatalog.gatewayprofile.proto.GatewayResourceProfile;
@@ -53,7 +53,7 @@ public class GatewayGroupsInitializerTest {
     SharingRegistryServerHandler mockSharingRegistryClient;
 
     @Mocked
-    CredentialStoreServerHandler mockCredentialStoreClient;
+    CredentialProvider mockCredentialStoreClient;
 
     GatewayGroupsInitializer gatewayGroupsInitializer;
 
diff --git a/airavata-server/pom.xml b/airavata-server/pom.xml
index 32ba53c7b0..4ac965d5c0 100644
--- a/airavata-server/pom.xml
+++ b/airavata-server/pom.xml
@@ -53,6 +53,11 @@ under the License.
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.airavata</groupId>
+            <artifactId>credential-service</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.airavata</groupId>
             <artifactId>agent-service</artifactId>
diff --git a/pom.xml b/pom.xml
index 1463666e3f..485f8aab2f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,6 +71,7 @@ under the License.
         <module>airavata-api</module>
         <module>airavata-api/agent-service</module>
         <module>airavata-api/research-service</module>
+        <module>airavata-api/credential-service</module>
         <module>airavata-server</module>
     </modules>
 

Reply via email to