Ticket #10 (closed enhancement: fixed)

Opened 4 years ago

Last modified 22 months ago

0016883: oAuth security feature (in addition to Dbus)

Reported by: admin Owned by: robert
Priority: major Milestone: MediaMosa 3.0
Component: 2.4 issue Version:
Keywords: oAuth Cc:
MoSCoW: Must Have Estimated time after impact analysis:
Related to project: none Tested:
Accepted: no Estimated Hours: 40

Description (last modified by admin) (diff)

See also:  http://oauth.net/

An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.

And to make cross-layer identity possible (Cool stuff!)


 http://mantis.kennisnet.nl/view.php?id=16883

Change History

Changed 4 years ago by admin

  • description modified (diff)

Changed 3 years ago by Frans

  • moscow set to Must Have
  • component set to CQL
  • related_to set to none
  • milestone changed from MediaMosa X.X to MediaMosa 2.2

Changed 3 years ago by robert

  • estimated_hours set to 40

Changed 3 years ago by Frans

  • moscow changed from Must Have to Should Have

Changed 3 years ago by Frans

  • milestone changed from MediaMosa 2.2 to MediaMosa X.X

Will be a separate project.

Changed 3 years ago by Frans

  • moscow changed from Should Have to Must Have
  • component changed from CQL to Core
  • milestone changed from MediaMosa X.X to MediaMosa 2.4

Changed 2 years ago by Frans

  • milestone changed from MediaMosa 3.0 to MediaMosa 2.4

Changed 2 years ago by forgacs

  • owner set to forgacs
  • status changed from new to assigned

Changed 2 years ago by forgacs

Subtickets:

- http://mediamosa.org/trac/ticket/462
"Test environment development"

- http://mediamosa.org/trac/ticket/463
"oAuth call developments"

- http://mediamosa.org/trac/ticket/464
"oAuth - Client authorization"

Changed 2 years ago by forgacs

  • owner changed from forgacs to robert

It is fixed.

You can find the code under:
core/app/authentication
modules/app/authentication

Two new table was created:
mediamosa_app_nonce
mediamosa_app_token

We have two new REST call:
openapi/oauth/request_token
openapi/oauth/access_token
Both uses the OpenAPI interface.

The solution uses a 3rd party open source application:
 http://oauth.googlecode.com/svn/code/php/

The Client application page was extended with a new oAuth fieldset with two new fields:
oAuth consumer key
oAuth consumer secret

A new page was created for user authentication (openapi/oauth/authorize).

The mediamosa_app_authentication_mediamosa_app_authorized() function / hook was extended with the oAuth code.

A new permission was introduced:
oauth login
This allows, that a user can use oAuth login.

The mediamosa_app_oauth.inc file has these classes:
mediamosa_app_oauth for common functions.
MediaMosaOAuthServer for oAuth server functions.
MediaMosaOAuthDataStore for oAuth database functions.

The application uses the hook_cron() function for cleaning up the expired tickets.

A simpletest was created for testing the login process.

Changed 2 years ago by robert

  • status changed from assigned to closed
  • resolution set to fixed

Changed 2 years ago by forgacs

Official documentation:
 http://tools.ietf.org/html/rfc5849
See 1.2 part about an example.

Other useful information:
 http://oauth.net/core/1.0/
Diagram about the workflow:
 http://oauth.net/core/diagram.png

Yahoo oAuth:
 http://developer.yahoo.com/oauth/guide/oauth-auth-flow.html

Prerequirements:
Openapi interface (like app1, app2, job1 etc. interfaces).
More information about the openapi interface here: http://mediamosa.org/trac/wiki/Installing%20MediaMosa

Usage:
* Setting an oauth user and password.

Go to the client application page: admin/mediamosa/config/app
Click to one, where you want to use oauth authentication.
In the "oAuth settings" fieldset set the "oAuth consumer key" and "oAuth consumer secret".
These data need to the 3rd party application to connect to MediaMosa ("Request token" step in the diagram) using oAuth.

* With these data the 3rd party application can start an oAuth authentication process.
* In this process the user is redirected to a MediaMosa page, where the client can log in with "Client application name" and "Shared key" ("Direct user to service provider" step in the diagram).
* If everything was all right, then the 3rd party application can use MediaMosa REST calls as a given client application ("Access protected resources" step in the diagram).

REST calls for oAuth:
* /openapi/oauth/request_token, method [GET]

 https://beheer.acceptatie.vpcore.snkn.nl/admin/mediamosa/browse/restcall/openapi-oauth-request_token/GET
This is the entry URL for 3rd party applications.

* /openapi/oauth/access_token, method [GET]

 https://beheer.acceptatie.vpcore.snkn.nl/admin/mediamosa/browse/restcall/openapi-oauth-access_token/GET

Changed 23 months ago by Frans

  • component changed from Core to 2.4 issue
  • milestone changed from MediaMosa 2.4 to MediaMosa 3.0

Changed 22 months ago by forgacs

You can find the simpletest of oAuth here:
 https://beheer.acceptatie.vpcore.snkn.nl/admin/mediamosa/simpletests

Steps to test:

* Set up the "Log in with oAuth" permission:
 https://beheer.acceptatie.vpcore.snkn.nl/admin/people/permissions

* Set an OpenAPI client application:
 https://beheer.acceptatie.vpcore.snkn.nl/admin/mediamosa/config/global

* Choose that client, and set the oAuth consumer key (user name) and secret (password):
 https://beheer.acceptatie.vpcore.snkn.nl/admin/mediamosa/config/app

* Example code:

  • I suggest to use this 3rd party oAuth helper code for testing:  http://oauth.googlecode.com/svn/code/php/OAuth.php
  • Test code:
    /**
     * Helper function for testing oAuth.
     */
    function _mediamosa_oauth_test() {
      $output = '';
      $output .= 'Start...<br />' . PHP_EOL;
    
      // Clean up.
      mediamosa_lib::purge_session('final_oauth_token');
      mediamosa_lib::purge_session('final_oauth_token_secret');
      mediamosa_lib::purge_session('oauth_token');
      mediamosa_lib::purge_session('oauth_token_secret');
      mediamosa_lib::purge_session('nid');
    
    
      // oAuth base parameters.
    
      // TODO: Fix it: Your URL, that MediaMosa will call after the user authentication.
      $callback_url = url('...', array('absolute' => TRUE));
    
      // TODO: Fix them.
      $consumer_key = "...";
      $consumer_secret = "...";
      if (!$consumer_key || !$consumer_secret) {
        return t('Consumer key or secret is missing.');
      }
    
      // TODO: Fix them: MediaMosa REST calls.
      $oauth_request_token = 'http://openapi.mediamosa.org/openapi/oauth/request_token';
      $oauth_authorize = 'http://openapi.mediamosa.org/openapi/oauth/authorize';
      $oauth_access_token = 'http://openapi.mediamosa.org/openapi/oauth/access_token';
    
      $sig_method = new OAuthSignatureMethod_HMAC_SHA1();
      $test_consumer = new OAuthConsumer($consumer_key, $consumer_secret, $callback_url);
    
    
      // Request token.
    
      $parameters = array();
      if ($callback_url) {
        $parameters['oauth_callback'] = $callback_url;
      }
      $req_req = OAuthRequest::from_consumer_and_token($test_consumer, NULL, 'GET', $oauth_request_token, $parameters);
      $req_req->sign_request($sig_method, $test_consumer, NULL);
    
    
      // Request parameters.
      $url = $req_req->to_url();
      $response = drupal_http_request($url);
    
      $output .= '<pre>Request token: ' . print_r($response->data, TRUE) . '</pre><br />' . PHP_EOL;
      parse_str($response->data, $reqOAuthData);
      $output .= '<pre>Request token: ' . print_r($reqOAuthData, TRUE) . '</pre><br />' . PHP_EOL;
    
    
      // User authorization.
    
      $req_token = new OAuthConsumer($reqOAuthData['oauth_token'], $reqOAuthData['oauth_token_secret']);
    
      $acc_req = OAuthRequest::from_consumer_and_token($test_consumer, $req_token, "GET", $oauth_authorize);
      $acc_req->sign_request($sig_method, $test_consumer, $req_token);
    
      $_SESSION['oauth_token'] = $reqOAuthData['oauth_token'];
      $_SESSION['oauth_token_secret'] = $reqOAuthData['oauth_token_secret'];
    
      header("Location: $acc_req");
    
    
      $output .= '... end.<br />' . PHP_EOL;
      return $output;
    }
    
    /**
     * Helper function for testing oAuth - page 2.
     */
    function _mediamosa_oauth_test_phase2() {
      $output = '';
      $output .= 'Start...<br />' . PHP_EOL;
    
      // Clean up.
      mediamosa_lib::purge_session('final_oauth_token');
      mediamosa_lib::purge_session('final_oauth_token_secret');
    
      // oAuth base parameters.
    
      if (empty($_SESSION['oauth_token'])) {
        return $output;
      }
    
      // TODO: Fix them.
      $consumer_key = "...";
      $consumer_secret = "...";
      if (!$consumer_key || !$consumer_secret) {
        return t('Consumer key or secret is missing.');
      }
    
      // TODO: Fix them.
      $oauth_request_token = 'http://openapi.mediamosa.org/openapi/oauth/request_token';
      $oauth_authorize = 'http://openapi.mediamosa.org/openapi/oauth/authorize';
      $oauth_access_token = 'http://openapi.mediamosa.org/openapi/oauth/access_token';
    
      $sig_method = new OAuthSignatureMethod_HMAC_SHA1();
      $test_consumer = new OAuthConsumer($consumer_key, $consumer_secret);
    
    
      // Access token.
    
      $acc_token = new OAuthConsumer($_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);
    
      $parameters = array();
      if ($_GET['oauth_verifier']) {
        $parameters['oauth_verifier'] = $_GET['oauth_verifier'];
      }
      $acc_req = OAuthRequest::from_consumer_and_token($test_consumer, $acc_token, "GET", $oauth_access_token, $parameters);
      $acc_req->sign_request($sig_method, $test_consumer, $acc_token);
    
      // Request parameters.
      $url = $acc_req->to_url();
      $response = drupal_http_request($url);
    
      $output .= '<pre>Access token: ' . print_r($response->data, TRUE) . '</pre><br />' . PHP_EOL;
      parse_str($response->data, $accOAuthData);
      $output .= '<pre>Access token: ' . print_r($accOAuthData, TRUE) . '</pre><br />' . PHP_EOL;
    
      // Clean up.
      mediamosa_lib::purge_session('final_oauth_token');
      mediamosa_lib::purge_session('final_oauth_token_secret');
      mediamosa_lib::purge_session('oauth_token');
      mediamosa_lib::purge_session('oauth_token_secret');
      //mediamosa_lib::purge_session('nid');
    
      if (!empty($accOAuthData['oauth_token']) && !empty($accOAuthData['oauth_token_secret'])) {
        $_SESSION['final_oauth_token'] = $accOAuthData['oauth_token'];
        $_SESSION['final_oauth_token_secret'] = $accOAuthData['oauth_token_secret'];
      }
    
      /*
      // Testing.
    
      // Use REST call with authorization.
    
      $rest_url = 'http://app1.mediamosa.org/asset?limit=1';
    
      $acc_token = new OAuthConsumer($_SESSION['final_oauth_token'], $_SESSION['final_oauth_token_secret']);
    
      $parameters = array(
        'limit' => 1,
      );
      $rest_req = OAuthRequest::from_consumer_and_token($test_consumer, $acc_token, "GET", $rest_url, $parameters);
      $rest_req->sign_request($sig_method, $test_consumer, $acc_token);
    
      // Request parameters.
      $url = $rest_req->to_url();
      $response = drupal_http_request($url);
    
      $output .= '<pre>REST call with authentication: ' . htmlspecialchars(print_r($response->data, TRUE)) . '</pre><br />' . PHP_EOL;
    
      // Use REST call without authorization.
    
      // Request parameters.
      $url = $rest_url;
      $response = drupal_http_request($url);
    
      $output .= '<pre>REST call without authentication: ' . htmlspecialchars(print_r($response->data, TRUE)) . '</pre><br />' . PHP_EOL;
       */
    
      return $output;
    }
    
Note: See TracTickets for help on using tickets.