You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
354 lines
9.7 KiB
354 lines
9.7 KiB
<?php |
|
/** |
|
* @link http://www.yiiframework.com/ |
|
* @copyright Copyright (c) 2008 Yii Software LLC |
|
* @license http://www.yiiframework.com/license/ |
|
*/ |
|
|
|
namespace yii\authclient; |
|
|
|
use yii\base\Exception; |
|
use Yii; |
|
|
|
/** |
|
* OAuth1 serves as a client for the OAuth 1/1.0a flow. |
|
* |
|
* In oder to acquire access token perform following sequence: |
|
* |
|
* ~~~ |
|
* use yii\authclient\OAuth1; |
|
* |
|
* $oauthClient = new OAuth1(); |
|
* $requestToken = $oauthClient->fetchRequestToken(); // Get request token |
|
* $url = $oauthClient->buildAuthUrl($requestToken); // Get authorization URL |
|
* return Yii::$app->getResponse()->redirect($url); // Redirect to authorization URL |
|
* // After user returns at our site: |
|
* $accessToken = $oauthClient->fetchAccessToken($requestToken); // Upgrade to access token |
|
* ~~~ |
|
* |
|
* @see http://oauth.net/ |
|
* |
|
* @author Paul Klimov <klimov.paul@gmail.com> |
|
* @since 2.0 |
|
*/ |
|
class OAuth1 extends BaseOAuth |
|
{ |
|
/** |
|
* @var string protocol version. |
|
*/ |
|
public $version = '1.0'; |
|
/** |
|
* @var string OAuth consumer key. |
|
*/ |
|
public $consumerKey; |
|
/** |
|
* @var string OAuth consumer secret. |
|
*/ |
|
public $consumerSecret; |
|
/** |
|
* @var string OAuth request token URL. |
|
*/ |
|
public $requestTokenUrl; |
|
/** |
|
* @var string request token HTTP method. |
|
*/ |
|
public $requestTokenMethod = 'GET'; |
|
/** |
|
* @var string OAuth access token URL. |
|
*/ |
|
public $accessTokenUrl; |
|
/** |
|
* @var string access token HTTP method. |
|
*/ |
|
public $accessTokenMethod = 'GET'; |
|
|
|
/** |
|
* Fetches the OAuth request token. |
|
* @param array $params additional request params. |
|
* @return OAuthToken request token. |
|
*/ |
|
public function fetchRequestToken(array $params = []) |
|
{ |
|
$this->removeState('token'); |
|
$defaultParams = [ |
|
'oauth_consumer_key' => $this->consumerKey, |
|
'oauth_callback' => $this->getReturnUrl(), |
|
//'xoauth_displayname' => Yii::$app->name, |
|
]; |
|
if (!empty($this->scope)) { |
|
$defaultParams['scope'] = $this->scope; |
|
} |
|
$response = $this->sendSignedRequest($this->requestTokenMethod, $this->requestTokenUrl, array_merge($defaultParams, $params)); |
|
$token = $this->createToken([ |
|
'params' => $response |
|
]); |
|
$this->setState('requestToken', $token); |
|
return $token; |
|
} |
|
|
|
/** |
|
* Composes user authorization URL. |
|
* @param OAuthToken $requestToken OAuth request token. |
|
* @param array $params additional request params. |
|
* @return string authorize URL |
|
* @throws Exception on failure. |
|
*/ |
|
public function buildAuthUrl(OAuthToken $requestToken = null, array $params = []) |
|
{ |
|
if (!is_object($requestToken)) { |
|
$requestToken = $this->getState('requestToken'); |
|
if (!is_object($requestToken)) { |
|
throw new Exception('Request token is required to build authorize URL!'); |
|
} |
|
} |
|
$params['oauth_token'] = $requestToken->getToken(); |
|
return $this->composeUrl($this->authUrl, $params); |
|
} |
|
|
|
/** |
|
* Fetches OAuth access token. |
|
* @param OAuthToken $requestToken OAuth request token. |
|
* @param string $oauthVerifier OAuth verifier. |
|
* @param array $params additional request params. |
|
* @return OAuthToken OAuth access token. |
|
* @throws Exception on failure. |
|
*/ |
|
public function fetchAccessToken(OAuthToken $requestToken = null, $oauthVerifier = null, array $params = []) |
|
{ |
|
if (!is_object($requestToken)) { |
|
$requestToken = $this->getState('requestToken'); |
|
if (!is_object($requestToken)) { |
|
throw new Exception('Request token is required to fetch access token!'); |
|
} |
|
} |
|
$this->removeState('requestToken'); |
|
$defaultParams = [ |
|
'oauth_consumer_key' => $this->consumerKey, |
|
'oauth_token' => $requestToken->getToken() |
|
]; |
|
if ($oauthVerifier === null) { |
|
if (isset($_REQUEST['oauth_verifier'])) { |
|
$oauthVerifier = $_REQUEST['oauth_verifier']; |
|
} |
|
} |
|
if (!empty($oauthVerifier)) { |
|
$defaultParams['oauth_verifier'] = $oauthVerifier; |
|
} |
|
$response = $this->sendSignedRequest($this->accessTokenMethod, $this->accessTokenUrl, array_merge($defaultParams, $params)); |
|
|
|
$token = $this->createToken([ |
|
'params' => $response |
|
]); |
|
$this->setAccessToken($token); |
|
return $token; |
|
} |
|
|
|
/** |
|
* Sends HTTP request, signed by {@link signatureMethod}. |
|
* @param string $method request type. |
|
* @param string $url request URL. |
|
* @param array $params request params. |
|
* @return array response. |
|
*/ |
|
protected function sendSignedRequest($method, $url, array $params = []) |
|
{ |
|
$params = array_merge($params, $this->generateCommonRequestParams()); |
|
$params = $this->signRequest($method, $url, $params); |
|
return $this->sendRequest($method, $url, $params); |
|
} |
|
|
|
/** |
|
* Composes HTTP request CUrl options, which will be merged with the default ones. |
|
* @param string $method request type. |
|
* @param string $url request URL. |
|
* @param array $params request params. |
|
* @return array CUrl options. |
|
* @throws Exception on failure. |
|
*/ |
|
protected function composeRequestCurlOptions($method, $url, array $params) |
|
{ |
|
$curlOptions = []; |
|
switch ($method) { |
|
case 'GET': { |
|
$curlOptions[CURLOPT_URL] = $this->composeUrl($url, $params); |
|
break; |
|
} |
|
case 'POST': { |
|
$curlOptions[CURLOPT_POST] = true; |
|
if (!empty($params)){ |
|
$curlOptions[CURLOPT_POSTFIELDS] = $params; |
|
} |
|
$authorizationHeader = $this->composeAuthorizationHeader($params); |
|
if (!empty($authorizationHeader)) { |
|
$curlOptions[CURLOPT_HTTPHEADER] = ['Content-Type: application/atom+xml', $authorizationHeader]; |
|
} |
|
break; |
|
} |
|
case 'HEAD': |
|
case 'PUT': |
|
case 'DELETE': { |
|
$curlOptions[CURLOPT_CUSTOMREQUEST] = $method; |
|
if (!empty($params)) { |
|
$curlOptions[CURLOPT_URL] = $this->composeUrl($url, $params); |
|
} |
|
break; |
|
} |
|
default: { |
|
throw new Exception("Unknown request method '{$method}'."); |
|
} |
|
} |
|
return $curlOptions; |
|
} |
|
|
|
/** |
|
* Performs request to the OAuth API. |
|
* @param OAuthToken $accessToken actual access token. |
|
* @param string $url absolute API URL. |
|
* @param string $method request method. |
|
* @param array $params request parameters. |
|
* @return array API response. |
|
* @throws Exception on failure. |
|
*/ |
|
protected function apiInternal($accessToken, $url, $method, array $params) |
|
{ |
|
$params['oauth_consumer_key'] = $this->consumerKey; |
|
$params['oauth_token'] = $accessToken->getToken(); |
|
$response = $this->sendSignedRequest($method, $url, $params); |
|
return $response; |
|
} |
|
|
|
/** |
|
* Gets new auth token to replace expired one. |
|
* @param OAuthToken $token expired auth token. |
|
* @return OAuthToken new auth token. |
|
*/ |
|
public function refreshAccessToken(OAuthToken $token) |
|
{ |
|
// @todo |
|
return null; |
|
} |
|
|
|
/** |
|
* Composes default {@link returnUrl} value. |
|
* @return string return URL. |
|
*/ |
|
protected function defaultReturnUrl() |
|
{ |
|
$params = $_GET; |
|
unset($params['oauth_token']); |
|
return Yii::$app->getUrlManager()->createAbsoluteUrl(Yii::$app->controller->getRoute(), $params); |
|
} |
|
|
|
/** |
|
* Generates nonce value. |
|
* @return string nonce value. |
|
*/ |
|
protected function generateNonce() |
|
{ |
|
return md5(microtime() . mt_rand()); |
|
} |
|
|
|
/** |
|
* Generates timestamp. |
|
* @return integer timestamp. |
|
*/ |
|
protected function generateTimestamp() |
|
{ |
|
return time(); |
|
} |
|
|
|
/** |
|
* Generate common request params like version, timestamp etc. |
|
* @return array common request params. |
|
*/ |
|
protected function generateCommonRequestParams() |
|
{ |
|
$params = [ |
|
'oauth_version' => $this->version, |
|
'oauth_nonce' => $this->generateNonce(), |
|
'oauth_timestamp' => $this->generateTimestamp(), |
|
]; |
|
return $params; |
|
} |
|
|
|
/** |
|
* Sign request with {@link signatureMethod}. |
|
* @param string $method request method. |
|
* @param string $url request URL. |
|
* @param array $params request params. |
|
* @return array signed request params. |
|
*/ |
|
protected function signRequest($method, $url, array $params) |
|
{ |
|
$signatureMethod = $this->getSignatureMethod(); |
|
$params['oauth_signature_method'] = $signatureMethod->getName(); |
|
$signatureBaseString = $this->composeSignatureBaseString($method, $url, $params); |
|
$signatureKey = $this->composeSignatureKey(); |
|
$params['oauth_signature'] = $signatureMethod->generateSignature($signatureBaseString, $signatureKey); |
|
return $params; |
|
} |
|
|
|
/** |
|
* Creates signature base string, which will be signed by {@link signatureMethod}. |
|
* @param string $method request method. |
|
* @param string $url request URL. |
|
* @param array $params request params. |
|
* @return string base signature string. |
|
*/ |
|
protected function composeSignatureBaseString($method, $url, array $params) |
|
{ |
|
unset($params['oauth_signature']); |
|
uksort($params, 'strcmp'); // Parameters are sorted by name, using lexicographical byte value ordering. Ref: Spec: 9.1.1 |
|
$parts = [ |
|
strtoupper($method), |
|
$url, |
|
http_build_query($params, '', '&', PHP_QUERY_RFC3986) |
|
]; |
|
$parts = array_map('rawurlencode', $parts); |
|
return implode('&', $parts); |
|
} |
|
|
|
/** |
|
* Composes request signature key. |
|
* @return string signature key. |
|
*/ |
|
protected function composeSignatureKey() |
|
{ |
|
$signatureKeyParts = [ |
|
$this->consumerSecret |
|
]; |
|
$accessToken = $this->getAccessToken(); |
|
if (is_object($accessToken)) { |
|
$signatureKeyParts[] = $accessToken->getTokenSecret(); |
|
} else { |
|
$signatureKeyParts[] = ''; |
|
} |
|
$signatureKeyParts = array_map('rawurlencode', $signatureKeyParts); |
|
return implode('&', $signatureKeyParts); |
|
} |
|
|
|
/** |
|
* Composes authorization header content. |
|
* @param array $params request params. |
|
* @param string $realm authorization realm. |
|
* @return string authorization header content. |
|
*/ |
|
protected function composeAuthorizationHeader(array $params, $realm = '') |
|
{ |
|
$header = 'Authorization: OAuth'; |
|
$headerParams = []; |
|
if (!empty($realm)) { |
|
$headerParams[] = 'realm="' . rawurlencode($realm) . '"'; |
|
} |
|
foreach ($params as $key => $value) { |
|
if (substr($key, 0, 5) != 'oauth') { |
|
continue; |
|
} |
|
$headerParams[] = rawurlencode($key) . '="' . rawurlencode($value) . '"'; |
|
} |
|
if (!empty($headerParams)) { |
|
$header .= ' ' . implode(', ', $headerParams); |
|
} |
|
return $header; |
|
} |
|
} |