You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by di...@apache.org on 2019/06/20 17:59:48 UTC

[airavata] branch master updated: Adding user email to groovy map

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

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


The following commit(s) were added to refs/heads/master by this push:
     new ca6a54f  Adding user email to groovy map
ca6a54f is described below

commit ca6a54f5f8c503368c25d95d1405529f3de8869d
Author: Dimuthu Wannipurage <di...@gmail.com>
AuthorDate: Thu Jun 20 13:59:35 2019 -0400

    Adding user email to groovy map
---
 airavata-services/services-security/pom.xml        |   5 +
 .../service/security/AiravataSecurityManager.java  |   2 +
 .../service/security/KeyCloakSecurityManager.java  | 105 ++++++++++++++++++++-
 .../participant/airavata-server.properties.j2      |   6 ++
 modules/airavata-helix/helix-spectator/pom.xml     |  10 ++
 .../airavata/helix/impl/task/AiravataTask.java     |  14 +++
 .../airavata/helix/impl/task/TaskContext.java      |  41 +++++++-
 .../task/submission/config/GroovyMapBuilder.java   |   6 +-
 .../impl/task/submission/config/GroovyMapData.java |  11 +++
 9 files changed, 193 insertions(+), 7 deletions(-)

diff --git a/airavata-services/services-security/pom.xml b/airavata-services/services-security/pom.xml
index 7ac3532..d5aa334 100644
--- a/airavata-services/services-security/pom.xml
+++ b/airavata-services/services-security/pom.xml
@@ -57,6 +57,11 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.airavata</groupId>
+            <artifactId>airavata-sharing-registry-stubs</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
             <version>4.4</version>
diff --git a/airavata-services/services-security/src/main/java/org/apache/airavata/service/security/AiravataSecurityManager.java b/airavata-services/services-security/src/main/java/org/apache/airavata/service/security/AiravataSecurityManager.java
index dcd04fb..895c4a6 100644
--- a/airavata-services/services-security/src/main/java/org/apache/airavata/service/security/AiravataSecurityManager.java
+++ b/airavata-services/services-security/src/main/java/org/apache/airavata/service/security/AiravataSecurityManager.java
@@ -39,4 +39,6 @@ public interface AiravataSecurityManager {
      * @throws AiravataSecurityException
      */
     public boolean isUserAuthorized(AuthzToken authzToken, Map<String, String> metaData) throws AiravataSecurityException;
+
+    public AuthzToken getUserManagementServiceAccountAuthzToken(String gatewayId) throws AiravataSecurityException;
 }
diff --git a/airavata-services/services-security/src/main/java/org/apache/airavata/service/security/KeyCloakSecurityManager.java b/airavata-services/services-security/src/main/java/org/apache/airavata/service/security/KeyCloakSecurityManager.java
index 38b70c5..f7987b6 100644
--- a/airavata-services/services-security/src/main/java/org/apache/airavata/service/security/KeyCloakSecurityManager.java
+++ b/airavata-services/services-security/src/main/java/org/apache/airavata/service/security/KeyCloakSecurityManager.java
@@ -22,18 +22,33 @@ package org.apache.airavata.service.security;
 import org.apache.airavata.common.exception.ApplicationSettingsException;
 import org.apache.airavata.common.utils.Constants;
 import org.apache.airavata.common.utils.ServerSettings;
+import org.apache.airavata.common.utils.ThriftUtils;
 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.gatewayprofile.GatewayResourceProfile;
 import org.apache.airavata.model.credential.store.PasswordCredential;
 import org.apache.airavata.model.security.AuthzToken;
+import org.apache.airavata.model.workspace.Gateway;
 import org.apache.airavata.registry.api.client.RegistryServiceClientFactory;
 import org.apache.airavata.registry.api.exception.RegistryServiceException;
 import org.apache.airavata.security.AiravataSecurityException;
 import org.apache.airavata.security.util.TrustStoreManager;
 import org.apache.airavata.service.security.authzcache.*;
 import org.apache.airavata.registry.api.RegistryService;
+import org.apache.airavata.sharing.registry.client.SharingRegistryServiceClientFactory;
+import org.apache.airavata.sharing.registry.models.SharingRegistryException;
+import org.apache.airavata.sharing.registry.service.cpi.SharingRegistryService;
+import org.apache.http.Consts;
+import org.apache.http.HttpHeaders;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
 import org.apache.thrift.TException;
 import org.json.JSONArray;
 import org.json.JSONObject;
@@ -41,11 +56,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.BufferedReader;
+import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -71,6 +87,9 @@ public class KeyCloakSecurityManager implements AiravataSecurityManager {
                     // configured for a gateway's compute resource preference
                     "/airavata/getGatewayResourceProfile";
 
+    private RegistryService.Client registryServiceClient = null;
+    private SharingRegistryService.Client sharingRegistryServiceClient = null;
+
     public KeyCloakSecurityManager() throws AiravataSecurityException {
         rolePermissionConfig.put("admin", "/airavata/.*");
         rolePermissionConfig.put("gateway-provider", "/airavata/.*");
@@ -200,6 +219,25 @@ public class KeyCloakSecurityManager implements AiravataSecurityManager {
         }
     }
 
+    @Override
+    public AuthzToken getUserManagementServiceAccountAuthzToken(String gatewayId) throws AiravataSecurityException {
+        try {
+            initServiceClients();
+            Gateway gateway = registryServiceClient.getGateway(gatewayId);
+            String tokenURL = getTokenEndpoint(gatewayId);
+            JSONObject clientCredentials = getClientCredentials(tokenURL, gateway.getOauthClientId(), gateway.getOauthClientSecret());
+            String accessToken = clientCredentials.getString("access_token");
+            AuthzToken authzToken = new AuthzToken(accessToken);
+            authzToken.putToClaimsMap(Constants.GATEWAY_ID, gatewayId);
+            authzToken.putToClaimsMap(Constants.USER_NAME, gateway.getOauthClientId());
+            return authzToken;
+        } catch (Exception e) {
+            throw new AiravataSecurityException("Failed to fetch authorization token for user management service for gateway " + gatewayId, e);
+        } finally {
+            closeServiceClients();
+        }
+    }
+
     private String[] getUserRolesFromOAuthToken(String username, String token, String gatewayId) throws Exception {
         GatewayResourceProfile gwrp = getRegistryServiceClient().getGatewayResourceProfile(gatewayId);
         String identityServerRealm = gwrp.getIdentityServerTenant();
@@ -306,4 +344,67 @@ public class KeyCloakSecurityManager implements AiravataSecurityManager {
             throw new TException("Unable to create credential store client...", e);
         }
     }
+
+    private JSONObject getClientCredentials(String tokenURL, String clientId, String clientSecret) throws ApplicationSettingsException, AiravataSecurityException {
+
+        CloseableHttpClient httpClient = HttpClients.createSystem();
+
+        HttpPost httpPost = new HttpPost(tokenURL);
+        String encoded = Base64.getEncoder().encodeToString((clientId+":"+clientSecret).getBytes(StandardCharsets.UTF_8));
+        httpPost.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + encoded);
+        List<NameValuePair> formParams = new ArrayList<>();
+        formParams.add(new BasicNameValuePair("grant_type", "client_credentials"));
+        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
+        httpPost.setEntity(entity);
+        try {
+            CloseableHttpResponse response = httpClient.execute(httpPost);
+            try {
+                String responseBody = EntityUtils.toString(response.getEntity());
+                JSONObject tokenInfo = new JSONObject(responseBody);
+                return tokenInfo;
+            } finally {
+                response.close();
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            try {
+                httpClient.close();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+
+    private String getTokenEndpoint(String gatewayId) throws Exception {
+        String openIdConnectUrl = getOpenIDConfigurationUrl(gatewayId);
+        JSONObject openIdConnectConfig = new JSONObject(getFromUrl(openIdConnectUrl, null));
+        return openIdConnectConfig.getString("token_endpoint");
+    }
+
+    private void initServiceClients() throws TException, ApplicationSettingsException {
+        registryServiceClient = getRegistryServiceClient();
+        sharingRegistryServiceClient = getSharingRegistryServiceClient();
+    }
+
+    private void closeServiceClients() {
+        if (registryServiceClient != null) {
+            ThriftUtils.close(registryServiceClient);
+        }
+        if (sharingRegistryServiceClient != null) {
+            ThriftUtils.close(sharingRegistryServiceClient);
+        }
+    }
+
+
+    private SharingRegistryService.Client getSharingRegistryServiceClient() throws TException, ApplicationSettingsException {
+        final int serverPort = Integer.parseInt(ServerSettings.getSharingRegistryPort());
+        final String serverHost = ServerSettings.getSharingRegistryHost();
+        try {
+            return SharingRegistryServiceClientFactory.createSharingRegistryClient(serverHost, serverPort);
+        } catch (SharingRegistryException e) {
+            throw new TException("Unable to create sharing registry client...", e);
+        }
+    }
 }
\ No newline at end of file
diff --git a/dev-tools/ansible/roles/helix_setup/templates/participant/airavata-server.properties.j2 b/dev-tools/ansible/roles/helix_setup/templates/participant/airavata-server.properties.j2
index 5aee4df..517c1ec 100644
--- a/dev-tools/ansible/roles/helix_setup/templates/participant/airavata-server.properties.j2
+++ b/dev-tools/ansible/roles/helix_setup/templates/participant/airavata-server.properties.j2
@@ -29,6 +29,12 @@ credential.store.server.host={{ cred_store_server_host }}
 credential.store.server.port={{ cred_store_port }}
 
 ###########################################################################
+# Profile Server Configuration
+###########################################################################
+profile.service.server.host={{ profile_service_host }}
+profile.service.server.port={{ profile_service_port }}
+
+###########################################################################
 # Monitoring module Configuration
 ###########################################################################
 email.based.monitor.address={{ monitor_email_address }}
diff --git a/modules/airavata-helix/helix-spectator/pom.xml b/modules/airavata-helix/helix-spectator/pom.xml
index 2d2c26d..7101a7a 100644
--- a/modules/airavata-helix/helix-spectator/pom.xml
+++ b/modules/airavata-helix/helix-spectator/pom.xml
@@ -75,6 +75,16 @@
         </dependency>
         <dependency>
             <groupId>org.apache.airavata</groupId>
+            <artifactId>profile-service-stubs</artifactId>
+            <version>0.18-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.airavata</groupId>
+            <artifactId>services-security</artifactId>
+            <version>0.18-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.airavata</groupId>
             <artifactId>airavata-messaging-core</artifactId>
             <version>0.18-SNAPSHOT</version>
         </dependency>
diff --git a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/AiravataTask.java b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/AiravataTask.java
index 5041d63..230764a 100644
--- a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/AiravataTask.java
+++ b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/AiravataTask.java
@@ -43,6 +43,9 @@ import org.apache.airavata.model.status.*;
 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.airavata.service.profile.client.ProfileServiceClientFactory;
+import org.apache.airavata.service.profile.user.cpi.UserProfileService;
+import org.apache.airavata.service.profile.user.cpi.exception.UserProfileServiceException;
 import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.helix.HelixManager;
 import org.apache.helix.task.TaskResult;
@@ -394,6 +397,7 @@ public abstract class AiravataTask extends AbstractTask {
 
             TaskContext.TaskContextBuilder taskContextBuilder = new TaskContext.TaskContextBuilder(getProcessId(), getGatewayId(), getTaskId())
                     .setRegistryClient(getRegistryServiceClient())
+                    .setProfileClient(getUserProfileClient())
                     .setProcessModel(getProcessModel())
                     .setGatewayResourceProfile(getRegistryServiceClient().getGatewayResourceProfile(gatewayId))
                     .setGatewayComputeResourcePreference(
@@ -495,4 +499,14 @@ public abstract class AiravataTask extends AbstractTask {
             throw new RuntimeException("Unable to create registry client...", e);
         }
     }
+
+    public static UserProfileService.Client getUserProfileClient() {
+        try {
+            final int serverPort = Integer.parseInt(ServerSettings.getProfileServiceServerPort());
+            final String serverHost = ServerSettings.getProfileServiceServerHost();
+            return ProfileServiceClientFactory.createUserProfileServiceClient(serverHost, serverPort);
+        } catch (UserProfileServiceException | ApplicationSettingsException e) {
+            throw new RuntimeException("Unable to create profile service client...", e);
+        }
+    }
 }
diff --git a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/TaskContext.java b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/TaskContext.java
index 6c4a1bb..b686b71 100644
--- a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/TaskContext.java
+++ b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/TaskContext.java
@@ -38,16 +38,17 @@ import org.apache.airavata.model.data.movement.DataMovementProtocol;
 import org.apache.airavata.model.job.JobModel;
 import org.apache.airavata.model.process.ProcessModel;
 import org.apache.airavata.model.scheduling.ComputationalResourceSchedulingModel;
+import org.apache.airavata.model.security.AuthzToken;
 import org.apache.airavata.model.status.ProcessState;
 import org.apache.airavata.model.status.ProcessStatus;
 import org.apache.airavata.model.status.TaskState;
 import org.apache.airavata.model.status.TaskStatus;
 import org.apache.airavata.model.task.TaskModel;
+import org.apache.airavata.model.user.UserProfile;
 import org.apache.airavata.registry.api.RegistryService;
-import org.apache.airavata.registry.cpi.AppCatalog;
-import org.apache.airavata.registry.cpi.AppCatalogException;
-import org.apache.airavata.registry.cpi.ExperimentCatalog;
-import org.apache.airavata.registry.cpi.ExperimentCatalogModelType;
+import org.apache.airavata.service.profile.user.cpi.UserProfileService;
+import org.apache.airavata.service.security.AiravataSecurityManager;
+import org.apache.airavata.service.security.SecurityManagerFactory;
 import org.apache.thrift.TException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -102,6 +103,8 @@ public class TaskContext {
     private String taskId;
     private Object subTaskModel = null;
     private RegistryService.Client registryClient;
+    private UserProfileService.Client profileClient;
+    private UserProfile userProfile;
 
 
     /**
@@ -564,6 +567,29 @@ public class TaskContext {
         return registryClient;
     }
 
+    public UserProfileService.Client getProfileClient() {
+        return profileClient;
+    }
+
+    public void setProfileClient(UserProfileService.Client profileClient) {
+        this.profileClient = profileClient;
+    }
+
+    public UserProfile getUserProfile() throws TaskOnFailException {
+
+        if (this.userProfile == null) {
+            try {
+                AiravataSecurityManager securityManager = SecurityManagerFactory.getSecurityManager();
+                AuthzToken authzToken = securityManager.getUserManagementServiceAccountAuthzToken(getGatewayId());
+                this.userProfile = getProfileClient().getUserProfileById(authzToken, getProcessModel().getUserName(), getGatewayId());
+            } catch (Exception e) {
+                logger.error("Failed to fetch the user profile for user id " + processModel.getUserName(), e);
+                throw new TaskOnFailException("Failed to fetch the user profile for user id " + processModel.getUserName(), true, e);
+            }
+        }
+        return this.userProfile;
+    }
+
     private boolean isValid(String str) {
         return str != null && !str.trim().isEmpty();
     }
@@ -686,6 +712,7 @@ public class TaskContext {
         private final String gatewayId;
         private final String taskId;
         private RegistryService.Client registryClient;
+        private UserProfileService.Client profileClient;
         private GatewayResourceProfile gatewayResourceProfile;
         private ComputeResourcePreference gatewayComputeResourcePreference;
         private StoragePreference gatewayStorageResourcePreference;
@@ -726,6 +753,11 @@ public class TaskContext {
             return this;
         }
 
+        public TaskContextBuilder setProfileClient(UserProfileService.Client profileClient) {
+            this.profileClient = profileClient;
+            return this;
+        }
+
         public TaskContext build() throws Exception {
             if (notValid(gatewayResourceProfile)) {
                 throwError("Invalid GatewayResourceProfile");
@@ -746,6 +778,7 @@ public class TaskContext {
             TaskContext ctx = new TaskContext(processId, gatewayId, taskId);
             ctx.setRegistryClient(registryClient);
             ctx.setProcessModel(processModel);
+            ctx.setProfileClient(profileClient);
             ctx.setGatewayResourceProfile(gatewayResourceProfile);
             ctx.setGatewayComputeResourcePreference(gatewayComputeResourcePreference);
             ctx.setGatewayStorageResourcePreference(gatewayStorageResourcePreference);
diff --git a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapBuilder.java b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapBuilder.java
index 2d1a7bc..d849ba4 100644
--- a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapBuilder.java
+++ b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapBuilder.java
@@ -36,7 +36,6 @@ import org.apache.airavata.model.parallelism.ApplicationParallelismType;
 import org.apache.airavata.model.process.ProcessModel;
 import org.apache.airavata.model.scheduling.ComputationalResourceSchedulingModel;
 import org.apache.airavata.model.task.JobSubmissionTaskModel;
-import org.apache.airavata.registry.cpi.AppCatalogException;
 import org.apache.thrift.TException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -81,6 +80,11 @@ public class GroovyMapBuilder {
         mapData.setTaskId(taskContext.getTaskId());
         mapData.setExperimentDataDir(taskContext.getProcessModel().getExperimentDataDir());
 
+        List<String> emails = taskContext.getUserProfile().getEmails();
+        if (emails != null && emails.size() > 0) {
+            mapData.setGatewayUserEmail(emails.get(0));
+        }
+
         List<String> inputValues = getProcessInputValues(taskContext.getProcessModel().getProcessInputs(), true);
         inputValues.addAll(getProcessOutputValues(taskContext.getProcessModel().getProcessOutputs(), true));
         mapData.setInputs(inputValues);
diff --git a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapData.java b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapData.java
index 7f74361..663687d 100644
--- a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapData.java
+++ b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapData.java
@@ -60,6 +60,9 @@ public class GroovyMapData {
     @ScriptTag(name = "gatewayUserName")
     private String gatewayUserName;
 
+    @ScriptTag(name = "gatewayUserEmail")
+    private String gatewayUserEmail;
+
     @ScriptTag(name = "applicationName")
     private String applicationName;
 
@@ -231,6 +234,14 @@ public class GroovyMapData {
         return this;
     }
 
+    public String getGatewayUserEmail() {
+        return gatewayUserEmail;
+    }
+
+    public void setGatewayUserEmail(String gatewayUserEmail) {
+        this.gatewayUserEmail = gatewayUserEmail;
+    }
+
     public String getApplicationName() {
         return applicationName;
     }