You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by sc...@apache.org on 2015/09/03 16:02:12 UTC

airavata-php-gateway git commit: Adding OAuth request_code grant flow support for PGA

Repository: airavata-php-gateway
Updated Branches:
  refs/heads/master 088dfff02 -> cc8308999


Adding OAuth request_code grant flow support for PGA


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/cc830899
Tree: http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/tree/cc830899
Diff: http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/diff/cc830899

Branch: refs/heads/master
Commit: cc83089998a0c33cd5bf713f086b8220545f0dcb
Parents: 088dfff
Author: Supun Nakandala <sc...@apache.org>
Authored: Thu Sep 3 19:31:33 2015 +0530
Committer: Supun Nakandala <sc...@apache.org>
Committed: Thu Sep 3 19:31:33 2015 +0530

----------------------------------------------------------------------
 app/config/pga_config.php.template              |  24 ++-
 app/controllers/AccountController.php           |  54 ++++++-
 app/filters.php                                 |  23 ++-
 app/libraries/Airavata/API/Airavata.php         |  42 +-----
 app/libraries/Wsis/Stubs/OAuthManager.php       | 147 +++++++++++++++++++
 app/libraries/Wsis/Stubs/UserProfileManager.php |   5 +
 app/libraries/Wsis/Wsis.php                     |  52 +++++++
 app/routes.php                                  |   2 +
 8 files changed, 300 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/cc830899/app/config/pga_config.php.template
----------------------------------------------------------------------
diff --git a/app/config/pga_config.php.template b/app/config/pga_config.php.template
index 19c4707..58323d0 100644
--- a/app/config/pga_config.php.template
+++ b/app/config/pga_config.php.template
@@ -26,12 +26,32 @@ return array(
         /**
          * Tenant admin's username
          */
-        'admin-username' => 'test@testphprg.scigap.org',
+        'admin-username' => 'master@master.airavata.scigap.org',
 
         /**
          * Tenant admin's password
          */
-        'admin-password' => 'testadmin@scigap.org',
+        'admin-password' => 'master',
+
+        /**
+         * Authentication mode (basic, oauth)
+         */
+        'auth-mode' => 'basic',
+
+        /**
+         * OAuth client key
+         */
+        'oauth-client-key' => 'iGEREhSBLuGapdcXwMU0b8jEpA4a',
+
+        /**
+         * OAuth client secret
+         */
+        'oauth-client-secret' => 'g4Lgp05JIJcNQryJkNKjXJYi8A8a',
+
+        /**
+         * OAuth callback url
+         */
+        'oauth-callback-url' => 'http://localhost/airavata-php-gateway/public/callback-url',
 
         /**
          * Identity server domain

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/cc830899/app/controllers/AccountController.php
----------------------------------------------------------------------
diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php
index 64a0b09..8dcbd0f 100755
--- a/app/controllers/AccountController.php
+++ b/app/controllers/AccountController.php
@@ -60,8 +60,6 @@ class AccountController extends BaseController
             //update user profile
             WSIS::updateUserProfile($username, $email, $first_name, $last_name);
 
-            //creating a default project for user
-            ProjectUtilities::create_default_project($username);
             CommonUtilities::print_success_message('New user created!');
             return View::make('account/login');
         }
@@ -69,7 +67,55 @@ class AccountController extends BaseController
 
     public function loginView()
     {
-        return View::make('account/login');
+        if(Config::get('pga_config.wsis')['auth-mode'] == "oauth"){
+            $url = WSIS::getOAuthRequestCodeUrl();
+            return Redirect::away($url);
+        }else{
+            return View::make('account/login');
+        }
+    }
+
+    public function oauthCallback()
+    {
+        if (!isset($_GET["code"])) {
+            CommonUtilities::print_error_message("Require the code parameter to validate!");
+        }
+
+        $code = $_GET["code"];
+        $response = WSIS::getOAuthToken($code);
+        $accessToken = $response->access_token;
+        $refreshToken = $response->refresh_token;
+        $expirationTime = time() + $response->expires_in - 5; //5 seconds safe margin
+        $authzToken = new Airavata\Model\Security\AuthzToken();
+        $authzToken->accessToken = $accessToken;
+        Session::put('authz-token',$authzToken);
+        Session::put('oauth-refresh-code',$refreshToken);
+        Session::put('oauth-expiration-time',$expirationTime);
+
+        $userProfile = WSIS::getUserProfileFromOAuthToken($accessToken);
+        Session::put("user-profile", $userProfile);
+
+        $userRoles = $userProfile['roles'];
+        if (in_array(Config::get('pga_config.wsis')['admin-role-name'], $userRoles)) {
+            Session::put("admin", true);
+        }
+        if (in_array(Config::get('pga_config.wsis')['read-only-admin'], $userRoles)) {
+            Session::put("admin-read-only", true);
+        }
+
+        $username = $userProfile['username'];
+        CommonUtilities::store_id_in_session($username);
+        CommonUtilities::print_success_message('Login successful! You will be redirected to your home page shortly.');
+        Session::put("gateway_id", Config::get('pga_config.airavata')['gateway-id']);
+
+        //creating a default project for user
+        $projects = ProjectUtilities::get_all_user_projects(Config::get('pga_config.airavata')['gateway-id'], $username);
+        if($projects == null || count($projects) == 0){
+            //creating a default project for user
+            ProjectUtilities::create_default_project($username);
+        }
+
+        return Redirect::to("home");
     }
 
     public function loginSubmit()
@@ -95,9 +141,7 @@ class AccountController extends BaseController
 
                     CommonUtilities::store_id_in_session($username);
                     CommonUtilities::print_success_message('Login successful! You will be redirected to your home page shortly.');
-                    //TODO::If this option is not safe, have to find a better method to send credentials to identity server on every connection.
                     Session::put("gateway_id", Config::get('pga_config.airavata')['gateway-id']);
-                    Session::put("password", $_POST["password"]);
 
                     //creating a default project for user
                     $projects = ProjectUtilities::get_all_user_projects(Config::get('pga_config.airavata')['gateway-id'], $username);

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/cc830899/app/filters.php
----------------------------------------------------------------------
diff --git a/app/filters.php b/app/filters.php
index 80336ab..ac98976 100755
--- a/app/filters.php
+++ b/app/filters.php
@@ -12,13 +12,26 @@
 */
 
 App::before(function ($request) {
-    $authzToken = new Airavata\Model\Security\AuthzToken();
-    $authzToken->accessToken = "emptyToken";
-    $apiVersion = Airavata::getAPIVersion($authzToken);
+    //Check Airavata Server is up
+    $apiVersion = Airavata::getAPIVersion();
     if (empty($apiVersion))
         return View::make("server-down");
-    else
-        Session::put('authz-token',$authzToken);
+
+    //Check OAuth token has expired
+    if(Config::get('pga_config.wsis')['auth-mode']=="oauth" && Session::has('authz-token')){
+        $currentTime = time();
+        if($currentTime > Session::get('oauth-expiration-time')){
+            $response = WSIS::getRefreshedOAutheToken(Session::get('oauth-refresh-code'));
+            $accessToken = $response->access_token;
+            $refreshToken = $response->refresh_token;
+            $expirationTime = time()/1000 + $response->expires_in - 300;
+            $authzToken = new Airavata\Model\Security\AuthzToken();
+            $authzToken->accessToken = $accessToken;
+            Session::put('authz-token',$authzToken);
+            Session::put('oauth-refresh-code',$refreshToken);
+            Session::put('oauth-expiration-time',$expirationTime);
+        }
+    }
 });
 
 

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/cc830899/app/libraries/Airavata/API/Airavata.php
----------------------------------------------------------------------
diff --git a/app/libraries/Airavata/API/Airavata.php b/app/libraries/Airavata/API/Airavata.php
index cab3cef..c068aa6 100644
--- a/app/libraries/Airavata/API/Airavata.php
+++ b/app/libraries/Airavata/API/Airavata.php
@@ -20,14 +20,13 @@ interface AiravataIf {
   /**
    * Fetch Apache Airavata API version
    * 
-   * @param \Airavata\Model\Security\AuthzToken $authzToken
    * @return string
    * @throws \Airavata\API\Error\InvalidRequestException
    * @throws \Airavata\API\Error\AiravataClientException
    * @throws \Airavata\API\Error\AiravataSystemException
    * @throws \Airavata\API\Error\AuthorizationException
    */
-  public function getAPIVersion(\Airavata\Model\Security\AuthzToken $authzToken);
+  public function getAPIVersion();
   /**
    * @param \Airavata\Model\Security\AuthzToken $authzToken
    * @param \Airavata\Model\Workspace\Gateway $gateway
@@ -2555,16 +2554,15 @@ class AiravataClient implements \Airavata\API\AiravataIf {
     $this->output_ = $output ? $output : $input;
   }
 
-  public function getAPIVersion(\Airavata\Model\Security\AuthzToken $authzToken)
+  public function getAPIVersion()
   {
-    $this->send_getAPIVersion($authzToken);
+    $this->send_getAPIVersion();
     return $this->recv_getAPIVersion();
   }
 
-  public function send_getAPIVersion(\Airavata\Model\Security\AuthzToken $authzToken)
+  public function send_getAPIVersion()
   {
     $args = new \Airavata\API\Airavata_getAPIVersion_args();
-    $args->authzToken = $authzToken;
     $bin_accel = ($this->output_ instanceof TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');
     if ($bin_accel)
     {
@@ -10204,26 +10202,12 @@ class AiravataClient implements \Airavata\API\AiravataIf {
 class Airavata_getAPIVersion_args {
   static $_TSPEC;
 
-  /**
-   * @var \Airavata\Model\Security\AuthzToken
-   */
-  public $authzToken = null;
 
-  public function __construct($vals=null) {
+  public function __construct() {
     if (!isset(self::$_TSPEC)) {
       self::$_TSPEC = array(
-        1 => array(
-          'var' => 'authzToken',
-          'type' => TType::STRUCT,
-          'class' => '\Airavata\Model\Security\AuthzToken',
-          ),
         );
     }
-    if (is_array($vals)) {
-      if (isset($vals['authzToken'])) {
-        $this->authzToken = $vals['authzToken'];
-      }
-    }
   }
 
   public function getName() {
@@ -10245,14 +10229,6 @@ class Airavata_getAPIVersion_args {
       }
       switch ($fid)
       {
-        case 1:
-          if ($ftype == TType::STRUCT) {
-            $this->authzToken = new \Airavata\Model\Security\AuthzToken();
-            $xfer += $this->authzToken->read($input);
-          } else {
-            $xfer += $input->skip($ftype);
-          }
-          break;
         default:
           $xfer += $input->skip($ftype);
           break;
@@ -10266,14 +10242,6 @@ class Airavata_getAPIVersion_args {
   public function write($output) {
     $xfer = 0;
     $xfer += $output->writeStructBegin('Airavata_getAPIVersion_args');
-    if ($this->authzToken !== null) {
-      if (!is_object($this->authzToken)) {
-        throw new TProtocolException('Bad type in structure.', TProtocolException::INVALID_DATA);
-      }
-      $xfer += $output->writeFieldBegin('authzToken', TType::STRUCT, 1);
-      $xfer += $this->authzToken->write($output);
-      $xfer += $output->writeFieldEnd();
-    }
     $xfer += $output->writeFieldStop();
     $xfer += $output->writeStructEnd();
     return $xfer;

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/cc830899/app/libraries/Wsis/Stubs/OAuthManager.php
----------------------------------------------------------------------
diff --git a/app/libraries/Wsis/Stubs/OAuthManager.php b/app/libraries/Wsis/Stubs/OAuthManager.php
new file mode 100644
index 0000000..5188fd6
--- /dev/null
+++ b/app/libraries/Wsis/Stubs/OAuthManager.php
@@ -0,0 +1,147 @@
+<?php
+
+namespace Wsis\Stubs;
+
+class OAuthManager
+{
+
+    public $CurlHeaders;
+    public $ResponseCode;
+
+    private $_AuthorizeUrl;
+    private $_AccessTokenUrl;
+    private $_UserInfoUrl;
+    private $_verifyPeer;
+    private $_cafilePath;
+
+    public function __construct($serverUrl, $verifyPeer, $cafilePath)
+    {
+        $this->_AuthorizeUrl  = $serverUrl . "oauth2/authorize";
+        $this->_AccessTokenUrl  = $serverUrl . "oauth2/token";
+        $this->_UserInfoUrl = $serverUrl . "oauth2/userinfo?schema=openid";
+        $this->_verifyPeer = $verifyPeer;
+        $this->_cafilePath = $cafilePath;
+        $this->CurlHeaders = array();
+        $this->ResponseCode = 0;
+    }
+
+    public function requestAccessCode($client_id, $redirect_url)
+    {
+        return ($this->_AuthorizeUrl . "?client_id=" . $client_id . "&response_type=code&scope=openid&redirect_uri=" . $redirect_url);
+    }
+
+    // Convert an authorization code from callback into an access token.
+    public function getAccessToken($client_id, $client_secret, $auth_code, $redirect_url)
+    {
+        // Init cUrl.
+        $r = $this->initCurl($this->_AccessTokenUrl);
+
+        // Add client ID and client secret to the headers.
+        curl_setopt($r, CURLOPT_HTTPHEADER, array(
+            "Authorization: Basic " . base64_encode($client_id . ":" . $client_secret),
+        ));
+
+        // Assemble POST parameters for the request.
+        $post_fields = "code=" . urlencode($auth_code) . "&grant_type=authorization_code&redirect_uri=" . $redirect_url;
+
+        // 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.
+        return json_decode($response);
+    }
+
+    // To get a refreshed access token
+    public function getRefreshedAccessToken($client_id, $client_secret, $refresh_token)
+    {
+        // Init cUrl.
+        $r = $this->initCurl($this->_AccessTokenUrl);
+
+        // Add client ID and client secret to the headers.
+        curl_setopt($r, CURLOPT_HTTPHEADER, array(
+            "Authorization: Basic " . base64_encode($client_id . ":" . $client_secret),
+        ));
+
+        // Assemble POST parameters for the request.
+        $post_fields = "refresh_token=" . urlencode($refresh_token) . "&grant_type=refresh_token";
+
+        // 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.
+        return json_decode($response);
+    }
+
+    private function initCurl($url)
+    {
+        $r = null;
+
+        if (($r = @curl_init($url)) == false) {
+            header("HTTP/1.1 500", true, 500);
+            die("Cannot initialize cUrl session. Is cUrl enabled for your PHP installation?");
+        }
+
+        curl_setopt($r, CURLOPT_RETURNTRANSFER, 1);
+
+        // Decode compressed responses.
+        curl_setopt($r, CURLOPT_ENCODING, 1);
+
+        curl_setopt($r, CURLOPT_SSL_VERIFYPEER, $this->_verifyPeer);
+        curl_setopt($r, CURLOPT_CAINFO, $this->_cafilePath);
+
+        return ($r);
+    }
+
+
+    public function getUserProfile($access_token)
+    {
+        $r = $this->initCurl($this->_UserInfoUrl);
+
+        curl_setopt($r, CURLOPT_HTTPHEADER, array(
+            "Authorization: Bearer " . $access_token
+        ));
+
+        $response = curl_exec($r);
+        if ($response == false) {
+            die("curl_exec() failed. Error: " . curl_error($r));
+        }
+
+        //Parse JSON return object.
+        return json_decode($response);
+    }
+
+    // A generic function that executes an API request.
+    public function execRequest($url, $access_token, $get_params)
+    {
+        // Create request string.
+        $full_url = http_build_query($url, $get_params);
+
+        $r = $this->initCurl($full_url);
+
+        curl_setopt($r, CURLOPT_HTTPHEADER, array(
+            "Authorization: Basic " . base64_encode($access_token)
+        ));
+
+        $response = curl_exec($r);
+        if ($response == false) {
+            die("curl_exec() failed. Error: " . curl_error($r));
+        }
+
+        //Parse JSON return object.
+        return json_decode($response);
+    }
+}
+
+?>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/cc830899/app/libraries/Wsis/Stubs/UserProfileManager.php
----------------------------------------------------------------------
diff --git a/app/libraries/Wsis/Stubs/UserProfileManager.php b/app/libraries/Wsis/Stubs/UserProfileManager.php
index eff2a35..6d5bcc8 100644
--- a/app/libraries/Wsis/Stubs/UserProfileManager.php
+++ b/app/libraries/Wsis/Stubs/UserProfileManager.php
@@ -38,6 +38,11 @@ class UserProfileManager {
         $profile = new UserProfileDTO();
         $fieldValues = array();
 
+        $usernameDTO = new UserFieldDTO();
+        $usernameDTO->claimUri = "http://wso2.org/claims/sub";
+        $usernameDTO->fieldValue = $username;
+        array_push($fieldValues, $usernameDTO);
+
         $emailDTO = new UserFieldDTO();
         $emailDTO->claimUri = "http://wso2.org/claims/emailaddress";
         $emailDTO->fieldValue = $email;

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/cc830899/app/libraries/Wsis/Wsis.php
----------------------------------------------------------------------
diff --git a/app/libraries/Wsis/Wsis.php b/app/libraries/Wsis/Wsis.php
index 456b02b..e3f8e26 100755
--- a/app/libraries/Wsis/Wsis.php
+++ b/app/libraries/Wsis/Wsis.php
@@ -6,6 +6,9 @@ use Wsis\Stubs\UserProfileManager;
 use Wsis\Stubs\UserStoreManager;
 use Wsis\Stubs\TenantManager;
 use Wsis\Stubs\UserInformationRecoveryManager;
+use Wsis\Stubs\OAuthManager;
+
+use Illuminate\Support\Facades\Config;
 
 class Wsis {
 
@@ -34,6 +37,12 @@ class Wsis {
     private $userInfoRecoveryManager;
 
     /**
+     * @var
+     * @access private
+     */
+    private $oauthManger;
+
+    /**
      * @var string
      * @access private
      */
@@ -87,6 +96,7 @@ class Wsis {
             $this->tenantManager = new TenantManager($service_url, $parameters);
             $this->userProfileManager = new UserProfileManager($service_url, $parameters);
             $this->userInfoRecoveryManager = new UserInformationRecoveryManager($service_url, $parameters);
+            $this->oauthManger = new OAuthManager(Config::get('pga_config.wsis')['service-url'], $verify_peer, $cafile_path);
         } catch (Exception $ex) {
             throw new Exception("Unable to instantiate WSO2 IS client", 0, $ex);
         }
@@ -142,6 +152,48 @@ class Wsis {
     }
 
     /**
+     * Function to get OAuth request code url
+     * @return mixed
+     */
+    public function getOAuthRequestCodeUrl(){
+        $url = $this->oauthManger->requestAccessCode(Config::get('pga_config.wsis')['oauth-client-key'],
+            Config::get('pga_config.wsis')['oauth-callback-url']);
+        return $url;
+    }
+
+    /**
+     * Function to get OAuth Access token
+     * @return string
+     */
+    public function getOAuthToken($code){
+        $response = $this->oauthManger->getAccessToken(Config::get('pga_config.wsis')['oauth-client-key'],
+            Config::get('pga_config.wsis')['oauth-client-secret'], $code,
+            Config::get('pga_config.wsis')['oauth-callback-url']);
+        return $response;
+    }
+
+    /**
+     * Method to get refreshed access token
+     * @param $refreshToken
+     * @return mixed
+     */
+    public function getRefreshedOAutheToken($refreshToken){
+        $response = $this->oauthManger->getRefreshedAccessToken(Config::get('pga_config.wsis')['oauth-client-key'],
+            Config::get('pga_config.wsis')['oauth-client-secret'], $refreshToken);
+        return $response;
+    }
+
+    /**
+     * Function to get user profile from OAuth token
+     * @param $token
+     */
+    public function getUserProfileFromOAuthToken($token){
+        $userProfile = $this->oauthManger->getUserProfile($token);
+        return array('username'=>$userProfile->sub, 'email'=>$userProfile->email, 'firstname'=>$userProfile->given_name,
+            'lastname'=>$userProfile->family_name, 'roles'=>explode(",",$userProfile->roles));
+    }
+
+    /**
      * Function to check whether username exists
      *
      * @param string $username

http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/cc830899/app/routes.php
----------------------------------------------------------------------
diff --git a/app/routes.php b/app/routes.php
index bb707a4..361291a 100755
--- a/app/routes.php
+++ b/app/routes.php
@@ -24,6 +24,8 @@ Route::get("login", "AccountController@loginView");
 
 Route::post("login", "AccountController@loginSubmit");
 
+Route::get("callback-url", "AccountController@oauthCallback");
+
 Route::get("logout", "AccountController@logout");
 
 Route::get("forgot-password", "AccountController@forgotPassword");