You are here

feeds_oauth.module in Feeds OAuth 7

Same filename and directory in other branches
  1. 6 feeds_oauth.module

The module file.

File

feeds_oauth.module
View source
<?php

/**
 * @file
 * The module file.
 */
define('FEEDS_OAUTH_LIBRARY_PATH_DEFAULT', 'sites/all/libraries/php-proauth');

/**
 * Implements hook_feed_plugins().
 */
function feeds_oauth_feeds_plugins() {
  $info = array();
  $info['OAuthHTTPFetcher'] = array(
    'name' => 'HTTP OAuth fetcher',
    'description' => 'Download content with OAuth authentication.',
    'help' => 'Uses OAuth to authenticate requests to remote resources.',
    'handler' => array(
      // This is the key name, not the class name.
      'parent' => 'FeedsHTTPFetcher',
      'class' => 'OAuthHTTPFetcher',
      'file' => 'OAuthHTTPFetcher.inc',
      'path' => drupal_get_path('module', 'feeds_oauth'),
    ),
  );
  $info['OAuth2HTTPSFetcher'] = array(
    'name' => 'HTTPS OAuth 2.0 fetcher',
    'description' => 'Download content with OAuth 2.0 authentication.',
    'help' => 'Uses OAuth 2.0 to authenticate requests to remote resources.',
    'handler' => array(
      // This is the key name, not the class name.
      'parent' => 'OAuthHTTPFetcher',
      'class' => 'OAuth2HTTPSFetcher',
      'file' => 'OAuth2HTTPSFetcher.inc',
      'path' => drupal_get_path('module', 'feeds_oauth'),
    ),
  );
  return $info;
}

/**
 * Implements hook_menu().
 */
function feeds_oauth_menu() {

  // For OAuth 1.0
  $items['feeds/oauth/authenticate/%'] = array(
    'title' => 'OAuth authentication',
    'type' => MENU_CALLBACK,
    'page callback' => 'feeds_oauth_authenticate',
    'page arguments' => array(
      3,
    ),
    'access callback' => TRUE,
  );
  $items['feeds/oauth/callback/%'] = array(
    'title' => 'OAuth callback',
    'type' => MENU_CALLBACK,
    'page callback' => 'feeds_oauth_callback',
    'page arguments' => array(
      3,
    ),
    'access callback' => TRUE,
  );

  // For OAuth 2.0
  $items['feeds/oauth2/authenticate/%'] = array(
    'title' => 'OAuth2 authentication',
    'type' => MENU_CALLBACK,
    'page callback' => 'feeds_oauth_authenticate2',
    'page arguments' => array(
      3,
    ),
    'access callback' => TRUE,
  );
  $items['feeds/oauth2/callback/%'] = array(
    'title' => 'OAuth2 callback',
    'type' => MENU_CALLBACK,
    'page callback' => 'feeds_oauth_callback2',
    'page arguments' => array(
      3,
    ),
    'access callback' => TRUE,
  );

  // Admin
  $items['admin/config/services/feeds-oauth'] = array(
    'title' => 'Feeds OAuth',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'feeds_oauth_admin',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
  );
  return $items;
}

/**
 * Form function for `feeds_oauth_admin`.
 */
function feeds_oauth_admin($form, $form_state) {
  $form['feeds_oauth_library_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Library path'),
    '#description' => t('Path for the <a href="@url">php-proauth</a> library.', array(
      '@url' => 'https://github.com/infojunkie/php-proauth',
    )),
    '#default_value' => variable_get('feeds_oauth_library_path', FEEDS_OAUTH_LIBRARY_PATH_DEFAULT),
    '#field_prefix' => DRUPAL_ROOT . '/',
  );
  $form['#validate'][] = '_feeds_oauth_admin_validate';
  return system_settings_form($form);
}

/**
 * Validate function for `feeds_oauth_admin`.
 */
function _feeds_oauth_admin_validate($form, $form_state) {
  $path = rtrim($form_state['values']['feeds_oauth_library_path'], '/');
  if (!is_dir($path) || !is_file($path . '/lib/oauth/OAuthClient.php')) {
    form_set_error('feeds_oauth_library_path', t('The php-proauth library path you entered does not point to a valid location. Please enter a valid full path.'));
    return;
  }
}

/**
 * Store the access token in our {feeds_oauth_access_tokens} table.
 */
function _feeds_oauth_store_token($token, $uid, $site_id) {
  $timestamp = time();
  $data = array(
    'uid' => $uid,
    'site_id' => $site_id,
    'oauth_token' => $token['access_token'],
    'oauth_token_secret' => isset($token['access_token_secret']) ? $token['access_token_secret'] : '',
    'timestamp' => $timestamp,
    'expires' => isset($token['expires_in']) ? $timestamp + $token['expires_in'] : (isset($token['expires']) ? $timestamp + $token['expires'] : 0),
    'oauth_refresh_token' => isset($token['refresh_token']) ? $token['refresh_token'] : '',
  );
  db_merge('feeds_oauth_access_tokens')
    ->key(array(
    'uid' => $uid,
    'site_id' => $site_id,
  ))
    ->fields($data)
    ->execute();
}

/**
 * Menu callback to start authenticating OAuth 1.
 */
function feeds_oauth_authenticate($id) {
  $path = variable_get('feeds_oauth_library_path', FEEDS_OAUTH_LIBRARY_PATH_DEFAULT);
  require_once $path . '/lib/oauth/OAuthClient.php';
  $fetcher = feeds_importer($id)->fetcher;
  $config = $fetcher
    ->getConfig();
  $oauth = new proauth\OAuthCurlClient(new proauth\OAuthConsumer($config['consumer_key'], $config['consumer_secret']), new proauth\OAuthSignatureHMACSHA1(), NULL);
  try {
    $request_token = $oauth
      ->_getTempToken($config['request_token_url'], array(), TRUE, strtoupper($config['method']));
  } catch (Exception $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
    drupal_goto($_SERVER['HTTP_REFERER']);
  }
  $_SESSION['feeds'] = array(
    'request_token' => serialize($request_token),
    'id' => $id,
    'destination' => $_SERVER['HTTP_REFERER'],
  );
  drupal_goto(url($config['authorize_url'], array(
    'absolute' => TRUE,
    'query' => array(
      'oauth_token' => $request_token
        ->getToken(),
      'oauth_verifier' => md5(microtime() . mt_rand()),
    ),
  )));
}

/**
 * Menu callback to complete authenticating OAuth 1.
 */
function feeds_oauth_callback($site_id) {
  $path = variable_get('feeds_oauth_library_path', FEEDS_OAUTH_LIBRARY_PATH_DEFAULT);
  require_once $path . '/lib/oauth/OAuthClient.php';
  $fetcher = feeds_importer($_SESSION['feeds']['id'])->fetcher;
  $config = $fetcher
    ->getConfig();
  $request_token = unserialize($_SESSION['feeds']['request_token']);
  $destination = $_SESSION['feeds']['destination'];
  unset($_SESSION['feeds']);
  $oauth = new proauth\OAuthCurlClient(new proauth\OAuthConsumer($config['consumer_key'], $config['consumer_secret']), new proauth\OAuthSignatureHMACSHA1(), $request_token);
  if (empty($_GET['oauth_token']) || empty($_GET['oauth_verifier']) || $_GET['oauth_token'] != $request_token
    ->getToken()) {
    drupal_set_message(t('Invalid OAuth token.'), 'error');
    drupal_goto($destination);
  }
  try {
    $access_token = $oauth
      ->_getAccessToken($config['access_token_url'], array(
      'oauth_verifier' => $_GET['oauth_verifier'],
    ), NULL, TRUE);
  } catch (Exception $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
    drupal_goto($destination);
  }
  global $user;
  _feeds_oauth_store_token(array(
    'access_token' => $access_token
      ->getToken(),
    'access_token_secret' => $access_token
      ->getSecret(),
  ), $user->uid, $site_id);
  drupal_goto($destination);
}

/**
 * Menu callback to start authenticating OAuth 2.
 */
function feeds_oauth_authenticate2($id) {
  $fetcher = feeds_importer($id)->fetcher;
  $config = $fetcher
    ->getConfig();
  $query = array(
    'client_id' => $config['consumer_key'],
    'redirect_uri' => url('feeds/oauth2/callback/' . $id, array(
      'absolute' => TRUE,
    )),
    'scope' => $config['scope'],
    'response_type' => 'code',
    'access_type' => 'offline',
  );
  $_SESSION['feeds'] = array(
    'destination' => $_SERVER['HTTP_REFERER'],
  );
  drupal_goto(url($config['authorize_url'], array(
    'absolute' => TRUE,
    'query' => $query,
  )));
}

/**
 * Menu callback to complete authenticating OAuth 2.
 */
function feeds_oauth_callback2($id) {
  $fetcher = feeds_importer($id)->fetcher;
  $config = $fetcher
    ->getConfig();
  $code = isset($_GET['code']) ? $_GET['code'] : FALSE;
  $token = FALSE;
  $destination = $_SESSION['feeds']['destination'];
  unset($_SESSION['feeds']);

  // TODO: Rewrite this using OAuth2CurlClient.
  if ($code) {
    $query = array(
      'code' => $code,
      'client_id' => $config['consumer_key'],
      'client_secret' => $config['consumer_secret'],
      'redirect_uri' => url('feeds/oauth2/callback/' . $id, array(
        'absolute' => TRUE,
      )),
      'grant_type' => 'authorization_code',
    );
    $response = drupal_http_request($config['access_token_url'], array(
      'method' => 'POST',
      'headers' => array(
        'Content-Type' => 'application/x-www-form-urlencoded',
      ),
      'data' => http_build_query($query, '', '&'),
    ));
    if ($response->code == 200) {
      $token = drupal_json_decode($response->data);
      if (empty($token)) {
        parse_str($response->data, $token);
      }
    }
    else {
      drupal_set_message(t('Attempt to retrieve access token failed: %response', array(
        '%response' => print_r($response, TRUE),
      )), 'error');
    }
  }
  else {
    drupal_set_message(t('OAuth 2 callback did not receive %code argument.', array(
      '%code' => 'code',
    )), 'error');
  }
  if ($token) {
    global $user;
    _feeds_oauth_store_token($token, $user->uid, $config['site_id']);
  }
  drupal_goto($destination);
}

/**
 * Menu callback to refresh access tokens for OAuth 2.
 */
function feeds_oauth_refresh2($refresh_token, $uid, $id) {
  $fetcher = feeds_importer($id)->fetcher;
  $config = $fetcher
    ->getConfig();
  $query = array(
    'client_id' => $config['consumer_key'],
    'client_secret' => $config['consumer_secret'],
    'refresh_token' => $refresh_token,
    'grant_type' => 'refresh_token',
  );
  $response = drupal_http_request($config['access_token_url'], array(
    'method' => 'POST',
    'headers' => array(
      'Content-Type' => 'application/x-www-form-urlencoded',
    ),
    'data' => http_build_query($query, '', '&'),
  ));
  $token = NULL;
  if ($response->code == 200) {
    $token = drupal_json_decode($response->data);

    // Pass on the old refresh token if we didn't get a new one.
    if (empty($token['refresh_token'])) {
      $token['refresh_token'] = $refresh_token;
    }
    _feeds_oauth_store_token($token, $uid, $config['site_id']);
  }
  else {
    watchdog('feeds_oauth', 'Attempt to refresh token failed: %response', array(
      '%response' => print_r($response, TRUE),
    ), WATCHDOG_ERROR);
  }
  return $token;
}

/**
 * Implements hook_feeds_oauth_authenticator().
 */
function feeds_oauth_feeds_oauth_authenticator() {
  return array(
    'feeds_oauth_get_tokens' => 'Feeds OAuth',
  );
}

/**
 * Get tokens from database.
 */
function feeds_oauth_get_tokens($uid, $site_id, $id) {
  $token = db_query("SELECT * FROM {feeds_oauth_access_tokens} WHERE uid = :uid AND site_id = :site_id", array(
    ':uid' => $uid,
    ':site_id' => $site_id,
  ))
    ->fetchAssoc();
  if ($token['expires'] && time() > $token['expires']) {

    // Remove the expired key.
    db_delete('feeds_oauth_access_tokens')
      ->condition('uid', $uid)
      ->condition('site_id', $site_id)
      ->execute();
    if (!empty($token['oauth_refresh_token'])) {

      // This is OAuth 2.0 and we have a refresh token!
      $token = feeds_oauth_refresh2($token['oauth_refresh_token'], $uid, $id);
    }
    else {

      // Just clear it out -- the user will have to authenticate again.
      $token = NULL;
    }
  }
  return $token;
}

Functions

Namesort descending Description
feeds_oauth_admin Form function for `feeds_oauth_admin`.
feeds_oauth_authenticate Menu callback to start authenticating OAuth 1.
feeds_oauth_authenticate2 Menu callback to start authenticating OAuth 2.
feeds_oauth_callback Menu callback to complete authenticating OAuth 1.
feeds_oauth_callback2 Menu callback to complete authenticating OAuth 2.
feeds_oauth_feeds_oauth_authenticator Implements hook_feeds_oauth_authenticator().
feeds_oauth_feeds_plugins Implements hook_feed_plugins().
feeds_oauth_get_tokens Get tokens from database.
feeds_oauth_menu Implements hook_menu().
feeds_oauth_refresh2 Menu callback to refresh access tokens for OAuth 2.
_feeds_oauth_admin_validate Validate function for `feeds_oauth_admin`.
_feeds_oauth_store_token Store the access token in our {feeds_oauth_access_tokens} table.

Constants

Namesort descending Description
FEEDS_OAUTH_LIBRARY_PATH_DEFAULT @file The module file.