Commit cdae9b60 by Paul Klimov

Extension "authclient" added as draft.

parent 22c45342
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.
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...
\ No newline at end of file
{
"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"
}
<?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);
}
}
\ No newline at end of file
<?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());
}
}
\ No newline at end of file
<?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);
}
}
\ No newline at end of file
<?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));
}
}
\ No newline at end of file
<?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;
}
}
\ No newline at end of file
<?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);
}
}
\ No newline at end of file
<?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
{
}
\ No newline at end of file
<?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;
}
}
}
\ No newline at end of file
<?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&param2=value2',
],
[
'http://test.url?with=some',
[
'param1' => 'value1',
'param2' => 'value2',
],
'http://test.url?with=some&param1=value1&param2=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));
}
}
\ No newline at end of file
<?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!');
}
}
\ No newline at end of file
<?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!');
}
}
\ No newline at end of file
<?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!');
}
}
\ No newline at end of file
<?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!');
}
}
\ No newline at end of file
<?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!');
}
}
\ No newline at end of file
<?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!');
}
}
\ No newline at end of file
<?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!');
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment