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

[3/3] airavata git commit: AIRAVATA-2402 Migrate user roles to Keycloak

AIRAVATA-2402 Migrate user roles to Keycloak


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

Branch: refs/heads/develop
Commit: bd526ade0ac87f9b3673cebd1e029761ee018a57
Parents: 020ecae
Author: Marcus Christie <ma...@apache.org>
Authored: Thu Jun 1 16:13:10 2017 -0400
Committer: Marcus Christie <ma...@apache.org>
Committed: Thu Jun 1 16:13:10 2017 -0400

----------------------------------------------------------------------
 .../airavata/KeycloakIdentityServerClient.java  | 76 ++++++++++++++++++--
 .../org/apache/airavata/MigrationManager.java   | 46 +++++++++---
 .../org/apache/airavata/UserProfileDAO.java     |  9 +++
 3 files changed, 119 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/airavata/blob/bd526ade/modules/user-profile-migration/src/main/java/org/apache/airavata/KeycloakIdentityServerClient.java
----------------------------------------------------------------------
diff --git a/modules/user-profile-migration/src/main/java/org/apache/airavata/KeycloakIdentityServerClient.java b/modules/user-profile-migration/src/main/java/org/apache/airavata/KeycloakIdentityServerClient.java
index cd55487..ed1bb8a 100644
--- a/modules/user-profile-migration/src/main/java/org/apache/airavata/KeycloakIdentityServerClient.java
+++ b/modules/user-profile-migration/src/main/java/org/apache/airavata/KeycloakIdentityServerClient.java
@@ -21,28 +21,79 @@ package org.apache.airavata;
  *
  */
 
+import org.apache.airavata.common.utils.ServerSettings;
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
 import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.KeycloakBuilder;
 import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 
+import javax.management.relation.Role;
 import javax.ws.rs.core.Response;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.KeyStore;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 public class KeycloakIdentityServerClient {
 
     private Keycloak client;
 
-    public KeycloakIdentityServerClient(String adminUrl, String realm, String adminUserName, String adminUserPassword) {
-        this.client = Keycloak.getInstance(
+    public KeycloakIdentityServerClient(String adminUrl, String realm, String adminUserName, String adminUserPassword, String trustStorePath, String trustStorePassword) {
+        KeyStore trustKeyStore = loadKeyStore(trustStorePath, trustStorePassword);
+        this.client = getClient(
                 adminUrl,
                 realm, // the realm to log in to
                 adminUserName, adminUserPassword,  // the user
-                "admin-cli"); // admin-cli is the client ID used for keycloak admin operations.
+                "admin-cli", // admin-cli is the client ID used for keycloak admin operations.
+                trustKeyStore);
     }
+    private Keycloak getClient(String adminUrl, String realm, String adminUserName, String adminUserPassword, String clientId, KeyStore trustKeyStore) {
 
-    boolean migrateUserStore(List<UserProfileDAO> userProfiles, String targetRealm, String tempPassword){
+        ResteasyClient resteasyClient = new ResteasyClientBuilder()
+                .connectionPoolSize(10)
+                .trustStore(trustKeyStore)
+                .build();
+        return KeycloakBuilder.builder()
+                .serverUrl(adminUrl)
+                .realm(realm)
+                .username(adminUserName)
+                .password(adminUserPassword)
+                .clientId(clientId)
+                .resteasyClient(resteasyClient)
+                .build();
+    }
+
+    private KeyStore loadKeyStore(String trustStorePath, String trustStorePassword) {
+
+        FileInputStream fis = null;
+        try {
+            fis = new java.io.FileInputStream(trustStorePath);
+            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+            ks.load(fis, trustStorePassword.toCharArray());
+            return ks;
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to load trust store KeyStore instance", e);
+        } finally {
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    throw new RuntimeException("Failed to close trust store FileInputStream", e);
+                }
+            }
+        }
+    }
+
+    boolean migrateUserStore(List<UserProfileDAO> userProfiles, String targetRealm, String tempPassword, Map<String,String> roleConversionMap){
+
+        Map<String, RoleRepresentation> allRealmRoles = getRealmRoleNameMap(targetRealm);
 
         for(UserProfileDAO userProfile : userProfiles){
             UserRepresentation user = new UserRepresentation();
@@ -63,6 +114,17 @@ public class KeycloakIdentityServerClient {
                         user.getEmail(),
                         0,1);
                 UserResource retirievedUser = this.client.realm(targetRealm).users().get(retrieveCreatedUserList.get(0).getId());
+
+                // Add user to realm roles
+                List<RoleRepresentation> userRealmRoles = userProfile.getRoles().stream()
+                        .filter(r -> roleConversionMap.containsKey(r))
+                        // Convert from IS role name to Keycloak role name
+                        .map(r -> roleConversionMap.get(r))
+                        // Convert from Keycloak role name to RoleRepresentation
+                        .map(r -> allRealmRoles.get(r))
+                        .collect(Collectors.toList());
+                retirievedUser.roles().realmLevel().add(userRealmRoles);
+
                 CredentialRepresentation credential = new CredentialRepresentation();
                 credential.setType(CredentialRepresentation.PASSWORD);
                 credential.setValue(tempPassword);
@@ -74,4 +136,10 @@ public class KeycloakIdentityServerClient {
         return true;
     }
 
+    private Map<String,RoleRepresentation> getRealmRoleNameMap(String targetRealm) {
+        return this.client.realm(targetRealm).roles().list()
+                .stream()
+                .collect(Collectors.toMap(r -> r.getName(), r -> r));
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/bd526ade/modules/user-profile-migration/src/main/java/org/apache/airavata/MigrationManager.java
----------------------------------------------------------------------
diff --git a/modules/user-profile-migration/src/main/java/org/apache/airavata/MigrationManager.java b/modules/user-profile-migration/src/main/java/org/apache/airavata/MigrationManager.java
index 85353ce..2cfbe59 100644
--- a/modules/user-profile-migration/src/main/java/org/apache/airavata/MigrationManager.java
+++ b/modules/user-profile-migration/src/main/java/org/apache/airavata/MigrationManager.java
@@ -21,6 +21,7 @@ package org.apache.airavata;
 
 import org.apache.airavata.common.exception.ApplicationSettingsException;
 import org.apache.airavata.model.security.AuthzToken;
+import org.apache.airavata.model.user.Status;
 import org.apache.airavata.model.user.UserProfile;
 import org.apache.airavata.service.profile.user.cpi.UserProfileService;
 import org.apache.thrift.TException;
@@ -29,8 +30,8 @@ import org.wso2.carbon.um.ws.api.stub.RemoteUserStoreManagerServiceStub;
 import org.wso2.carbon.um.ws.api.stub.RemoteUserStoreManagerServiceUserStoreExceptionException;
 
 import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
 
 public class MigrationManager {
 
@@ -38,10 +39,21 @@ public class MigrationManager {
     private static AuthzToken authzToken = new AuthzToken("empy_token");
     private String profileServiceServerHost = "localhost";
     private int profileServiceServerPort = 8962;
+    private Map<String,String> roleConversionMap = createDefaultRoleConversionMap();
+
+    private Map<String,String> createDefaultRoleConversionMap() {
+        Map<String,String> roleConversionMap = new HashMap<>();
+        roleConversionMap.put("admin", "admin");
+        roleConversionMap.put("admin-read-only", "admin-read-only");
+        roleConversionMap.put("gateway-user", "gateway-user");
+        roleConversionMap.put("user-pending", "user-pending");
+        roleConversionMap.put("gateway-provider", "gateway-provider");
+        return roleConversionMap;
+    }
     /*Add the credentials for all the tenants from which the profile should be migrated to Airavata DB*/
 
     public void setISLoginCredentials(){
-        adminCredentials.add(new Wso2ISLoginCredentialsDAO("prod.seagrid","username","password"));
+        adminCredentials.add(new Wso2ISLoginCredentialsDAO("gateway-id","username","password"));
         // new credential records here...
     }
 
@@ -55,7 +67,7 @@ public class MigrationManager {
             System.out.println("Fetching User Profiles for " + creds.getGateway() + " tenant ...");
             try {
                 userList = isClient.getUserList("http://wso2.org/claims/givenname", "*", "default");
-                System.out.println("FirstName\tLastName\tEmail\t\t\tuserName\tCountry\tOrganization\tphone");
+                System.out.println("FirstName\tLastName\tEmail\t\t\tuserName\tCountry\tOrganization\tphone\tRoles");
                 String[] claims = {"http://wso2.org/claims/givenname",
                         "http://wso2.org/claims/lastname",
                         "http://wso2.org/claims/emailaddress",
@@ -63,7 +75,8 @@ public class MigrationManager {
                         "http://wso2.org/claims/organization",
                         "http://wso2.org/claims/mobile",
                         "http://wso2.org/claims/telephone",
-                        "http://wso2.org/claims/streetaddress"};
+                        "http://wso2.org/claims/streetaddress",
+                        "http://wso2.org/claims/role"};
                 for (String user : userList) {
                     UserProfileDAO userProfile = new UserProfileDAO();
                     ClaimValue[] retrievedClaimValues = isClient.getUserClaimValuesForClaims(user, claims, null);
@@ -83,12 +96,14 @@ public class MigrationManager {
                             phones.add(claim.getValue());
                         } else if(claim.getClaimURI().equals(claims[7])){
                             userProfile.setAddress(claim.getValue());
+                        } else if(claim.getClaimURI().equals(claims[8])){
+                            userProfile.setRoles(convertCommaSeparatedRolesToList(claim.getValue()));
                         }
                     }
                     userProfile.setUserName(user);
                     userProfile.setGatewayID(creds.getGateway());
                     userProfile.setPhones(phones);
-                    System.out.println(userProfile.getFirstName()+"\t"+userProfile.getLastName()+"\t"+userProfile.getUserName()+"\t"+userProfile.getEmail()+"\t"+userProfile.getCountry()+"\t"+userProfile.getOrganization() + userProfile.getAddress());
+                    System.out.println(userProfile.getFirstName()+"\t"+userProfile.getLastName()+"\t"+userProfile.getUserName()+"\t"+userProfile.getEmail()+"\t"+userProfile.getCountry()+"\t"+userProfile.getOrganization() + "\t" + userProfile.getAddress() + "\t" + userProfile.getRoles());
                     userProfileList.add(userProfile);
                 }
             } catch (RemoteException e) {
@@ -105,6 +120,14 @@ public class MigrationManager {
         return userProfileList;
     }
 
+    private List<String> convertCommaSeparatedRolesToList(String roles) {
+
+        return Arrays.stream(roles.split(","))
+                .filter(s -> !"Internal/everyone".equals(s))
+                .filter(s -> !"Internal/identity".equals(s))
+                .collect(Collectors.toList());
+    }
+
     /* Method used to migrate User profiles to Airavata DB by making a call to User profile thrift Service */
     private boolean migrateUserProfilesToAiravata(List<UserProfileDAO> ISProfileList) throws TException, ApplicationSettingsException {
         System.out.println("Initiating migration to Airavata internal DB ...");
@@ -113,6 +136,7 @@ public class MigrationManager {
         UserProfile airavataUserProfile = new UserProfile();
         // Here are the data associations...
         for(UserProfileDAO ISProfile : ISProfileList){
+            airavataUserProfile.setAiravataInternalUserId(ISProfile.getUserName() + "@" + ISProfile.getGatewayID());
             airavataUserProfile.setFirstName(ISProfile.getFirstName());
             airavataUserProfile.setLastName(ISProfile.getLastName());
             airavataUserProfile.setUserId(ISProfile.getUserName());
@@ -123,6 +147,10 @@ public class MigrationManager {
             airavataUserProfile.setHomeOrganization(ISProfile.getOrganization());
             airavataUserProfile.setPhones(ISProfile.getPhones());
             airavataUserProfile.setCountry(ISProfile.getCountry());
+            airavataUserProfile.setCreationTime(new Date().getTime());
+            airavataUserProfile.setLastAccessTime(new Date().getTime());
+            airavataUserProfile.setValidUntil(-1);
+            airavataUserProfile.setState(Status.ACTIVE);
             //TODO: fix authtzToken, for now we are using empty token
             client.addUserProfile(authzToken, airavataUserProfile);
         }
@@ -133,8 +161,10 @@ public class MigrationManager {
         KeycloakIdentityServerClient client = new KeycloakIdentityServerClient("https://iam.scigap.org/auth",
                 "master",
                 "SuperRealmUsername",
-                "MasterRealmPassword");
-        client.migrateUserStore(Wso2ISProfileList,"keycloakTargetRealm","tempPassword");
+                "MasterRealmPassword",
+                "trustStorePath",
+                "trustStorePassword");
+        client.migrateUserStore(Wso2ISProfileList,"keycloakTargetRealm","tempPassword", roleConversionMap);
     }
 
     public static void main(String[] args) {

http://git-wip-us.apache.org/repos/asf/airavata/blob/bd526ade/modules/user-profile-migration/src/main/java/org/apache/airavata/UserProfileDAO.java
----------------------------------------------------------------------
diff --git a/modules/user-profile-migration/src/main/java/org/apache/airavata/UserProfileDAO.java b/modules/user-profile-migration/src/main/java/org/apache/airavata/UserProfileDAO.java
index cb000cf..12571b2 100644
--- a/modules/user-profile-migration/src/main/java/org/apache/airavata/UserProfileDAO.java
+++ b/modules/user-profile-migration/src/main/java/org/apache/airavata/UserProfileDAO.java
@@ -32,6 +32,7 @@ public class UserProfileDAO {
     private List<String> Phones;
     private String gatewayID;
     private String address;
+    private List<String> roles;
 
     public String getAddress() {
         return address;
@@ -115,4 +116,12 @@ public class UserProfileDAO {
     public void setEmail(String email) {
         this.email = email;
     }
+
+    public List<String> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<String> roles) {
+        this.roles = roles;
+    }
 }