Paul Klimov
11 years ago
21 changed files with 2398 additions and 0 deletions
@ -0,0 +1,32 @@
|
||||
The Yii framework is free software. It is released under the terms of |
||||
the following BSD License. |
||||
|
||||
Copyright © 2008-2013 by Yii Software LLC (http://www.yiisoft.com) |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions |
||||
are met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above copyright |
||||
notice, this list of conditions and the following disclaimer in |
||||
the documentation and/or other materials provided with the |
||||
distribution. |
||||
* Neither the name of Yii Software LLC nor the names of its |
||||
contributors may be used to endorse or promote products derived |
||||
from this software without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,30 @@
|
||||
AuthClient Extension for Yii 2 |
||||
============================== |
||||
|
||||
This extension adds [OpenID](http://openid.net/), [OAuth](http://oauth.net/) and [OAuth2](http://oauth.net/2/) consumers for the Yii 2 framework. |
||||
|
||||
|
||||
Installation |
||||
------------ |
||||
|
||||
The preferred way to install this extension is through [composer](http://getcomposer.org/download/). |
||||
|
||||
Either run |
||||
|
||||
``` |
||||
php composer.phar require yiisoft/yii2-authclient "*" |
||||
``` |
||||
|
||||
or add |
||||
|
||||
```json |
||||
"yiisoft/yii2-authclient": "*" |
||||
``` |
||||
|
||||
to the require section of your composer.json. |
||||
|
||||
|
||||
Usage & Documentation |
||||
--------------------- |
||||
|
||||
This extension... |
@ -0,0 +1,28 @@
|
||||
{ |
||||
"name": "yiisoft/yii2-authclient", |
||||
"description": "External authentication via OAuth and OpenID for the Yii framework", |
||||
"keywords": ["yii", "OAuth", "OpenID", "auth"], |
||||
"type": "yii2-extension", |
||||
"license": "BSD-3-Clause", |
||||
"support": { |
||||
"issues": "https://github.com/yiisoft/yii2/issues?state=open", |
||||
"forum": "http://www.yiiframework.com/forum/", |
||||
"wiki": "http://www.yiiframework.com/wiki/", |
||||
"irc": "irc://irc.freenode.net/yii", |
||||
"source": "https://github.com/yiisoft/yii2" |
||||
}, |
||||
"authors": [ |
||||
{ |
||||
"name": "Paul Klimov", |
||||
"email": "klimov.paul@gmail.com" |
||||
} |
||||
], |
||||
"require": { |
||||
"yiisoft/yii2": "*", |
||||
"ext-curl": "*" |
||||
}, |
||||
"autoload": { |
||||
"psr-0": { "yii\\authclient\\": "" } |
||||
}, |
||||
"target-dir": "yii/authclient" |
||||
} |
@ -0,0 +1,504 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\oauth; |
||||
|
||||
use yii\base\Component; |
||||
use yii\base\Exception; |
||||
use yii\base\InvalidParamException; |
||||
use Yii; |
||||
use yii\helpers\Json; |
||||
|
||||
/** |
||||
* BaseClient is a base class for the OAuth clients. |
||||
* |
||||
* @see http://oauth.net/ |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
abstract class BaseClient extends Component |
||||
{ |
||||
const CONTENT_TYPE_JSON = 'json'; // JSON format |
||||
const CONTENT_TYPE_URLENCODED = 'urlencoded'; // urlencoded query string, like name1=value1&name2=value2 |
||||
const CONTENT_TYPE_XML = 'xml'; // XML format |
||||
const CONTENT_TYPE_AUTO = 'auto'; // attempts to determine format automatically |
||||
|
||||
/** |
||||
* @var string protocol version. |
||||
*/ |
||||
public $version = '1.0'; |
||||
/** |
||||
* @var string URL, which user will be redirected after authentication at the OAuth provider web site. |
||||
* Note: this should be absolute URL (with http:// or https:// leading). |
||||
* By default current URL will be used. |
||||
*/ |
||||
private $_returnUrl = ''; |
||||
/** |
||||
* @var string API base URL. |
||||
*/ |
||||
public $apiBaseUrl = ''; |
||||
/** |
||||
* @var string authorize URL. |
||||
*/ |
||||
public $authUrl = ''; |
||||
/** |
||||
* @var string auth request scope. |
||||
*/ |
||||
public $scope = ''; |
||||
/** |
||||
* @var array cURL request options. Option values from this field will overwrite corresponding |
||||
* values from {@link defaultCurlOptions()}. |
||||
*/ |
||||
private $_curlOptions = []; |
||||
/** |
||||
* @var Token|array access token instance or its array configuration. |
||||
*/ |
||||
private $_accessToken = null; |
||||
/** |
||||
* @var signature\BaseMethod|array signature method instance or its array configuration. |
||||
*/ |
||||
private $_signatureMethod = []; |
||||
|
||||
/** |
||||
* @param string $returnUrl return URL |
||||
*/ |
||||
public function setReturnUrl($returnUrl) |
||||
{ |
||||
$this->_returnUrl = $returnUrl; |
||||
} |
||||
|
||||
/** |
||||
* @return string return URL. |
||||
*/ |
||||
public function getReturnUrl() |
||||
{ |
||||
if (empty($this->_returnUrl)) { |
||||
$this->_returnUrl = $this->defaultReturnUrl(); |
||||
} |
||||
return $this->_returnUrl; |
||||
} |
||||
|
||||
/** |
||||
* @param array $curlOptions cURL options. |
||||
*/ |
||||
public function setCurlOptions(array $curlOptions) |
||||
{ |
||||
$this->_curlOptions = $curlOptions; |
||||
} |
||||
|
||||
/** |
||||
* @return array cURL options. |
||||
*/ |
||||
public function getCurlOptions() |
||||
{ |
||||
return $this->_curlOptions; |
||||
} |
||||
|
||||
/** |
||||
* @param array|Token $token |
||||
*/ |
||||
public function setAccessToken($token) |
||||
{ |
||||
if (!is_object($token)) { |
||||
$token = $this->createToken($token); |
||||
} |
||||
$this->_accessToken = $token; |
||||
$this->saveAccessToken($token); |
||||
} |
||||
|
||||
/** |
||||
* @return Token auth token instance. |
||||
*/ |
||||
public function getAccessToken() |
||||
{ |
||||
if (!is_object($this->_accessToken)) { |
||||
$this->_accessToken = $this->restoreAccessToken(); |
||||
} |
||||
return $this->_accessToken; |
||||
} |
||||
|
||||
/** |
||||
* @param array|signature\BaseMethod $signatureMethod signature method instance or its array configuration. |
||||
* @throws InvalidParamException on wrong argument. |
||||
*/ |
||||
public function setSignatureMethod($signatureMethod) |
||||
{ |
||||
if (!is_object($signatureMethod) && !is_array($signatureMethod)) { |
||||
throw new InvalidParamException('"'.get_class($this).'::signatureMethod" should be instance of "\yii\autclient\oauth\signature\BaseMethod" or its array configuration. "' . gettype($signatureMethod) . '" has been given.'); |
||||
} |
||||
$this->_signatureMethod = $signatureMethod; |
||||
} |
||||
|
||||
/** |
||||
* @return signature\BaseMethod signature method instance. |
||||
*/ |
||||
public function getSignatureMethod() |
||||
{ |
||||
if (!is_object($this->_signatureMethod)) { |
||||
$this->_signatureMethod = $this->createSignatureMethod($this->_signatureMethod); |
||||
} |
||||
return $this->_signatureMethod; |
||||
} |
||||
|
||||
/** |
||||
* Composes default {@link returnUrl} value. |
||||
* @return string return URL. |
||||
*/ |
||||
protected function defaultReturnUrl() |
||||
{ |
||||
return Yii::$app->getRequest()->getAbsoluteUrl(); |
||||
} |
||||
|
||||
/** |
||||
* Sends HTTP request. |
||||
* @param string $method request type. |
||||
* @param string $url request URL. |
||||
* @param array $params request params. |
||||
* @return array response. |
||||
* @throws Exception on failure. |
||||
*/ |
||||
protected function sendRequest($method, $url, array $params = []) |
||||
{ |
||||
$curlOptions = $this->mergeCurlOptions( |
||||
$this->defaultCurlOptions(), |
||||
$this->getCurlOptions(), |
||||
array( |
||||
CURLOPT_RETURNTRANSFER => true, |
||||
CURLOPT_URL => $url, |
||||
), |
||||
$this->composeRequestCurlOptions(strtoupper($method), $url, $params) |
||||
); |
||||
$curlResource = curl_init(); |
||||
foreach ($curlOptions as $option => $value) { |
||||
curl_setopt($curlResource, $option, $value); |
||||
} |
||||
$response = curl_exec($curlResource); |
||||
$responseHeaders = curl_getinfo($curlResource); |
||||
|
||||
// check cURL error |
||||
$errorNumber = curl_errno($curlResource); |
||||
$errorMessage = curl_error($curlResource); |
||||
|
||||
curl_close($curlResource); |
||||
|
||||
if ($errorNumber > 0) { |
||||
throw new Exception('Curl error requesting "' . $url . '": #' . $errorNumber . ' - ' . $errorMessage); |
||||
} |
||||
if ($responseHeaders['http_code'] != 200) { |
||||
throw new Exception('Request failed with code: ' . $responseHeaders['http_code'] . ', message: ' . $response); |
||||
} |
||||
return $this->processResponse($response, $this->determineContentTypeByHeaders($responseHeaders)); |
||||
} |
||||
|
||||
/** |
||||
* Merge CUrl options. |
||||
* If each options array has an element with the same key value, the latter |
||||
* will overwrite the former. |
||||
* @param array $options1 options to be merged to. |
||||
* @param array $options2 options to be merged from. You can specify additional |
||||
* arrays via third argument, fourth argument etc. |
||||
* @return array merged options (the original options are not changed.) |
||||
*/ |
||||
protected function mergeCurlOptions($options1, $options2) |
||||
{ |
||||
$args = func_get_args(); |
||||
$res = array_shift($args); |
||||
while (!empty($args)) { |
||||
$next = array_shift($args); |
||||
foreach ($next as $k => $v) { |
||||
$res[$k]=$v; |
||||
} |
||||
} |
||||
return $res; |
||||
} |
||||
|
||||
/** |
||||
* Returns default cURL options. |
||||
* @return array cURL options. |
||||
*/ |
||||
protected function defaultCurlOptions() |
||||
{ |
||||
return [ |
||||
CURLOPT_USERAGENT => Yii::$app->name . ' OAuth Client', |
||||
CURLOPT_CONNECTTIMEOUT => 30, |
||||
CURLOPT_TIMEOUT => 30, |
||||
CURLOPT_SSL_VERIFYPEER => false, |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* Processes raw response converting it to actual data. |
||||
* @param string $rawResponse raw response. |
||||
* @param string $contentType response content type. |
||||
* @throws Exception on failure. |
||||
* @return array actual response. |
||||
*/ |
||||
protected function processResponse($rawResponse, $contentType = self::CONTENT_TYPE_AUTO) |
||||
{ |
||||
if (empty($rawResponse)) { |
||||
return []; |
||||
} |
||||
switch ($contentType) { |
||||
case self::CONTENT_TYPE_AUTO: { |
||||
$contentType = $this->determineContentTypeByRaw($rawResponse); |
||||
if ($contentType == self::CONTENT_TYPE_AUTO) { |
||||
throw new Exception('Unable to determine response content type automatically.'); |
||||
} |
||||
$response = $this->processResponse($rawResponse, $contentType); |
||||
break; |
||||
} |
||||
case self::CONTENT_TYPE_JSON: { |
||||
$response = Json::decode($rawResponse, true); |
||||
if (isset($response['error'])) { |
||||
throw new Exception('Response error: ' . $response['error']); |
||||
} |
||||
break; |
||||
} |
||||
case self::CONTENT_TYPE_URLENCODED: { |
||||
$response = []; |
||||
parse_url($rawResponse, $response); |
||||
break; |
||||
} |
||||
case self::CONTENT_TYPE_XML: { |
||||
$response = $this->convertXmlToArray($rawResponse); |
||||
break; |
||||
} |
||||
default: { |
||||
throw new Exception('Unknown response type "' . $contentType . '".'); |
||||
} |
||||
} |
||||
return $response; |
||||
} |
||||
|
||||
/** |
||||
* Converts XML document to array. |
||||
* @param string|\SimpleXMLElement $xml xml to process. |
||||
* @return array XML array representation. |
||||
*/ |
||||
protected function convertXmlToArray($xml) |
||||
{ |
||||
if (!is_object($xml)) { |
||||
$xml = simplexml_load_string($xml); |
||||
} |
||||
$result = (array)$xml; |
||||
foreach ($result as $key => $value) { |
||||
if (is_object($value)) { |
||||
$result[$key] = $this->convertXmlToArray($value); |
||||
} |
||||
} |
||||
return $result; |
||||
} |
||||
|
||||
/** |
||||
* Attempts to determine HTTP request content type by headers. |
||||
* @param array $headers request headers. |
||||
* @return string content type. |
||||
*/ |
||||
protected function determineContentTypeByHeaders(array $headers) |
||||
{ |
||||
if (isset($headers['content_type'])) { |
||||
if (stripos($headers['content_type'], 'json') !== false) { |
||||
return self::CONTENT_TYPE_JSON; |
||||
} |
||||
if (stripos($headers['content_type'], 'urlencoded') !== false) { |
||||
return self::CONTENT_TYPE_URLENCODED; |
||||
} |
||||
if (stripos($headers['content_type'], 'xml') !== false) { |
||||
return self::CONTENT_TYPE_XML; |
||||
} |
||||
} |
||||
return self::CONTENT_TYPE_AUTO; |
||||
} |
||||
|
||||
/** |
||||
* Attempts to determine the content type from raw content. |
||||
* @param string $rawContent raw response content. |
||||
* @return string response type. |
||||
*/ |
||||
protected function determineContentTypeByRaw($rawContent) |
||||
{ |
||||
if (preg_match('/^\\{.*\\}$/is', $rawContent)) { |
||||
return self::CONTENT_TYPE_JSON; |
||||
} |
||||
if (preg_match('/^[^=|^&]+=[^=|^&]+(&[^=|^&]+=[^=|^&]+)*$/is', $rawContent)) { |
||||
return self::CONTENT_TYPE_URLENCODED; |
||||
} |
||||
if (preg_match('/^<.*>$/is', $rawContent)) { |
||||
return self::CONTENT_TYPE_XML; |
||||
} |
||||
return self::CONTENT_TYPE_AUTO; |
||||
} |
||||
|
||||
/** |
||||
* Creates signature method instance from its configuration. |
||||
* @param array $signatureMethodConfig signature method configuration. |
||||
* @return signature\BaseMethod signature method instance. |
||||
*/ |
||||
protected function createSignatureMethod(array $signatureMethodConfig) |
||||
{ |
||||
if (!array_key_exists('class', $signatureMethodConfig)) { |
||||
$signatureMethodConfig['class'] = signature\HmacSha1::className(); |
||||
} |
||||
return Yii::createObject($signatureMethodConfig); |
||||
} |
||||
|
||||
/** |
||||
* Creates token from its configuration. |
||||
* @param array $tokenConfig token configuration. |
||||
* @return Token token instance. |
||||
*/ |
||||
protected function createToken(array $tokenConfig = []) |
||||
{ |
||||
if (!array_key_exists('class', $tokenConfig)) { |
||||
$tokenConfig['class'] = Token::className(); |
||||
} |
||||
return Yii::createObject($tokenConfig); |
||||
} |
||||
|
||||
/** |
||||
* Composes URL from base URL and GET params. |
||||
* @param string $url base URL. |
||||
* @param array $params GET params. |
||||
* @return string composed URL. |
||||
*/ |
||||
protected function composeUrl($url, array $params = []) |
||||
{ |
||||
if (strpos($url, '?') === false) { |
||||
$url .= '?'; |
||||
} else { |
||||
$url .= '&'; |
||||
} |
||||
$url .= http_build_query($params, '', '&', PHP_QUERY_RFC3986); |
||||
return $url; |
||||
} |
||||
|
||||
/** |
||||
* Saves token as persistent state. |
||||
* @param Token $token auth token |
||||
* @return static self reference. |
||||
*/ |
||||
protected function saveAccessToken(Token $token) |
||||
{ |
||||
return $this->setState('token', $token); |
||||
} |
||||
|
||||
/** |
||||
* Restores access token. |
||||
* @return Token auth token. |
||||
*/ |
||||
protected function restoreAccessToken() |
||||
{ |
||||
$token = $this->getState('token'); |
||||
if (is_object($token)) { |
||||
/* @var $token Token */ |
||||
if ($token->getIsExpired()) { |
||||
$token = $this->refreshAccessToken($token); |
||||
} |
||||
} |
||||
return $token; |
||||
} |
||||
|
||||
/** |
||||
* Sets persistent state. |
||||
* @param string $key state key. |
||||
* @param mixed $value state value |
||||
* @return static self reference. |
||||
*/ |
||||
protected function setState($key, $value) |
||||
{ |
||||
$session = Yii::$app->getSession(); |
||||
$key = $this->getStateKeyPrefix() . $key; |
||||
$session->set($key, $value); |
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Returns persistent state value. |
||||
* @param string $key state key. |
||||
* @return mixed state value. |
||||
*/ |
||||
protected function getState($key) |
||||
{ |
||||
$session = Yii::$app->getSession(); |
||||
$key = $this->getStateKeyPrefix() . $key; |
||||
$value = $session->get($key); |
||||
return $value; |
||||
} |
||||
|
||||
/** |
||||
* Removes persistent state value. |
||||
* @param string $key state key. |
||||
* @return boolean success. |
||||
*/ |
||||
protected function removeState($key) |
||||
{ |
||||
$session = Yii::$app->getSession(); |
||||
$key = $this->getStateKeyPrefix() . $key; |
||||
$session->remove($key); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Returns session key prefix, which is used to store internal states. |
||||
* @return string session key prefix. |
||||
*/ |
||||
protected function getStateKeyPrefix() |
||||
{ |
||||
return get_class($this) . '_' . sha1($this->authUrl) . '_'; |
||||
} |
||||
|
||||
/** |
||||
* Performs request to the OAuth API. |
||||
* @param string $apiSubUrl API sub URL, which will be append to [[apiBaseUrl]], or absolute API URL. |
||||
* @param string $method request method. |
||||
* @param array $params request parameters. |
||||
* @return array API response |
||||
* @throws Exception on failure. |
||||
*/ |
||||
public function api($apiSubUrl, $method = 'GET', array $params = []) |
||||
{ |
||||
if (preg_match('/^https?:\\/\\//is', $apiSubUrl)) { |
||||
$url = $apiSubUrl; |
||||
} else { |
||||
$url = $this->apiBaseUrl . '/' . $apiSubUrl; |
||||
} |
||||
$accessToken = $this->getAccessToken(); |
||||
if (!is_object($accessToken) || !$accessToken->getIsValid()) { |
||||
throw new Exception('Invalid access token.'); |
||||
} |
||||
return $this->apiInternal($accessToken, $url, $method, $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. |
||||
*/ |
||||
abstract protected function composeRequestCurlOptions($method, $url, array $params); |
||||
|
||||
/** |
||||
* Gets new auth token to replace expired one. |
||||
* @param Token $token expired auth token. |
||||
* @return Token new auth token. |
||||
*/ |
||||
abstract public function refreshAccessToken(Token $token); |
||||
|
||||
/** |
||||
* Performs request to the OAuth API. |
||||
* @param Token $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. |
||||
*/ |
||||
abstract protected function apiInternal($accessToken, $url, $method, array $params); |
||||
} |
@ -0,0 +1,353 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\oauth; |
||||
|
||||
use yii\base\Exception; |
||||
use Yii; |
||||
|
||||
/** |
||||
* Client1 serves as a client for the OAuth 1/1.0a flow. |
||||
* |
||||
* In oder to acquire access token perform following sequence: |
||||
* |
||||
* ~~~ |
||||
* use yii\authclient\oauth\Client1; |
||||
* |
||||
* $oauthClient = new Client1(); |
||||
* $requestToken = $oauthClient->fetchRequestToken(); // Get request token |
||||
* $url = $oauthClient->buildAuthUrl($requestToken); // Get authorization URL |
||||
* 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 Client1 extends BaseClient |
||||
{ |
||||
/** |
||||
* @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 Token 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 Token $requestToken OAuth request token. |
||||
* @param array $params additional request params. |
||||
* @return string authorize URL |
||||
* @throws Exception on failure. |
||||
*/ |
||||
public function buildAuthUrl(Token $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 Token $requestToken OAuth request token. |
||||
* @param string $oauthVerifier OAuth verifier. |
||||
* @param array $params additional request params. |
||||
* @return Token OAuth access token. |
||||
* @throws Exception on failure. |
||||
*/ |
||||
public function fetchAccessToken(Token $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)/* && $this->curlAuthHeader*/) { |
||||
$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 Token $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 Token $token expired auth token. |
||||
* @return Token new auth token. |
||||
*/ |
||||
public function refreshAccessToken(Token $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']); |
||||
$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; |
||||
} |
||||
} |
@ -0,0 +1,184 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\oauth; |
||||
|
||||
use Yii; |
||||
use yii\base\Exception; |
||||
|
||||
/** |
||||
* Client2 serves as a client for the OAuth 2 flow. |
||||
* |
||||
* In oder to acquire access token perform following sequence: |
||||
* |
||||
* ~~~ |
||||
* use yii\authclient\oauth\Client2; |
||||
* |
||||
* $oauthClient = new Client2(); |
||||
* $url = $oauthClient->buildAuthUrl(); // Build authorization URL |
||||
* Yii::$app->getResponse()->redirect($url); // Redirect to authorization URL. |
||||
* // After user returns at our site: |
||||
* $code = $_GET['code']; |
||||
* $accessToken = $oauthClient->fetchAccessToken($code); // Get access token |
||||
* ~~~ |
||||
* |
||||
* @see http://oauth.net/2/ |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Client2 extends BaseClient |
||||
{ |
||||
/** |
||||
* @var string protocol version. |
||||
*/ |
||||
public $version = '2.0'; |
||||
/** |
||||
* @var string OAuth client ID. |
||||
*/ |
||||
public $clientId = ''; |
||||
/** |
||||
* @var string OAuth client secret. |
||||
*/ |
||||
public $clientSecret = ''; |
||||
/** |
||||
* @var string token request URL endpoint. |
||||
*/ |
||||
public $tokenUrl = ''; |
||||
|
||||
/** |
||||
* Composes user authorization URL. |
||||
* @param array $params additional auth GET params. |
||||
* @return string authorization URL. |
||||
*/ |
||||
public function buildAuthUrl(array $params = []) |
||||
{ |
||||
$defaultParams = [ |
||||
'client_id' => $this->clientId, |
||||
'response_type' => 'code', |
||||
'redirect_uri' => $this->getReturnUrl(), |
||||
'xoauth_displayname' => Yii::$app->name, |
||||
]; |
||||
if (!empty($this->scope)) { |
||||
$defaultParams['scope'] = $this->scope; |
||||
} |
||||
return $this->composeUrl($this->authUrl, array_merge($defaultParams, $params)); |
||||
} |
||||
|
||||
/** |
||||
* Fetches access token from authorization code. |
||||
* @param string $authCode authorization code, usually comes at $_GET['code']. |
||||
* @param array $params additional request params. |
||||
* @return Token access token. |
||||
*/ |
||||
public function fetchAccessToken($authCode, array $params = []) |
||||
{ |
||||
$defaultParams = [ |
||||
'client_id' => $this->clientId, |
||||
'client_secret' => $this->clientSecret, |
||||
'code' => $authCode, |
||||
'grant_type' => 'authorization_code', |
||||
'redirect_uri' => $this->getReturnUrl(), |
||||
]; |
||||
$response = $this->sendRequest('POST', $this->tokenUrl, array_merge($defaultParams, $params)); |
||||
$token = $this->createToken(['params' => $response]); |
||||
$this->setAccessToken($token); |
||||
return $token; |
||||
} |
||||
|
||||
/** |
||||
* 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; |
||||
$curlOptions[CURLOPT_HTTPHEADER] = ['Content-type: application/x-www-form-urlencoded']; |
||||
$curlOptions[CURLOPT_POSTFIELDS] = http_build_query($params, '', '&', PHP_QUERY_RFC3986); |
||||
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 Token $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['access_token'] = $accessToken->getToken(); |
||||
return $this->sendRequest($method, $url, $params); |
||||
} |
||||
|
||||
/** |
||||
* Gets new auth token to replace expired one. |
||||
* @param Token $token expired auth token. |
||||
* @return Token new auth token. |
||||
*/ |
||||
public function refreshAccessToken(Token $token) |
||||
{ |
||||
$params = [ |
||||
'client_id' => $this->clientId, |
||||
'client_secret' => $this->clientSecret, |
||||
'grant_type' => 'refresh_token' |
||||
]; |
||||
$params = array_merge($token->getParams(), $params); |
||||
$response = $this->sendRequest('POST', $this->tokenUrl, $params); |
||||
return $response; |
||||
} |
||||
|
||||
/** |
||||
* Composes default {@link returnUrl} value. |
||||
* @return string return URL. |
||||
*/ |
||||
protected function defaultReturnUrl() |
||||
{ |
||||
$params = $_GET; |
||||
unset($params['code']); |
||||
return Yii::$app->getUrlManager()->createAbsoluteUrl(Yii::$app->controller->getRoute(), $params); |
||||
} |
||||
|
||||
/** |
||||
* Creates token from its configuration. |
||||
* @param array $tokenConfig token configuration. |
||||
* @return Token token instance. |
||||
*/ |
||||
protected function createToken(array $tokenConfig = []) |
||||
{ |
||||
$tokenConfig['tokenParamKey'] = 'access_token'; |
||||
return parent::createToken($tokenConfig); |
||||
} |
||||
} |
@ -0,0 +1,186 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\oauth; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
/** |
||||
* Token represents OAuth token. |
||||
* |
||||
* @property array $params token parameters. |
||||
* @property string $token token value. |
||||
* @property string $tokenSecret token secret value. |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Token extends Object |
||||
{ |
||||
/** |
||||
* @var string key in {@link _params} array, which stores token key. |
||||
*/ |
||||
public $tokenParamKey = 'oauth_token'; |
||||
/** |
||||
* @var string key in {@link _params} array, which stores token secret key. |
||||
*/ |
||||
public $tokenSecretParamKey = 'oauth_token_secret'; |
||||
/** |
||||
* @var string key in {@link _params} array, which stores token expiration duration. |
||||
* If not set will attempt to fetch its value automatically. |
||||
*/ |
||||
private $_expireDurationParamKey; |
||||
/** |
||||
* @var array token parameters. |
||||
*/ |
||||
private $_params = []; |
||||
/** |
||||
* @var integer object creation timestamp. |
||||
*/ |
||||
public $createTimestamp; |
||||
|
||||
public function init() |
||||
{ |
||||
if ($this->createTimestamp === null) { |
||||
$this->createTimestamp = time(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param string $expireDurationParamKey expire duration param key. |
||||
*/ |
||||
public function setExpireDurationParamKey($expireDurationParamKey) { |
||||
$this->_expireDurationParamKey = $expireDurationParamKey; |
||||
} |
||||
|
||||
/** |
||||
* @return string expire duration param key. |
||||
*/ |
||||
public function getExpireDurationParamKey() { |
||||
if ($this->_expireDurationParamKey === null) { |
||||
$this->_expireDurationParamKey = $this->defaultExpireDurationParamKey(); |
||||
} |
||||
return $this->_expireDurationParamKey; |
||||
} |
||||
|
||||
/** |
||||
* @return array |
||||
*/ |
||||
public function getParams() { |
||||
return $this->_params; |
||||
} |
||||
|
||||
/** |
||||
* @param array $params |
||||
*/ |
||||
public function setParams(array $params) { |
||||
$this->_params = $params; |
||||
} |
||||
|
||||
/** |
||||
* Sets param by name. |
||||
* @param string $name param name. |
||||
* @param mixed $value param value, |
||||
*/ |
||||
public function setParam($name, $value) { |
||||
$this->_params[$name] = $value; |
||||
} |
||||
|
||||
/** |
||||
* Returns param by name. |
||||
* @param string $name param name. |
||||
* @return mixed param value. |
||||
*/ |
||||
public function getParam($name) { |
||||
return isset($this->_params[$name]) ? $this->_params[$name] : null; |
||||
} |
||||
|
||||
/** |
||||
* Sets token value. |
||||
* @param string $token token value. |
||||
* @return static self reference. |
||||
*/ |
||||
public function setToken($token) { |
||||
$this->setParam($this->tokenParamKey, $token); |
||||
} |
||||
|
||||
/** |
||||
* Returns token value. |
||||
* @return string token value. |
||||
*/ |
||||
public function getToken() { |
||||
return $this->getParam($this->tokenParamKey); |
||||
} |
||||
|
||||
/** |
||||
* Sets the token secret value. |
||||
* @param string $tokenSecret token secret. |
||||
*/ |
||||
public function setTokenSecret($tokenSecret) { |
||||
$this->setParam($this->tokenSecretParamKey, $tokenSecret); |
||||
} |
||||
|
||||
/** |
||||
* Returns the token secret value. |
||||
* @return string token secret value. |
||||
*/ |
||||
public function getTokenSecret() { |
||||
return $this->getParam($this->tokenSecretParamKey); |
||||
} |
||||
|
||||
/** |
||||
* Sets token expire duration. |
||||
* @param string $expireDuration token expiration duration. |
||||
*/ |
||||
public function setExpireDuration($expireDuration) { |
||||
$this->setParam($this->getExpireDurationParamKey(), $expireDuration); |
||||
} |
||||
|
||||
/** |
||||
* Returns the token expiration duration. |
||||
* @return integer token expiration duration. |
||||
*/ |
||||
public function getExpireDuration() { |
||||
return $this->getParam($this->getExpireDurationParamKey()); |
||||
} |
||||
|
||||
/** |
||||
* Fetches default expire duration param key. |
||||
* @return string expire duration param key. |
||||
*/ |
||||
protected function defaultExpireDurationParamKey() { |
||||
$expireDurationParamKey = 'expires_in'; |
||||
foreach ($this->getParams() as $name => $value) { |
||||
if (strpos($name, 'expir') !== false) { |
||||
$expireDurationParamKey = $name; |
||||
break; |
||||
} |
||||
} |
||||
return $expireDurationParamKey; |
||||
} |
||||
|
||||
/** |
||||
* Checks if token has expired. |
||||
* @return boolean is token expired. |
||||
*/ |
||||
public function getIsExpired() { |
||||
$expirationDuration = $this->getExpireDuration(); |
||||
if (empty($expirationDuration)) { |
||||
return false; |
||||
} |
||||
return (time() >= ($this->createTimestamp + $expirationDuration)); |
||||
} |
||||
|
||||
/** |
||||
* Checks if token is valid. |
||||
* @return boolean is token valid. |
||||
*/ |
||||
public function getIsValid() { |
||||
$token = $this->getToken(); |
||||
return (!empty($token) && !$this->getIsExpired()); |
||||
} |
||||
} |
@ -0,0 +1,51 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\oauth\signature; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
/** |
||||
* BaseMethod is a base class for the OAuth signature methods. |
||||
* |
||||
* @property string $name method canonical name. This property is read-only. |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
abstract class BaseMethod extends Object |
||||
{ |
||||
/** |
||||
* Return the canonical name of the Signature Method. |
||||
* @return string method name. |
||||
*/ |
||||
abstract public function getName(); |
||||
|
||||
/** |
||||
* Generates OAuth request signature. |
||||
* @param string $baseString signature base string. |
||||
* @param string $key signature key. |
||||
* @return string signature string. |
||||
*/ |
||||
abstract public function generateSignature($baseString, $key); |
||||
|
||||
/** |
||||
* Verifies given OAuth request. |
||||
* @param string $signature signature to be verified. |
||||
* @param string $baseString signature base string. |
||||
* @param string $key signature key. |
||||
* @return boolean success. |
||||
*/ |
||||
public function verify($signature, $baseString, $key) |
||||
{ |
||||
$expectedSignature = $this->generateSignature($baseString, $key); |
||||
if (empty($signature) || empty($expectedSignature)) { |
||||
return false; |
||||
} |
||||
return (strcmp($expectedSignature, $signature) === 0); |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\oauth\signature; |
||||
|
||||
use yii\base\NotSupportedException; |
||||
|
||||
/** |
||||
* HmacSha1 represents 'HMAC-SHA1' signature method. |
||||
* |
||||
* Note: This class require PHP "Hash" extension({@link http://php.net/manual/en/book.hash.php}). |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class HmacSha1 extends BaseMethod |
||||
{ |
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function init() |
||||
{ |
||||
if (!function_exists('hash_hmac')) { |
||||
throw new NotSupportedException('PHP "Hash" extension is required.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return 'HMAC-SHA1'; |
||||
} |
||||
|
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function generateSignature($baseString, $key) |
||||
{ |
||||
return base64_encode(hash_hmac('sha1', $baseString, $key, true)); |
||||
} |
||||
} |
@ -0,0 +1,33 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\oauth\signature; |
||||
|
||||
/** |
||||
* PlainText represents 'PLAINTEXT' signature method. |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class PlainText extends BaseMethod |
||||
{ |
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return 'PLAINTEXT'; |
||||
} |
||||
|
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function generateSignature($baseString, $key) |
||||
{ |
||||
return $key; |
||||
} |
||||
} |
@ -0,0 +1,168 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\oauth\signature; |
||||
|
||||
use yii\base\InvalidConfigException; |
||||
use yii\base\NotSupportedException; |
||||
|
||||
/** |
||||
* RsaSha1 represents 'RSA-SHA1' signature method. |
||||
* |
||||
* Note: This class require PHP "OpenSSL" extension({@link http://php.net/manual/en/book.openssl.php}). |
||||
* |
||||
* @property string $privateCertificate OpenSSL private key certificate content. |
||||
* @property string $publicCertificate OpenSSL public key certificate content. |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class RsaSha1 extends BaseMethod |
||||
{ |
||||
/** |
||||
* @var string OpenSSL private key certificate content. |
||||
* This value can be fetched from file specified by {@link privateCertificateFile}. |
||||
*/ |
||||
protected $_privateCertificate; |
||||
/** |
||||
* @var string OpenSSL public key certificate content. |
||||
* This value can be fetched from file specified by {@link publicCertificateFile}. |
||||
*/ |
||||
protected $_publicCertificate; |
||||
/** |
||||
* @var string path to the file, which holds private key certificate. |
||||
*/ |
||||
public $privateCertificateFile = ''; |
||||
/** |
||||
* @var string path to the file, which holds public key certificate. |
||||
*/ |
||||
public $publicCertificateFile = ''; |
||||
|
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function init() |
||||
{ |
||||
if (!function_exists('openssl_sign')) { |
||||
throw new NotSupportedException('PHP "OpenSSL" extension is required.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param string $publicCertificate public key certificate content. |
||||
*/ |
||||
public function setPublicCertificate($publicCertificate) |
||||
{ |
||||
$this->_publicCertificate = $publicCertificate; |
||||
} |
||||
|
||||
/** |
||||
* @return string public key certificate content. |
||||
*/ |
||||
public function getPublicCertificate() |
||||
{ |
||||
if ($this->_publicCertificate === null) { |
||||
$this->_publicCertificate = $this->initPublicCertificate(); |
||||
} |
||||
return $this->_publicCertificate; |
||||
} |
||||
|
||||
/** |
||||
* @param string $privateCertificate private key certificate content. |
||||
*/ |
||||
public function setPrivateCertificate($privateCertificate) |
||||
{ |
||||
$this->_privateCertificate = $privateCertificate; |
||||
} |
||||
|
||||
/** |
||||
* @return string private key certificate content. |
||||
*/ |
||||
public function getPrivateCertificate() |
||||
{ |
||||
if ($this->_privateCertificate === null) { |
||||
$this->_privateCertificate = $this->initPrivateCertificate(); |
||||
} |
||||
return $this->_privateCertificate; |
||||
} |
||||
|
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return 'RSA-SHA1'; |
||||
} |
||||
|
||||
/** |
||||
* Creates initial value for {@link publicCertificate}. |
||||
* This method will attempt to fetch the certificate value from {@link publicCertificateFile} file. |
||||
* @throws InvalidConfigException on failure. |
||||
* @return string public certificate content. |
||||
*/ |
||||
protected function initPublicCertificate() |
||||
{ |
||||
if (!empty($this->publicCertificateFile)) { |
||||
if (!file_exists($this->publicCertificateFile)) { |
||||
throw new InvalidConfigException("Public certificate file '{$this->publicCertificateFile}' does not exist!"); |
||||
} |
||||
return file_get_contents($this->publicCertificateFile); |
||||
} else { |
||||
return ''; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates initial value for {@link privateCertificate}. |
||||
* This method will attempt to fetch the certificate value from {@link privateCertificateFile} file. |
||||
* @throws InvalidConfigException on failure. |
||||
* @return string private certificate content. |
||||
*/ |
||||
protected function initPrivateCertificate() |
||||
{ |
||||
if (!empty($this->privateCertificateFile)) { |
||||
if (!file_exists($this->privateCertificateFile)) { |
||||
throw new InvalidConfigException("Private certificate file '{$this->privateCertificateFile}' does not exist!"); |
||||
} |
||||
return file_get_contents($this->privateCertificateFile); |
||||
} else { |
||||
return ''; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function generateSignature($baseString, $key) |
||||
{ |
||||
$privateCertificateContent = $this->getPrivateCertificate(); |
||||
// Pull the private key ID from the certificate |
||||
$privateKeyId = openssl_pkey_get_private($privateCertificateContent); |
||||
// Sign using the key |
||||
openssl_sign($baseString, $signature, $privateKeyId); |
||||
// Release the key resource |
||||
openssl_free_key($privateKeyId); |
||||
return base64_encode($signature); |
||||
} |
||||
|
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function verify($signature, $baseString, $key) |
||||
{ |
||||
$decodedSignature = base64_decode($signature); |
||||
// Fetch the public key cert based on the request |
||||
$publicCertificate = $this->getPublicCertificate(); |
||||
// Pull the public key ID from the certificate |
||||
$publicKeyId = openssl_pkey_get_public($publicCertificate); |
||||
// Check the computed signature against the one passed in the query |
||||
$verificationResult = openssl_verify($baseString, $decodedSignature, $publicKeyId); |
||||
// Release the key resource |
||||
openssl_free_key($publicKeyId); |
||||
return ($verificationResult == 1); |
||||
} |
||||
} |
@ -0,0 +1,23 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\authclient\openid; |
||||
|
||||
use yii\base\Component; |
||||
|
||||
/** |
||||
* Class Client |
||||
* |
||||
* @see http://openid.net/ |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Client extends Component |
||||
{ |
||||
|
||||
} |
@ -0,0 +1,33 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient; |
||||
|
||||
use yii\helpers\FileHelper; |
||||
use Yii; |
||||
|
||||
/** |
||||
* TestCase for "authclient" extension. |
||||
*/ |
||||
class TestCase extends \yiiunit\TestCase |
||||
{ |
||||
public static function setUpBeforeClass() |
||||
{ |
||||
static::loadClassMap(); |
||||
} |
||||
|
||||
/** |
||||
* Adds sphinx extension files to [[Yii::$classPath]], |
||||
* avoiding the necessity of usage Composer autoloader. |
||||
*/ |
||||
protected static function loadClassMap() |
||||
{ |
||||
$baseNameSpace = 'yii/authclient'; |
||||
$basePath = realpath(__DIR__. '/../../../../extensions/yii/authclient'); |
||||
$files = FileHelper::findFiles($basePath); |
||||
foreach ($files as $file) { |
||||
$classRelativePath = str_replace($basePath, '', $file); |
||||
$classFullName = str_replace(['/', '.php'], ['\\', ''], $baseNameSpace . $classRelativePath); |
||||
Yii::$classMap[$classFullName] = $file; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,251 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient\oauth; |
||||
|
||||
use yii\authclient\oauth\signature\PlainText; |
||||
use yii\authclient\oauth\Token; |
||||
use yiiunit\extensions\authclient\TestCase; |
||||
use yii\authclient\oauth\BaseClient; |
||||
|
||||
class BaseClientTest extends TestCase |
||||
{ |
||||
/** |
||||
* Creates test OAuth client instance. |
||||
* @return BaseClient oauth client. |
||||
*/ |
||||
protected function createOAuthClient() |
||||
{ |
||||
$oauthClient = $this->getMock(BaseClient::className(), ['setState', 'getState', 'composeRequestCurlOptions', 'refreshAccessToken', 'apiInternal']); |
||||
$oauthClient->expects($this->any())->method('setState')->will($this->returnValue($oauthClient)); |
||||
$oauthClient->expects($this->any())->method('getState')->will($this->returnValue(null)); |
||||
return $oauthClient; |
||||
} |
||||
|
||||
/** |
||||
* Invokes the OAuth client method even if it is protected. |
||||
* @param BaseClient $oauthClient OAuth client instance. |
||||
* @param string $methodName name of the method to be invoked. |
||||
* @param array $arguments method arguments. |
||||
* @return mixed method invoke result. |
||||
*/ |
||||
protected function invokeOAuthClientMethod($oauthClient, $methodName, array $arguments = []) |
||||
{ |
||||
$classReflection = new \ReflectionClass(get_class($oauthClient)); |
||||
$methodReflection = $classReflection->getMethod($methodName); |
||||
$methodReflection->setAccessible(true); |
||||
$result = $methodReflection->invokeArgs($oauthClient, $arguments); |
||||
$methodReflection->setAccessible(false); |
||||
return $result; |
||||
} |
||||
|
||||
// Tests : |
||||
|
||||
public function testSetGet() |
||||
{ |
||||
$oauthClient = $this->createOAuthClient(); |
||||
|
||||
$returnUrl = 'http://test.return.url'; |
||||
$oauthClient->setReturnUrl($returnUrl); |
||||
$this->assertEquals($returnUrl, $oauthClient->getReturnUrl(), 'Unable to setup return URL!'); |
||||
|
||||
$curlOptions = [ |
||||
'option1' => 'value1', |
||||
'option2' => 'value2', |
||||
]; |
||||
$oauthClient->setCurlOptions($curlOptions); |
||||
$this->assertEquals($curlOptions, $oauthClient->getCurlOptions(), 'Unable to setup cURL options!'); |
||||
} |
||||
|
||||
public function testSetupComponents() |
||||
{ |
||||
$oauthClient = $this->createOAuthClient(); |
||||
|
||||
$oauthToken = new Token(); |
||||
$oauthClient->setAccessToken($oauthToken); |
||||
$this->assertEquals($oauthToken, $oauthClient->getAccessToken(), 'Unable to setup token!'); |
||||
|
||||
$oauthSignatureMethod = new PlainText(); |
||||
$oauthClient->setSignatureMethod($oauthSignatureMethod); |
||||
$this->assertEquals($oauthSignatureMethod, $oauthClient->getSignatureMethod(), 'Unable to setup signature method!'); |
||||
} |
||||
|
||||
/** |
||||
* @depends testSetupComponents |
||||
*/ |
||||
public function testSetupComponentsByConfig() |
||||
{ |
||||
$oauthClient = $this->createOAuthClient(); |
||||
|
||||
$oauthToken = [ |
||||
'token' => 'test_token', |
||||
'tokenSecret' => 'test_token_secret', |
||||
]; |
||||
$oauthClient->setAccessToken($oauthToken); |
||||
$this->assertEquals($oauthToken['token'], $oauthClient->getAccessToken()->getToken(), 'Unable to setup token as config!'); |
||||
|
||||
$oauthSignatureMethod = [ |
||||
'class' => 'yii\authclient\oauth\signature\PlainText' |
||||
]; |
||||
$oauthClient->setSignatureMethod($oauthSignatureMethod); |
||||
$returnedSignatureMethod = $oauthClient->getSignatureMethod(); |
||||
$this->assertEquals($oauthSignatureMethod['class'], get_class($returnedSignatureMethod), 'Unable to setup signature method as config!'); |
||||
} |
||||
|
||||
/** |
||||
* Data provider for [[testComposeUrl()]]. |
||||
* @return array test data. |
||||
*/ |
||||
public function composeUrlDataProvider() |
||||
{ |
||||
return [ |
||||
[ |
||||
'http://test.url', |
||||
[ |
||||
'param1' => 'value1', |
||||
'param2' => 'value2', |
||||
], |
||||
'http://test.url?param1=value1¶m2=value2', |
||||
], |
||||
[ |
||||
'http://test.url?with=some', |
||||
[ |
||||
'param1' => 'value1', |
||||
'param2' => 'value2', |
||||
], |
||||
'http://test.url?with=some¶m1=value1¶m2=value2', |
||||
], |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider composeUrlDataProvider |
||||
* |
||||
* @param string $url request URL. |
||||
* @param array $params request params |
||||
* @param string $expectedUrl expected composed URL. |
||||
*/ |
||||
public function testComposeUrl($url, array $params, $expectedUrl) |
||||
{ |
||||
$oauthClient = $this->createOAuthClient(); |
||||
$composedUrl = $this->invokeOAuthClientMethod($oauthClient, 'composeUrl', [$url, $params]); |
||||
$this->assertEquals($expectedUrl, $composedUrl); |
||||
} |
||||
|
||||
/** |
||||
* Data provider for {@link testDetermineContentTypeByHeaders}. |
||||
* @return array test data. |
||||
*/ |
||||
public function determineContentTypeByHeadersDataProvider() |
||||
{ |
||||
return [ |
||||
[ |
||||
['content_type' => 'application/json'], |
||||
'json' |
||||
], |
||||
[ |
||||
['content_type' => 'application/x-www-form-urlencoded'], |
||||
'urlencoded' |
||||
], |
||||
[ |
||||
['content_type' => 'application/xml'], |
||||
'xml' |
||||
], |
||||
[ |
||||
['some_header' => 'some_header_value'], |
||||
'auto' |
||||
], |
||||
[ |
||||
['content_type' => 'unknown'], |
||||
'auto' |
||||
], |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider determineContentTypeByHeadersDataProvider |
||||
* |
||||
* @param array $headers request headers. |
||||
* @param string $expectedResponseType expected response type. |
||||
*/ |
||||
public function testDetermineContentTypeByHeaders(array $headers, $expectedResponseType) |
||||
{ |
||||
$oauthClient = $this->createOAuthClient(); |
||||
$responseType = $this->invokeOAuthClientMethod($oauthClient, 'determineContentTypeByHeaders', [$headers]); |
||||
$this->assertEquals($expectedResponseType, $responseType); |
||||
} |
||||
|
||||
/** |
||||
* Data provider for [[testDetermineContentTypeByRaw]]. |
||||
* @return array test data. |
||||
*/ |
||||
public function determineContentTypeByRawDataProvider() |
||||
{ |
||||
return array( |
||||
['{name: value}', 'json'], |
||||
['name=value', 'urlencoded'], |
||||
['name1=value1&name2=value2', 'urlencoded'], |
||||
['<?xml version="1.0" encoding="UTF-8"?><tag>Value</tag>', 'xml'],
|
||||
['<tag>Value</tag>', 'xml'], |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider determineContentTypeByRawDataProvider |
||||
* |
||||
* @param string $rawResponse raw response content. |
||||
* @param string $expectedResponseType expected response type. |
||||
*/ |
||||
public function testDetermineContentTypeByRaw($rawResponse, $expectedResponseType) |
||||
{ |
||||
$oauthClient = $this->createOAuthClient(); |
||||
$responseType = $this->invokeOAuthClientMethod($oauthClient, 'determineContentTypeByRaw', [$rawResponse]); |
||||
$this->assertEquals($expectedResponseType, $responseType); |
||||
} |
||||
|
||||
/** |
||||
* Data provider for [[testApiUrl]]. |
||||
* @return array test data. |
||||
*/ |
||||
public function apiUrlDataProvider() |
||||
{ |
||||
return [ |
||||
[ |
||||
'http://api.base.url', |
||||
'sub/url', |
||||
'http://api.base.url/sub/url', |
||||
], |
||||
[ |
||||
'http://api.base.url', |
||||
'http://api.base.url/sub/url', |
||||
'http://api.base.url/sub/url', |
||||
], |
||||
[ |
||||
'http://api.base.url', |
||||
'https://api.base.url/sub/url', |
||||
'https://api.base.url/sub/url', |
||||
], |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider apiUrlDataProvider |
||||
* |
||||
* @param $apiBaseUrl |
||||
* @param $apiSubUrl |
||||
* @param $expectedApiFullUrl |
||||
*/ |
||||
public function testApiUrl($apiBaseUrl, $apiSubUrl, $expectedApiFullUrl) |
||||
{ |
||||
$oauthClient = $this->createOAuthClient(); |
||||
$oauthClient->expects($this->any())->method('apiInternal')->will($this->returnArgument(1)); |
||||
|
||||
$accessToken = new Token(); |
||||
$accessToken->setToken('test_access_token'); |
||||
$accessToken->setExpireDuration(1000); |
||||
$oauthClient->setAccessToken($accessToken); |
||||
|
||||
$oauthClient->apiBaseUrl = $apiBaseUrl; |
||||
|
||||
$this->assertEquals($expectedApiFullUrl, $oauthClient->api($apiSubUrl)); |
||||
} |
||||
} |
@ -0,0 +1,109 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient\oauth; |
||||
|
||||
use yii\authclient\oauth\Client1; |
||||
use yii\authclient\oauth\signature\PlainText; |
||||
use yii\authclient\oauth\Token; |
||||
use yiiunit\extensions\authclient\TestCase; |
||||
|
||||
class Client1Test extends TestCase |
||||
{ |
||||
protected function setUp() |
||||
{ |
||||
$this->mockApplication([], '\yii\web\Application'); |
||||
} |
||||
|
||||
/** |
||||
* Invokes the OAuth client method even if it is protected. |
||||
* @param Client1 $oauthClient OAuth client instance. |
||||
* @param string $methodName name of the method to be invoked. |
||||
* @param array $arguments method arguments. |
||||
* @return mixed method invoke result. |
||||
*/ |
||||
protected function invokeOAuthClientMethod($oauthClient, $methodName, array $arguments = []) |
||||
{ |
||||
$classReflection = new \ReflectionClass(get_class($oauthClient)); |
||||
$methodReflection = $classReflection->getMethod($methodName); |
||||
$methodReflection->setAccessible(true); |
||||
$result = $methodReflection->invokeArgs($oauthClient, $arguments); |
||||
$methodReflection->setAccessible(false); |
||||
return $result; |
||||
} |
||||
|
||||
// Tests : |
||||
|
||||
public function testSignRequest() |
||||
{ |
||||
$oauthClient = new Client1(); |
||||
|
||||
$oauthSignatureMethod = new PlainText(); |
||||
$oauthClient->setSignatureMethod($oauthSignatureMethod); |
||||
|
||||
$signedParams = $this->invokeOAuthClientMethod($oauthClient, 'signRequest', ['GET', 'http://test.url', []]); |
||||
$this->assertNotEmpty($signedParams['oauth_signature'], 'Unable to sign request!'); |
||||
} |
||||
|
||||
/** |
||||
* Data provider for [[testComposeAuthorizationHeader()]]. |
||||
* @return array test data. |
||||
*/ |
||||
public function composeAuthorizationHeaderDataProvider() |
||||
{ |
||||
return [ |
||||
[ |
||||
'', |
||||
[ |
||||
'oauth_test_name_1' => 'oauth_test_value_1', |
||||
'oauth_test_name_2' => 'oauth_test_value_2', |
||||
], |
||||
'Authorization: OAuth oauth_test_name_1="oauth_test_value_1", oauth_test_name_2="oauth_test_value_2"' |
||||
], |
||||
[ |
||||
'test_realm', |
||||
[ |
||||
'oauth_test_name_1' => 'oauth_test_value_1', |
||||
'oauth_test_name_2' => 'oauth_test_value_2', |
||||
], |
||||
'Authorization: OAuth realm="test_realm", oauth_test_name_1="oauth_test_value_1", oauth_test_name_2="oauth_test_value_2"' |
||||
], |
||||
[ |
||||
'', |
||||
[ |
||||
'oauth_test_name_1' => 'oauth_test_value_1', |
||||
'test_name_2' => 'test_value_2', |
||||
], |
||||
'Authorization: OAuth oauth_test_name_1="oauth_test_value_1"' |
||||
], |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider composeAuthorizationHeaderDataProvider |
||||
* |
||||
* @param string $realm authorization realm. |
||||
* @param array $params request params. |
||||
* @param string $expectedAuthorizationHeader expected authorization header. |
||||
*/ |
||||
public function testComposeAuthorizationHeader($realm, array $params, $expectedAuthorizationHeader) |
||||
{ |
||||
$oauthClient = new Client1(); |
||||
$authorizationHeader = $this->invokeOAuthClientMethod($oauthClient, 'composeAuthorizationHeader', [$params, $realm]); |
||||
$this->assertEquals($expectedAuthorizationHeader, $authorizationHeader); |
||||
} |
||||
|
||||
public function testBuildAuthUrl() { |
||||
$oauthClient = new Client1(); |
||||
$authUrl = 'http://test.auth.url'; |
||||
$oauthClient->authUrl = $authUrl; |
||||
|
||||
$requestTokenToken = 'test_request_token'; |
||||
$requestToken = new Token(); |
||||
$requestToken->setToken($requestTokenToken); |
||||
|
||||
$builtAuthUrl = $oauthClient->buildAuthUrl($requestToken); |
||||
|
||||
$this->assertContains($authUrl, $builtAuthUrl, 'No auth URL present!'); |
||||
$this->assertContains($requestTokenToken, $builtAuthUrl, 'No token present!'); |
||||
} |
||||
} |
@ -0,0 +1,33 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient\oauth; |
||||
|
||||
use yii\authclient\oauth\Client2; |
||||
use yiiunit\extensions\authclient\TestCase; |
||||
|
||||
class Client2Test extends TestCase |
||||
{ |
||||
protected function setUp() |
||||
{ |
||||
$this->mockApplication([], '\yii\web\Application'); |
||||
} |
||||
|
||||
// Tests : |
||||
|
||||
public function testBuildAuthUrl() |
||||
{ |
||||
$oauthClient = new Client2(); |
||||
$authUrl = 'http://test.auth.url'; |
||||
$oauthClient->authUrl = $authUrl; |
||||
$clientId = 'test_client_id'; |
||||
$oauthClient->clientId = $clientId; |
||||
$returnUrl = 'http://test.return.url'; |
||||
$oauthClient->setReturnUrl($returnUrl); |
||||
|
||||
$builtAuthUrl = $oauthClient->buildAuthUrl(); |
||||
|
||||
$this->assertContains($authUrl, $builtAuthUrl, 'No auth URL present!'); |
||||
$this->assertContains($clientId, $builtAuthUrl, 'No client id present!'); |
||||
$this->assertContains(rawurlencode($returnUrl), $builtAuthUrl, 'No return URL present!'); |
||||
} |
||||
} |
@ -0,0 +1,133 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient\oauth; |
||||
|
||||
use yii\authclient\oauth\Token; |
||||
use yiiunit\extensions\authclient\TestCase; |
||||
|
||||
class TokenTest extends TestCase |
||||
{ |
||||
public function testCreate() |
||||
{ |
||||
$config = [ |
||||
'tokenParamKey' => 'test_token_param_key', |
||||
'tokenSecretParamKey' => 'test_token_secret_param_key', |
||||
]; |
||||
$oauthToken = new Token($config); |
||||
$this->assertTrue(is_object($oauthToken), 'Unable to create access token!'); |
||||
foreach ($config as $name => $value) { |
||||
$this->assertEquals($value, $oauthToken->$name, 'Unable to setup attributes by constructor!'); |
||||
} |
||||
$this->assertTrue($oauthToken->createTimestamp > 0, 'Unable to fill create timestamp!'); |
||||
} |
||||
|
||||
public function testSetupParams() |
||||
{ |
||||
$oauthToken = new Token(); |
||||
|
||||
$params = [ |
||||
'name_1' => 'value_1', |
||||
'name_2' => 'value_2', |
||||
]; |
||||
$oauthToken->setParams($params); |
||||
$this->assertEquals($params, $oauthToken->getParams(), 'Unable to setup params!'); |
||||
|
||||
$newParamName = 'new_param_name'; |
||||
$newParamValue = 'new_param_value'; |
||||
$oauthToken->setParam($newParamName, $newParamValue); |
||||
$this->assertEquals($newParamValue, $oauthToken->getParam($newParamName), 'Unable to setup param by name!'); |
||||
} |
||||
|
||||
/** |
||||
* @depends testSetupParams |
||||
*/ |
||||
public function testSetupParamsShortcuts() |
||||
{ |
||||
$oauthToken = new Token(); |
||||
|
||||
$token = 'test_token_value'; |
||||
$oauthToken->setToken($token); |
||||
$this->assertEquals($token, $oauthToken->getToken(), 'Unable to setup token!'); |
||||
|
||||
$tokenSecret = 'test_token_secret'; |
||||
$oauthToken->setTokenSecret($tokenSecret); |
||||
$this->assertEquals($tokenSecret, $oauthToken->getTokenSecret(), 'Unable to setup token secret!'); |
||||
|
||||
$tokenExpireDuration = rand(1000, 2000); |
||||
$oauthToken->setExpireDuration($tokenExpireDuration); |
||||
$this->assertEquals($tokenExpireDuration, $oauthToken->getExpireDuration(), 'Unable to setup expire duration!'); |
||||
} |
||||
|
||||
/** |
||||
* Data provider for {@link testAutoFetchExpireDuration}. |
||||
* @return array test data. |
||||
*/ |
||||
public function autoFetchExpireDurationDataProvider() |
||||
{ |
||||
return [ |
||||
[ |
||||
['expire_in' => 123345], |
||||
123345 |
||||
], |
||||
[ |
||||
['expire' => 233456], |
||||
233456 |
||||
], |
||||
[ |
||||
['expiry_in' => 34567], |
||||
34567 |
||||
], |
||||
[ |
||||
['expiry' => 45678], |
||||
45678 |
||||
], |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* @depends testSetupParamsShortcuts |
||||
* @dataProvider autoFetchExpireDurationDataProvider |
||||
* |
||||
* @param array $params |
||||
* @param $expectedExpireDuration |
||||
*/ |
||||
public function testAutoFetchExpireDuration(array $params, $expectedExpireDuration) |
||||
{ |
||||
$oauthToken = new Token(); |
||||
$oauthToken->setParams($params); |
||||
$this->assertEquals($expectedExpireDuration, $oauthToken->getExpireDuration()); |
||||
} |
||||
|
||||
/** |
||||
* @depends testSetupParamsShortcuts |
||||
*/ |
||||
public function testGetIsExpired() |
||||
{ |
||||
$oauthToken = new Token(); |
||||
$expireDuration = 3600; |
||||
$oauthToken->setExpireDuration($expireDuration); |
||||
|
||||
$this->assertFalse($oauthToken->getIsExpired(), 'Not expired token check fails!'); |
||||
|
||||
$oauthToken->createTimestamp = $oauthToken->createTimestamp - ($expireDuration +1); |
||||
$this->assertTrue($oauthToken->getIsExpired(), 'Expired token check fails!'); |
||||
} |
||||
|
||||
/** |
||||
* @depends testGetIsExpired |
||||
*/ |
||||
public function testGetIsValid() |
||||
{ |
||||
$oauthToken = new Token(); |
||||
$expireDuration = 3600; |
||||
$oauthToken->setExpireDuration($expireDuration); |
||||
|
||||
$this->assertFalse($oauthToken->getIsValid(), 'Empty token is valid!'); |
||||
|
||||
$oauthToken->setToken('test_token'); |
||||
$this->assertTrue($oauthToken->getIsValid(), 'Filled up token is invalid!'); |
||||
|
||||
$oauthToken->createTimestamp = $oauthToken->createTimestamp - ($expireDuration +1); |
||||
$this->assertFalse($oauthToken->getIsValid(), 'Expired token is valid!'); |
||||
} |
||||
} |
@ -0,0 +1,50 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient\oauth\signature; |
||||
|
||||
use yiiunit\extensions\authclient\TestCase; |
||||
|
||||
class BaseMethodTest extends TestCase |
||||
{ |
||||
/** |
||||
* Creates test signature method instance. |
||||
* @return \yii\authclient\oauth\signature\BaseMethod |
||||
*/ |
||||
protected function createTestSignatureMethod() |
||||
{ |
||||
$signatureMethod = $this->getMock('\yii\authclient\oauth\signature\BaseMethod', ['getName', 'generateSignature']); |
||||
$signatureMethod->expects($this->any())->method('getName')->will($this->returnValue('testMethodName')); |
||||
$signatureMethod->expects($this->any())->method('generateSignature')->will($this->returnValue('testSignature')); |
||||
return $signatureMethod; |
||||
} |
||||
|
||||
// Tests : |
||||
|
||||
public function testGenerateSignature() |
||||
{ |
||||
$signatureMethod = $this->createTestSignatureMethod(); |
||||
|
||||
$baseString = 'test_base_string'; |
||||
$key = 'test_key'; |
||||
|
||||
$signature = $signatureMethod->generateSignature($baseString, $key); |
||||
|
||||
$this->assertNotEmpty($signature, 'Unable to generate signature!'); |
||||
} |
||||
|
||||
/** |
||||
* @depends testGenerateSignature |
||||
*/ |
||||
public function testVerify() |
||||
{ |
||||
$signatureMethod = $this->createTestSignatureMethod(); |
||||
|
||||
$baseString = 'test_base_string'; |
||||
$key = 'test_key'; |
||||
$signature = 'unsigned'; |
||||
$this->assertFalse($signatureMethod->verify($signature, $baseString, $key), 'Unsigned signature is valid!'); |
||||
|
||||
$generatedSignature = $signatureMethod->generateSignature($baseString, $key); |
||||
$this->assertTrue($signatureMethod->verify($generatedSignature, $baseString, $key), 'Generated signature is invalid!'); |
||||
} |
||||
} |
@ -0,0 +1,20 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient\oauth\signature; |
||||
|
||||
use yii\authclient\oauth\signature\HmacSha1; |
||||
use yiiunit\extensions\authclient\TestCase; |
||||
|
||||
class HmacSha1Test extends TestCase |
||||
{ |
||||
public function testGenerateSignature() |
||||
{ |
||||
$signatureMethod = new HmacSha1(); |
||||
|
||||
$baseString = 'test_base_string'; |
||||
$key = 'test_key'; |
||||
|
||||
$signature = $signatureMethod->generateSignature($baseString, $key); |
||||
$this->assertNotEmpty($signature, 'Unable to generate signature!'); |
||||
} |
||||
} |
@ -0,0 +1,20 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient\oauth\signature; |
||||
|
||||
use yii\authclient\oauth\signature\PlainText; |
||||
use yiiunit\extensions\authclient\TestCase; |
||||
|
||||
class PlainTextTest extends TestCase |
||||
{ |
||||
public function testGenerateSignature() |
||||
{ |
||||
$signatureMethod = new PlainText(); |
||||
|
||||
$baseString = 'test_base_string'; |
||||
$key = 'test_key'; |
||||
|
||||
$signature = $signatureMethod->generateSignature($baseString, $key); |
||||
$this->assertNotEmpty($signature, 'Unable to generate signature!'); |
||||
} |
||||
} |
@ -0,0 +1,110 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\extensions\authclient\oauth\signature; |
||||
|
||||
use yii\authclient\oauth\signature\RsaSha1; |
||||
use yiiunit\extensions\authclient\TestCase; |
||||
|
||||
class RsaSha1Test extends TestCase |
||||
{ |
||||
/** |
||||
* Returns test public certificate string. |
||||
* @return string public certificate string. |
||||
*/ |
||||
protected function getTestPublicCertificate() |
||||
{ |
||||
return '-----BEGIN CERTIFICATE----- |
||||
MIIDJDCCAo2gAwIBAgIJALCFAl3nj1ibMA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD |
||||
VQQGEwJOTDESMBAGA1UECAwJQW1zdGVyZGFtMRIwEAYDVQQHDAlBbXN0ZXJkYW0x |
||||
DzANBgNVBAoMBlBpbVRpbTEPMA0GA1UECwwGUGltVGltMSswKQYDVQQDDCJkZXY1 |
||||
My5xdWFydHNvZnQuY29tL3BrbGltb3YvcGltdGltMSQwIgYJKoZIhvcNAQkBFhVw |
||||
a2xpbW92QHF1YXJ0c29mdC5jb20wHhcNMTIxMTA2MTQxNjUzWhcNMTMxMTA2MTQx |
||||
NjUzWjCBqjELMAkGA1UEBhMCTkwxEjAQBgNVBAgMCUFtc3RlcmRhbTESMBAGA1UE |
||||
BwwJQW1zdGVyZGFtMQ8wDQYDVQQKDAZQaW1UaW0xDzANBgNVBAsMBlBpbVRpbTEr |
||||
MCkGA1UEAwwiZGV2NTMucXVhcnRzb2Z0LmNvbS9wa2xpbW92L3BpbXRpbTEkMCIG |
||||
CSqGSIb3DQEJARYVcGtsaW1vdkBxdWFydHNvZnQuY29tMIGfMA0GCSqGSIb3DQEB |
||||
AQUAA4GNADCBiQKBgQDE0d63YwpBLxzxQAW887JALcGruAHkHu7Ui1oc7bCIMy+u |
||||
d6rPgNmbFLw3GoGzQ8xhMmksZHsS07IfWRTDeisPHAqfgcApOZbyMyZUAL6+1ko4 |
||||
xAIPnQSia7l8M4nWgtgqifDCbFKAoPXuWSrYDOFtgSkBLH5xYyFPRc04nnHpoQID |
||||
AQABo1AwTjAdBgNVHQ4EFgQUE2oxXYDFRNtgvn8tyXldepRFWzYwHwYDVR0jBBgw |
||||
FoAUE2oxXYDFRNtgvn8tyXldepRFWzYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B |
||||
AQUFAAOBgQB1/S46dWBECaOs4byCysFhzXw8qx8znJkSZcIdDilmg1kkfusXKi2S |
||||
DiiFw5gDrc6Qp6WtPmVhxHUWl6O5bOG8lG0Dcppeed9454CGvBShmYdwC6vk0s7/ |
||||
gVdK2V4fYsUeT6u49ONshvJ/8xhHz2gGXeLWaqHwtK3Dl3S6TIDuoQ== |
||||
-----END CERTIFICATE-----'; |
||||
} |
||||
|
||||
/** |
||||
* Returns test private certificate string. |
||||
* @return string private certificate string. |
||||
*/ |
||||
protected function getTestPrivateCertificate() |
||||
{ |
||||
return '-----BEGIN RSA PRIVATE KEY----- |
||||
MIICXAIBAAKBgQDE0d63YwpBLxzxQAW887JALcGruAHkHu7Ui1oc7bCIMy+ud6rP |
||||
gNmbFLw3GoGzQ8xhMmksZHsS07IfWRTDeisPHAqfgcApOZbyMyZUAL6+1ko4xAIP |
||||
nQSia7l8M4nWgtgqifDCbFKAoPXuWSrYDOFtgSkBLH5xYyFPRc04nnHpoQIDAQAB |
||||
AoGAPm1e2gYE86Xw5ShsaYFWcXrR6hiEKQoSsMG+hFxz2M97eTglqolw+/p4tHWo |
||||
2+ZORioKJ/V6//67iavkpRfz3dloUlNE9ZzlvqvPjHePt3BI22GI8D84dcqnxWW5 |
||||
4okEAfDfXk2B4UNOpVNU5FZjg4XvBEbbhRVrsBWAPMduDX0CQQDtFgLLLWr50F3z |
||||
lGuFy68Y1d01sZsyf7xUPaLcDWbrnVMIjZIs60BbLg9PZ6sYcwV2RwL/WaJU0Ap/ |
||||
KKjHW51zAkEA1IWBicQtt6yGaUqydq+ifX8/odFjIrlZklwckLl65cImyxqDYMnA |
||||
m+QdbZznSH96BHjduhJAEAtfYx5CVMrXmwJAHKiWedzpm3z2fmUoginW5pejf8QS |
||||
UI5kQ4KX1yW/lSeVS+lhDBD73Im6zAxqADCXLm7zC87X8oybWDef/0kxxQJAebRX |
||||
AalKMSRo+QVg/F0Kpenoa+f4aNtSc2GyriK6QbeU9b0iPZxsZBoXzD0NqlPucX8y |
||||
IyvuagHJR379p4dePwJBAMCkYSATGdhYbeDfySWUro5K0QAvBNj8FuNJQ4rqUxz8 |
||||
8b+OXIyd5WlmuDRTDGJBTxAYeaioTuMCFWaZm4jG0I4= |
||||
-----END RSA PRIVATE KEY-----'; |
||||
} |
||||
|
||||
// Tests : |
||||
|
||||
public function testGenerateSignature() |
||||
{ |
||||
$signatureMethod = new RsaSha1(); |
||||
$signatureMethod->setPrivateCertificate($this->getTestPrivateCertificate()); |
||||
$signatureMethod->setPublicCertificate($this->getTestPublicCertificate()); |
||||
|
||||
$baseString = 'test_base_string'; |
||||
$key = 'test_key'; |
||||
|
||||
$signature = $signatureMethod->generateSignature($baseString, $key); |
||||
$this->assertNotEmpty($signature, 'Unable to generate signature!'); |
||||
} |
||||
|
||||
/** |
||||
* @depends testGenerateSignature |
||||
*/ |
||||
public function testVerify() |
||||
{ |
||||
$signatureMethod = new RsaSha1(); |
||||
$signatureMethod->setPrivateCertificate($this->getTestPrivateCertificate()); |
||||
$signatureMethod->setPublicCertificate($this->getTestPublicCertificate()); |
||||
|
||||
$baseString = 'test_base_string'; |
||||
$key = 'test_key'; |
||||
$signature = 'unsigned'; |
||||
$this->assertFalse($signatureMethod->verify($signature, $baseString, $key), 'Unsigned signature is valid!'); |
||||
|
||||
$generatedSignature = $signatureMethod->generateSignature($baseString, $key); |
||||
$this->assertTrue($signatureMethod->verify($generatedSignature, $baseString, $key), 'Generated signature is invalid!'); |
||||
} |
||||
|
||||
public function testInitPrivateCertificate() |
||||
{ |
||||
$signatureMethod = new RsaSha1(); |
||||
|
||||
$certificateFileName = __FILE__; |
||||
$signatureMethod->privateCertificateFile = $certificateFileName; |
||||
$this->assertEquals(file_get_contents($certificateFileName), $signatureMethod->getPrivateCertificate(), 'Unable to fetch private certificate from file!'); |
||||
} |
||||
|
||||
public function testInitPublicCertificate() |
||||
{ |
||||
$signatureMethod = new RsaSha1(); |
||||
|
||||
$certificateFileName = __FILE__; |
||||
$signatureMethod->publicCertificateFile = $certificateFileName; |
||||
$this->assertEquals(file_get_contents($certificateFileName), $signatureMethod->getPublicCertificate(), 'Unable to fetch public certificate from file!'); |
||||
} |
||||
} |
Loading…
Reference in new issue