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/16 20:36:25 UTC

[22/50] [abbrv] airavata-php-gateway git commit: AIRAVATA-2342 Keycloak: implement password grant type flow

AIRAVATA-2342 Keycloak: implement password grant type flow


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

Branch: refs/heads/develop
Commit: e9f3b24a04bf5e2353039b31779578aaad25418d
Parents: 60951a2
Author: Marcus Christie <ma...@iu.edu>
Authored: Thu Apr 27 12:17:44 2017 -0400
Committer: Marcus Christie <ma...@iu.edu>
Committed: Thu Apr 27 12:17:44 2017 -0400

----------------------------------------------------------------------
 app/controllers/AccountController.php           | 16 ++-----
 .../Keycloak/API/BaseKeycloakAPIEndpoint.php    | 49 +++++++++++++++++++
 app/libraries/Keycloak/API/RoleMapper.php       | 50 ++------------------
 app/libraries/Keycloak/API/Roles.php            | 45 +-----------------
 app/libraries/Keycloak/API/Users.php            | 49 ++-----------------
 app/libraries/Keycloak/Keycloak.php             | 45 ++++++++++++++++++
 6 files changed, 107 insertions(+), 147 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/e9f3b24a/app/controllers/AccountController.php
----------------------------------------------------------------------
diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php
index 7900c7c..303c3b4 100644
--- a/app/controllers/AccountController.php
+++ b/app/controllers/AccountController.php
@@ -99,32 +99,22 @@ class AccountController extends BaseController
     {
         if (CommonUtilities::form_submitted()) {
             $wsisConfig = Config::get('pga_config.wsis');
-            if( $wsisConfig['tenant-domain'] == "")
-                $username = Input::get("username");
-            else
-                $username = Input::get("username") . "@" . $wsisConfig['tenant-domain'];
+            $username = Input::get("username");
 
             $password = $_POST['password'];
-            $response = WSIS::authenticate($username, $password);
+            $response = Keycloak::authenticate($username, $password);
             if(!isset($response->access_token)){
                 return Redirect::to("login")->with("invalid-credentials", true);
             }
 
             $accessToken = $response->access_token;
             $refreshToken = $response->refresh_token;
-            $expirationTime = time() + $response->expires_in - 5; //5 seconds safe margin
+            $expirationTime = time() + $response->expires_in - 300; // 5 minutes safe margin
 
             $userProfile = Keycloak::getUserProfileFromOAuthToken($accessToken);
             $username = $userProfile['username'];
             $userRoles = $userProfile['roles'];
 
-            //FIXME There is a bug in WSO2 IS which doest not return the admin role for the default admin user.
-            //FIXME Hence as a workaround we manually add it here.
-            if ($username == Config::get('pga_config.wsis')['admin-username']
-                || $username == Config::get('pga_config.wsis')['admin-username'] . '@' . Config::get('pga_config.wsis')['tenant-domain']){
-                $userRoles[] = Config::get('pga_config.wsis')['admin-role-name'];
-            }
-
             $authzToken = new Airavata\Model\Security\AuthzToken();
             $authzToken->accessToken = $accessToken;
             $authzToken->claimsMap['gatewayID'] = Config::get('pga_config.airavata')['gateway-id'];

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/e9f3b24a/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php
----------------------------------------------------------------------
diff --git a/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php b/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php
new file mode 100644
index 0000000..c440179
--- /dev/null
+++ b/app/libraries/Keycloak/API/BaseKeycloakAPIEndpoint.php
@@ -0,0 +1,49 @@
+<?php
+namespace Keycloak\API;
+
+use Exception;
+use Log;
+
+class BaseKeycloakAPIEndpoint {
+
+    protected $base_endpoint_url;
+    protected $admin_username;
+    protected $admin_password;
+    protected $verify_peer;
+
+    function __construct($base_endpoint_url, $admin_username, $admin_password, $verify_peer) {
+        $this->base_endpoint_url = $base_endpoint_url;
+        $this->admin_username = $admin_username;
+        $this->admin_password = $admin_password;
+        $this->verify_peer = $verify_peer;
+    }
+
+    protected function getAPIAccessToken($realm) {
+
+        // http://www.keycloak.org/docs/2.5/server_development/topics/admin-rest-api.html
+        // curl -d client_id=admin-cli -d username=username \
+        //   -d "password=password" -d grant_type=password https://149.165.156.62:8443/auth/realms/master/protocol/openid-connect/token
+
+        $r = curl_init($this->base_endpoint_url . '/realms/' . rawurlencode($realm) . '/protocol/openid-connect/token');
+        curl_setopt($r, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($r, CURLOPT_ENCODING, 1);
+        curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer);
+
+        // Assemble POST parameters for the request.
+        $post_fields = "client_id=admin-cli&username=" . urlencode($this->admin_username) . "&password=" . urlencode($this->admin_password) . "&grant_type=password";
+
+        // Obtain and return the access token from the response.
+        curl_setopt($r, CURLOPT_POST, true);
+        curl_setopt($r, CURLOPT_POSTFIELDS, $post_fields);
+
+        $response = curl_exec($r);
+        if ($response == false) {
+            Log::error("Failed to retrieve API Access Token");
+            die("curl_exec() failed. Error: " . curl_error($r));
+        }
+
+        $result = json_decode($response);
+        // Log::debug("API Access Token result", array($result));
+        return $result->access_token;
+    }
+}

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/e9f3b24a/app/libraries/Keycloak/API/RoleMapper.php
----------------------------------------------------------------------
diff --git a/app/libraries/Keycloak/API/RoleMapper.php b/app/libraries/Keycloak/API/RoleMapper.php
index 18a477b..f2fab42 100644
--- a/app/libraries/Keycloak/API/RoleMapper.php
+++ b/app/libraries/Keycloak/API/RoleMapper.php
@@ -10,19 +10,7 @@ use Log;
  * This class provide an easy to use interface for
  * the Keycloak RoleMapper REST API.
  */
-class RoleMapper {
-
-    private $base_endpoint_url;
-    private $admin_username;
-    private $admin_password;
-    private $verify_peer;
-
-    public function __construct($base_endpoint_url, $admin_username, $admin_password, $verify_peer) {
-        $this->base_endpoint_url = $base_endpoint_url;
-        $this->admin_username = $admin_username;
-        $this->admin_password = $admin_password;
-        $this->verify_peer = $verify_peer;
-    }
+class RoleMapper extends BaseKeycloakAPIEndpoint {
 
     /**
      * Get realm-level role mappings for a user
@@ -35,7 +23,7 @@ class RoleMapper {
         // 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();
+        $access_token = $this->getAPIAccessToken($realm);
         $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);
@@ -63,7 +51,7 @@ class RoleMapper {
     public function addRealmRoleMappingsToUser($realm, $user_id, $role_representations) {
 
         // get access token for admin API
-        $access_token = $this->getAPIAccessToken();
+        $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));
         $r = curl_init($url);
@@ -96,7 +84,7 @@ class RoleMapper {
     public function deleteRealmRoleMappingsToUser($realm, $user_id, $role_representations) {
 
         // get access token for admin API
-        $access_token = $this->getAPIAccessToken();
+        $access_token = $this->getAPIAccessToken($realm);
         $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users/' . rawurlencode($user_id) . '/role-mappings/realm';
         // Log::debug("deleteRealmRoleMappingsToUser", array($url, $role_representations));
         $r = curl_init($url);
@@ -122,34 +110,4 @@ class RoleMapper {
         }
         return;
     }
-
-    // TODO: factor this out into base class?
-    private function getAPIAccessToken() {
-
-        // http://www.keycloak.org/docs/2.5/server_development/topics/admin-rest-api.html
-        // curl -d client_id=admin-cli -d username=username \
-        //   -d "password=password" -d grant_type=password https://149.165.156.62:8443/auth/realms/master/protocol/openid-connect/token
-
-        $r = curl_init($this->base_endpoint_url . '/realms/master/protocol/openid-connect/token');
-        curl_setopt($r, CURLOPT_RETURNTRANSFER, 1);
-        curl_setopt($r, CURLOPT_ENCODING, 1);
-        curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer);
-
-        // Assemble POST parameters for the request.
-        $post_fields = "client_id=admin-cli&username=" . urlencode($this->admin_username) . "&password=" . urlencode($this->admin_password) . "&grant_type=password";
-
-        // Obtain and return the access token from the response.
-        curl_setopt($r, CURLOPT_POST, true);
-        curl_setopt($r, CURLOPT_POSTFIELDS, $post_fields);
-
-        $response = curl_exec($r);
-        if ($response == false) {
-            Log::error("Failed to retrieve API Access Token");
-            die("curl_exec() failed. Error: " . curl_error($r));
-        }
-
-        $result = json_decode($response);
-        // Log::debug("API Access Token result", array($result));
-        return $result->access_token;
-    }
 }

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/e9f3b24a/app/libraries/Keycloak/API/Roles.php
----------------------------------------------------------------------
diff --git a/app/libraries/Keycloak/API/Roles.php b/app/libraries/Keycloak/API/Roles.php
index 02f5b8f..565b860 100644
--- a/app/libraries/Keycloak/API/Roles.php
+++ b/app/libraries/Keycloak/API/Roles.php
@@ -7,19 +7,7 @@ namespace Keycloak\API;
  * This class provide an easy to use interface for
  * the Keycloak Roles REST API.
  */
-class Roles {
-
-    private $base_endpoint_url;
-    private $admin_username;
-    private $admin_password;
-    private $verify_peer;
-
-    public function __construct($base_endpoint_url, $admin_username, $admin_password, $verify_peer) {
-        $this->base_endpoint_url = $base_endpoint_url;
-        $this->admin_username = $admin_username;
-        $this->admin_password = $admin_password;
-        $this->verify_peer = $verify_peer;
-    }
+class Roles extends BaseKeycloakAPIEndpoint {
 
     /**
      * Get representations of all of a realm's roles
@@ -29,7 +17,7 @@ class Roles {
     public function getRoles($realm){
 
         // get access token for admin API
-        $access_token = $this->getAPIAccessToken();
+        $access_token = $this->getAPIAccessToken($realm);
         $r = curl_init($this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/roles');
         curl_setopt($r, CURLOPT_RETURNTRANSFER, 1);
         curl_setopt($r, CURLOPT_ENCODING, 1);
@@ -46,33 +34,4 @@ class Roles {
         // Log::debug("getRealmRoleMappingsForUser result", array($result));
         return $result;
     }
-
-    // TODO: factor this out into base class?
-    private function getAPIAccessToken() {
-
-        // http://www.keycloak.org/docs/2.5/server_development/topics/admin-rest-api.html
-        // curl -d client_id=admin-cli -d username=username \
-        //   -d "password=password" -d grant_type=password https://149.165.156.62:8443/auth/realms/master/protocol/openid-connect/token
-
-        $r = curl_init($this->base_endpoint_url . '/realms/master/protocol/openid-connect/token');
-        curl_setopt($r, CURLOPT_RETURNTRANSFER, 1);
-        curl_setopt($r, CURLOPT_ENCODING, 1);
-        curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer);
-
-        // Assemble POST parameters for the request.
-        $post_fields = "client_id=admin-cli&username=" . urlencode($this->admin_username) . "&password=" . urlencode($this->admin_password) . "&grant_type=password";
-
-        // Obtain and return the access token from the response.
-        curl_setopt($r, CURLOPT_POST, true);
-        curl_setopt($r, CURLOPT_POSTFIELDS, $post_fields);
-
-        $response = curl_exec($r);
-        if ($response == false) {
-            die("curl_exec() failed. Error: " . curl_error($r));
-        }
-
-        $result = json_decode($response);
-        // Log::debug("API Access Token result", array($result));
-        return $result->access_token;
-    }
 }

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/e9f3b24a/app/libraries/Keycloak/API/Users.php
----------------------------------------------------------------------
diff --git a/app/libraries/Keycloak/API/Users.php b/app/libraries/Keycloak/API/Users.php
index 089ad3a..d03be02 100644
--- a/app/libraries/Keycloak/API/Users.php
+++ b/app/libraries/Keycloak/API/Users.php
@@ -9,19 +9,7 @@ use Log;
  * This class provide an easy to use interface for
  * the Keycloak Users REST API.
  */
-class Users {
-
-    private $base_endpoint_url;
-    private $admin_username;
-    private $admin_password;
-    private $verify_peer;
-
-    public function __construct($base_endpoint_url, $admin_username, $admin_password, $verify_peer) {
-        $this->base_endpoint_url = $base_endpoint_url;
-        $this->admin_username = $admin_username;
-        $this->admin_password = $admin_password;
-        $this->verify_peer = $verify_peer;
-    }
+class Users extends BaseKeycloakAPIEndpoint {
 
     /**
      * Get representations of all users
@@ -31,7 +19,7 @@ class Users {
     public function getUsers($realm, $username = null){
 
         // get access token for admin API
-        $access_token = $this->getAPIAccessToken();
+        $access_token = $this->getAPIAccessToken($realm);
         $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users';
         if ($username) {
             $url = $url . '?username=' . rawurlencode($username);
@@ -64,7 +52,7 @@ class Users {
     public function searchUsers($realm, $keyword){
 
         // get access token for admin API
-        $access_token = $this->getAPIAccessToken();
+        $access_token = $this->getAPIAccessToken($realm);
         $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users?search=' . rawurlencode($keyword);
         // Log::debug("getUsers url", array($url));
         $r = curl_init($url);
@@ -92,7 +80,7 @@ class Users {
     public function getUser($realm, $user_id) {
 
         // get access token for admin API
-        $access_token = $this->getAPIAccessToken();
+        $access_token = $this->getAPIAccessToken($realm);
         $url = $this->base_endpoint_url . '/admin/realms/' . rawurlencode($realm) . '/users/' . rawurlencode($user_id);
         // Log::debug("getUser url", array($url));
         $r = curl_init($url);
@@ -111,33 +99,4 @@ class Users {
         // Log::debug("getUsers result", array($result));
         return $result;
     }
-
-    // TODO: factor this out into base class?
-    private function getAPIAccessToken() {
-
-        // http://www.keycloak.org/docs/2.5/server_development/topics/admin-rest-api.html
-        // curl -d client_id=admin-cli -d username=username \
-        //   -d "password=password" -d grant_type=password https://149.165.156.62:8443/auth/realms/master/protocol/openid-connect/token
-
-        $r = curl_init($this->base_endpoint_url . '/realms/master/protocol/openid-connect/token');
-        curl_setopt($r, CURLOPT_RETURNTRANSFER, 1);
-        curl_setopt($r, CURLOPT_ENCODING, 1);
-        curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer);
-
-        // Assemble POST parameters for the request.
-        $post_fields = "client_id=admin-cli&username=" . urlencode($this->admin_username) . "&password=" . urlencode($this->admin_password) . "&grant_type=password";
-
-        // Obtain and return the access token from the response.
-        curl_setopt($r, CURLOPT_POST, true);
-        curl_setopt($r, CURLOPT_POSTFIELDS, $post_fields);
-
-        $response = curl_exec($r);
-        if ($response == false) {
-            die("curl_exec() failed. Error: " . curl_error($r));
-        }
-
-        $result = json_decode($response);
-        // Log::debug("API Access Token result", array($result));
-        return $result->access_token;
-    }
 }

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/e9f3b24a/app/libraries/Keycloak/Keycloak.php
----------------------------------------------------------------------
diff --git a/app/libraries/Keycloak/Keycloak.php b/app/libraries/Keycloak/Keycloak.php
index 1f876b0..71706e5 100644
--- a/app/libraries/Keycloak/Keycloak.php
+++ b/app/libraries/Keycloak/Keycloak.php
@@ -43,6 +43,51 @@ class Keycloak {
         $this->users = new Users($base_endpoint_url, $admin_username, $admin_password, $verify_peer);
     }
 
+    /**
+     * Function to authenticate user
+     *
+     * @param string $username
+     * @param string $password
+     * @return boolean
+     * @throws Exception
+     */
+     public function authenticate($username, $password){
+
+        $config = $this->getOpenIDConnectDiscoveryConfiguration();
+        $token_endpoint = $config->token_endpoint;
+
+        // Init cUrl.
+        $r = curl_init($token_endpoint);
+        curl_setopt($r, CURLOPT_RETURNTRANSFER, 1);
+        // Decode compressed responses.
+        curl_setopt($r, CURLOPT_ENCODING, 1);
+        curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->verify_peer);
+
+        // 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),
+        ));
+
+        // 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 .= "&username=" . urlencode($username) . "&password=" . urlencode($password);
+
+        // Obtain and return the access token from the response.
+        curl_setopt($r, CURLOPT_POST, true);
+        curl_setopt($r, CURLOPT_POSTFIELDS, $post_fields);
+
+        $response = curl_exec($r);
+        if ($response == false) {
+            die("curl_exec() failed. Error: " . curl_error($r));
+        }
+
+        //Parse JSON return object.
+        $result = json_decode($response);
+        // Log::debug("password grant type authenciation response", array($result));
+
+        return $result;
+     }
+
     public function getOAuthRequestCodeUrl(){
         $config = $this->getOpenIDConnectDiscoveryConfiguration();
         $authorization_endpoint = $config->authorization_endpoint;