From 0a28f5ba1a3ab90cab82f3ed300e8c9de911a8ed Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Wed, 12 Aug 2020 15:22:52 -0400 Subject: [PATCH 1/9] custos integration --- .../Keycloak/API/BaseKeycloakAPIEndpoint.php | 8 +- app/libraries/Keycloak/API/RoleMapper.php | 1 + app/libraries/Keycloak/Keycloak.php | 173 +++++++++++------- .../Keycloak/KeycloakServiceProvider.php | 4 +- app/libraries/Keycloak/KeycloakUtil.php | 52 +++++- 5 files changed, 161 insertions(+), 77 deletions(-) diff --git a/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php b/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php index 93e7f7de3..48f0f2027 100644 --- a/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php +++ b/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php @@ -13,17 +13,21 @@ class BaseKeycloakAPIEndpoint { protected $admin_password; protected $verify_peer; protected $cafile_path; + protected $client_id; + protected $client_secret; - function __construct($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $cafile_path) { + function __construct($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_secret) { $this->base_endpoint_url = $base_endpoint_url; $this->admin_username = $admin_username; $this->admin_password = $admin_password; $this->verify_peer = $verify_peer; $this->cafile_path = $cafile_path; + $this->client_id = $client_id; + $this->client_secret = $client_secret; } protected function getAPIAccessToken($realm) { - return KeycloakUtil::getAPIAccessToken($this->base_endpoint_url, $realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path); + return KeycloakUtil::getAPIAccessToken($this->base_endpoint_url, $realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); } } diff --git a/app/libraries/Keycloak/API/RoleMapper.php b/app/libraries/Keycloak/API/RoleMapper.php index 9a44f50cc..216cc77a7 100644 --- a/app/libraries/Keycloak/API/RoleMapper.php +++ b/app/libraries/Keycloak/API/RoleMapper.php @@ -24,6 +24,7 @@ public function getRealmRoleMappingsForUser($realm, $user_id){ // get access token for admin API $access_token = $this->getAPIAccessToken($realm); + Log::info("Access token from getAPIAccessToken ", array($access_token)); $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users/' . rawurlencode($user_id) . '/role-mappings/realm'; // Log::debug("getRealmRoleMappingsForUser url", array($url)); $r = curl_init($url); diff --git a/app/libraries/Keycloak/Keycloak.php b/app/libraries/Keycloak/Keycloak.php index 8f859755e..2ea056f16 100644 --- a/app/libraries/Keycloak/Keycloak.php +++ b/app/libraries/Keycloak/Keycloak.php @@ -2,19 +2,18 @@ namespace Keycloak; -use Keycloak\API\RoleMapper; -use Keycloak\API\Roles; -use Keycloak\API\Users; -use Keycloak\KeycloakUtil; - use CommonUtilities; - use Exception; -use Log; use Illuminate\Routing\UrlGenerator; use Illuminate\Support\Facades\Config; +use Keycloak\API\RoleMapper; +use Keycloak\API\Roles; +use Keycloak\API\Users; +use Log; +use Keycloak\KeycloakUtil; -class Keycloak { +class Keycloak +{ private $realm; private $openid_connect_discovery_url; @@ -27,6 +26,7 @@ class Keycloak { private $admin_username; private $admin_password; private $gateway_id; + private $custos_credentials_uri; // API clients private $role_mapper; @@ -37,7 +37,8 @@ class Keycloak { * Constructor * */ - public function __construct($realm, $openid_connect_discovery_url, $client_id, $client_secret, $callback_url, $cafile_path, $verify_peer, $base_endpoint_url, $admin_username, $admin_password, $gateway_id) { + public function __construct($realm, $openid_connect_discovery_url, $client_id, $client_secret, $callback_url, $cafile_path, $verify_peer, $base_endpoint_url, $admin_username, $admin_password, $gateway_id, $custos_credentials_uri) + { $this->realm = $realm; $this->openid_connect_discovery_url = $openid_connect_discovery_url; @@ -46,14 +47,15 @@ public function __construct($realm, $openid_connect_discovery_url, $client_id, $ $this->callback_url = $callback_url; $this->cafile_path = $cafile_path; $this->verify_peer = $verify_peer; - $this->base_endpoint_url = $base_endpoint_url; + $this->base_endpoint_url = $custos_credentials_uri; $this->admin_username = $admin_username; $this->admin_password = $admin_password; $this->gateway_id = $gateway_id; + $this->custos_credentials_uri = $custos_credentials_uri; - $this->role_mapper = new RoleMapper($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path); - $this->roles = new Roles($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path); - $this->users = new Users($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path); + $this->role_mapper = new RoleMapper($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); + $this->roles = new Roles($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); + $this->users = new Users($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); } /** @@ -64,9 +66,12 @@ public function __construct($realm, $openid_connect_discovery_url, $client_id, $ * @return boolean * @throws Exception */ - public function authenticate($username, $password){ + public function authenticate($username, $password) + { + + + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); - $config = $this->getOpenIDConnectDiscoveryConfiguration(); $token_endpoint = $config->token_endpoint; // Init cUrl. @@ -75,17 +80,22 @@ public function authenticate($username, $password){ // Decode compressed responses. curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); - if($this->verify_peer && $this->cafile_path){ + if ($this->verify_peer && $this->cafile_path) { curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } + $auth_credentials = $this->getAuthCredentials(); + + $iam_secret = $auth_credentials->iam_client_secret; + + // Add client ID and client secret to the headers. curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), + "Authorization: Basic " . base64_encode($this->client_id . ":" . $iam_secret), )); // Assemble POST parameters for the request. - $post_fields = "client_id=" . urlencode($this->client_id) . "&client_secret=" . urlencode($this->client_secret) . "&grant_type=password"; + $post_fields = "client_id=" . urlencode($this->client_id) . "&client_secret=" . urlencode($iam_secret) . "&grant_type=password"; $post_fields .= "&username=" . urlencode($username) . "&password=" . urlencode($password); // Obtain and return the access token from the response. @@ -99,13 +109,15 @@ public function authenticate($username, $password){ //Parse JSON return object. $result = json_decode($response); - // Log::debug("password grant type authenciation response", array($result)); + + Log::debug("password grant type authenciation response", array($result)); return $result; - } + } - public function getOAuthRequestCodeUrl($extra_params=null){ - $config = $this->getOpenIDConnectDiscoveryConfiguration(); + public function getOAuthRequestCodeUrl($extra_params = null) + { + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); $authorization_endpoint = $config->authorization_endpoint; // TODO: add state variable to request and put into session @@ -118,9 +130,10 @@ public function getOAuthRequestCodeUrl($extra_params=null){ return $url; } - public function getOAuthToken($code){ + public function getOAuthToken($code) + { - $config = $this->getOpenIDConnectDiscoveryConfiguration(); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); $token_endpoint = $config->token_endpoint; // Init cUrl. @@ -129,13 +142,17 @@ public function getOAuthToken($code){ // Decode compressed responses. curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); - if($this->verify_peer && $this->cafile_path){ + if ($this->verify_peer && $this->cafile_path) { curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } + $auth_credentials = $this->getAuthCredentials(); + + $iam_secret = $auth_credentials->iam_client_secret; + // Add client ID and client secret to the headers. curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), + "Authorization: Basic " . base64_encode($this->client_id . ":" . $iam_secret), )); // Assemble POST parameters for the request. @@ -157,9 +174,12 @@ public function getOAuthToken($code){ return $result; } - public function getUserProfileFromOAuthToken($token){ + public function getUserProfileFromOAuthToken($token) + { - $config = $this->getOpenIDConnectDiscoveryConfiguration(); + Log::info("Calling user info endpoint"); + + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); $userinfo_endpoint = $config->userinfo_endpoint; $r = curl_init($userinfo_endpoint); @@ -167,7 +187,7 @@ public function getUserProfileFromOAuthToken($token){ // Decode compressed responses. curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); - if($this->verify_peer && $this->cafile_path){ + if ($this->verify_peer && $this->cafile_path) { curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } curl_setopt($r, CURLOPT_HTTPHEADER, array( @@ -181,7 +201,7 @@ public function getUserProfileFromOAuthToken($token){ //Parse JSON return object. $userinfo = json_decode($response); - Log::debug("Keycloak userinfo", array($userinfo)); + Log::info("Keycloak userinfo", array($userinfo)); $username = $userinfo->preferred_username; $firstname = $userinfo->given_name; $lastname = $userinfo->family_name; @@ -194,7 +214,7 @@ public function getUserProfileFromOAuthToken($token){ $roles[] = $role_mapping->name; } $roles = CommonUtilities::filterAiravataRoles($roles); - return array('username'=>$username, 'firstname'=>$firstname, 'lastname'=>$lastname, 'email'=>$email, 'roles'=>$roles); + return array('username' => $username, 'firstname' => $firstname, 'lastname' => $lastname, 'email' => $email, 'roles' => $roles); } /** @@ -202,9 +222,10 @@ public function getUserProfileFromOAuthToken($token){ * @param $refreshToken * @return mixed */ - public function getRefreshedOAuthToken($refresh_token){ + public function getRefreshedOAuthToken($refresh_token) + { - $config = $this->getOpenIDConnectDiscoveryConfiguration(); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); $token_endpoint = $config->token_endpoint; // Init cUrl. @@ -213,7 +234,7 @@ public function getRefreshedOAuthToken($refresh_token){ // Decode compressed responses. curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); - if($this->verify_peer && $this->cafile_path){ + if ($this->verify_peer && $this->cafile_path) { curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } @@ -244,8 +265,9 @@ public function getRefreshedOAuthToken($refresh_token){ /** * Function to get the OAuth logout url */ - public function getOAuthLogoutUrl($redirect_uri) { - $config = $this->getOpenIDConnectDiscoveryConfiguration(); + public function getOAuthLogoutUrl($redirect_uri) + { + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); $logout_endpoint = $config->end_session_endpoint; return $logout_endpoint . '?redirect_uri=' . rawurlencode($redirect_uri); } @@ -255,12 +277,13 @@ public function getOAuthLogoutUrl($redirect_uri) { * * @return Array of usernames */ - public function listUsers(){ + public function listUsers() + { $users = $this->users->getUsers($this->realm); $usernames = []; foreach ($users as $user) { Log::debug("user", array($user)); - array_push($usernames, (object)["firstName"=>$user->firstName,"lastName"=>$user->lastName,"email"=>$user->email,"userEnabled"=>$user->enabled,"userName"=>$user->username]); + array_push($usernames, (object)["firstName" => $user->firstName, "lastName" => $user->lastName, "email" => $user->email, "userEnabled" => $user->enabled, "userName" => $user->username]); } return $usernames; } @@ -272,11 +295,12 @@ public function listUsers(){ * @param $keyword * @return Array of usernames */ - public function searchUsers($phrase){ + public function searchUsers($phrase) + { $users = $this->users->searchUsers($this->realm, $phrase); $usernames = []; foreach ($users as $user) { - array_push($usernames, (object)["firstName"=>$user->firstName,"lastName"=>$user->lastName,"email"=>$user->email,"userEnabled"=>$user->enabled,"userName"=>$user->username]); + array_push($usernames, (object)["firstName" => $user->firstName, "lastName" => $user->lastName, "email" => $user->email, "userEnabled" => $user->enabled, "userName" => $user->username]); } return $usernames; } @@ -287,7 +311,8 @@ public function searchUsers($phrase){ * * @return roles list */ - public function getAllRoles(){ + public function getAllRoles() + { try { $roles = $this->roles->getRoles($this->realm); $role_names = []; @@ -306,7 +331,8 @@ public function getAllRoles(){ * * @return array of role names */ - public function getUserRoles( $username ){ + public function getUserRoles($username) + { try { // get userid from username $user_id = $this->getUserId($username); @@ -326,11 +352,12 @@ public function getUserRoles( $username ){ * Function to update role list of user * * @param $username - * @param $roles, an Array with two entries, "deleted" and "new", each of + * @param $roles , an Array with two entries, "deleted" and "new", each of * which has a value of roles to be removed or added respectively * @return void */ - public function updateUserRoles( $username, $roles){ + public function updateUserRoles($username, $roles) + { // Log::debug("updateUserRoles", array($user_id, $roles)); try { // get userid from username @@ -343,8 +370,8 @@ public function updateUserRoles( $username, $roles){ } // Process the role deletions - if(isset($roles["deleted"])){ - if(!is_array($roles["deleted"])) + if (isset($roles["deleted"])) { + if (!is_array($roles["deleted"])) $roles["deleted"] = array($roles["deleted"]); foreach ($roles["deleted"] as $role) { $this->role_mapper->deleteRealmRoleMappingsToUser($this->realm, $user_id, array($roles_by_name[$role])); @@ -352,8 +379,8 @@ public function updateUserRoles( $username, $roles){ } // Process the role additions - if(isset($roles["new"])){ - if(!is_array($roles["new"])) + if (isset($roles["new"])) { + if (!is_array($roles["new"])) $roles["new"] = array($roles["new"]); foreach ($roles["new"] as $role) { $this->role_mapper->addRealmRoleMappingsToUser($this->realm, $user_id, array($roles_by_name[$role])); @@ -368,16 +395,17 @@ public function updateUserRoles( $username, $roles){ * Function to get the user profile of a user * @param $username */ - public function getUserProfile($username){ + public function getUserProfile($username) + { $user = $this->users->getUserByUsername($this->realm, $username); - if($user != null){ + if ($user != null) { $result = []; $result["email"] = $user->email; $result["firstname"] = $user->firstName; $result["lastname"] = $user->lastName; $result["userEnabled"] = $user->enabled; return $result; - }else{ + } else { return []; } @@ -388,33 +416,36 @@ public function getUserProfile($username){ * @param $username * @return bool */ - public function usernameExists($username){ - try{ + public function usernameExists($username) + { + try { $user = $this->users->getUserByUsername($this->realm, $username); return $user != null; - }catch (Exception $ex){ + } catch (Exception $ex) { // Username does not exists return false; } } // TODO: move this to IamAdminServices - public function isUpdatePasswordRequired($username) { + public function isUpdatePasswordRequired($username) + { - try{ + try { $user = $this->users->getUserByUsername($this->realm, $username); if ($user != null) { return in_array("UPDATE_PASSWORD", $user->requiredActions); } else { return false; } - }catch (Exception $ex){ + } catch (Exception $ex) { // Username does not exists return false; } } - public function getAdminAuthzToken() { + public function getAdminAuthzToken() + { $access_token = KeycloakUtil::getAPIAccessToken($this->base_endpoint_url, $this->realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path); $authzToken = new \Airavata\Model\Security\AuthzToken(); @@ -427,7 +458,8 @@ public function getAdminAuthzToken() { /** * Get the user's Keycloak user_id from their username */ - private function getUserId($username) { + private function getUserId($username) + { $user = $this->users->getUserByUsername($this->realm, $username); if ($user != null) { return $user->id; @@ -436,17 +468,26 @@ private function getUserId($username) { } } - private function getOpenIDConnectDiscoveryConfiguration() { + + + + private function getAuthCredentials() + { + + $post_files = "?client_id=" . urlencode($this->client_id); + $url = $this->custos_credentials_uri . $post_files; // TODO: cache the result of the request - $r = curl_init($this->openid_connect_discovery_url); + $r = curl_init($url); + + curl_setopt($r, CURLOPT_HTTPHEADER, array( + "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), + )); + + curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); // Decode compressed responses. curl_setopt($r, CURLOPT_ENCODING, 1); - curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); - if($this->verify_peer && $this->cafile_path){ - curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); - } $result = curl_exec($r); if ($result == false) { @@ -458,5 +499,7 @@ private function getOpenIDConnectDiscoveryConfiguration() { // Log::debug("openid connect discovery configuration", array($json)); return $json; } + + } diff --git a/app/libraries/Keycloak/KeycloakServiceProvider.php b/app/libraries/Keycloak/KeycloakServiceProvider.php index db64fb084..06694f347 100644 --- a/app/libraries/Keycloak/KeycloakServiceProvider.php +++ b/app/libraries/Keycloak/KeycloakServiceProvider.php @@ -46,7 +46,9 @@ public function register() $identityServerConfig['service-url'], $identityServerConfig['admin-username'], $identityServerConfig['admin-password'], - $airavataConfig['gateway-id'] + $airavataConfig['gateway-id'], + $identityServerConfig['custos-credentials-uri'] + ); }); diff --git a/app/libraries/Keycloak/KeycloakUtil.php b/app/libraries/Keycloak/KeycloakUtil.php index 41880cb54..7fc7d8cf8 100644 --- a/app/libraries/Keycloak/KeycloakUtil.php +++ b/app/libraries/Keycloak/KeycloakUtil.php @@ -1,22 +1,24 @@ token_endpoint; - $r = curl_init($base_endpoint_url . '/realms/' . rawurlencode($realm) . '/protocol/openid-connect/token'); + $r = curl_init($token_endpoint); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $verify_peer); - if($verify_peer && $cafile_path){ + if ($verify_peer && $cafile_path) { curl_setopt($r, CURLOPT_CAINFO, $cafile_path); } @@ -34,7 +36,39 @@ public static function getAPIAccessToken($base_endpoint_url, $realm, $admin_user } $result = json_decode($response); - // Log::debug("API Access Token result", array($result)); + return $result->access_token; } + + public static function getOpenIDConnectDiscoveryConfiguration($openid_connect_discovery_url, $client_id, $client_secret) + { + + $post_files = "?client_id=" . urlencode($client_id); + $url = $openid_connect_discovery_url . $post_files; + + // TODO: cache the result of the request + $r = curl_init($url); + + curl_setopt($r, CURLOPT_HTTPHEADER, array( + "Authorization: Basic " . base64_encode($client_id . ":" . $client_secret), + )); + + + curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); + // Decode compressed responses. + curl_setopt($r, CURLOPT_ENCODING, 1); + + $result = curl_exec($r); + if ($result == false) { + die("curl_exec() failed. Error: " . curl_error($r)); + } + + $json = json_decode($result); + + + // Log::debug("openid connect discovery configuration", array($json)); + return $json; + } + + } From 67ab36d1b253d450baed35020f6c7ce03ed27a45 Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Thu, 13 Aug 2020 09:49:44 -0400 Subject: [PATCH 2/9] fixing custos access issuess --- .../Keycloak/API/BaseKeycloakAPIEndpoint.php | 6 +- app/libraries/Keycloak/API/RoleMapper.php | 15 ++--- app/libraries/Keycloak/Keycloak.php | 55 ++++++++++++------- app/libraries/Keycloak/KeycloakUtil.php | 4 +- 4 files changed, 48 insertions(+), 32 deletions(-) diff --git a/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php b/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php index 48f0f2027..de9a34bb9 100644 --- a/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php +++ b/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php @@ -15,8 +15,9 @@ class BaseKeycloakAPIEndpoint { protected $cafile_path; protected $client_id; protected $client_secret; + protected $openid_discovery_endpoint_url; - function __construct($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_secret) { + function __construct($openid_discovery_endpoint_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_secret) { $this->base_endpoint_url = $base_endpoint_url; $this->admin_username = $admin_username; $this->admin_password = $admin_password; @@ -24,10 +25,11 @@ function __construct($base_endpoint_url, $admin_username, $admin_password, $veri $this->cafile_path = $cafile_path; $this->client_id = $client_id; $this->client_secret = $client_secret; + $this->openid_discovery_endpoint_url = $openid_discovery_endpoint_url; } protected function getAPIAccessToken($realm) { - return KeycloakUtil::getAPIAccessToken($this->base_endpoint_url, $realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); + return KeycloakUtil::getAPIAccessToken($this->openid_discovery_endpoint_url, $realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); } } diff --git a/app/libraries/Keycloak/API/RoleMapper.php b/app/libraries/Keycloak/API/RoleMapper.php index 216cc77a7..3c796b13c 100644 --- a/app/libraries/Keycloak/API/RoleMapper.php +++ b/app/libraries/Keycloak/API/RoleMapper.php @@ -18,14 +18,16 @@ class RoleMapper extends BaseKeycloakAPIEndpoint { * * Returns Array of RoleRepresentations */ - public function getRealmRoleMappingsForUser($realm, $user_id){ + public function getRealmRoleMappingsForUser($user_id){ // curl -H "Authorization: bearer $access_token" https://149.165.156.62:8443/auth/admin/realms/airavata/users/2c9ad2c6-0212-4aef-a5fb-9df862578934/role-mappings/realm // get access token for admin API - $access_token = $this->getAPIAccessToken($realm); - Log::info("Access token from getAPIAccessToken ", array($access_token)); - $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users/' . rawurlencode($user_id) . '/role-mappings/realm'; + + $url = $this->base_endpoint_url . 'user-management/v1.0.0/user'; + $params = "?client_id=" . urlencode($this->client_id). "&user.username=".urlencode($user_id); + $url = $url.$params; + // Log::debug("getRealmRoleMappingsForUser url", array($url)); $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); @@ -35,9 +37,8 @@ public function getRealmRoleMappingsForUser($realm, $user_id){ curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Bearer " . $access_token + "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), )); - $response = curl_exec($r); if ($response == false) { Log::error("Failed to retrieve realm role mappings for user"); @@ -45,7 +46,7 @@ public function getRealmRoleMappingsForUser($realm, $user_id){ } $result = json_decode($response); // Log::debug("getRealmRoleMappingsForUser result", array($result)); - return $result; + return $result->realm_roles; } /** diff --git a/app/libraries/Keycloak/Keycloak.php b/app/libraries/Keycloak/Keycloak.php index 2ea056f16..67d5f66d4 100644 --- a/app/libraries/Keycloak/Keycloak.php +++ b/app/libraries/Keycloak/Keycloak.php @@ -10,7 +10,6 @@ use Keycloak\API\Roles; use Keycloak\API\Users; use Log; -use Keycloak\KeycloakUtil; class Keycloak { @@ -47,15 +46,15 @@ public function __construct($realm, $openid_connect_discovery_url, $client_id, $ $this->callback_url = $callback_url; $this->cafile_path = $cafile_path; $this->verify_peer = $verify_peer; - $this->base_endpoint_url = $custos_credentials_uri; + $this->base_endpoint_url = $base_endpoint_url; $this->admin_username = $admin_username; $this->admin_password = $admin_password; $this->gateway_id = $gateway_id; $this->custos_credentials_uri = $custos_credentials_uri; - $this->role_mapper = new RoleMapper($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); - $this->roles = new Roles($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); - $this->users = new Users($base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); + $this->role_mapper = new RoleMapper($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); + $this->roles = new Roles($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); + $this->users = new Users($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); } /** @@ -69,8 +68,8 @@ public function __construct($realm, $openid_connect_discovery_url, $client_id, $ public function authenticate($username, $password) { - - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); + Log::info("Calling authenticate ", array($username)); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $token_endpoint = $config->token_endpoint; @@ -117,7 +116,8 @@ public function authenticate($username, $password) public function getOAuthRequestCodeUrl($extra_params = null) { - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); + Log::info("Calling getOAuthRequestCodeUrl ", array($extra_params)); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $authorization_endpoint = $config->authorization_endpoint; // TODO: add state variable to request and put into session @@ -133,7 +133,8 @@ public function getOAuthRequestCodeUrl($extra_params = null) public function getOAuthToken($code) { - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); + Log::info("Calling getOAuthToken ", array($code)); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $token_endpoint = $config->token_endpoint; // Init cUrl. @@ -177,9 +178,9 @@ public function getOAuthToken($code) public function getUserProfileFromOAuthToken($token) { - Log::info("Calling user info endpoint"); + Log::info("Calling getUserProfileFromOAuthToken"); - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $userinfo_endpoint = $config->userinfo_endpoint; $r = curl_init($userinfo_endpoint); @@ -208,7 +209,7 @@ public function getUserProfileFromOAuthToken($token) $email = $userinfo->email; // get roles from Keycloak API - $role_mappings = $this->role_mapper->getRealmRoleMappingsForUser($this->realm, $userinfo->sub); + $role_mappings = $this->role_mapper->getRealmRoleMappingsForUser($userinfo->sub); $roles = []; foreach ($role_mappings as $role_mapping) { $roles[] = $role_mapping->name; @@ -224,8 +225,8 @@ public function getUserProfileFromOAuthToken($token) */ public function getRefreshedOAuthToken($refresh_token) { - - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); + Log::info("Calling getRefreshedOAuthToken"); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $token_endpoint = $config->token_endpoint; // Init cUrl. @@ -238,9 +239,13 @@ public function getRefreshedOAuthToken($refresh_token) curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } + $auth_credentials = $this->getAuthCredentials(); + + $iam_secret = $auth_credentials->iam_client_secret; + // Add client ID and client secret to the headers. curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), + "Authorization: Basic " . base64_encode($this->client_id . ":" . $iam_secret), )); // Assemble POST parameters for the request. @@ -267,7 +272,8 @@ public function getRefreshedOAuthToken($refresh_token) */ public function getOAuthLogoutUrl($redirect_uri) { - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url,$this->client_id,$this->client_secret); + Log::info("Calling getOAuthLogoutUrl"); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $logout_endpoint = $config->end_session_endpoint; return $logout_endpoint . '?redirect_uri=' . rawurlencode($redirect_uri); } @@ -279,6 +285,7 @@ public function getOAuthLogoutUrl($redirect_uri) */ public function listUsers() { + Log::info("Calling listUsers"); $users = $this->users->getUsers($this->realm); $usernames = []; foreach ($users as $user) { @@ -297,6 +304,7 @@ public function listUsers() */ public function searchUsers($phrase) { + Log::info("Calling searchUsers"); $users = $this->users->searchUsers($this->realm, $phrase); $usernames = []; foreach ($users as $user) { @@ -314,6 +322,7 @@ public function searchUsers($phrase) public function getAllRoles() { try { + Log::info("Calling getAllRoles"); $roles = $this->roles->getRoles($this->realm); $role_names = []; foreach ($roles as $role) { @@ -334,10 +343,11 @@ public function getAllRoles() public function getUserRoles($username) { try { + Log::info("Calling getUserRoles"); // get userid from username $user_id = $this->getUserId($username); // Get the user's realm roles, then convert to an array of just names - $roles = $this->role_mapper->getRealmRoleMappingsForUser($this->realm, $user_id); + $roles = $this->role_mapper->getRealmRoleMappingsForUser($user_id); $role_names = []; foreach ($roles as $role) { $role_names[] = $role->name; @@ -360,6 +370,7 @@ public function updateUserRoles($username, $roles) { // Log::debug("updateUserRoles", array($user_id, $roles)); try { + Log::info("Calling updateUserRoles"); // get userid from username $user_id = $this->getUserId($username); // Get all of the roles into an array keyed by role name @@ -397,6 +408,7 @@ public function updateUserRoles($username, $roles) */ public function getUserProfile($username) { + Log::info("Calling getUserProfile"); $user = $this->users->getUserByUsername($this->realm, $username); if ($user != null) { $result = []; @@ -419,6 +431,7 @@ public function getUserProfile($username) public function usernameExists($username) { try { + Log::info("Calling usernameExists"); $user = $this->users->getUserByUsername($this->realm, $username); return $user != null; } catch (Exception $ex) { @@ -432,6 +445,7 @@ public function isUpdatePasswordRequired($username) { try { + Log::info("Calling isUpdatePasswordRequired"); $user = $this->users->getUserByUsername($this->realm, $username); if ($user != null) { return in_array("UPDATE_PASSWORD", $user->requiredActions); @@ -446,12 +460,13 @@ public function isUpdatePasswordRequired($username) public function getAdminAuthzToken() { - - $access_token = KeycloakUtil::getAPIAccessToken($this->base_endpoint_url, $this->realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path); + Log::info("Calling getAdminAuthzToken"); + $access_token = KeycloakUtil::getAPIAccessToken($this->openid_connect_discovery_url, $this->realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path); $authzToken = new \Airavata\Model\Security\AuthzToken(); $authzToken->accessToken = $access_token; $authzToken->claimsMap['gatewayID'] = $this->gateway_id; $authzToken->claimsMap['userName'] = $this->admin_username; + $authzToken->claimsMap['custosId'] = $this->client_id; return $authzToken; } @@ -469,8 +484,6 @@ private function getUserId($username) } - - private function getAuthCredentials() { diff --git a/app/libraries/Keycloak/KeycloakUtil.php b/app/libraries/Keycloak/KeycloakUtil.php index 7fc7d8cf8..185e7eb35 100644 --- a/app/libraries/Keycloak/KeycloakUtil.php +++ b/app/libraries/Keycloak/KeycloakUtil.php @@ -7,10 +7,10 @@ class KeycloakUtil { - public static function getAPIAccessToken($base_endpoint_url, $realm, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_sec) + public static function getAPIAccessToken($openid_connect_discovery_url, $realm, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_sec) { - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($base_endpoint_url,$client_id,$client_sec); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($openid_connect_discovery_url,$client_id,$client_sec); $token_endpoint = $config->token_endpoint; From 76031ea2aa2f5115e35eb471b7873cb2576e7bdc Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Thu, 13 Aug 2020 13:42:15 -0400 Subject: [PATCH 3/9] bug fixing --- app/controllers/AccountController.php | 3 +- app/libraries/Keycloak/API/RoleMapper.php | 2 +- app/libraries/Keycloak/API/Users.php | 46 ++++++++++++++--------- app/libraries/Keycloak/Keycloak.php | 2 +- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php index c95e285af..4999aa2e2 100644 --- a/app/controllers/AccountController.php +++ b/app/controllers/AccountController.php @@ -147,6 +147,7 @@ public function loginSubmit() $authzToken->accessToken = $accessToken; $authzToken->claimsMap['gatewayID'] = Config::get('pga_config.airavata')['gateway-id']; $authzToken->claimsMap['userName'] = $username; + $authzToken->claimsMap['custosId'] = Config::get('pga_config.wsis')['oauth-client-key']; Session::put('authz-token',$authzToken); Session::put('oauth-refresh-code',$refreshToken); @@ -156,7 +157,7 @@ public function loginSubmit() // AIRAVATA-3086: get gateway groups and get the groups this user is a member of $gatewayGroups = Airavata::getGatewayGroups($authzToken); $groupMemberships = GroupManagerService::getAllGroupsUserBelongs( - $authzToken, $username . "@" . Config::get('pga_config.airavata')['gateway-id']); + $authzToken, $username); $get_group_id = function($group) { return $group->id; }; diff --git a/app/libraries/Keycloak/API/RoleMapper.php b/app/libraries/Keycloak/API/RoleMapper.php index 3c796b13c..041d76b38 100644 --- a/app/libraries/Keycloak/API/RoleMapper.php +++ b/app/libraries/Keycloak/API/RoleMapper.php @@ -24,7 +24,7 @@ public function getRealmRoleMappingsForUser($user_id){ // get access token for admin API - $url = $this->base_endpoint_url . 'user-management/v1.0.0/user'; + $url = $this->base_endpoint_url . '/user-management/v1.0.0/user'; $params = "?client_id=" . urlencode($this->client_id). "&user.username=".urlencode($user_id); $url = $url.$params; diff --git a/app/libraries/Keycloak/API/Users.php b/app/libraries/Keycloak/API/Users.php index efbdf57b3..a5b6eb711 100644 --- a/app/libraries/Keycloak/API/Users.php +++ b/app/libraries/Keycloak/API/Users.php @@ -1,4 +1,5 @@ getAPIAccessToken($realm); - $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users'; + $url = $this->base_endpoint_url . '/user-management/v1.0.0/users'; + $params = "?client_id=" . urlencode($this->client_id) . "&offset=" . urlencode(0) . "&limit=" . urlencode(100); + if ($username) { - $url = $url . '?username=' . rawurlencode($username); + $params = $params . '&user.username=' . rawurlencode($username); } + $url = $url . $params; // Log::debug("getUsers url", array($url)); $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); - if($this->verify_peer && $this->cafile_path){ + if ($this->verify_peer && $this->cafile_path) { curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Bearer " . $access_token + "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), )); $response = curl_exec($r); @@ -45,7 +50,8 @@ public function getUsers($realm, $username = null){ return $result; } - public function getUserByUsername($realm, $username){ + public function getUserByUsername($realm, $username) + { # getUsers returns all users that have a username containing $username # so we need to check the returned users for one that matches exactly @@ -65,21 +71,23 @@ public function getUserByUsername($realm, $username){ * last names, and email address * Returns Array of UserRepresentation */ - public function searchUsers($realm, $keyword){ + public function searchUsers($realm, $keyword) + { // get access token for admin API - $access_token = $this->getAPIAccessToken($realm); - $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users?search=' . rawurlencode($keyword); + $url = $this->base_endpoint_url . '/user-management/v1.0.0/users'; + $params = "?client_id=" . urlencode($this->client_id) . "&offset=" . urlencode(0) . "&limit=" . urlencode(100) . "&keyword=" . urlencode($keyword); // Log::debug("getUsers url", array($url)); + $url = $url . $params; $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); - if($this->verify_peer && $this->cafile_path){ + if ($this->verify_peer && $this->cafile_path) { curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Bearer " . $access_token + "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), )); $response = curl_exec($r); @@ -96,21 +104,23 @@ public function searchUsers($realm, $keyword){ * GET /admin/realms/{realm}/users/{id} * Returns a UserRepresentation */ - public function getUser($realm, $user_id) { + public function getUser($realm, $user_id) + { // get access token for admin API - $access_token = $this->getAPIAccessToken($realm); - $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users/' . rawurlencode($user_id); + $url = $this->base_endpoint_url . '/user-management/v1.0.0/users'; + $params = "?client_id=" . urlencode($this->client_id) . "&offset=" . urlencode(0) . "&limit=" . urlencode(100) . "&user.username=" . urlencode($user_id); + $url = $url . $params; // Log::debug("getUser url", array($url)); $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); - if($this->verify_peer && $this->cafile_path){ + if ($this->verify_peer && $this->cafile_path) { curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Bearer " . $access_token + "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), )); $response = curl_exec($r); diff --git a/app/libraries/Keycloak/Keycloak.php b/app/libraries/Keycloak/Keycloak.php index 67d5f66d4..cc1765f23 100644 --- a/app/libraries/Keycloak/Keycloak.php +++ b/app/libraries/Keycloak/Keycloak.php @@ -209,7 +209,7 @@ public function getUserProfileFromOAuthToken($token) $email = $userinfo->email; // get roles from Keycloak API - $role_mappings = $this->role_mapper->getRealmRoleMappingsForUser($userinfo->sub); + $role_mappings = $this->role_mapper->getRealmRoleMappingsForUser($username); $roles = []; foreach ($role_mappings as $role_mapping) { $roles[] = $role_mapping->name; From 4f3e57273633cf02dd8be9812923c17707854259 Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Fri, 14 Aug 2020 09:48:26 -0400 Subject: [PATCH 4/9] Fix getAccessTokenAPI --- .../Keycloak/API/BaseKeycloakAPIEndpoint.php | 8 ++- app/libraries/Keycloak/API/RoleMapper.php | 56 ++++++++++----- app/libraries/Keycloak/API/Roles.php | 9 +-- app/libraries/Keycloak/API/Users.php | 6 +- app/libraries/Keycloak/Keycloak.php | 70 ++++++------------- app/libraries/Keycloak/KeycloakUtil.php | 36 +++++++++- 6 files changed, 106 insertions(+), 79 deletions(-) diff --git a/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php b/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php index de9a34bb9..62dc56b98 100644 --- a/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php +++ b/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php @@ -16,8 +16,9 @@ class BaseKeycloakAPIEndpoint { protected $client_id; protected $client_secret; protected $openid_discovery_endpoint_url; + protected $custos_credential_uri; - function __construct($openid_discovery_endpoint_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_secret) { + function __construct($openid_discovery_endpoint_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_secret, $custos_credential_uri) { $this->base_endpoint_url = $base_endpoint_url; $this->admin_username = $admin_username; $this->admin_password = $admin_password; @@ -26,10 +27,11 @@ function __construct($openid_discovery_endpoint_url, $base_endpoint_url, $admin_ $this->client_id = $client_id; $this->client_secret = $client_secret; $this->openid_discovery_endpoint_url = $openid_discovery_endpoint_url; + $this->custos_credential_uri = $custos_credential_uri; } - protected function getAPIAccessToken($realm) { + protected function getAPIAccessToken() { - return KeycloakUtil::getAPIAccessToken($this->openid_discovery_endpoint_url, $realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); + return KeycloakUtil::getAPIAccessToken($this->openid_discovery_endpoint_url, $this->custos_credential_uri, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); } } diff --git a/app/libraries/Keycloak/API/RoleMapper.php b/app/libraries/Keycloak/API/RoleMapper.php index 041d76b38..2436f47bf 100644 --- a/app/libraries/Keycloak/API/RoleMapper.php +++ b/app/libraries/Keycloak/API/RoleMapper.php @@ -56,9 +56,8 @@ public function getRealmRoleMappingsForUser($user_id){ public function addRealmRoleMappingsToUser($realm, $user_id, $role_representations) { // get access token for admin API - $access_token = $this->getAPIAccessToken($realm); - $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users/' . rawurlencode($user_id) . '/role-mappings/realm'; - // Log::debug("addRealmRoleMappingsToUser", array($url, $role_representations)); + $access_token = $this->getAPIAccessToken(); + $url = $this->base_endpoint_url . 'user-management/v1.0.0/users/roles'; $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); curl_setopt($r, CURLOPT_ENCODING, 1); @@ -68,19 +67,33 @@ public function addRealmRoleMappingsToUser($realm, $user_id, $role_representatio } curl_setopt($r, CURLOPT_POST, true); - $data = json_encode($role_representations); - // Log::debug("addRealmRoleMappingsToUser data=$data"); + + $roles = []; + foreach ($role_representations as $role) { + $roles[] = $role->name; + } + + $usernames = []; + $usernames[] = $user_id; + $client_level = false; + + $json = array("roles"=> $roles, "usernames"=> $usernames, "client_level" => $client_level); + + + $data = json_encode($json); + Log::debug("addRealmRoleMappingsToUser data=$data"); curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Bearer " . $access_token, + "Authorization: Bearer " .$access_token, 'Content-Type: application/json', 'Content-Length: ' . strlen($data)) ); curl_setopt($r, CURLOPT_POSTFIELDS, $data); $response = curl_exec($r); - $info = curl_getinfo($r); - if ($info['http_code'] != 200 && $info['http_code'] != 204) { - throw new Exception("Failed to add realm role mapping to user"); + + if ($response == false || ! ($response->status)) { + Log::error("Failed to add realm role mappings for user"); + die("curl_exec() failed. Error: " . curl_error($r)); } return; } @@ -92,8 +105,8 @@ public function addRealmRoleMappingsToUser($realm, $user_id, $role_representatio public function deleteRealmRoleMappingsToUser($realm, $user_id, $role_representations) { // get access token for admin API - $access_token = $this->getAPIAccessToken($realm); - $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users/' . rawurlencode($user_id) . '/role-mappings/realm'; + $access_token = $this->getAPIAccessToken(); + $url = $this->base_endpoint_url . 'user-management/v1.0.0/user/roles'; // Log::debug("deleteRealmRoleMappingsToUser", array($url, $role_representations)); $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); @@ -105,19 +118,28 @@ public function deleteRealmRoleMappingsToUser($realm, $user_id, $role_representa curl_setopt($r, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_setopt($r, CURLOPT_POST, true); - $data = json_encode($role_representations); - // Log::debug("deleteRealmRoleMappingsToUser data=$data"); + + $roles = []; + foreach ($role_representations as $role) { + $roles[] = $role->name; + } + + $json = array("roles"=> $roles, "username"=> $user_id); + + $data = json_encode($json); + Log::debug("deleteRealmRoleMappingsToUser data=$data"); curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Bearer " . $access_token, + "Authorization: Bearer " .$access_token, 'Content-Type: application/json', 'Content-Length: ' . strlen($data)) ); curl_setopt($r, CURLOPT_POSTFIELDS, $data); $response = curl_exec($r); - $info = curl_getinfo($r); - if ($info['http_code'] != 200 && $info['http_code'] != 204) { - throw new Exception("Failed to delete realm role mapping to user"); + + if ($response == false || ! ($response->status)) { + Log::error("Failed to add realm role mappings for user"); + die("curl_exec() failed. Error: " . curl_error($r)); } return; } diff --git a/app/libraries/Keycloak/API/Roles.php b/app/libraries/Keycloak/API/Roles.php index 1972e741a..f6e28e466 100644 --- a/app/libraries/Keycloak/API/Roles.php +++ b/app/libraries/Keycloak/API/Roles.php @@ -17,8 +17,9 @@ class Roles extends BaseKeycloakAPIEndpoint { public function getRoles($realm){ // get access token for admin API - $access_token = $this->getAPIAccessToken($realm); - $r = curl_init($this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/roles'); + $url = $this->base_endpoint_url . '/tenant-management/v1.0.0/roles'; + $url = $url; + $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); curl_setopt($r, CURLOPT_ENCODING, 1); curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); @@ -26,7 +27,7 @@ public function getRoles($realm){ curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Bearer " . $access_token + "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), )); $response = curl_exec($r); @@ -35,6 +36,6 @@ public function getRoles($realm){ } $result = json_decode($response); // Log::debug("getRealmRoleMappingsForUser result", array($result)); - return $result; + return $result->roles; } } diff --git a/app/libraries/Keycloak/API/Users.php b/app/libraries/Keycloak/API/Users.php index a5b6eb711..cc5fbee15 100644 --- a/app/libraries/Keycloak/API/Users.php +++ b/app/libraries/Keycloak/API/Users.php @@ -47,7 +47,7 @@ public function getUsers($realm, $username = null) } $result = json_decode($response); // Log::debug("getUsers result", array($result)); - return $result; + return $result->users; } public function getUserByUsername($realm, $username) @@ -76,7 +76,7 @@ public function searchUsers($realm, $keyword) // get access token for admin API $url = $this->base_endpoint_url . '/user-management/v1.0.0/users'; - $params = "?client_id=" . urlencode($this->client_id) . "&offset=" . urlencode(0) . "&limit=" . urlencode(100) . "&keyword=" . urlencode($keyword); + $params = "?client_id=" . urlencode($this->client_id) . "&offset=" . urlencode(0) . "&limit=" . urlencode(100) . "&user.id=" . urlencode($keyword); // Log::debug("getUsers url", array($url)); $url = $url . $params; $r = curl_init($url); @@ -96,7 +96,7 @@ public function searchUsers($realm, $keyword) } $result = json_decode($response); // Log::debug("getUsers result", array($result)); - return $result; + return $result->users; } /** diff --git a/app/libraries/Keycloak/Keycloak.php b/app/libraries/Keycloak/Keycloak.php index cc1765f23..c1d3e6a61 100644 --- a/app/libraries/Keycloak/Keycloak.php +++ b/app/libraries/Keycloak/Keycloak.php @@ -52,9 +52,9 @@ public function __construct($realm, $openid_connect_discovery_url, $client_id, $ $this->gateway_id = $gateway_id; $this->custos_credentials_uri = $custos_credentials_uri; - $this->role_mapper = new RoleMapper($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); - $this->roles = new Roles($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); - $this->users = new Users($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); + $this->role_mapper = new RoleMapper($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret, $this->custos_credentials_uri); + $this->roles = new Roles($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret, $this->custos_credentials_uri); + $this->users = new Users($openid_connect_discovery_url, $base_endpoint_url, $admin_username, $admin_password, $verify_peer, $this->cafile_path, $this->client_id, $this->client_secret, $this->custos_credentials_uri); } /** @@ -83,7 +83,7 @@ public function authenticate($username, $password) curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } - $auth_credentials = $this->getAuthCredentials(); + $auth_credentials = KeycloakUtil::getAuthCredentials($this->custos_credentials_uri, $this->client_id, $this->client_secret); $iam_secret = $auth_credentials->iam_client_secret; @@ -147,7 +147,8 @@ public function getOAuthToken($code) curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } - $auth_credentials = $this->getAuthCredentials(); + $auth_credentials = KeycloakUtil::getAuthCredentials($this->custos_credentials_uri, $this->client_id, $this->client_secret); + $iam_secret = $auth_credentials->iam_client_secret; @@ -212,7 +213,7 @@ public function getUserProfileFromOAuthToken($token) $role_mappings = $this->role_mapper->getRealmRoleMappingsForUser($username); $roles = []; foreach ($role_mappings as $role_mapping) { - $roles[] = $role_mapping->name; + $roles[] = $role_mapping; } $roles = CommonUtilities::filterAiravataRoles($roles); return array('username' => $username, 'firstname' => $firstname, 'lastname' => $lastname, 'email' => $email, 'roles' => $roles); @@ -239,7 +240,8 @@ public function getRefreshedOAuthToken($refresh_token) curl_setopt($r, CURLOPT_CAINFO, $this->cafile_path); } - $auth_credentials = $this->getAuthCredentials(); + $auth_credentials = KeycloakUtil::getAuthCredentials($this->custos_credentials_uri, $this->client_id, $this->client_secret); + $iam_secret = $auth_credentials->iam_client_secret; @@ -290,7 +292,7 @@ public function listUsers() $usernames = []; foreach ($users as $user) { Log::debug("user", array($user)); - array_push($usernames, (object)["firstName" => $user->firstName, "lastName" => $user->lastName, "email" => $user->email, "userEnabled" => $user->enabled, "userName" => $user->username]); + array_push($usernames, (object)["firstName" => $user->first_name, "lastName" => $user->last_name, "email" => $user->email, "userEnabled" => ($user->state === "ACTIVE"), "userName" => $user->username]); } return $usernames; } @@ -308,7 +310,7 @@ public function searchUsers($phrase) $users = $this->users->searchUsers($this->realm, $phrase); $usernames = []; foreach ($users as $user) { - array_push($usernames, (object)["firstName" => $user->firstName, "lastName" => $user->lastName, "email" => $user->email, "userEnabled" => $user->enabled, "userName" => $user->username]); + array_push($usernames, (object)["firstName" => $user->first_name, "lastName" => $user->last_name, "email" => $user->email, "userEnabled" => ($user->state === "ACTIVE"), "userName" => $user->username]); } return $usernames; } @@ -345,12 +347,11 @@ public function getUserRoles($username) try { Log::info("Calling getUserRoles"); // get userid from username - $user_id = $this->getUserId($username); // Get the user's realm roles, then convert to an array of just names - $roles = $this->role_mapper->getRealmRoleMappingsForUser($user_id); + $roles = $this->role_mapper->getRealmRoleMappingsForUser($username); $role_names = []; foreach ($roles as $role) { - $role_names[] = $role->name; + $role_names[] = $role; } return CommonUtilities::filterAiravataRoles($role_names); } catch (Exception $ex) { @@ -372,7 +373,6 @@ public function updateUserRoles($username, $roles) try { Log::info("Calling updateUserRoles"); // get userid from username - $user_id = $this->getUserId($username); // Get all of the roles into an array keyed by role name $all_roles = $this->roles->getRoles($this->realm); $roles_by_name = []; @@ -385,7 +385,7 @@ public function updateUserRoles($username, $roles) if (!is_array($roles["deleted"])) $roles["deleted"] = array($roles["deleted"]); foreach ($roles["deleted"] as $role) { - $this->role_mapper->deleteRealmRoleMappingsToUser($this->realm, $user_id, array($roles_by_name[$role])); + $this->role_mapper->deleteRealmRoleMappingsToUser($this->realm, $username, array($roles_by_name[$role])); } } @@ -394,7 +394,7 @@ public function updateUserRoles($username, $roles) if (!is_array($roles["new"])) $roles["new"] = array($roles["new"]); foreach ($roles["new"] as $role) { - $this->role_mapper->addRealmRoleMappingsToUser($this->realm, $user_id, array($roles_by_name[$role])); + $this->role_mapper->addRealmRoleMappingsToUser($this->realm, $username, array($roles_by_name[$role])); } } } catch (Exception $ex) { @@ -413,9 +413,9 @@ public function getUserProfile($username) if ($user != null) { $result = []; $result["email"] = $user->email; - $result["firstname"] = $user->firstName; - $result["lastname"] = $user->lastName; - $result["userEnabled"] = $user->enabled; + $result["firstname"] = $user->first_name; + $result["lastname"] = $user->last_name; + $result["userEnabled"] = ($user->state === "ACTIVE"); return $result; } else { return []; @@ -461,7 +461,9 @@ public function isUpdatePasswordRequired($username) public function getAdminAuthzToken() { Log::info("Calling getAdminAuthzToken"); - $access_token = KeycloakUtil::getAPIAccessToken($this->openid_connect_discovery_url, $this->realm, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path); + $access_token = KeycloakUtil::getAPIAccessToken($this->openid_connect_discovery_url, $this->custos_credentials_uri, + $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path, + $this->client_id, $this->client_secret); $authzToken = new \Airavata\Model\Security\AuthzToken(); $authzToken->accessToken = $access_token; $authzToken->claimsMap['gatewayID'] = $this->gateway_id; @@ -484,35 +486,5 @@ private function getUserId($username) } - private function getAuthCredentials() - { - - $post_files = "?client_id=" . urlencode($this->client_id); - $url = $this->custos_credentials_uri . $post_files; - - // TODO: cache the result of the request - $r = curl_init($url); - - curl_setopt($r, CURLOPT_HTTPHEADER, array( - "Authorization: Basic " . base64_encode($this->client_id . ":" . $this->client_secret), - )); - - - curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); - // Decode compressed responses. - curl_setopt($r, CURLOPT_ENCODING, 1); - - $result = curl_exec($r); - if ($result == false) { - die("curl_exec() failed. Error: " . curl_error($r)); - } - - $json = json_decode($result); - - // Log::debug("openid connect discovery configuration", array($json)); - return $json; - } - - } diff --git a/app/libraries/Keycloak/KeycloakUtil.php b/app/libraries/Keycloak/KeycloakUtil.php index 185e7eb35..361db9859 100644 --- a/app/libraries/Keycloak/KeycloakUtil.php +++ b/app/libraries/Keycloak/KeycloakUtil.php @@ -7,10 +7,10 @@ class KeycloakUtil { - public static function getAPIAccessToken($openid_connect_discovery_url, $realm, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_sec) + public static function getAPIAccessToken($openid_connect_discovery_url, $custos_credentials_uri, $admin_username, $admin_password, $verify_peer, $cafile_path, $client_id, $client_sec) { - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($openid_connect_discovery_url,$client_id,$client_sec); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($openid_connect_discovery_url, $client_id, $client_sec); $token_endpoint = $config->token_endpoint; @@ -22,8 +22,11 @@ public static function getAPIAccessToken($openid_connect_discovery_url, $realm, curl_setopt($r, CURLOPT_CAINFO, $cafile_path); } + $credentials = KeycloakUtil::getAuthCredentials($custos_credentials_uri, $client_id, $client_sec); + // Assemble POST parameters for the request. - $post_fields = "client_id=admin-cli&username=" . urlencode($admin_username) . "&password=" . urlencode($admin_password) . "&grant_type=password"; + $post_fields = "client_id=" . urlencode($client_id) . "&client_secret=" . urlencode($credentials->iam_client_secret) . "&username=" + . urlencode($admin_username) . "&password=" . urlencode($admin_password) . "&grant_type=password"; // Obtain and return the access token from the response. curl_setopt($r, CURLOPT_POST, true); @@ -70,5 +73,32 @@ public static function getOpenIDConnectDiscoveryConfiguration($openid_connect_di return $json; } + public static function getAuthCredentials($custos_credentials_uri, $client_id, $client_secret) + { + + $post_files = "?client_id=" . urlencode($client_id); + $url = $custos_credentials_uri . $post_files; + + // TODO: cache the result of the request + $r = curl_init($url); + + curl_setopt($r, CURLOPT_HTTPHEADER, array( + "Authorization: Basic " . base64_encode($client_id . ":" . $client_secret), + )); + + + curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); + // Decode compressed responses. + curl_setopt($r, CURLOPT_ENCODING, 1); + $result = curl_exec($r); + if ($result == false) { + die("curl_exec() failed. Error: " . curl_error($r)); + } + + $json = json_decode($result); + + // Log::debug("openid connect discovery configuration", array($json)); + return $json; + } } From b47c2099852cd9e38faab328c0a9dccda03b0896 Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Mon, 17 Aug 2020 11:37:15 -0400 Subject: [PATCH 5/9] extend Gateway model --- .../Airavata/Model/Workspace/Types.php | 72 +++++++++++++++++++ app/libraries/Keycloak/API/RoleMapper.php | 20 ++++-- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/app/libraries/Airavata/Model/Workspace/Types.php b/app/libraries/Airavata/Model/Workspace/Types.php index 8a2f3cb82..efd10d01d 100644 --- a/app/libraries/Airavata/Model/Workspace/Types.php +++ b/app/libraries/Airavata/Model/Workspace/Types.php @@ -708,6 +708,14 @@ class Gateway { * @var string */ public $requesterUsername = null; + /** + * @var string[] + */ + public $redirectURLs = null; + /** + * @var string + */ + public $scope = null; public function __construct($vals=null) { if (!isset(self::$_TSPEC)) { @@ -792,6 +800,18 @@ public function __construct($vals=null) { 'var' => 'requesterUsername', 'type' => TType::STRING, ), + 21 => array( + 'var' => 'redirectURLs', + 'type' => TType::LST, + 'etype' => TType::STRING, + 'elem' => array( + 'type' => TType::STRING, + ), + ), + 22 => array( + 'var' => 'scope', + 'type' => TType::STRING, + ), ); } if (is_array($vals)) { @@ -855,6 +875,12 @@ public function __construct($vals=null) { if (isset($vals['requesterUsername'])) { $this->requesterUsername = $vals['requesterUsername']; } + if (isset($vals['redirectURLs'])) { + $this->redirectURLs = $vals['redirectURLs']; + } + if (isset($vals['scope'])) { + $this->scope = $vals['scope']; + } } } @@ -1017,6 +1043,30 @@ public function read($input) $xfer += $input->skip($ftype); } break; + case 21: + if ($ftype == TType::LST) { + $this->redirectURLs = array(); + $_size14 = 0; + $_etype17 = 0; + $xfer += $input->readListBegin($_etype17, $_size14); + for ($_i18 = 0; $_i18 < $_size14; ++$_i18) + { + $elem19 = null; + $xfer += $input->readString($elem19); + $this->redirectURLs []= $elem19; + } + $xfer += $input->readListEnd(); + } else { + $xfer += $input->skip($ftype); + } + break; + case 22: + if ($ftype == TType::STRING) { + $xfer += $input->readString($this->scope); + } else { + $xfer += $input->skip($ftype); + } + break; default: $xfer += $input->skip($ftype); break; @@ -1130,6 +1180,28 @@ public function write($output) { $xfer += $output->writeString($this->requesterUsername); $xfer += $output->writeFieldEnd(); } + if ($this->redirectURLs !== null) { + if (!is_array($this->redirectURLs)) { + throw new TProtocolException('Bad type in structure.', TProtocolException::INVALID_DATA); + } + $xfer += $output->writeFieldBegin('redirectURLs', TType::LST, 21); + { + $output->writeListBegin(TType::STRING, count($this->redirectURLs)); + { + foreach ($this->redirectURLs as $iter20) + { + $xfer += $output->writeString($iter20); + } + } + $output->writeListEnd(); + } + $xfer += $output->writeFieldEnd(); + } + if ($this->scope !== null) { + $xfer += $output->writeFieldBegin('scope', TType::STRING, 22); + $xfer += $output->writeString($this->scope); + $xfer += $output->writeFieldEnd(); + } $xfer += $output->writeFieldStop(); $xfer += $output->writeStructEnd(); return $xfer; diff --git a/app/libraries/Keycloak/API/RoleMapper.php b/app/libraries/Keycloak/API/RoleMapper.php index 2436f47bf..39845f293 100644 --- a/app/libraries/Keycloak/API/RoleMapper.php +++ b/app/libraries/Keycloak/API/RoleMapper.php @@ -57,7 +57,7 @@ public function addRealmRoleMappingsToUser($realm, $user_id, $role_representatio // get access token for admin API $access_token = $this->getAPIAccessToken(); - $url = $this->base_endpoint_url . 'user-management/v1.0.0/users/roles'; + $url = $this->base_endpoint_url . '/user-management/v1.0.0/users/roles'; $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); curl_setopt($r, CURLOPT_ENCODING, 1); @@ -91,7 +91,12 @@ public function addRealmRoleMappingsToUser($realm, $user_id, $role_representatio $response = curl_exec($r); - if ($response == false || ! ($response->status)) { + if ($response == false) { + Log::error("Failed to add realm role mappings for user"); + die("curl_exec() failed. Error: " . curl_error($r)); + } + $result = json_decode($response); + if ($result->status == false) { Log::error("Failed to add realm role mappings for user"); die("curl_exec() failed. Error: " . curl_error($r)); } @@ -106,7 +111,7 @@ public function deleteRealmRoleMappingsToUser($realm, $user_id, $role_representa // get access token for admin API $access_token = $this->getAPIAccessToken(); - $url = $this->base_endpoint_url . 'user-management/v1.0.0/user/roles'; + $url = $this->base_endpoint_url . '/user-management/v1.0.0/user/roles'; // Log::debug("deleteRealmRoleMappingsToUser", array($url, $role_representations)); $r = curl_init($url); curl_setopt($r, CURLOPT_RETURNTRANSFER, 1); @@ -137,8 +142,13 @@ public function deleteRealmRoleMappingsToUser($realm, $user_id, $role_representa $response = curl_exec($r); - if ($response == false || ! ($response->status)) { - Log::error("Failed to add realm role mappings for user"); + if ($response == false) { + Log::error("Failed to delete realm role mappings for user"); + die("curl_exec() failed. Error: " . curl_error($r)); + } + $result = json_decode($response); + if ($result->status == false) { + Log::error("Failed to delete realm role mappings for user"); die("curl_exec() failed. Error: " . curl_error($r)); } return; From 1dcb50ee487d93b6b7e9540b1ef6a355fb0b7f4f Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Mon, 17 Aug 2020 15:10:57 -0400 Subject: [PATCH 6/9] Adding logs --- app/libraries/AdminUtilities.php | 67 ++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/app/libraries/AdminUtilities.php b/app/libraries/AdminUtilities.php index 3c11266e4..c9a4e2a02 100644 --- a/app/libraries/AdminUtilities.php +++ b/app/libraries/AdminUtilities.php @@ -39,8 +39,16 @@ public static function add_gateway($inputs) $gateway->requesterUsername = Session::get('username'); $gateway->gatewayApprovalStatus = GatewayApprovalStatus::APPROVED; + + + $logoutURI = $gateway->gatewayURL; + $redirectURI = $logoutURI."auth/callback*"; + $gateway->redirectURLs = array($logoutURI,$redirectURI); + $gateway->scope = "openid profile email org.cilogon.userinfo" ; + try { - TenantProfileService::addGateway(Session::get('authz-token'), $gateway); + Log::info("Gateway #####".$gateway); + // TenantProfileService::addGateway(Session::get('authz-token'), $gateway); return 1; } catch (Exception $ex) { @@ -71,13 +79,15 @@ public static function check_request( $inputs) $gateway->gatewayPublicAbstract = $inputs["public-project-description"]; $gateway->requesterUsername = Session::get('username'); - try { - TenantProfileService::addGateway(Session::get('authz-token'), $gateway); + + Log::info("Check request #####".$gateway); + // try { + // TenantProfileService::addGateway(Session::get('authz-token'), $gateway); return 1; - } - catch (Exception $ex) { - return -1; - } + // } + // catch (Exception $ex) { + // return -1; + // } } public static function request_gateway( $inputs) @@ -105,7 +115,18 @@ public static function request_gateway( $inputs) $gateway->gatewayPublicAbstract = $inputs["public-project-description"]; $gateway->requesterUsername = Session::get('username'); - return TenantProfileService::addGateway(Session::get('authz-token'), $gateway); + + $logoutURI = $gateway->gatewayURL; + $redirectURI = $logoutURI."auth/callback*"; + $gateway->redirectURLs = array($logoutURI,$redirectURI); + $gateway->scope = "openid profile email org.cilogon.userinfo" ; + + + Log::info ("Request_Gateway ".$gateway); + + return 1; + + // return TenantProfileService::addGateway(Session::get('authz-token'), $gateway); } public static function get_gateway_approval_statuses() @@ -129,14 +150,17 @@ public static function user_update_gateway( $gatewayId, $gatewayData){ $gateway->gatewayURL = $gatewayData["gateway-url"]; $gateway->reviewProposalDescription = $gatewayData["project-details"]; $gateway->gatewayPublicAbstract = $gatewayData["public-project-description"]; - if( TenantProfileService::updateGateway( Session::get('authz-token'), $gateway) ){ + + Log::info("user_update_gateway ".$gateway); + + // if( TenantProfileService::updateGateway( Session::get('authz-token'), $gateway) ){ return 1; - } - else{ + // } + // else{ //Need to find a better way for this. // retun echo "Tenant Name is already in use"; - return -1; - } + // return -1; + // } } public static function update_gateway( $gatewayId, $gatewayData){ @@ -166,7 +190,7 @@ public static function update_gateway( $gatewayId, $gatewayData){ return -1; } } - $gateway = IamAdminServices::setUpGateway( Session::get('authz-token'), $gateway); + // $gateway = IamAdminServices::setUpGateway( Session::get('authz-token'), $gateway); $gateway->gatewayApprovalStatus = GatewayApprovalStatus::CREATED; } elseif( isset( $gatewayData["approveRequest"])){ @@ -217,14 +241,15 @@ public static function update_gateway( $gatewayId, $gatewayData){ $gateway->gatewayApprovalStatus = GatewayApprovalStatus::DEACTIVATED; } - if( TenantProfileService::updateGateway( Session::get('authz-token'), $gateway) ){ + Log.info("Calling update gateway".$gateway); + // if( TenantProfileService::updateGateway( Session::get('authz-token'), $gateway) ){ return 1; - } - else{ - //Need to find a better way for this. - // retun echo "Tenant Name is already in use"; - return -1; - } +// } +// else{ +// //Need to find a better way for this. +// // retun echo "Tenant Name is already in use"; +// return -1; +// } } public static function add_tenant( $gateway){ From 33988736a5a96dac49deefe76fcf66b899b4e606 Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Wed, 19 Aug 2020 09:27:35 -0400 Subject: [PATCH 7/9] clean up --- .../GatewayRequestUpdateController.php | 2 +- app/libraries/AdminUtilities.php | 103 ++++++++++++------ app/libraries/Keycloak/Keycloak.php | 23 ++-- 3 files changed, 81 insertions(+), 47 deletions(-) diff --git a/app/controllers/GatewayRequestUpdateController.php b/app/controllers/GatewayRequestUpdateController.php index f75019e69..cbedd0695 100644 --- a/app/controllers/GatewayRequestUpdateController.php +++ b/app/controllers/GatewayRequestUpdateController.php @@ -41,7 +41,7 @@ public function updateDetails(){ return Redirect::back()->withErrors($validator); } else { - $returnVal = AdminUtilities::user_update_gateway(Input::get("internal-gateway-id"), Input::all()); + $returnVal = AdminUtilities::user_update_gateway(Input::get("gateway-id"), Input::all()); if ($returnVal == 1) { $email = Config::get('pga_config.portal')['admin-emails']; diff --git a/app/libraries/AdminUtilities.php b/app/libraries/AdminUtilities.php index c9a4e2a02..9fcdf8ea5 100644 --- a/app/libraries/AdminUtilities.php +++ b/app/libraries/AdminUtilities.php @@ -39,16 +39,17 @@ public static function add_gateway($inputs) $gateway->requesterUsername = Session::get('username'); $gateway->gatewayApprovalStatus = GatewayApprovalStatus::APPROVED; - - $logoutURI = $gateway->gatewayURL; + if(!(AdminUtilities::endsWith($logoutURI,"/"))) { + $logoutURI = $logoutURI."/"; + } $redirectURI = $logoutURI."auth/callback*"; $gateway->redirectURLs = array($logoutURI,$redirectURI); $gateway->scope = "openid profile email org.cilogon.userinfo" ; try { - Log::info("Gateway #####".$gateway); - // TenantProfileService::addGateway(Session::get('authz-token'), $gateway); + + TenantProfileService::addGateway(Session::get('authz-token'), $gateway); return 1; } catch (Exception $ex) { @@ -79,15 +80,12 @@ public static function check_request( $inputs) $gateway->gatewayPublicAbstract = $inputs["public-project-description"]; $gateway->requesterUsername = Session::get('username'); - - Log::info("Check request #####".$gateway); - // try { - // TenantProfileService::addGateway(Session::get('authz-token'), $gateway); + try { + TenantProfileService::addGateway(Session::get('authz-token'), $gateway); return 1; - // } - // catch (Exception $ex) { - // return -1; - // } + } catch (Exception $ex) { + return -1; + } } public static function request_gateway( $inputs) @@ -117,16 +115,20 @@ public static function request_gateway( $inputs) $logoutURI = $gateway->gatewayURL; + if(!(AdminUtilities::endsWith($logoutURI,"/"))) { + $logoutURI = $logoutURI."/"; + } $redirectURI = $logoutURI."auth/callback*"; $gateway->redirectURLs = array($logoutURI,$redirectURI); $gateway->scope = "openid profile email org.cilogon.userinfo" ; + $logoutURI = $gateway->gatewayURL; + $redirectURI = $logoutURI."auth/callback*"; + $gateway->redirectURLs = array($logoutURI,$redirectURI); + $gateway->scope = "openid profile email org.cilogon.userinfo" ; - Log::info ("Request_Gateway ".$gateway); - - return 1; - // return TenantProfileService::addGateway(Session::get('authz-token'), $gateway); + return TenantProfileService::addGateway(Session::get('authz-token'), $gateway); } public static function get_gateway_approval_statuses() @@ -151,16 +153,23 @@ public static function user_update_gateway( $gatewayId, $gatewayData){ $gateway->reviewProposalDescription = $gatewayData["project-details"]; $gateway->gatewayPublicAbstract = $gatewayData["public-project-description"]; - Log::info("user_update_gateway ".$gateway); + $logoutURI = $gateway->gatewayURL; + if(!(AdminUtilities::endsWith($logoutURI,"/"))) { + $logoutURI = $logoutURI."/"; + } + $redirectURI = $logoutURI."auth/callback*"; + $gateway->redirectURLs = array($logoutURI,$redirectURI); + $gateway->scope = "openid profile email org.cilogon.userinfo" ; + - // if( TenantProfileService::updateGateway( Session::get('authz-token'), $gateway) ){ + if( TenantProfileService::updateGateway( Session::get('authz-token'), $gateway) ){ return 1; - // } - // else{ + } + else{ //Need to find a better way for this. // retun echo "Tenant Name is already in use"; - // return -1; - // } + return -1; + } } public static function update_gateway( $gatewayId, $gatewayData){ @@ -190,7 +199,15 @@ public static function update_gateway( $gatewayId, $gatewayData){ return -1; } } - // $gateway = IamAdminServices::setUpGateway( Session::get('authz-token'), $gateway); + $logoutURI = $gateway->gatewayURL; + if(!(AdminUtilities::endsWith($logoutURI,"/"))) { + $logoutURI = $logoutURI."/"; + } + $redirectURI = $logoutURI."auth/callback*"; + $gateway->redirectURLs = array($logoutURI,$redirectURI); + $gateway->scope = "openid profile email org.cilogon.userinfo" ; + + $gateway = IamAdminServices::setUpGateway( Session::get('authz-token'), $gateway); $gateway->gatewayApprovalStatus = GatewayApprovalStatus::CREATED; } elseif( isset( $gatewayData["approveRequest"])){ @@ -201,6 +218,7 @@ public static function update_gateway( $gatewayId, $gatewayData){ $gateway->gatewayAdminEmail = $gatewayData["gatewayAdminEmail"]; $gateway->identityServerUserName = $gatewayData["identityServerUserName"]; if (!empty($gatewayData["gatewayAdminPassword"])) { + Log::info("Gateway password ".gatewayData["gatewayAdminPassword"]); $token = AdminUtilities::create_pwd_token([ "username" => $gatewayData["identityServerUserName"], "password" => $gatewayData["gatewayAdminPassword"], @@ -211,6 +229,15 @@ public static function update_gateway( $gatewayId, $gatewayData){ $gateway->reviewProposalDescription = $gatewayData["reviewProposalDescription"]; $gateway->gatewayPublicAbstract = $gatewayData["gatewayPublicAbstract"]; $gateway->gatewayApprovalStatus = GatewayApprovalStatus::APPROVED; + + $logoutURI = $gateway->gatewayURL; + $logoutURI = $gateway->gatewayURL; + if(!(AdminUtilities::endsWith($logoutURI,"/"))) { + $logoutURI = $logoutURI."/"; + } + $redirectURI = $logoutURI."auth/callback*"; + $gateway->redirectURLs = array($logoutURI,$redirectURI); + $gateway->scope = "openid profile email org.cilogon.userinfo" ; } elseif( isset( $gatewayData["denyRequest"])){ $gateway->gatewayApprovalStatus = GatewayApprovalStatus::DENIED; @@ -233,6 +260,13 @@ public static function update_gateway( $gatewayId, $gatewayData){ $gateway->reviewProposalDescription = $gatewayData["reviewProposalDescription"]; $gateway->gatewayPublicAbstract = $gatewayData["gatewayPublicAbstract"]; $gateway->gatewayApprovalStatus = GatewayApprovalStatus::APPROVED; + $logoutURI = $gateway->gatewayURL; + if(!(AdminUtilities::endsWith($logoutURI,"/"))) { + $logoutURI = $logoutURI."/"; + } + $redirectURI = $logoutURI."auth/callback*"; + $gateway->redirectURLs = array($logoutURI,$redirectURI); + $gateway->scope = "openid profile email org.cilogon.userinfo" ; } elseif( isset( $gatewayData["deployGateway"])){ $gateway->gatewayApprovalStatus = GatewayApprovalStatus::DEPLOYED; @@ -241,15 +275,15 @@ public static function update_gateway( $gatewayId, $gatewayData){ $gateway->gatewayApprovalStatus = GatewayApprovalStatus::DEACTIVATED; } - Log.info("Calling update gateway".$gateway); - // if( TenantProfileService::updateGateway( Session::get('authz-token'), $gateway) ){ + + if( TenantProfileService::updateGateway( Session::get('authz-token'), $gateway) ){ return 1; -// } -// else{ -// //Need to find a better way for this. -// // retun echo "Tenant Name is already in use"; -// return -1; -// } + } + else{ + //Need to find a better way for this. + // retun echo "Tenant Name is already in use"; + return -1; + } } public static function add_tenant( $gateway){ @@ -346,6 +380,7 @@ public static function create_pwd_token($inputs){ $username = $inputs['username']; $password = $inputs['password']; $description = $inputs['description']; + Log::info(array($username, $password, $description)); return $newToken = Airavata::registerPwdCredential( Session::get('authz-token'), $username, $password, $description); @@ -427,4 +462,10 @@ public static function add_or_update_IDP($inputs) return true; } + + + public static function endsWith($haystack, $needle) { + return substr_compare($haystack, $needle, -strlen($needle)) === 0; + } + } diff --git a/app/libraries/Keycloak/Keycloak.php b/app/libraries/Keycloak/Keycloak.php index c1d3e6a61..2aeff0184 100644 --- a/app/libraries/Keycloak/Keycloak.php +++ b/app/libraries/Keycloak/Keycloak.php @@ -133,7 +133,7 @@ public function getOAuthRequestCodeUrl($extra_params = null) public function getOAuthToken($code) { - Log::info("Calling getOAuthToken ", array($code)); + $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $token_endpoint = $config->token_endpoint; @@ -179,8 +179,6 @@ public function getOAuthToken($code) public function getUserProfileFromOAuthToken($token) { - Log::info("Calling getUserProfileFromOAuthToken"); - $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $userinfo_endpoint = $config->userinfo_endpoint; @@ -203,7 +201,6 @@ public function getUserProfileFromOAuthToken($token) //Parse JSON return object. $userinfo = json_decode($response); - Log::info("Keycloak userinfo", array($userinfo)); $username = $userinfo->preferred_username; $firstname = $userinfo->given_name; $lastname = $userinfo->family_name; @@ -226,7 +223,6 @@ public function getUserProfileFromOAuthToken($token) */ public function getRefreshedOAuthToken($refresh_token) { - Log::info("Calling getRefreshedOAuthToken"); $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $token_endpoint = $config->token_endpoint; @@ -274,7 +270,6 @@ public function getRefreshedOAuthToken($refresh_token) */ public function getOAuthLogoutUrl($redirect_uri) { - Log::info("Calling getOAuthLogoutUrl"); $config = KeycloakUtil::getOpenIDConnectDiscoveryConfiguration($this->openid_connect_discovery_url, $this->client_id, $this->client_secret); $logout_endpoint = $config->end_session_endpoint; return $logout_endpoint . '?redirect_uri=' . rawurlencode($redirect_uri); @@ -287,7 +282,6 @@ public function getOAuthLogoutUrl($redirect_uri) */ public function listUsers() { - Log::info("Calling listUsers"); $users = $this->users->getUsers($this->realm); $usernames = []; foreach ($users as $user) { @@ -306,7 +300,6 @@ public function listUsers() */ public function searchUsers($phrase) { - Log::info("Calling searchUsers"); $users = $this->users->searchUsers($this->realm, $phrase); $usernames = []; foreach ($users as $user) { @@ -324,7 +317,7 @@ public function searchUsers($phrase) public function getAllRoles() { try { - Log::info("Calling getAllRoles"); + $roles = $this->roles->getRoles($this->realm); $role_names = []; foreach ($roles as $role) { @@ -345,7 +338,7 @@ public function getAllRoles() public function getUserRoles($username) { try { - Log::info("Calling getUserRoles"); + // get userid from username // Get the user's realm roles, then convert to an array of just names $roles = $this->role_mapper->getRealmRoleMappingsForUser($username); @@ -371,7 +364,7 @@ public function updateUserRoles($username, $roles) { // Log::debug("updateUserRoles", array($user_id, $roles)); try { - Log::info("Calling updateUserRoles"); + // get userid from username // Get all of the roles into an array keyed by role name $all_roles = $this->roles->getRoles($this->realm); @@ -408,7 +401,7 @@ public function updateUserRoles($username, $roles) */ public function getUserProfile($username) { - Log::info("Calling getUserProfile"); + $user = $this->users->getUserByUsername($this->realm, $username); if ($user != null) { $result = []; @@ -431,7 +424,7 @@ public function getUserProfile($username) public function usernameExists($username) { try { - Log::info("Calling usernameExists"); + $user = $this->users->getUserByUsername($this->realm, $username); return $user != null; } catch (Exception $ex) { @@ -445,7 +438,7 @@ public function isUpdatePasswordRequired($username) { try { - Log::info("Calling isUpdatePasswordRequired"); + $user = $this->users->getUserByUsername($this->realm, $username); if ($user != null) { return in_array("UPDATE_PASSWORD", $user->requiredActions); @@ -460,7 +453,7 @@ public function isUpdatePasswordRequired($username) public function getAdminAuthzToken() { - Log::info("Calling getAdminAuthzToken"); + $access_token = KeycloakUtil::getAPIAccessToken($this->openid_connect_discovery_url, $this->custos_credentials_uri, $this->admin_username, $this->admin_password, $this->verify_peer, $this->cafile_path, $this->client_id, $this->client_secret); From 3240dfc42a9e82afcb6fd1cda4a6804376e115d3 Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Wed, 19 Aug 2020 09:48:27 -0400 Subject: [PATCH 8/9] remove gateway appending --- app/libraries/GrouperUtilities.php | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/app/libraries/GrouperUtilities.php b/app/libraries/GrouperUtilities.php index a167a3d66..28961e2cb 100644 --- a/app/libraries/GrouperUtilities.php +++ b/app/libraries/GrouperUtilities.php @@ -19,12 +19,8 @@ public static function getAllGatewayUsers() */ public static function shareResourceWithUsers($resourceId, $userPermissionMap) { - $newUserPermissionsMap = []; - foreach($userPermissionMap as $key=> $value){ - $key = $key . "@" . Config::get('pga_config.airavata')['gateway-id']; - $newUserPermissionsMap[$key] = $value; - } - Airavata::shareResourceWithUsers(Session::get('authz-token'), $resourceId, $newUserPermissionsMap); + + Airavata::shareResourceWithUsers(Session::get('authz-token'), $resourceId, $userPermissionMap); } /** @@ -33,12 +29,8 @@ public static function shareResourceWithUsers($resourceId, $userPermissionMap) */ public static function revokeSharingOfResourceFromUsers($resourceId, $userPermissionMap) { - $newUserPermissionsMap = []; - foreach($userPermissionMap as $key=> $value){ - $key = $key . "@" . Config::get('pga_config.airavata')['gateway-id']; - $newUserPermissionsMap[$key] = $value; - } - Airavata::revokeSharingOfResourceFromUsers(Session::get('authz-token'), $resourceId, $newUserPermissionsMap); + + Airavata::revokeSharingOfResourceFromUsers(Session::get('authz-token'), $resourceId, $userPermissionMap); } /** @@ -65,7 +57,7 @@ public static function getAllAccessibleUsers($resourceId, $permissionType) * @param $group Airavata/Model/Group/GrouoModel */ public static function createGroup($group){ - $group->ownerId = $group->ownerId . "@" . Config::get('pga_config.airavata')['gateway-id']; + Airavata::createGroup(Session::get('authz-token'),$group); } @@ -74,7 +66,7 @@ public static function createGroup($group){ * @param $group Airavata/Model/Group/GrouoModel */ public static function updateGroup($group){ - $group->ownerId = $group->ownerId . "@" . Config::get('pga_config.airavata')['gateway-id']; + Airavata::updateGroup(Session::get('authz-token'),$group); } From 30e393493936e9294e3471e4035f7771b790d818 Mon Sep 17 00:00:00 2001 From: Isuru Ranawaka Date: Wed, 19 Aug 2020 09:55:53 -0400 Subject: [PATCH 9/9] remove info logs --- app/libraries/AdminUtilities.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/libraries/AdminUtilities.php b/app/libraries/AdminUtilities.php index 9fcdf8ea5..a043699af 100644 --- a/app/libraries/AdminUtilities.php +++ b/app/libraries/AdminUtilities.php @@ -218,7 +218,7 @@ public static function update_gateway( $gatewayId, $gatewayData){ $gateway->gatewayAdminEmail = $gatewayData["gatewayAdminEmail"]; $gateway->identityServerUserName = $gatewayData["identityServerUserName"]; if (!empty($gatewayData["gatewayAdminPassword"])) { - Log::info("Gateway password ".gatewayData["gatewayAdminPassword"]); + $token = AdminUtilities::create_pwd_token([ "username" => $gatewayData["identityServerUserName"], "password" => $gatewayData["gatewayAdminPassword"], @@ -380,7 +380,7 @@ public static function create_pwd_token($inputs){ $username = $inputs['username']; $password = $inputs['password']; $description = $inputs['description']; - Log::info(array($username, $password, $description)); + return $newToken = Airavata::registerPwdCredential( Session::get('authz-token'), $username, $password, $description);