Qiang Xue
11 years ago
43 changed files with 5629 additions and 0 deletions
@ -0,0 +1,359 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient; |
||||||
|
|
||||||
|
use yii\base\Action; |
||||||
|
use yii\base\Exception; |
||||||
|
use yii\base\InvalidConfigException; |
||||||
|
use yii\base\NotSupportedException; |
||||||
|
use yii\web\Response; |
||||||
|
use yii\web\HttpException; |
||||||
|
use yii\web\NotFoundHttpException; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
/** |
||||||
|
* AuthAction performs authentication via different auth clients. |
||||||
|
* It supports [[OpenId]], [[OAuth1] and [[OAuth2]] client types. |
||||||
|
* |
||||||
|
* Usage: |
||||||
|
* ~~~ |
||||||
|
* class SiteController extends Controller |
||||||
|
* { |
||||||
|
* public function actions() |
||||||
|
* { |
||||||
|
* return [ |
||||||
|
* 'auth' => [ |
||||||
|
* 'class' => 'yii\authclient\AuthAction', |
||||||
|
* 'successCallback' => [$this, 'successCallback'], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* } |
||||||
|
* |
||||||
|
* public function successCallback($client) |
||||||
|
* { |
||||||
|
* $atributes = $client->getUserAttributes(); |
||||||
|
* // user login or signup comes here |
||||||
|
* } |
||||||
|
* } |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* Usually authentication via external services is performed inside the popup window. |
||||||
|
* This action handles the redirection and closing of popup window correctly. |
||||||
|
* |
||||||
|
* @see Collection |
||||||
|
* @see \yii\authclient\widgets\Choice |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class AuthAction extends Action |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string name of the auth client collection application component. |
||||||
|
* It should point to [[Collection]] instance. |
||||||
|
*/ |
||||||
|
public $clientCollection = 'authClientCollection'; |
||||||
|
/** |
||||||
|
* @var string name of the GET param, which is used to passed auth client id to this action. |
||||||
|
* Note: watch for the naming, make sure you do not choose name used in some auth protocol. |
||||||
|
*/ |
||||||
|
public $clientIdGetParamName = 'authclient'; |
||||||
|
/** |
||||||
|
* @var callable PHP callback, which should be triggered in case of successful authentication. |
||||||
|
* This callback should accept [[ClientInterface]] instance as an argument. |
||||||
|
* For example: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* public function onAuthSuccess($client) |
||||||
|
* { |
||||||
|
* $atributes = $client->getUserAttributes(); |
||||||
|
* // user login or signup comes here |
||||||
|
* } |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* If this callback returns [[Response]] instance, it will be used as action response, |
||||||
|
* otherwise redirection to [[successUrl]] will be performed. |
||||||
|
* |
||||||
|
*/ |
||||||
|
public $successCallback; |
||||||
|
/** |
||||||
|
* @var string the redirect url after successful authorization. |
||||||
|
*/ |
||||||
|
private $_successUrl = ''; |
||||||
|
/** |
||||||
|
* @var string the redirect url after unsuccessful authorization (e.g. user canceled). |
||||||
|
*/ |
||||||
|
private $_cancelUrl = ''; |
||||||
|
/** |
||||||
|
* @var string name or alias of the view file, which should be rendered in order to perform redirection. |
||||||
|
* If not set default one will be used. |
||||||
|
*/ |
||||||
|
public $redirectView; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $url successful URL. |
||||||
|
*/ |
||||||
|
public function setSuccessUrl($url) |
||||||
|
{ |
||||||
|
$this->_successUrl = $url; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string successful URL. |
||||||
|
*/ |
||||||
|
public function getSuccessUrl() |
||||||
|
{ |
||||||
|
if (empty($this->_successUrl)) { |
||||||
|
$this->_successUrl = $this->defaultSuccessUrl(); |
||||||
|
} |
||||||
|
return $this->_successUrl; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $url cancel URL. |
||||||
|
*/ |
||||||
|
public function setCancelUrl($url) |
||||||
|
{ |
||||||
|
$this->_cancelUrl = $url; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string cancel URL. |
||||||
|
*/ |
||||||
|
public function getCancelUrl() |
||||||
|
{ |
||||||
|
if (empty($this->_cancelUrl)) { |
||||||
|
$this->_cancelUrl = $this->defaultCancelUrl(); |
||||||
|
} |
||||||
|
return $this->_cancelUrl; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates default {@link successUrl} value. |
||||||
|
* @return string success URL value. |
||||||
|
*/ |
||||||
|
protected function defaultSuccessUrl() |
||||||
|
{ |
||||||
|
return Yii::$app->getUser()->getReturnUrl(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates default {@link cancelUrl} value. |
||||||
|
* @return string cancel URL value. |
||||||
|
*/ |
||||||
|
protected function defaultCancelUrl() |
||||||
|
{ |
||||||
|
return Yii::$app->getRequest()->getAbsoluteUrl(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Runs the action. |
||||||
|
*/ |
||||||
|
public function run() |
||||||
|
{ |
||||||
|
if (!empty($_GET[$this->clientIdGetParamName])) { |
||||||
|
$clientId = $_GET[$this->clientIdGetParamName]; |
||||||
|
/** @var \yii\authclient\Collection $collection */ |
||||||
|
$collection = Yii::$app->getComponent($this->clientCollection); |
||||||
|
if (!$collection->hasClient($clientId)) { |
||||||
|
throw new NotFoundHttpException("Unknown auth client '{$clientId}'"); |
||||||
|
} |
||||||
|
$client = $collection->getClient($clientId); |
||||||
|
return $this->auth($client); |
||||||
|
} else { |
||||||
|
throw new NotFoundHttpException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param mixed $client auth client instance. |
||||||
|
* @return Response response instance. |
||||||
|
* @throws \yii\base\NotSupportedException on invalid client. |
||||||
|
*/ |
||||||
|
protected function auth($client) |
||||||
|
{ |
||||||
|
if ($client instanceof OpenId) { |
||||||
|
return $this->authOpenId($client); |
||||||
|
} elseif ($client instanceof OAuth2) { |
||||||
|
return $this->authOAuth2($client); |
||||||
|
} elseif ($client instanceof OAuth1) { |
||||||
|
return $this->authOAuth1($client); |
||||||
|
} else { |
||||||
|
throw new NotSupportedException('Provider "' . get_class($client) . '" is not supported.'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is invoked in case of successful authentication via auth client. |
||||||
|
* @param ClientInterface $client auth client instance. |
||||||
|
* @throws InvalidConfigException on invalid success callback. |
||||||
|
* @return Response response instance. |
||||||
|
*/ |
||||||
|
protected function authSuccess($client) |
||||||
|
{ |
||||||
|
if (!is_callable($this->successCallback)) { |
||||||
|
throw new InvalidConfigException('"' . get_class($this) . '::successCallback" should be a valid callback.'); |
||||||
|
} |
||||||
|
$response = call_user_func($this->successCallback, $client); |
||||||
|
if ($response instanceof Response) { |
||||||
|
return $response; |
||||||
|
} |
||||||
|
return $this->redirectSuccess(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Redirect to the given URL or simply close the popup window. |
||||||
|
* @param mixed $url URL to redirect, could be a string or array config to generate a valid URL. |
||||||
|
* @param boolean $enforceRedirect indicates if redirect should be performed even in case of popup window. |
||||||
|
* @return \yii\web\Response response instance. |
||||||
|
*/ |
||||||
|
public function redirect($url, $enforceRedirect = true) |
||||||
|
{ |
||||||
|
$viewFile = $this->redirectView; |
||||||
|
if ($viewFile === null) { |
||||||
|
$viewFile = __DIR__ . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'redirect.php'; |
||||||
|
} else { |
||||||
|
$viewFile = Yii::getAlias($viewFile); |
||||||
|
} |
||||||
|
$viewData = [ |
||||||
|
'url' => $url, |
||||||
|
'enforceRedirect' => $enforceRedirect, |
||||||
|
]; |
||||||
|
$response = Yii::$app->getResponse(); |
||||||
|
$response->content = Yii::$app->getView()->renderFile($viewFile, $viewData); |
||||||
|
return $response; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Redirect to the URL. If URL is null, {@link successUrl} will be used. |
||||||
|
* @param string $url URL to redirect. |
||||||
|
* @return \yii\web\Response response instance. |
||||||
|
*/ |
||||||
|
public function redirectSuccess($url = null) |
||||||
|
{ |
||||||
|
if ($url === null) { |
||||||
|
$url = $this->getSuccessUrl(); |
||||||
|
} |
||||||
|
return $this->redirect($url); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Redirect to the {@link cancelUrl} or simply close the popup window. |
||||||
|
* @param string $url URL to redirect. |
||||||
|
* @return \yii\web\Response response instance. |
||||||
|
*/ |
||||||
|
public function redirectCancel($url = null) |
||||||
|
{ |
||||||
|
if ($url === null) { |
||||||
|
$url = $this->getCancelUrl(); |
||||||
|
} |
||||||
|
return $this->redirect($url, false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs OpenID auth flow. |
||||||
|
* @param OpenId $client auth client instance. |
||||||
|
* @return Response action response. |
||||||
|
* @throws Exception on failure. |
||||||
|
* @throws HttpException on failure. |
||||||
|
*/ |
||||||
|
protected function authOpenId($client) |
||||||
|
{ |
||||||
|
if (!empty($_REQUEST['openid_mode'])) { |
||||||
|
switch ($_REQUEST['openid_mode']) { |
||||||
|
case 'id_res': |
||||||
|
if ($client->validate()) { |
||||||
|
return $this->authSuccess($client); |
||||||
|
} else { |
||||||
|
throw new HttpException(400, 'Unable to complete the authentication because the required data was not received.'); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 'cancel': |
||||||
|
$this->redirectCancel(); |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new HttpException(400); |
||||||
|
break; |
||||||
|
} |
||||||
|
} else { |
||||||
|
$url = $client->buildAuthUrl(); |
||||||
|
return Yii::$app->getResponse()->redirect($url); |
||||||
|
} |
||||||
|
return $this->redirectCancel(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs OAuth1 auth flow. |
||||||
|
* @param OAuth1 $client auth client instance. |
||||||
|
* @return Response action response. |
||||||
|
*/ |
||||||
|
protected function authOAuth1($client) |
||||||
|
{ |
||||||
|
// user denied error |
||||||
|
if (isset($_GET['denied'])) { |
||||||
|
return $this->redirectCancel(); |
||||||
|
} |
||||||
|
|
||||||
|
if (isset($_REQUEST['oauth_token'])) { |
||||||
|
$oauthToken = $_REQUEST['oauth_token']; |
||||||
|
} |
||||||
|
|
||||||
|
if (!isset($oauthToken)) { |
||||||
|
// Get request token. |
||||||
|
$requestToken = $client->fetchRequestToken(); |
||||||
|
// Get authorization URL. |
||||||
|
$url = $client->buildAuthUrl($requestToken); |
||||||
|
// Redirect to authorization URL. |
||||||
|
return Yii::$app->getResponse()->redirect($url); |
||||||
|
} else { |
||||||
|
// Upgrade to access token. |
||||||
|
$accessToken = $client->fetchAccessToken(); |
||||||
|
return $this->authSuccess($client); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs OAuth2 auth flow. |
||||||
|
* @param OAuth2 $client auth client instance. |
||||||
|
* @return Response action response. |
||||||
|
* @throws \yii\base\Exception on failure. |
||||||
|
*/ |
||||||
|
protected function authOAuth2($client) |
||||||
|
{ |
||||||
|
if (isset($_GET['error'])) { |
||||||
|
if ($_GET['error'] == 'access_denied') { |
||||||
|
// user denied error |
||||||
|
return $this->redirectCancel(); |
||||||
|
} else { |
||||||
|
// request error |
||||||
|
if (isset($_GET['error_description'])) { |
||||||
|
$errorMessage = $_GET['error_description']; |
||||||
|
} elseif (isset($_GET['error_message'])) { |
||||||
|
$errorMessage = $_GET['error_message']; |
||||||
|
} else { |
||||||
|
$errorMessage = http_build_query($_GET); |
||||||
|
} |
||||||
|
throw new Exception('Auth error: ' . $errorMessage); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Get the access_token and save them to the session. |
||||||
|
if (isset($_GET['code'])) { |
||||||
|
$code = $_GET['code']; |
||||||
|
$token = $client->fetchAccessToken($code); |
||||||
|
if (!empty($token)) { |
||||||
|
return $this->authSuccess($client); |
||||||
|
} else { |
||||||
|
return $this->redirectCancel(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
$url = $client->buildAuthUrl(); |
||||||
|
return Yii::$app->getResponse()->redirect($url); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,237 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient; |
||||||
|
|
||||||
|
use Yii; |
||||||
|
use yii\base\Component; |
||||||
|
use yii\base\NotSupportedException; |
||||||
|
use yii\helpers\Inflector; |
||||||
|
use yii\helpers\StringHelper; |
||||||
|
|
||||||
|
/** |
||||||
|
* BaseClient is a base Auth Client class. |
||||||
|
* |
||||||
|
* @see ClientInterface |
||||||
|
* |
||||||
|
* @property string $id auth service id. |
||||||
|
* @property string $name auth service name. |
||||||
|
* @property string $title auth service title. |
||||||
|
* @property array $userAttributes authenticated user attributes. |
||||||
|
* @property array $normalizeUserAttributeMap map used to normalize user attributes fetched from |
||||||
|
* external auth service in format: rawAttributeName => normalizedAttributeName. |
||||||
|
* @property array $viewOptions view options in format: optionName => optionValue. |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
abstract class BaseClient extends Component implements ClientInterface |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string auth service id. |
||||||
|
* This value mainly used as HTTP request parameter. |
||||||
|
*/ |
||||||
|
private $_id; |
||||||
|
/** |
||||||
|
* @var string auth service name. |
||||||
|
* This value may be used in database records, CSS files and so on. |
||||||
|
*/ |
||||||
|
private $_name; |
||||||
|
/** |
||||||
|
* @var string auth service title to display in views. |
||||||
|
*/ |
||||||
|
private $_title; |
||||||
|
/** |
||||||
|
* @var array authenticated user attributes. |
||||||
|
*/ |
||||||
|
private $_userAttributes; |
||||||
|
/** |
||||||
|
* @var array map used to normalize user attributes fetched from external auth service |
||||||
|
* in format: rawAttributeName => normalizedAttributeName |
||||||
|
*/ |
||||||
|
private $_normalizeUserAttributeMap; |
||||||
|
/** |
||||||
|
* @var array view options in format: optionName => optionValue |
||||||
|
*/ |
||||||
|
private $_viewOptions; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $id service id. |
||||||
|
*/ |
||||||
|
public function setId($id) |
||||||
|
{ |
||||||
|
$this->_id = $id; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string service id |
||||||
|
*/ |
||||||
|
public function getId() |
||||||
|
{ |
||||||
|
if (empty($this->_id)) { |
||||||
|
$this->_id = $this->getName(); |
||||||
|
} |
||||||
|
return $this->_id; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $name service name. |
||||||
|
*/ |
||||||
|
public function setName($name) |
||||||
|
{ |
||||||
|
$this->_name = $name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string service name. |
||||||
|
*/ |
||||||
|
public function getName() |
||||||
|
{ |
||||||
|
if ($this->_name === null) { |
||||||
|
$this->_name = $this->defaultName(); |
||||||
|
} |
||||||
|
return $this->_name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $title service title. |
||||||
|
*/ |
||||||
|
public function setTitle($title) |
||||||
|
{ |
||||||
|
$this->_title = $title; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string service title. |
||||||
|
*/ |
||||||
|
public function getTitle() |
||||||
|
{ |
||||||
|
if ($this->_title === null) { |
||||||
|
$this->_title = $this->defaultTitle(); |
||||||
|
} |
||||||
|
return $this->_title; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param array $userAttributes list of user attributes |
||||||
|
*/ |
||||||
|
public function setUserAttributes($userAttributes) |
||||||
|
{ |
||||||
|
$this->_userAttributes = $this->normalizeUserAttributes($userAttributes); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array list of user attributes |
||||||
|
*/ |
||||||
|
public function getUserAttributes() |
||||||
|
{ |
||||||
|
if ($this->_userAttributes === null) { |
||||||
|
$this->_userAttributes = $this->normalizeUserAttributes($this->initUserAttributes()); |
||||||
|
} |
||||||
|
return $this->_userAttributes; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param array $normalizeUserAttributeMap normalize user attribute map. |
||||||
|
*/ |
||||||
|
public function setNormalizeUserAttributeMap($normalizeUserAttributeMap) |
||||||
|
{ |
||||||
|
$this->_normalizeUserAttributeMap = $normalizeUserAttributeMap; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array normalize user attribute map. |
||||||
|
*/ |
||||||
|
public function getNormalizeUserAttributeMap() |
||||||
|
{ |
||||||
|
if ($this->_normalizeUserAttributeMap === null) { |
||||||
|
$this->_normalizeUserAttributeMap = $this->defaultNormalizeUserAttributeMap(); |
||||||
|
} |
||||||
|
return $this->_normalizeUserAttributeMap; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param array $viewOptions view options in format: optionName => optionValue |
||||||
|
*/ |
||||||
|
public function setViewOptions($viewOptions) |
||||||
|
{ |
||||||
|
$this->_viewOptions = $viewOptions; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array view options in format: optionName => optionValue |
||||||
|
*/ |
||||||
|
public function getViewOptions() |
||||||
|
{ |
||||||
|
if ($this->_viewOptions === null) { |
||||||
|
$this->_viewOptions = $this->defaultViewOptions(); |
||||||
|
} |
||||||
|
return $this->_viewOptions; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generates service name. |
||||||
|
* @return string service name. |
||||||
|
*/ |
||||||
|
protected function defaultName() |
||||||
|
{ |
||||||
|
return Inflector::camel2id(StringHelper::basename(get_class($this))); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generates service title. |
||||||
|
* @return string service title. |
||||||
|
*/ |
||||||
|
protected function defaultTitle() |
||||||
|
{ |
||||||
|
return StringHelper::basename(get_class($this)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initializes authenticated user attributes. |
||||||
|
* @return array auth user attributes. |
||||||
|
*/ |
||||||
|
protected function initUserAttributes() |
||||||
|
{ |
||||||
|
throw new NotSupportedException('Method "' . get_class($this) . '::' . __FUNCTION__ . '" not implemented.'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the default [[normalizeUserAttributeMap]] value. |
||||||
|
* Particular client may override this method in order to provide specific default map. |
||||||
|
* @return array normalize attribute map. |
||||||
|
*/ |
||||||
|
protected function defaultNormalizeUserAttributeMap() |
||||||
|
{ |
||||||
|
return []; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the default [[viewOptions]] value. |
||||||
|
* Particular client may override this method in order to provide specific default view options. |
||||||
|
* @return array list of default [[viewOptions]] |
||||||
|
*/ |
||||||
|
protected function defaultViewOptions() |
||||||
|
{ |
||||||
|
return []; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Normalize given user attributes according to {@link normalizeUserAttributeMap}. |
||||||
|
* @param array $attributes raw attributes. |
||||||
|
* @return array normalized attributes. |
||||||
|
*/ |
||||||
|
protected function normalizeUserAttributes($attributes) |
||||||
|
{ |
||||||
|
foreach ($this->getNormalizeUserAttributeMap() as $normalizedName => $actualName) { |
||||||
|
if (array_key_exists($actualName, $attributes)) { |
||||||
|
$attributes[$normalizedName] = $attributes[$actualName]; |
||||||
|
} |
||||||
|
} |
||||||
|
return $attributes; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,503 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient; |
||||||
|
|
||||||
|
use yii\base\Exception; |
||||||
|
use yii\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 BaseOAuth extends BaseClient implements ClientInterface |
||||||
|
{ |
||||||
|
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 OAuthToken|array access token instance or its array configuration. |
||||||
|
*/ |
||||||
|
private $_accessToken; |
||||||
|
/** |
||||||
|
* @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 ($this->_returnUrl === null) { |
||||||
|
$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|OAuthToken $token |
||||||
|
*/ |
||||||
|
public function setAccessToken($token) |
||||||
|
{ |
||||||
|
if (!is_object($token)) { |
||||||
|
$token = $this->createToken($token); |
||||||
|
} |
||||||
|
$this->_accessToken = $token; |
||||||
|
$this->saveAccessToken($token); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return OAuthToken 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\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 ' . $this->version . ' 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_str($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 OAuthToken token instance. |
||||||
|
*/ |
||||||
|
protected function createToken(array $tokenConfig = []) |
||||||
|
{ |
||||||
|
if (!array_key_exists('class', $tokenConfig)) { |
||||||
|
$tokenConfig['class'] = OAuthToken::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 OAuthToken $token auth token |
||||||
|
* @return static self reference. |
||||||
|
*/ |
||||||
|
protected function saveAccessToken(OAuthToken $token) |
||||||
|
{ |
||||||
|
return $this->setState('token', $token); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Restores access token. |
||||||
|
* @return OAuthToken auth token. |
||||||
|
*/ |
||||||
|
protected function restoreAccessToken() |
||||||
|
{ |
||||||
|
$token = $this->getState('token'); |
||||||
|
if (is_object($token)) { |
||||||
|
/* @var $token OAuthToken */ |
||||||
|
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 OAuthToken $token expired auth token. |
||||||
|
* @return OAuthToken new auth token. |
||||||
|
*/ |
||||||
|
abstract public function refreshAccessToken(OAuthToken $token); |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs request to the OAuth API. |
||||||
|
* @param OAuthToken $accessToken actual access token. |
||||||
|
* @param string $url absolute API URL. |
||||||
|
* @param string $method request method. |
||||||
|
* @param array $params request parameters. |
||||||
|
* @return array API response. |
||||||
|
* @throws Exception on failure. |
||||||
|
*/ |
||||||
|
abstract protected function apiInternal($accessToken, $url, $method, array $params); |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient; |
||||||
|
|
||||||
|
/** |
||||||
|
* ClientInterface declares basic interface all Auth clients should follow. |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
interface ClientInterface |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @param string $id service id. |
||||||
|
*/ |
||||||
|
public function setId($id); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string service id |
||||||
|
*/ |
||||||
|
public function getId(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string service name. |
||||||
|
*/ |
||||||
|
public function getName(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $name service name. |
||||||
|
*/ |
||||||
|
public function setName($name); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string service title. |
||||||
|
*/ |
||||||
|
public function getTitle(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $title service title. |
||||||
|
*/ |
||||||
|
public function setTitle($title); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array list of user attributes |
||||||
|
*/ |
||||||
|
public function getUserAttributes(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array view options in format: optionName => optionValue |
||||||
|
*/ |
||||||
|
public function getViewOptions(); |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient; |
||||||
|
|
||||||
|
use yii\base\Component; |
||||||
|
use yii\base\InvalidParamException; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
/** |
||||||
|
* Collection is a storage for all auth clients in the application. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'google' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\GoogleOpenId' |
||||||
|
* ], |
||||||
|
* 'facebook' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\Facebook', |
||||||
|
* 'clientId' => 'facebook_client_id', |
||||||
|
* 'clientSecret' => 'facebook_client_secret', |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @property array $clients list of Auth clients with their configuration in format: 'clientId' => [...] |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Collection extends Component |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var array list of Auth clients with their configuration in format: 'clientId' => [...] |
||||||
|
*/ |
||||||
|
private $_clients = []; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param array $clients list of auth clients |
||||||
|
*/ |
||||||
|
public function setClients(array $clients) |
||||||
|
{ |
||||||
|
$this->_clients = $clients; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return ClientInterface[] list of auth clients. |
||||||
|
*/ |
||||||
|
public function getClients() |
||||||
|
{ |
||||||
|
$clients = []; |
||||||
|
foreach ($this->_clients as $id => $client) { |
||||||
|
$clients[$id] = $this->getClient($id); |
||||||
|
} |
||||||
|
return $clients; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $id service id. |
||||||
|
* @return ClientInterface auth client instance. |
||||||
|
* @throws InvalidParamException on non existing client request. |
||||||
|
*/ |
||||||
|
public function getClient($id) |
||||||
|
{ |
||||||
|
if (!array_key_exists($id, $this->_clients)) { |
||||||
|
throw new InvalidParamException("Unknown auth client '{$id}'."); |
||||||
|
} |
||||||
|
if (!is_object($this->_clients[$id])) { |
||||||
|
$this->_clients[$id] = $this->createClient($id, $this->_clients[$id]); |
||||||
|
} |
||||||
|
return $this->_clients[$id]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if client exists in the hub. |
||||||
|
* @param string $id client id. |
||||||
|
* @return boolean whether client exist. |
||||||
|
*/ |
||||||
|
public function hasClient($id) |
||||||
|
{ |
||||||
|
return array_key_exists($id, $this->_clients); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates auth client instance from its array configuration. |
||||||
|
* @param string $id auth client id. |
||||||
|
* @param array $config auth client instance configuration. |
||||||
|
* @return ClientInterface auth client instance. |
||||||
|
*/ |
||||||
|
protected function createClient($id, $config) |
||||||
|
{ |
||||||
|
$config['id'] = $id; |
||||||
|
return Yii::createObject($config); |
||||||
|
} |
||||||
|
} |
@ -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,354 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient; |
||||||
|
|
||||||
|
use yii\base\Exception; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
/** |
||||||
|
* OAuth1 serves as a client for the OAuth 1/1.0a flow. |
||||||
|
* |
||||||
|
* In oder to acquire access token perform following sequence: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* use yii\authclient\OAuth1; |
||||||
|
* |
||||||
|
* $oauthClient = new OAuth1(); |
||||||
|
* $requestToken = $oauthClient->fetchRequestToken(); // Get request token |
||||||
|
* $url = $oauthClient->buildAuthUrl($requestToken); // Get authorization URL |
||||||
|
* return Yii::$app->getResponse()->redirect($url); // Redirect to authorization URL |
||||||
|
* // After user returns at our site: |
||||||
|
* $accessToken = $oauthClient->fetchAccessToken($requestToken); // Upgrade to access token |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @see http://oauth.net/ |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class OAuth1 extends BaseOAuth |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string protocol version. |
||||||
|
*/ |
||||||
|
public $version = '1.0'; |
||||||
|
/** |
||||||
|
* @var string OAuth consumer key. |
||||||
|
*/ |
||||||
|
public $consumerKey; |
||||||
|
/** |
||||||
|
* @var string OAuth consumer secret. |
||||||
|
*/ |
||||||
|
public $consumerSecret; |
||||||
|
/** |
||||||
|
* @var string OAuth request token URL. |
||||||
|
*/ |
||||||
|
public $requestTokenUrl; |
||||||
|
/** |
||||||
|
* @var string request token HTTP method. |
||||||
|
*/ |
||||||
|
public $requestTokenMethod = 'GET'; |
||||||
|
/** |
||||||
|
* @var string OAuth access token URL. |
||||||
|
*/ |
||||||
|
public $accessTokenUrl; |
||||||
|
/** |
||||||
|
* @var string access token HTTP method. |
||||||
|
*/ |
||||||
|
public $accessTokenMethod = 'GET'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Fetches the OAuth request token. |
||||||
|
* @param array $params additional request params. |
||||||
|
* @return OAuthToken request token. |
||||||
|
*/ |
||||||
|
public function fetchRequestToken(array $params = []) |
||||||
|
{ |
||||||
|
$this->removeState('token'); |
||||||
|
$defaultParams = [ |
||||||
|
'oauth_consumer_key' => $this->consumerKey, |
||||||
|
'oauth_callback' => $this->getReturnUrl(), |
||||||
|
//'xoauth_displayname' => Yii::$app->name, |
||||||
|
]; |
||||||
|
if (!empty($this->scope)) { |
||||||
|
$defaultParams['scope'] = $this->scope; |
||||||
|
} |
||||||
|
$response = $this->sendSignedRequest($this->requestTokenMethod, $this->requestTokenUrl, array_merge($defaultParams, $params)); |
||||||
|
$token = $this->createToken([ |
||||||
|
'params' => $response |
||||||
|
]); |
||||||
|
$this->setState('requestToken', $token); |
||||||
|
return $token; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes user authorization URL. |
||||||
|
* @param OAuthToken $requestToken OAuth request token. |
||||||
|
* @param array $params additional request params. |
||||||
|
* @return string authorize URL |
||||||
|
* @throws Exception on failure. |
||||||
|
*/ |
||||||
|
public function buildAuthUrl(OAuthToken $requestToken = null, array $params = []) |
||||||
|
{ |
||||||
|
if (!is_object($requestToken)) { |
||||||
|
$requestToken = $this->getState('requestToken'); |
||||||
|
if (!is_object($requestToken)) { |
||||||
|
throw new Exception('Request token is required to build authorize URL!'); |
||||||
|
} |
||||||
|
} |
||||||
|
$params['oauth_token'] = $requestToken->getToken(); |
||||||
|
return $this->composeUrl($this->authUrl, $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Fetches OAuth access token. |
||||||
|
* @param OAuthToken $requestToken OAuth request token. |
||||||
|
* @param string $oauthVerifier OAuth verifier. |
||||||
|
* @param array $params additional request params. |
||||||
|
* @return OAuthToken OAuth access token. |
||||||
|
* @throws Exception on failure. |
||||||
|
*/ |
||||||
|
public function fetchAccessToken(OAuthToken $requestToken = null, $oauthVerifier = null, array $params = []) |
||||||
|
{ |
||||||
|
if (!is_object($requestToken)) { |
||||||
|
$requestToken = $this->getState('requestToken'); |
||||||
|
if (!is_object($requestToken)) { |
||||||
|
throw new Exception('Request token is required to fetch access token!'); |
||||||
|
} |
||||||
|
} |
||||||
|
$this->removeState('requestToken'); |
||||||
|
$defaultParams = [ |
||||||
|
'oauth_consumer_key' => $this->consumerKey, |
||||||
|
'oauth_token' => $requestToken->getToken() |
||||||
|
]; |
||||||
|
if ($oauthVerifier === null) { |
||||||
|
if (isset($_REQUEST['oauth_verifier'])) { |
||||||
|
$oauthVerifier = $_REQUEST['oauth_verifier']; |
||||||
|
} |
||||||
|
} |
||||||
|
if (!empty($oauthVerifier)) { |
||||||
|
$defaultParams['oauth_verifier'] = $oauthVerifier; |
||||||
|
} |
||||||
|
$response = $this->sendSignedRequest($this->accessTokenMethod, $this->accessTokenUrl, array_merge($defaultParams, $params)); |
||||||
|
|
||||||
|
$token = $this->createToken([ |
||||||
|
'params' => $response |
||||||
|
]); |
||||||
|
$this->setAccessToken($token); |
||||||
|
return $token; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sends HTTP request, signed by {@link signatureMethod}. |
||||||
|
* @param string $method request type. |
||||||
|
* @param string $url request URL. |
||||||
|
* @param array $params request params. |
||||||
|
* @return array response. |
||||||
|
*/ |
||||||
|
protected function sendSignedRequest($method, $url, array $params = []) |
||||||
|
{ |
||||||
|
$params = array_merge($params, $this->generateCommonRequestParams()); |
||||||
|
$params = $this->signRequest($method, $url, $params); |
||||||
|
return $this->sendRequest($method, $url, $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes HTTP request CUrl options, which will be merged with the default ones. |
||||||
|
* @param string $method request type. |
||||||
|
* @param string $url request URL. |
||||||
|
* @param array $params request params. |
||||||
|
* @return array CUrl options. |
||||||
|
* @throws Exception on failure. |
||||||
|
*/ |
||||||
|
protected function composeRequestCurlOptions($method, $url, array $params) |
||||||
|
{ |
||||||
|
$curlOptions = []; |
||||||
|
switch ($method) { |
||||||
|
case 'GET': { |
||||||
|
$curlOptions[CURLOPT_URL] = $this->composeUrl($url, $params); |
||||||
|
break; |
||||||
|
} |
||||||
|
case 'POST': { |
||||||
|
$curlOptions[CURLOPT_POST] = true; |
||||||
|
if (!empty($params)){ |
||||||
|
$curlOptions[CURLOPT_POSTFIELDS] = $params; |
||||||
|
} |
||||||
|
$authorizationHeader = $this->composeAuthorizationHeader($params); |
||||||
|
if (!empty($authorizationHeader)) { |
||||||
|
$curlOptions[CURLOPT_HTTPHEADER] = ['Content-Type: application/atom+xml', $authorizationHeader]; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
case 'HEAD': |
||||||
|
case 'PUT': |
||||||
|
case 'DELETE': { |
||||||
|
$curlOptions[CURLOPT_CUSTOMREQUEST] = $method; |
||||||
|
if (!empty($params)) { |
||||||
|
$curlOptions[CURLOPT_URL] = $this->composeUrl($url, $params); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
default: { |
||||||
|
throw new Exception("Unknown request method '{$method}'."); |
||||||
|
} |
||||||
|
} |
||||||
|
return $curlOptions; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs request to the OAuth API. |
||||||
|
* @param OAuthToken $accessToken actual access token. |
||||||
|
* @param string $url absolute API URL. |
||||||
|
* @param string $method request method. |
||||||
|
* @param array $params request parameters. |
||||||
|
* @return array API response. |
||||||
|
* @throws Exception on failure. |
||||||
|
*/ |
||||||
|
protected function apiInternal($accessToken, $url, $method, array $params) |
||||||
|
{ |
||||||
|
$params['oauth_consumer_key'] = $this->consumerKey; |
||||||
|
$params['oauth_token'] = $accessToken->getToken(); |
||||||
|
$response = $this->sendSignedRequest($method, $url, $params); |
||||||
|
return $response; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets new auth token to replace expired one. |
||||||
|
* @param OAuthToken $token expired auth token. |
||||||
|
* @return OAuthToken new auth token. |
||||||
|
*/ |
||||||
|
public function refreshAccessToken(OAuthToken $token) |
||||||
|
{ |
||||||
|
// @todo |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes default {@link returnUrl} value. |
||||||
|
* @return string return URL. |
||||||
|
*/ |
||||||
|
protected function defaultReturnUrl() |
||||||
|
{ |
||||||
|
$params = $_GET; |
||||||
|
unset($params['oauth_token']); |
||||||
|
return Yii::$app->getUrlManager()->createAbsoluteUrl(Yii::$app->controller->getRoute(), $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generates nonce value. |
||||||
|
* @return string nonce value. |
||||||
|
*/ |
||||||
|
protected function generateNonce() |
||||||
|
{ |
||||||
|
return md5(microtime() . mt_rand()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generates timestamp. |
||||||
|
* @return integer timestamp. |
||||||
|
*/ |
||||||
|
protected function generateTimestamp() |
||||||
|
{ |
||||||
|
return time(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generate common request params like version, timestamp etc. |
||||||
|
* @return array common request params. |
||||||
|
*/ |
||||||
|
protected function generateCommonRequestParams() |
||||||
|
{ |
||||||
|
$params = [ |
||||||
|
'oauth_version' => $this->version, |
||||||
|
'oauth_nonce' => $this->generateNonce(), |
||||||
|
'oauth_timestamp' => $this->generateTimestamp(), |
||||||
|
]; |
||||||
|
return $params; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sign request with {@link signatureMethod}. |
||||||
|
* @param string $method request method. |
||||||
|
* @param string $url request URL. |
||||||
|
* @param array $params request params. |
||||||
|
* @return array signed request params. |
||||||
|
*/ |
||||||
|
protected function signRequest($method, $url, array $params) |
||||||
|
{ |
||||||
|
$signatureMethod = $this->getSignatureMethod(); |
||||||
|
$params['oauth_signature_method'] = $signatureMethod->getName(); |
||||||
|
$signatureBaseString = $this->composeSignatureBaseString($method, $url, $params); |
||||||
|
$signatureKey = $this->composeSignatureKey(); |
||||||
|
$params['oauth_signature'] = $signatureMethod->generateSignature($signatureBaseString, $signatureKey); |
||||||
|
return $params; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates signature base string, which will be signed by {@link signatureMethod}. |
||||||
|
* @param string $method request method. |
||||||
|
* @param string $url request URL. |
||||||
|
* @param array $params request params. |
||||||
|
* @return string base signature string. |
||||||
|
*/ |
||||||
|
protected function composeSignatureBaseString($method, $url, array $params) |
||||||
|
{ |
||||||
|
unset($params['oauth_signature']); |
||||||
|
uksort($params, 'strcmp'); // Parameters are sorted by name, using lexicographical byte value ordering. Ref: Spec: 9.1.1 |
||||||
|
$parts = [ |
||||||
|
strtoupper($method), |
||||||
|
$url, |
||||||
|
http_build_query($params, '', '&', PHP_QUERY_RFC3986) |
||||||
|
]; |
||||||
|
$parts = array_map('rawurlencode', $parts); |
||||||
|
return implode('&', $parts); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes request signature key. |
||||||
|
* @return string signature key. |
||||||
|
*/ |
||||||
|
protected function composeSignatureKey() |
||||||
|
{ |
||||||
|
$signatureKeyParts = [ |
||||||
|
$this->consumerSecret |
||||||
|
]; |
||||||
|
$accessToken = $this->getAccessToken(); |
||||||
|
if (is_object($accessToken)) { |
||||||
|
$signatureKeyParts[] = $accessToken->getTokenSecret(); |
||||||
|
} else { |
||||||
|
$signatureKeyParts[] = ''; |
||||||
|
} |
||||||
|
$signatureKeyParts = array_map('rawurlencode', $signatureKeyParts); |
||||||
|
return implode('&', $signatureKeyParts); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes authorization header content. |
||||||
|
* @param array $params request params. |
||||||
|
* @param string $realm authorization realm. |
||||||
|
* @return string authorization header content. |
||||||
|
*/ |
||||||
|
protected function composeAuthorizationHeader(array $params, $realm = '') |
||||||
|
{ |
||||||
|
$header = 'Authorization: OAuth'; |
||||||
|
$headerParams = []; |
||||||
|
if (!empty($realm)) { |
||||||
|
$headerParams[] = 'realm="' . rawurlencode($realm) . '"'; |
||||||
|
} |
||||||
|
foreach ($params as $key => $value) { |
||||||
|
if (substr($key, 0, 5) != 'oauth') { |
||||||
|
continue; |
||||||
|
} |
||||||
|
$headerParams[] = rawurlencode($key) . '="' . rawurlencode($value) . '"'; |
||||||
|
} |
||||||
|
if (!empty($headerParams)) { |
||||||
|
$header .= ' ' . implode(', ', $headerParams); |
||||||
|
} |
||||||
|
return $header; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
|
||||||
|
use Yii; |
||||||
|
use yii\base\Exception; |
||||||
|
|
||||||
|
/** |
||||||
|
* OAuth2 serves as a client for the OAuth 2 flow. |
||||||
|
* |
||||||
|
* In oder to acquire access token perform following sequence: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* use yii\authclient\OAuth2; |
||||||
|
* |
||||||
|
* $oauthClient = new OAuth2(); |
||||||
|
* $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 OAuth2 extends BaseOAuth |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @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 OAuthToken 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 OAuthToken $accessToken actual access token. |
||||||
|
* @param string $url absolute API URL. |
||||||
|
* @param string $method request method. |
||||||
|
* @param array $params request parameters. |
||||||
|
* @return array API response. |
||||||
|
* @throws Exception on failure. |
||||||
|
*/ |
||||||
|
protected function apiInternal($accessToken, $url, $method, array $params) |
||||||
|
{ |
||||||
|
$params['access_token'] = $accessToken->getToken(); |
||||||
|
return $this->sendRequest($method, $url, $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets new auth token to replace expired one. |
||||||
|
* @param OAuthToken $token expired auth token. |
||||||
|
* @return OAuthToken new auth token. |
||||||
|
*/ |
||||||
|
public function refreshAccessToken(OAuthToken $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 OAuthToken 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; |
||||||
|
|
||||||
|
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 OAuthToken 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,928 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient; |
||||||
|
|
||||||
|
use yii\base\Exception; |
||||||
|
use yii\base\NotSupportedException; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
/** |
||||||
|
* OpenId provides a simple interface for OpenID (1.1 and 2.0) authentication. |
||||||
|
* Supports Yadis and HTML discovery. |
||||||
|
* |
||||||
|
* Usage: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* use yii\authclient\OpenId; |
||||||
|
* |
||||||
|
* $client = new OpenId(); |
||||||
|
* $client->authUrl = 'https://open.id.provider.url'; // Setup provider endpoint |
||||||
|
* $url = $client->buildAuthUrl(); // Get authentication URL |
||||||
|
* return Yii::$app->getResponse()->redirect($url); // Redirect to authentication URL |
||||||
|
* // After user returns at our site: |
||||||
|
* if ($client->validate()) { // validate response |
||||||
|
* $userAttributes = $client->getUserAttributes(); // get account info |
||||||
|
* ... |
||||||
|
* } |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* AX and SREG extensions are supported. |
||||||
|
* To use them, specify [[requiredAttributes]] and/or [[optionalAttributes]]. |
||||||
|
* |
||||||
|
* @see http://openid.net/ |
||||||
|
* |
||||||
|
* @property string $returnUrl authentication return URL. |
||||||
|
* @property string $claimedId claimed identifier (identity). |
||||||
|
* @property string $trustRoot client trust root (realm), by default [[\yii\web\Request::hostInfo]] value will be used. |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class OpenId extends BaseClient implements ClientInterface |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string authentication base URL, which should be used to compose actual authentication URL |
||||||
|
* by [[buildAuthUrl()]] method. |
||||||
|
*/ |
||||||
|
public $authUrl; |
||||||
|
/** |
||||||
|
* @var array list of attributes, which always should be returned from server. |
||||||
|
* Attribute names should be always specified in AX format. |
||||||
|
* For example: |
||||||
|
* ~~~ |
||||||
|
* ['namePerson/friendly', 'contact/email'] |
||||||
|
* ~~~ |
||||||
|
*/ |
||||||
|
public $requiredAttributes = []; |
||||||
|
/** |
||||||
|
* @var array list of attributes, which could be returned from server. |
||||||
|
* Attribute names should be always specified in AX format. |
||||||
|
* For example: |
||||||
|
* ~~~ |
||||||
|
* ['namePerson/first', 'namePerson/last'] |
||||||
|
* ~~~ |
||||||
|
*/ |
||||||
|
public $optionalAttributes = []; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var boolean whether to verify the peer's certificate. |
||||||
|
*/ |
||||||
|
public $verifyPeer; |
||||||
|
/** |
||||||
|
* @var string directory that holds multiple CA certificates. |
||||||
|
* This value will take effect only if [[verifyPeer]] is set. |
||||||
|
*/ |
||||||
|
public $capath; |
||||||
|
/** |
||||||
|
* @var string the name of a file holding one or more certificates to verify the peer with. |
||||||
|
* This value will take effect only if [[verifyPeer]] is set. |
||||||
|
*/ |
||||||
|
public $cainfo; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var string authentication return URL. |
||||||
|
*/ |
||||||
|
private $_returnUrl; |
||||||
|
/** |
||||||
|
* @var string claimed identifier (identity) |
||||||
|
*/ |
||||||
|
private $_claimedId; |
||||||
|
/** |
||||||
|
* @var string client trust root (realm), by default [[\yii\web\Request::hostInfo]] value will be used. |
||||||
|
*/ |
||||||
|
private $_trustRoot; |
||||||
|
/** |
||||||
|
* @var array data, which should be used to retrieve the OpenID response. |
||||||
|
* If not set combination of GET and POST will be used. |
||||||
|
*/ |
||||||
|
public $data; |
||||||
|
/** |
||||||
|
* @var array map of matches between AX and SREG attribute names in format: axAttributeName => sregAttributeName |
||||||
|
*/ |
||||||
|
public $axToSregMap = [ |
||||||
|
'namePerson/friendly' => 'nickname', |
||||||
|
'contact/email' => 'email', |
||||||
|
'namePerson' => 'fullname', |
||||||
|
'birthDate' => 'dob', |
||||||
|
'person/gender' => 'gender', |
||||||
|
'contact/postalCode/home' => 'postcode', |
||||||
|
'contact/country/home' => 'country', |
||||||
|
'pref/language' => 'language', |
||||||
|
'pref/timezone' => 'timezone', |
||||||
|
]; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public function init() |
||||||
|
{ |
||||||
|
if ($this->data === null) { |
||||||
|
$this->data = array_merge($_GET, $_POST); // OPs may send data as POST or GET. |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $claimedId claimed identifier (identity). |
||||||
|
*/ |
||||||
|
public function setClaimedId($claimedId) |
||||||
|
{ |
||||||
|
$this->_claimedId = $claimedId; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string claimed identifier (identity). |
||||||
|
*/ |
||||||
|
public function getClaimedId() |
||||||
|
{ |
||||||
|
if ($this->_claimedId === null) { |
||||||
|
if (isset($this->data['openid_claimed_id'])) { |
||||||
|
$this->_claimedId = $this->data['openid_claimed_id']; |
||||||
|
} elseif (isset($this->data['openid_identity'])) { |
||||||
|
$this->_claimedId = $this->data['openid_identity']; |
||||||
|
} |
||||||
|
} |
||||||
|
return $this->_claimedId; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $returnUrl authentication return URL. |
||||||
|
*/ |
||||||
|
public function setReturnUrl($returnUrl) |
||||||
|
{ |
||||||
|
$this->_returnUrl = $returnUrl; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string authentication return URL. |
||||||
|
*/ |
||||||
|
public function getReturnUrl() |
||||||
|
{ |
||||||
|
if ($this->_returnUrl === null) { |
||||||
|
$this->_returnUrl = $this->defaultReturnUrl(); |
||||||
|
} |
||||||
|
return $this->_returnUrl; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $value client trust root (realm). |
||||||
|
*/ |
||||||
|
public function setTrustRoot($value) |
||||||
|
{ |
||||||
|
$this->_trustRoot = $value; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string client trust root (realm). |
||||||
|
*/ |
||||||
|
public function getTrustRoot() |
||||||
|
{ |
||||||
|
if ($this->_trustRoot === null) { |
||||||
|
$this->_trustRoot = Yii::$app->getRequest()->getHostInfo(); |
||||||
|
} |
||||||
|
return $this->_trustRoot; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generates default [[returnUrl]] value. |
||||||
|
* @return string default authentication return URL. |
||||||
|
*/ |
||||||
|
protected function defaultReturnUrl() |
||||||
|
{ |
||||||
|
$params = $_GET; |
||||||
|
foreach ($params as $name => $value) { |
||||||
|
if (strncmp('openid', $name, 6) === 0) { |
||||||
|
unset($params[$name]); |
||||||
|
} |
||||||
|
} |
||||||
|
$url = Yii::$app->getUrlManager()->createUrl(Yii::$app->requestedRoute, $params); |
||||||
|
return $this->getTrustRoot() . $url; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if the server specified in the url exists. |
||||||
|
* @param string $url URL to check |
||||||
|
* @return boolean true, if the server exists; false otherwise |
||||||
|
*/ |
||||||
|
public function hostExists($url) |
||||||
|
{ |
||||||
|
if (strpos($url, '/') === false) { |
||||||
|
$server = $url; |
||||||
|
} else { |
||||||
|
$server = @parse_url($url, PHP_URL_HOST); |
||||||
|
} |
||||||
|
if (!$server) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$ips = gethostbynamel($server); |
||||||
|
return !empty($ips); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sends HTTP request. |
||||||
|
* @param string $url request URL. |
||||||
|
* @param string $method request method. |
||||||
|
* @param array $params request params. |
||||||
|
* @return array|string response. |
||||||
|
* @throws \yii\base\Exception on failure. |
||||||
|
*/ |
||||||
|
protected function sendCurlRequest($url, $method = 'GET', $params = []) |
||||||
|
{ |
||||||
|
$params = http_build_query($params, '', '&'); |
||||||
|
$curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : '')); |
||||||
|
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); |
||||||
|
curl_setopt($curl, CURLOPT_HEADER, false); |
||||||
|
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); |
||||||
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); |
||||||
|
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*')); |
||||||
|
|
||||||
|
if ($this->verifyPeer !== null) { |
||||||
|
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifyPeer); |
||||||
|
if($this->capath) { |
||||||
|
curl_setopt($curl, CURLOPT_CAPATH, $this->capath); |
||||||
|
} |
||||||
|
if($this->cainfo) { |
||||||
|
curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ($method == 'POST') { |
||||||
|
curl_setopt($curl, CURLOPT_POST, true); |
||||||
|
curl_setopt($curl, CURLOPT_POSTFIELDS, $params); |
||||||
|
} elseif ($method == 'HEAD') { |
||||||
|
curl_setopt($curl, CURLOPT_HEADER, true); |
||||||
|
curl_setopt($curl, CURLOPT_NOBODY, true); |
||||||
|
} else { |
||||||
|
curl_setopt($curl, CURLOPT_HTTPGET, true); |
||||||
|
} |
||||||
|
$response = curl_exec($curl); |
||||||
|
|
||||||
|
if ($method == 'HEAD') { |
||||||
|
$headers = []; |
||||||
|
foreach (explode("\n", $response) as $header) { |
||||||
|
$pos = strpos($header, ':'); |
||||||
|
$name = strtolower(trim(substr($header, 0, $pos))); |
||||||
|
$headers[$name] = trim(substr($header, $pos+1)); |
||||||
|
} |
||||||
|
return $headers; |
||||||
|
} |
||||||
|
|
||||||
|
if (curl_errno($curl)) { |
||||||
|
throw new Exception(curl_error($curl), curl_errno($curl)); |
||||||
|
} |
||||||
|
|
||||||
|
return $response; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sends HTTP request. |
||||||
|
* @param string $url request URL. |
||||||
|
* @param string $method request method. |
||||||
|
* @param array $params request params. |
||||||
|
* @return array|string response. |
||||||
|
* @throws \yii\base\Exception on failure. |
||||||
|
* @throws \yii\base\NotSupportedException if request method is not supported. |
||||||
|
*/ |
||||||
|
protected function sendStreamRequest($url, $method = 'GET', $params = []) |
||||||
|
{ |
||||||
|
if (!$this->hostExists($url)) { |
||||||
|
throw new Exception('Invalid request.'); |
||||||
|
} |
||||||
|
|
||||||
|
$params = http_build_query($params, '', '&'); |
||||||
|
switch ($method) { |
||||||
|
case 'GET': |
||||||
|
$options = [ |
||||||
|
'http' => [ |
||||||
|
'method' => 'GET', |
||||||
|
'header' => 'Accept: application/xrds+xml, */*', |
||||||
|
'ignore_errors' => true, |
||||||
|
] |
||||||
|
]; |
||||||
|
$url = $url . ($params ? '?' . $params : ''); |
||||||
|
break; |
||||||
|
case 'POST': |
||||||
|
$options = [ |
||||||
|
'http' => [ |
||||||
|
'method' => 'POST', |
||||||
|
'header' => 'Content-type: application/x-www-form-urlencoded', |
||||||
|
'content' => $params, |
||||||
|
'ignore_errors' => true, |
||||||
|
] |
||||||
|
]; |
||||||
|
break; |
||||||
|
case 'HEAD': |
||||||
|
/* We want to send a HEAD request, |
||||||
|
but since get_headers doesn't accept $context parameter, |
||||||
|
we have to change the defaults.*/ |
||||||
|
$default = stream_context_get_options(stream_context_get_default()); |
||||||
|
stream_context_get_default([ |
||||||
|
'http' => [ |
||||||
|
'method' => 'HEAD', |
||||||
|
'header' => 'Accept: application/xrds+xml, */*', |
||||||
|
'ignore_errors' => true, |
||||||
|
] |
||||||
|
]); |
||||||
|
|
||||||
|
$url = $url . ($params ? '?' . $params : ''); |
||||||
|
$headersTmp = get_headers($url); |
||||||
|
if (empty($headersTmp)) { |
||||||
|
return []; |
||||||
|
} |
||||||
|
|
||||||
|
// Parsing headers. |
||||||
|
$headers = []; |
||||||
|
foreach ($headersTmp as $header) { |
||||||
|
$pos = strpos($header, ':'); |
||||||
|
$name = strtolower(trim(substr($header, 0, $pos))); |
||||||
|
$headers[$name] = trim(substr($header, $pos + 1)); |
||||||
|
} |
||||||
|
|
||||||
|
// and restore them |
||||||
|
stream_context_get_default($default); |
||||||
|
return $headers; |
||||||
|
default: |
||||||
|
throw new NotSupportedException("Method {$method} not supported"); |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->verifyPeer) { |
||||||
|
$options = array_merge( |
||||||
|
$options, |
||||||
|
[ |
||||||
|
'ssl' => [ |
||||||
|
'verify_peer' => true, |
||||||
|
'capath' => $this->capath, |
||||||
|
'cafile' => $this->cainfo, |
||||||
|
] |
||||||
|
] |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
$context = stream_context_create($options); |
||||||
|
return file_get_contents($url, false, $context); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sends request to the server |
||||||
|
* @param string $url request URL. |
||||||
|
* @param string $method request method. |
||||||
|
* @param array $params request parameters. |
||||||
|
* @return array|string response. |
||||||
|
*/ |
||||||
|
protected function sendRequest($url, $method = 'GET', $params = []) |
||||||
|
{ |
||||||
|
if (function_exists('curl_init') && !ini_get('safe_mode')) { |
||||||
|
return $this->sendCurlRequest($url, $method, $params); |
||||||
|
} |
||||||
|
return $this->sendStreamRequest($url, $method, $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Combines given URLs into single one. |
||||||
|
* @param string $baseUrl base URL. |
||||||
|
* @param string|array $additionalUrl additional URL string or information array. |
||||||
|
* @return string composed URL. |
||||||
|
*/ |
||||||
|
protected function buildUrl($baseUrl, $additionalUrl) |
||||||
|
{ |
||||||
|
$baseUrl = parse_url($baseUrl); |
||||||
|
if (!is_array($additionalUrl)) { |
||||||
|
$additionalUrl = parse_url($additionalUrl); |
||||||
|
} |
||||||
|
|
||||||
|
if (isset($baseUrl['query'], $additionalUrl['query'])) { |
||||||
|
$additionalUrl['query'] = $baseUrl['query'] . '&' . $additionalUrl['query']; |
||||||
|
} |
||||||
|
|
||||||
|
$urlInfo = array_merge($baseUrl, $additionalUrl); |
||||||
|
$url = $urlInfo['scheme'] . '://' |
||||||
|
. (empty($urlInfo['username']) ? '' |
||||||
|
:(empty($urlInfo['password']) ? "{$urlInfo['username']}@" |
||||||
|
:"{$urlInfo['username']}:{$urlInfo['password']}@")) |
||||||
|
. $urlInfo['host'] |
||||||
|
. (empty($urlInfo['port']) ? '' : ":{$urlInfo['port']}") |
||||||
|
. (empty($urlInfo['path']) ? '' : $urlInfo['path']) |
||||||
|
. (empty($urlInfo['query']) ? '' : "?{$urlInfo['query']}") |
||||||
|
. (empty($urlInfo['fragment']) ? '' : "#{$urlInfo['fragment']}"); |
||||||
|
return $url; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Scans content for <meta>/<link> tags and extract information from them. |
||||||
|
* @param string $content HTML content to be be parsed. |
||||||
|
* @param string $tag name of the source tag. |
||||||
|
* @param string $matchAttributeName name of the source tag attribute, which should contain $matchAttributeValue |
||||||
|
* @param string $matchAttributeValue required value of $matchAttributeName |
||||||
|
* @param string $valueAttributeName name of the source tag attribute, which should contain searched value. |
||||||
|
* @return string|boolean searched value, "false" on failure. |
||||||
|
*/ |
||||||
|
protected function extractHtmlTagValue($content, $tag, $matchAttributeName, $matchAttributeValue, $valueAttributeName) |
||||||
|
{ |
||||||
|
preg_match_all("#<{$tag}[^>]*$matchAttributeName=['\"].*?$matchAttributeValue.*?['\"][^>]*$valueAttributeName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1); |
||||||
|
preg_match_all("#<{$tag}[^>]*$valueAttributeName=['\"](.+?)['\"][^>]*$matchAttributeName=['\"].*?$matchAttributeValue.*?['\"][^>]*/?>#i", $content, $matches2); |
||||||
|
$result = array_merge($matches1[1], $matches2[1]); |
||||||
|
return empty($result) ? false : $result[0]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs Yadis and HTML discovery. |
||||||
|
* @param string $url Identity URL. |
||||||
|
* @return array OpenID provider info, following keys will be available: |
||||||
|
* - 'url' - string OP Endpoint (i.e. OpenID provider address). |
||||||
|
* - 'version' - integer OpenID protocol version used by provider. |
||||||
|
* - 'identity' - string identity value. |
||||||
|
* - 'identifier_select' - boolean whether to request OP to select identity for an user in OpenID 2, does not affect OpenID 1. |
||||||
|
* - 'ax' - boolean whether AX attributes should be used. |
||||||
|
* - 'sreg' - boolean whether SREG attributes should be used. |
||||||
|
* @throws Exception on failure. |
||||||
|
*/ |
||||||
|
public function discover($url) |
||||||
|
{ |
||||||
|
if (empty($url)) { |
||||||
|
throw new Exception('No identity supplied.'); |
||||||
|
} |
||||||
|
$result = [ |
||||||
|
'url' => null, |
||||||
|
'version' => null, |
||||||
|
'identity' => $url, |
||||||
|
'identifier_select' => false, |
||||||
|
'ax' => false, |
||||||
|
'sreg' => false, |
||||||
|
]; |
||||||
|
|
||||||
|
// Use xri.net proxy to resolve i-name identities |
||||||
|
if (!preg_match('#^https?:#', $url)) { |
||||||
|
$url = 'https://xri.net/' . $url; |
||||||
|
} |
||||||
|
|
||||||
|
/* We save the original url in case of Yadis discovery failure. |
||||||
|
It can happen when we'll be lead to an XRDS document |
||||||
|
which does not have any OpenID2 services.*/ |
||||||
|
$originalUrl = $url; |
||||||
|
|
||||||
|
// A flag to disable yadis discovery in case of failure in headers. |
||||||
|
$yadis = true; |
||||||
|
|
||||||
|
// We'll jump a maximum of 5 times, to avoid endless redirections. |
||||||
|
for ($i = 0; $i < 5; $i ++) { |
||||||
|
if ($yadis) { |
||||||
|
$headers = $this->sendRequest($url, 'HEAD'); |
||||||
|
|
||||||
|
$next = false; |
||||||
|
if (isset($headers['x-xrds-location'])) { |
||||||
|
$url = $this->buildUrl($url, trim($headers['x-xrds-location'])); |
||||||
|
$next = true; |
||||||
|
} |
||||||
|
|
||||||
|
if (isset($headers['content-type']) |
||||||
|
&& (strpos($headers['content-type'], 'application/xrds+xml') !== false |
||||||
|
|| strpos($headers['content-type'], 'text/xml') !== false) |
||||||
|
) { |
||||||
|
/* Apparently, some providers return XRDS documents as text/html. |
||||||
|
While it is against the spec, allowing this here shouldn't break |
||||||
|
compatibility with anything. |
||||||
|
--- |
||||||
|
Found an XRDS document, now let's find the server, and optionally delegate.*/ |
||||||
|
$content = $this->sendRequest($url, 'GET'); |
||||||
|
|
||||||
|
preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m); |
||||||
|
foreach ($m[1] as $content) { |
||||||
|
$content = ' ' . $content; // The space is added, so that strpos doesn't return 0. |
||||||
|
|
||||||
|
// OpenID 2 |
||||||
|
$ns = preg_quote('http://specs.openid.net/auth/2.0/'); |
||||||
|
if (preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) { |
||||||
|
if ($type[1] == 'server') { |
||||||
|
$result['identifier_select'] = true; |
||||||
|
} |
||||||
|
|
||||||
|
preg_match('#<URI.*?>(.*)</URI>#', $content, $server); |
||||||
|
preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate); |
||||||
|
if (empty($server)) { |
||||||
|
throw new Exception('No servers found!'); |
||||||
|
} |
||||||
|
// Does the server advertise support for either AX or SREG? |
||||||
|
$result['ax'] = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>'); |
||||||
|
$result['sreg'] = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); |
||||||
|
|
||||||
|
$server = $server[1]; |
||||||
|
if (isset($delegate[2])) { |
||||||
|
$result['identity'] = trim($delegate[2]); |
||||||
|
} |
||||||
|
|
||||||
|
$result['url'] = $server; |
||||||
|
$result['version'] = 2; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
// OpenID 1.1 |
||||||
|
$ns = preg_quote('http://openid.net/signon/1.1'); |
||||||
|
if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) { |
||||||
|
preg_match('#<URI.*?>(.*)</URI>#', $content, $server); |
||||||
|
preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate); |
||||||
|
if (empty($server)) { |
||||||
|
throw new Exception('No servers found!'); |
||||||
|
} |
||||||
|
// AX can be used only with OpenID 2.0, so checking only SREG |
||||||
|
$result['sreg'] = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); |
||||||
|
|
||||||
|
$server = $server[1]; |
||||||
|
if (isset($delegate[1])) { |
||||||
|
$result['identity'] = $delegate[1]; |
||||||
|
} |
||||||
|
|
||||||
|
$result['url'] = $server; |
||||||
|
$result['version'] = 1; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
$next = true; |
||||||
|
$yadis = false; |
||||||
|
$url = $originalUrl; |
||||||
|
$content = null; |
||||||
|
break; |
||||||
|
} |
||||||
|
if ($next) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// There are no relevant information in headers, so we search the body. |
||||||
|
$content = $this->sendRequest($url, 'GET'); |
||||||
|
$location = $this->extractHtmlTagValue($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content'); |
||||||
|
if ($location) { |
||||||
|
$url = $this->buildUrl($url, $location); |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!isset($content)) { |
||||||
|
$content = $this->sendRequest($url, 'GET'); |
||||||
|
} |
||||||
|
|
||||||
|
// At this point, the YADIS Discovery has failed, so we'll switch to openid2 HTML discovery, then fallback to openid 1.1 discovery. |
||||||
|
$server = $this->extractHtmlTagValue($content, 'link', 'rel', 'openid2.provider', 'href'); |
||||||
|
if (!$server) { |
||||||
|
// The same with openid 1.1 |
||||||
|
$server = $this->extractHtmlTagValue($content, 'link', 'rel', 'openid.server', 'href'); |
||||||
|
$delegate = $this->extractHtmlTagValue($content, 'link', 'rel', 'openid.delegate', 'href'); |
||||||
|
$version = 1; |
||||||
|
} else { |
||||||
|
$delegate = $this->extractHtmlTagValue($content, 'link', 'rel', 'openid2.local_id', 'href'); |
||||||
|
$version = 2; |
||||||
|
} |
||||||
|
|
||||||
|
if ($server) { |
||||||
|
// We found an OpenID2 OP Endpoint |
||||||
|
if ($delegate) { |
||||||
|
// We have also found an OP-Local ID. |
||||||
|
$result['identity'] = $delegate; |
||||||
|
} |
||||||
|
$result['url'] = $server; |
||||||
|
$result['version'] = $version; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
throw new Exception('No servers found!'); |
||||||
|
} |
||||||
|
throw new Exception('Endless redirection!'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes SREG request parameters. |
||||||
|
* @return array SREG parameters. |
||||||
|
*/ |
||||||
|
protected function buildSregParams() |
||||||
|
{ |
||||||
|
$params = []; |
||||||
|
/* We always use SREG 1.1, even if the server is advertising only support for 1.0. |
||||||
|
That's because it's fully backwards compatibile with 1.0, and some providers |
||||||
|
advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com */ |
||||||
|
$params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1'; |
||||||
|
if (!empty($this->requiredAttributes)) { |
||||||
|
$params['openid.sreg.required'] = []; |
||||||
|
foreach ($this->requiredAttributes as $required) { |
||||||
|
if (!isset($this->axToSregMap[$required])) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
$params['openid.sreg.required'][] = $this->axToSregMap[$required]; |
||||||
|
} |
||||||
|
$params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']); |
||||||
|
} |
||||||
|
|
||||||
|
if (!empty($this->optionalAttributes)) { |
||||||
|
$params['openid.sreg.optional'] = []; |
||||||
|
foreach ($this->optionalAttributes as $optional) { |
||||||
|
if (!isset($this->axToSregMap[$optional])) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
$params['openid.sreg.optional'][] = $this->axToSregMap[$optional]; |
||||||
|
} |
||||||
|
$params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']); |
||||||
|
} |
||||||
|
return $params; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes AX request parameters. |
||||||
|
* @return array AX parameters. |
||||||
|
*/ |
||||||
|
protected function buildAxParams() |
||||||
|
{ |
||||||
|
$params = []; |
||||||
|
if (!empty($this->requiredAttributes) || !empty($this->optionalAttributes)) { |
||||||
|
$params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0'; |
||||||
|
$params['openid.ax.mode'] = 'fetch_request'; |
||||||
|
$aliases = []; |
||||||
|
$counts = []; |
||||||
|
$required = []; |
||||||
|
$optional = []; |
||||||
|
foreach (['requiredAttributes', 'optionalAttributes'] as $type) { |
||||||
|
foreach ($this->$type as $alias => $field) { |
||||||
|
if (is_int($alias)) { |
||||||
|
$alias = strtr($field, '/', '_'); |
||||||
|
} |
||||||
|
$aliases[$alias] = 'http://axschema.org/' . $field; |
||||||
|
if (empty($counts[$alias])) { |
||||||
|
$counts[$alias] = 0; |
||||||
|
} |
||||||
|
$counts[$alias] += 1; |
||||||
|
${$type}[] = $alias; |
||||||
|
} |
||||||
|
} |
||||||
|
foreach ($aliases as $alias => $ns) { |
||||||
|
$params['openid.ax.type.' . $alias] = $ns; |
||||||
|
} |
||||||
|
foreach ($counts as $alias => $count) { |
||||||
|
if ($count == 1) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
$params['openid.ax.count.' . $alias] = $count; |
||||||
|
} |
||||||
|
|
||||||
|
// Don't send empty ax.requied and ax.if_available. |
||||||
|
// Google and possibly other providers refuse to support ax when one of these is empty. |
||||||
|
if ($required) { |
||||||
|
$params['openid.ax.required'] = implode(',', $required); |
||||||
|
} |
||||||
|
if ($optional) { |
||||||
|
$params['openid.ax.if_available'] = implode(',', $optional); |
||||||
|
} |
||||||
|
} |
||||||
|
return $params; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds authentication URL for the protocol version 1. |
||||||
|
* @param array $serverInfo OpenID server info. |
||||||
|
* @return string authentication URL. |
||||||
|
*/ |
||||||
|
protected function buildAuthUrlV1($serverInfo) |
||||||
|
{ |
||||||
|
$returnUrl = $this->getReturnUrl(); |
||||||
|
/* If we have an openid.delegate that is different from our claimed id, |
||||||
|
we need to somehow preserve the claimed id between requests. |
||||||
|
The simplest way is to just send it along with the return_to url.*/ |
||||||
|
if ($serverInfo['identity'] != $this->getClaimedId()) { |
||||||
|
$returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->getClaimedId(); |
||||||
|
} |
||||||
|
|
||||||
|
$params = array_merge( |
||||||
|
$this->buildSregParams(), |
||||||
|
[ |
||||||
|
'openid.return_to' => $returnUrl, |
||||||
|
'openid.mode' => 'checkid_setup', |
||||||
|
'openid.identity' => $serverInfo['identity'], |
||||||
|
'openid.trust_root' => $this->trustRoot, |
||||||
|
] |
||||||
|
); |
||||||
|
|
||||||
|
return $this->buildUrl($serverInfo['url'], ['query' => http_build_query($params, '', '&')]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds authentication URL for the protocol version 2. |
||||||
|
* @param array $serverInfo OpenID server info. |
||||||
|
* @return string authentication URL. |
||||||
|
*/ |
||||||
|
protected function buildAuthUrlV2($serverInfo) |
||||||
|
{ |
||||||
|
$params = [ |
||||||
|
'openid.ns' => 'http://specs.openid.net/auth/2.0', |
||||||
|
'openid.mode' => 'checkid_setup', |
||||||
|
'openid.return_to' => $this->getReturnUrl(), |
||||||
|
'openid.realm' => $this->getTrustRoot(), |
||||||
|
]; |
||||||
|
if ($serverInfo['ax']) { |
||||||
|
$params = array_merge($this->buildAxParams(), $params); |
||||||
|
} |
||||||
|
if ($serverInfo['sreg']) { |
||||||
|
$params = array_merge($this->buildSregParams(), $params); |
||||||
|
} |
||||||
|
if (!$serverInfo['ax'] && !$serverInfo['sreg']) { |
||||||
|
// If OP doesn't advertise either SREG, nor AX, let's send them both in worst case we don't get anything in return. |
||||||
|
$params = array_merge($this->buildSregParams(), $this->buildAxParams(), $params); |
||||||
|
} |
||||||
|
|
||||||
|
if ($serverInfo['identifier_select']) { |
||||||
|
$url = 'http://specs.openid.net/auth/2.0/identifier_select'; |
||||||
|
$params['openid.identity'] = $url; |
||||||
|
$params['openid.claimed_id']= $url; |
||||||
|
} else { |
||||||
|
$params['openid.identity'] = $serverInfo['identity']; |
||||||
|
$params['openid.claimed_id'] = $this->getClaimedId(); |
||||||
|
} |
||||||
|
return $this->buildUrl($serverInfo['url'], ['query' => http_build_query($params, '', '&')]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns authentication URL. Usually, you want to redirect your user to it. |
||||||
|
* @param boolean $identifierSelect whether to request OP to select identity for an user in OpenID 2, does not affect OpenID 1. |
||||||
|
* @return string the authentication URL. |
||||||
|
* @throws Exception on failure. |
||||||
|
*/ |
||||||
|
public function buildAuthUrl($identifierSelect = null) |
||||||
|
{ |
||||||
|
$authUrl = $this->authUrl; |
||||||
|
$claimedId = $this->getClaimedId(); |
||||||
|
if (empty($claimedId)) { |
||||||
|
$this->setClaimedId($authUrl); |
||||||
|
} |
||||||
|
$serverInfo = $this->discover($authUrl); |
||||||
|
if ($serverInfo['version'] == 2) { |
||||||
|
if ($identifierSelect !== null) { |
||||||
|
$serverInfo['identifier_select'] = $identifierSelect; |
||||||
|
} |
||||||
|
return $this->buildAuthUrlV2($serverInfo); |
||||||
|
} |
||||||
|
return $this->buildAuthUrlV1($serverInfo); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs OpenID verification with the OP. |
||||||
|
* @param boolean $validateRequiredAttributes whether to validate required attributes. |
||||||
|
* @return boolean whether the verification was successful. |
||||||
|
*/ |
||||||
|
public function validate($validateRequiredAttributes = true) |
||||||
|
{ |
||||||
|
$claimedId = $this->getClaimedId(); |
||||||
|
if (empty($claimedId)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$params = [ |
||||||
|
'openid.assoc_handle' => $this->data['openid_assoc_handle'], |
||||||
|
'openid.signed' => $this->data['openid_signed'], |
||||||
|
'openid.sig' => $this->data['openid_sig'], |
||||||
|
]; |
||||||
|
|
||||||
|
if (isset($this->data['openid_ns'])) { |
||||||
|
/* We're dealing with an OpenID 2.0 server, so let's set an ns |
||||||
|
Even though we should know location of the endpoint, |
||||||
|
we still need to verify it by discovery, so $server is not set here*/ |
||||||
|
$params['openid.ns'] = 'http://specs.openid.net/auth/2.0'; |
||||||
|
} elseif (isset($this->data['openid_claimed_id']) && $this->data['openid_claimed_id'] != $this->data['openid_identity']) { |
||||||
|
// If it's an OpenID 1 provider, and we've got claimed_id, |
||||||
|
// we have to append it to the returnUrl, like authUrlV1 does. |
||||||
|
$this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $claimedId; |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->data['openid_return_to'] != $this->returnUrl) { |
||||||
|
// The return_to url must match the url of current request. |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
$serverInfo = $this->discover($claimedId); |
||||||
|
|
||||||
|
foreach (explode(',', $this->data['openid_signed']) as $item) { |
||||||
|
$value = $this->data['openid_' . str_replace('.', '_', $item)]; |
||||||
|
$params['openid.' . $item] = $value; |
||||||
|
} |
||||||
|
|
||||||
|
$params['openid.mode'] = 'check_authentication'; |
||||||
|
|
||||||
|
$response = $this->sendRequest($serverInfo['url'], 'POST', $params); |
||||||
|
|
||||||
|
if (preg_match('/is_valid\s*:\s*true/i', $response)) { |
||||||
|
if ($validateRequiredAttributes) { |
||||||
|
return $this->validateRequiredAttributes(); |
||||||
|
} else { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if all required attributes are present in the server response. |
||||||
|
* @return boolean whether all required attributes are present. |
||||||
|
*/ |
||||||
|
protected function validateRequiredAttributes() |
||||||
|
{ |
||||||
|
if (!empty($this->requiredAttributes)) { |
||||||
|
$attributes = $this->fetchAttributes(); |
||||||
|
foreach ($this->requiredAttributes as $openIdAttributeName) { |
||||||
|
if (!isset($attributes[$openIdAttributeName])) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets AX attributes provided by OP. |
||||||
|
* @return array array of attributes. |
||||||
|
*/ |
||||||
|
protected function fetchAxAttributes() |
||||||
|
{ |
||||||
|
$alias = null; |
||||||
|
if (isset($this->data['openid_ns_ax']) && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0') { |
||||||
|
// It's the most likely case, so we'll check it before |
||||||
|
$alias = 'ax'; |
||||||
|
} else { |
||||||
|
// 'ax' prefix is either undefined, or points to another extension, so we search for another prefix |
||||||
|
foreach ($this->data as $key => $value) { |
||||||
|
if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_' && $value == 'http://openid.net/srv/ax/1.0') { |
||||||
|
$alias = substr($key, strlen('openid_ns_')); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (!$alias) { |
||||||
|
// An alias for AX schema has not been found, so there is no AX data in the OP's response |
||||||
|
return []; |
||||||
|
} |
||||||
|
|
||||||
|
$attributes = []; |
||||||
|
foreach ($this->data as $key => $value) { |
||||||
|
$keyMatch = 'openid_' . $alias . '_value_'; |
||||||
|
if (substr($key, 0, strlen($keyMatch)) != $keyMatch) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
$key = substr($key, strlen($keyMatch)); |
||||||
|
if (!isset($this->data['openid_' . $alias . '_type_' . $key])) { |
||||||
|
/* OP is breaking the spec by returning a field without |
||||||
|
associated ns. This shouldn't happen, but it's better |
||||||
|
to check, than cause an E_NOTICE.*/ |
||||||
|
continue; |
||||||
|
} |
||||||
|
$key = substr($this->data['openid_' . $alias . '_type_' . $key], strlen('http://axschema.org/')); |
||||||
|
$attributes[$key] = $value; |
||||||
|
} |
||||||
|
return $attributes; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets SREG attributes provided by OP. SREG names will be mapped to AX names. |
||||||
|
* @return array array of attributes with keys being the AX schema names, e.g. 'contact/email' |
||||||
|
*/ |
||||||
|
protected function fetchSregAttributes() |
||||||
|
{ |
||||||
|
$attributes = []; |
||||||
|
$sregToAx = array_flip($this->axToSregMap); |
||||||
|
foreach ($this->data as $key => $value) { |
||||||
|
$keyMatch = 'openid_sreg_'; |
||||||
|
if (substr($key, 0, strlen($keyMatch)) != $keyMatch) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
$key = substr($key, strlen($keyMatch)); |
||||||
|
if (!isset($sregToAx[$key])) { |
||||||
|
// The field name isn't part of the SREG spec, so we ignore it. |
||||||
|
continue; |
||||||
|
} |
||||||
|
$attributes[$sregToAx[$key]] = $value; |
||||||
|
} |
||||||
|
return $attributes; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets AX/SREG attributes provided by OP. Should be used only after successful validation. |
||||||
|
* Note that it does not guarantee that any of the required/optional parameters will be present, |
||||||
|
* or that there will be no other attributes besides those specified. |
||||||
|
* In other words. OP may provide whatever information it wants to. |
||||||
|
* SREG names will be mapped to AX names. |
||||||
|
* @return array array of attributes with keys being the AX schema names, e.g. 'contact/email' |
||||||
|
* @see http://www.axschema.org/types/ |
||||||
|
*/ |
||||||
|
public function fetchAttributes() |
||||||
|
{ |
||||||
|
if (isset($this->data['openid_ns']) && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0') { |
||||||
|
// OpenID 2.0 |
||||||
|
// We search for both AX and SREG attributes, with AX taking precedence. |
||||||
|
return array_merge($this->fetchSregAttributes(), $this->fetchAxAttributes()); |
||||||
|
} |
||||||
|
return $this->fetchSregAttributes(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function initUserAttributes() |
||||||
|
{ |
||||||
|
return array_merge(['id' => $this->getClaimedId()], $this->fetchAttributes()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,83 @@ |
|||||||
|
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 provides the ability of the authentication via external credentials providers. |
||||||
|
It covers OpenID, OAuth1 and OAuth2 protocols. |
||||||
|
|
||||||
|
You need to setup auth client collection application component: |
||||||
|
|
||||||
|
``` |
||||||
|
'components' => [ |
||||||
|
'authClientCollection' => [ |
||||||
|
'class' => 'yii\authclient\Collection', |
||||||
|
'clients' => [ |
||||||
|
'google' => [ |
||||||
|
'class' => 'yii\authclient\clients\GoogleOpenId' |
||||||
|
], |
||||||
|
'facebook' => [ |
||||||
|
'class' => 'yii\authclient\clients\Facebook', |
||||||
|
'clientId' => 'facebook_client_id', |
||||||
|
'clientSecret' => 'facebook_client_secret', |
||||||
|
], |
||||||
|
], |
||||||
|
] |
||||||
|
... |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
Then you need to apply [[yii\authclient\AuthAction]] to some of your web controllers: |
||||||
|
|
||||||
|
``` |
||||||
|
class SiteController extends Controller |
||||||
|
{ |
||||||
|
public function actions() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'auth' => [ |
||||||
|
'class' => 'yii\authclient\AuthAction', |
||||||
|
'successCallback' => [$this, 'successCallback'], |
||||||
|
], |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
|
public function successCallback($client) |
||||||
|
{ |
||||||
|
$atributes = $client->getUserAttributes(); |
||||||
|
// user login or signup comes here |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
You may use [[yii\authclient\widgets\Choice]] to compose auth client selection: |
||||||
|
|
||||||
|
``` |
||||||
|
<?= yii\authclient\Choice::widget([ |
||||||
|
'baseAuthUrl' => ['site/auth'] |
||||||
|
]); ?> |
||||||
|
``` |
@ -0,0 +1,82 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\clients; |
||||||
|
|
||||||
|
use yii\authclient\OAuth2; |
||||||
|
|
||||||
|
/** |
||||||
|
* Facebook allows authentication via Facebook OAuth. |
||||||
|
* In order to use Facebook OAuth you must register your application at [[https://developers.facebook.com/apps]]. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'facebook' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\Facebook', |
||||||
|
* 'clientId' => 'facebook_client_id', |
||||||
|
* 'clientSecret' => 'facebook_client_secret', |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @see https://developers.facebook.com/apps |
||||||
|
* @see http://developers.facebook.com/docs/reference/api |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Facebook extends OAuth2 |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $authUrl = 'https://www.facebook.com/dialog/oauth'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $tokenUrl = 'https://graph.facebook.com/oauth/access_token'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $apiBaseUrl = 'https://graph.facebook.com'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $scope = 'email'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function initUserAttributes() |
||||||
|
{ |
||||||
|
return $this->api('me', 'GET'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultName() |
||||||
|
{ |
||||||
|
return 'facebook'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultTitle() |
||||||
|
{ |
||||||
|
return 'Facebook'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\clients; |
||||||
|
|
||||||
|
use yii\authclient\OAuth2; |
||||||
|
|
||||||
|
/** |
||||||
|
* GitHub allows authentication via GitHub OAuth. |
||||||
|
* In order to use GitHub OAuth you must register your application at [[https://github.com/settings/applications/new]]. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'github' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\GitHub', |
||||||
|
* 'clientId' => 'github_client_id', |
||||||
|
* 'clientSecret' => 'github_client_secret', |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @see http://developer.github.com/v3/oauth/ |
||||||
|
* @see https://github.com/settings/applications/new |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class GitHub extends OAuth2 |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $authUrl = 'https://github.com/login/oauth/authorize'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $tokenUrl = 'https://github.com/login/oauth/access_token'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $apiBaseUrl = 'https://api.github.com'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public function init() |
||||||
|
{ |
||||||
|
parent::init(); |
||||||
|
if ($this->scope === null) { |
||||||
|
$this->scope = implode(' ', [ |
||||||
|
'user', |
||||||
|
'user:email', |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function initUserAttributes() |
||||||
|
{ |
||||||
|
return $this->api('user', 'GET'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\clients; |
||||||
|
|
||||||
|
use yii\authclient\OAuth2; |
||||||
|
|
||||||
|
/** |
||||||
|
* GoogleOAuth allows authentication via Google OAuth. |
||||||
|
* In order to use Google OAuth you must register your application at [[https://code.google.com/apis/console#access]]. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'google' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\GoogleOAuth', |
||||||
|
* 'clientId' => 'google_client_id', |
||||||
|
* 'clientSecret' => 'google_client_secret', |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @see https://code.google.com/apis/console#access |
||||||
|
* @see https://developers.google.com/google-apps/contacts/v3/ |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class GoogleOAuth extends OAuth2 |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $authUrl = 'https://accounts.google.com/o/oauth2/auth'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $tokenUrl = 'https://accounts.google.com/o/oauth2/token'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $apiBaseUrl = 'https://www.googleapis.com/oauth2/v1'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public function init() |
||||||
|
{ |
||||||
|
parent::init(); |
||||||
|
if ($this->scope === null) { |
||||||
|
$this->scope = implode(' ', [ |
||||||
|
'https://www.googleapis.com/auth/userinfo.profile', |
||||||
|
'https://www.googleapis.com/auth/userinfo.email', |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function initUserAttributes() |
||||||
|
{ |
||||||
|
return $this->api('userinfo', 'GET'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultName() |
||||||
|
{ |
||||||
|
return 'google'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultTitle() |
||||||
|
{ |
||||||
|
return 'Google'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\clients; |
||||||
|
|
||||||
|
use yii\authclient\OpenId; |
||||||
|
|
||||||
|
/** |
||||||
|
* GoogleOpenId allows authentication via Google OpenId. |
||||||
|
* Unlike Google OAuth you do not need to register your application anywhere in order to use Google OpenId. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'google' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\GoogleOpenId' |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class GoogleOpenId extends OpenId |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $authUrl = 'https://www.google.com/accounts/o8/id'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $requiredAttributes = [ |
||||||
|
'namePerson/first', |
||||||
|
'namePerson/last', |
||||||
|
'contact/email', |
||||||
|
'pref/language', |
||||||
|
]; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultNormalizeUserAttributeMap() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'first_name' => 'namePerson/first', |
||||||
|
'last_name' => 'namePerson/last', |
||||||
|
'email' => 'contact/email', |
||||||
|
'language' => 'pref/language', |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultViewOptions() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'popupWidth' => 880, |
||||||
|
'popupHeight' => 520, |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultName() |
||||||
|
{ |
||||||
|
return 'google'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultTitle() |
||||||
|
{ |
||||||
|
return 'Google'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,167 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\clients; |
||||||
|
|
||||||
|
use yii\authclient\OAuth2; |
||||||
|
use yii\web\HttpException; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
/** |
||||||
|
* LinkedIn allows authentication via LinkedIn OAuth. |
||||||
|
* In order to use linkedIn OAuth you must register your application at [[https://www.linkedin.com/secure/developer]]. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'linkedin' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\LinkedIn', |
||||||
|
* 'clientId' => 'linkedin_client_id', |
||||||
|
* 'clientSecret' => 'linkedin_client_secret', |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @see http://developer.linkedin.com/documents/authentication |
||||||
|
* @see https://www.linkedin.com/secure/developer |
||||||
|
* @see http://developer.linkedin.com/apis |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class LinkedIn extends OAuth2 |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $authUrl = 'https://www.linkedin.com/uas/oauth2/authorization'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $tokenUrl = 'https://www.linkedin.com/uas/oauth2/accessToken'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $apiBaseUrl = 'https://api.linkedin.com/v1'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public function init() |
||||||
|
{ |
||||||
|
parent::init(); |
||||||
|
if ($this->scope === null) { |
||||||
|
$this->scope = implode(' ', [ |
||||||
|
'r_basicprofile', |
||||||
|
'r_emailaddress', |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultNormalizeUserAttributeMap() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'email' => 'email-address', |
||||||
|
'first_name' => 'first-name', |
||||||
|
'last_name' => 'last-name', |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function initUserAttributes() |
||||||
|
{ |
||||||
|
$attributeNames = [ |
||||||
|
'id', |
||||||
|
'email-address', |
||||||
|
'first-name', |
||||||
|
'last-name', |
||||||
|
'public-profile-url', |
||||||
|
]; |
||||||
|
return $this->api('people/~:(' . implode(',', $attributeNames) . ')', 'GET'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public function buildAuthUrl(array $params = []) |
||||||
|
{ |
||||||
|
$authState = $this->generateAuthState(); |
||||||
|
$this->setState('authState', $authState); |
||||||
|
$params['state'] = $authState; |
||||||
|
return parent::buildAuthUrl($params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public function fetchAccessToken($authCode, array $params = []) |
||||||
|
{ |
||||||
|
$authState = $this->getState('authState'); |
||||||
|
if (!isset($_REQUEST['state']) || empty($authState) || strcmp($_REQUEST['state'], $authState) !== 0) { |
||||||
|
throw new HttpException(400, 'Invalid auth state parameter.'); |
||||||
|
} else { |
||||||
|
$this->removeState('authState'); |
||||||
|
} |
||||||
|
return parent::fetchAccessToken($authCode, $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function apiInternal($accessToken, $url, $method, array $params) |
||||||
|
{ |
||||||
|
$params['oauth2_access_token'] = $accessToken->getToken(); |
||||||
|
return $this->sendRequest($method, $url, $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultReturnUrl() |
||||||
|
{ |
||||||
|
$params = $_GET; |
||||||
|
unset($params['code']); |
||||||
|
unset($params['state']); |
||||||
|
return Yii::$app->getUrlManager()->createAbsoluteUrl(Yii::$app->controller->getRoute(), $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generates the auth state value. |
||||||
|
* @return string auth state value. |
||||||
|
*/ |
||||||
|
protected function generateAuthState() { |
||||||
|
return sha1(uniqid(get_class($this), true)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultName() |
||||||
|
{ |
||||||
|
return 'linkedin'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultTitle() |
||||||
|
{ |
||||||
|
return 'LinkedIn'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\clients; |
||||||
|
|
||||||
|
use yii\authclient\OAuth1; |
||||||
|
|
||||||
|
/** |
||||||
|
* Twitter allows authentication via Twitter OAuth. |
||||||
|
* In order to use Twitter OAuth you must register your application at [[https://dev.twitter.com/apps/new]]. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'twitter' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\Twitter', |
||||||
|
* 'consumerKey' => 'twitter_consumer_key', |
||||||
|
* 'consumerSecret' => 'twitter_consumer_secret', |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @see https://dev.twitter.com/apps/new |
||||||
|
* @see https://dev.twitter.com/docs/api |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Twitter extends OAuth1 |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $authUrl = 'https://api.twitter.com/oauth/authorize'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $requestTokenUrl = 'https://api.twitter.com/oauth/request_token'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $requestTokenMethod = 'POST'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $accessTokenUrl = 'https://api.twitter.com/oauth/access_token'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $accessTokenMethod = 'POST'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $apiBaseUrl = 'https://api.twitter.com/1.1'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function initUserAttributes() |
||||||
|
{ |
||||||
|
return $this->api('account/verify_credentials.json', 'GET'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultName() |
||||||
|
{ |
||||||
|
return 'twitter'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultTitle() |
||||||
|
{ |
||||||
|
return 'Twitter'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\clients; |
||||||
|
|
||||||
|
use yii\authclient\OAuth2; |
||||||
|
|
||||||
|
/** |
||||||
|
* YandexOAuth allows authentication via Yandex OAuth. |
||||||
|
* In order to use Yandex OAuth you must register your application at [[https://oauth.yandex.ru/client/new]]. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'yandex' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\YandexOAuth', |
||||||
|
* 'clientId' => 'yandex_client_id', |
||||||
|
* 'clientSecret' => 'yandex_client_secret', |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @see https://oauth.yandex.ru/client/new |
||||||
|
* @see http://api.yandex.ru/login/doc/dg/reference/response.xml |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class YandexOAuth extends OAuth2 |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $authUrl = 'https://oauth.yandex.ru/authorize'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $tokenUrl = 'https://oauth.yandex.ru/token'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $apiBaseUrl = 'https://login.yandex.ru'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function initUserAttributes() |
||||||
|
{ |
||||||
|
return $this->api('info', 'GET'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function apiInternal($accessToken, $url, $method, array $params) |
||||||
|
{ |
||||||
|
if (!isset($params['format'])) { |
||||||
|
$params['format'] = 'json'; |
||||||
|
} |
||||||
|
$params['oauth_token'] = $accessToken->getToken(); |
||||||
|
return $this->sendRequest($method, $url, $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultName() |
||||||
|
{ |
||||||
|
return 'yandex'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultTitle() |
||||||
|
{ |
||||||
|
return 'Yandex'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\clients; |
||||||
|
|
||||||
|
use yii\authclient\OpenId; |
||||||
|
|
||||||
|
/** |
||||||
|
* YandexOpenId allows authentication via Yandex OpenId. |
||||||
|
* Unlike Yandex OAuth you do not need to register your application anywhere in order to use Yandex OpenId. |
||||||
|
* |
||||||
|
* Example application configuration: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* 'components' => [ |
||||||
|
* 'authClientCollection' => [ |
||||||
|
* 'class' => 'yii\authclient\Collection', |
||||||
|
* 'clients' => [ |
||||||
|
* 'yandex' => [ |
||||||
|
* 'class' => 'yii\authclient\clients\YandexOpenId' |
||||||
|
* ], |
||||||
|
* ], |
||||||
|
* ] |
||||||
|
* ... |
||||||
|
* ] |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class YandexOpenId extends OpenId |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $authUrl = 'http://openid.yandex.ru'; |
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
public $requiredAttributes = [ |
||||||
|
'namePerson', |
||||||
|
'contact/email', |
||||||
|
]; |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultNormalizeUserAttributeMap() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'name' => 'namePerson', |
||||||
|
'email' => 'contact/email', |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultViewOptions() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'popupWidth' => 900, |
||||||
|
'popupHeight' => 550, |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultName() |
||||||
|
{ |
||||||
|
return 'yandex'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
protected function defaultTitle() |
||||||
|
{ |
||||||
|
return 'Yandex'; |
||||||
|
} |
||||||
|
} |
@ -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,51 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\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\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\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\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,38 @@ |
|||||||
|
<?php |
||||||
|
use yii\helpers\Html; |
||||||
|
use yii\helpers\Json; |
||||||
|
|
||||||
|
/* @var $this \yii\base\View */ |
||||||
|
/* @var $url string */ |
||||||
|
/* @var $enforceRedirect boolean */ |
||||||
|
|
||||||
|
$redirectJavaScript = <<<EOL |
||||||
|
function popupWindowRedirect(url, enforceRedirect = true) { |
||||||
|
if (window.opener) { |
||||||
|
window.close(); |
||||||
|
if (enforceRedirect) { |
||||||
|
window.opener.location = url; |
||||||
|
} |
||||||
|
} else { |
||||||
|
window.location = url; |
||||||
|
} |
||||||
|
} |
||||||
|
EOL; |
||||||
|
|
||||||
|
$redirectJavaScript .= 'popupWindowRedirect(' . Json::encode($url) . ', ' . Json::encode($enforceRedirect) . ');'; |
||||||
|
|
||||||
|
?> |
||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<?= Html::script($redirectJavaScript); ?> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h2 id="title" style="display:none;">Redirecting back to the "<?= Yii::$app->name; ?>"...</h2>
|
||||||
|
<h3 id="link"><a href="<?= $url; ?>">Click here to return to the "<?= Yii::$app->name; ?>".</a></h3>
|
||||||
|
<script type="text/javascript"> |
||||||
|
document.getElementById('title').style.display = ''; |
||||||
|
document.getElementById('link').style.display = 'none'; |
||||||
|
</script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,229 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\widgets; |
||||||
|
|
||||||
|
use yii\base\Widget; |
||||||
|
use Yii; |
||||||
|
use yii\helpers\Html; |
||||||
|
use yii\authclient\ClientInterface; |
||||||
|
|
||||||
|
/** |
||||||
|
* Choice prints buttons for authentication via various auth clients. |
||||||
|
* By default this widget relies on presence of [[\yii\authclient\Collection]] among application components |
||||||
|
* to get auth clients information. |
||||||
|
* |
||||||
|
* Example: |
||||||
|
* ~~~ |
||||||
|
* <?= yii\authclient\Choice::widget([ |
||||||
|
* 'baseAuthUrl' => ['site/auth'] |
||||||
|
* ]); ?> |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* You can customize the widget appearance by using [[beginWidget()]] and [[endWidget()]] syntax |
||||||
|
* along with using method {@link clientLink()} or {@link createClientUrl()}. |
||||||
|
* For example: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* <?php $authChoice = yii\authclient\Choice::beginWidget([ |
||||||
|
* 'baseAuthUrl' => ['site/auth'] |
||||||
|
* ]); ?> |
||||||
|
* <ul> |
||||||
|
* <?php foreach ($authChoice->getClients() as $client): ?> |
||||||
|
* <li><?= $authChoice->clientLink($client); ?></li>
|
||||||
|
* <?php endforeach; ?> |
||||||
|
* </ul> |
||||||
|
* <?php yii\authclient\Choice::endWidget(); ?> |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @see \yii\authclient\AuthAction |
||||||
|
* |
||||||
|
* @property ClientInterface[] $providers auth providers list. |
||||||
|
* @property array $baseAuthUrl configuration for the external services base authentication URL. |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Choice extends Widget |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var ClientInterface[] auth providers list. |
||||||
|
*/ |
||||||
|
private $_clients; |
||||||
|
/** |
||||||
|
* @var string name of the auth client collection application component. |
||||||
|
* This component will be used to fetch {@link services} value if it is not set. |
||||||
|
*/ |
||||||
|
public $clientCollection = 'authClientCollection'; |
||||||
|
/** |
||||||
|
* @var array configuration for the external clients base authentication URL. |
||||||
|
*/ |
||||||
|
private $_baseAuthUrl; |
||||||
|
/** |
||||||
|
* @var string name of the GET param , which should be used to passed auth client id to URL |
||||||
|
* defined by {@link baseAuthUrl}. |
||||||
|
*/ |
||||||
|
public $clientIdGetParamName = 'authclient'; |
||||||
|
/** |
||||||
|
* @var array the HTML attributes that should be rendered in the div HTML tag representing the container element. |
||||||
|
*/ |
||||||
|
public $mainContainerHtmlOptions = [ |
||||||
|
'class' => 'auth-clients' |
||||||
|
]; |
||||||
|
/** |
||||||
|
* @var boolean indicates if popup window should be used instead of direct links. |
||||||
|
*/ |
||||||
|
public $popupMode = true; |
||||||
|
/** |
||||||
|
* @var boolean indicates if widget content, should be rendered automatically. |
||||||
|
* Note: this value automatically set to 'false' at the first call of [[createProviderUrl()]] |
||||||
|
*/ |
||||||
|
public $autoRender = true; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param ClientInterface[] $clients auth providers |
||||||
|
*/ |
||||||
|
public function setClients(array $clients) |
||||||
|
{ |
||||||
|
$this->_clients = $clients; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return ClientInterface[] auth providers |
||||||
|
*/ |
||||||
|
public function getClients() |
||||||
|
{ |
||||||
|
if ($this->_clients === null) { |
||||||
|
$this->_clients = $this->defaultClients(); |
||||||
|
} |
||||||
|
return $this->_clients; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param array $baseAuthUrl base auth URL configuration. |
||||||
|
*/ |
||||||
|
public function setBaseAuthUrl(array $baseAuthUrl) |
||||||
|
{ |
||||||
|
$this->_baseAuthUrl = $baseAuthUrl; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array base auth URL configuration. |
||||||
|
*/ |
||||||
|
public function getBaseAuthUrl() |
||||||
|
{ |
||||||
|
if (!is_array($this->_baseAuthUrl)) { |
||||||
|
$this->_baseAuthUrl = $this->defaultBaseAuthUrl(); |
||||||
|
} |
||||||
|
return $this->_baseAuthUrl; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns default auth clients list. |
||||||
|
* @return ClientInterface[] auth clients list. |
||||||
|
*/ |
||||||
|
protected function defaultClients() |
||||||
|
{ |
||||||
|
/** @var $collection \yii\authclient\Collection */ |
||||||
|
$collection = Yii::$app->getComponent($this->clientCollection); |
||||||
|
return $collection->getClients(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes default base auth URL configuration. |
||||||
|
* @return array base auth URL configuration. |
||||||
|
*/ |
||||||
|
protected function defaultBaseAuthUrl() |
||||||
|
{ |
||||||
|
$baseAuthUrl = [ |
||||||
|
Yii::$app->controller->getRoute() |
||||||
|
]; |
||||||
|
$params = $_GET; |
||||||
|
unset($params[$this->clientIdGetParamName]); |
||||||
|
$baseAuthUrl = array_merge($baseAuthUrl, $params); |
||||||
|
return $baseAuthUrl; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Outputs client auth link. |
||||||
|
* @param ClientInterface $client external auth client instance. |
||||||
|
* @param string $text link text, if not set - default value will be generated. |
||||||
|
* @param array $htmlOptions link HTML options. |
||||||
|
*/ |
||||||
|
public function clientLink($client, $text = null, array $htmlOptions = []) |
||||||
|
{ |
||||||
|
if ($text === null) { |
||||||
|
$text = Html::tag('span', '', ['class' => 'auth-icon ' . $client->getName()]); |
||||||
|
$text .= Html::tag('span', $client->getTitle(), ['class' => 'auth-title']); |
||||||
|
} |
||||||
|
if (!array_key_exists('class', $htmlOptions)) { |
||||||
|
$htmlOptions['class'] = 'auth-link ' . $client->getName(); |
||||||
|
} |
||||||
|
if ($this->popupMode) { |
||||||
|
$viewOptions = $client->getViewOptions(); |
||||||
|
if (isset($viewOptions['popupWidth'])) { |
||||||
|
$htmlOptions['data-popup-width'] = $viewOptions['popupWidth']; |
||||||
|
} |
||||||
|
if (isset($viewOptions['popupHeight'])) { |
||||||
|
$htmlOptions['data-popup-height'] = $viewOptions['popupHeight']; |
||||||
|
} |
||||||
|
} |
||||||
|
echo Html::a($text, $this->createClientUrl($client), $htmlOptions); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes client auth URL. |
||||||
|
* @param ClientInterface $provider external auth client instance. |
||||||
|
* @return string auth URL. |
||||||
|
*/ |
||||||
|
public function createClientUrl($provider) |
||||||
|
{ |
||||||
|
$this->autoRender = false; |
||||||
|
$url = $this->getBaseAuthUrl(); |
||||||
|
$url[$this->clientIdGetParamName] = $provider->getId(); |
||||||
|
return Html::url($url); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Renders the main content, which includes all external services links. |
||||||
|
*/ |
||||||
|
protected function renderMainContent() |
||||||
|
{ |
||||||
|
echo Html::beginTag('ul', ['class' => 'auth-clients clear']); |
||||||
|
foreach ($this->getClients() as $externalService) { |
||||||
|
echo Html::beginTag('li', ['class' => 'auth-client']); |
||||||
|
$this->clientLink($externalService); |
||||||
|
echo Html::endTag('li'); |
||||||
|
} |
||||||
|
echo Html::endTag('ul'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initializes the widget. |
||||||
|
*/ |
||||||
|
public function init() |
||||||
|
{ |
||||||
|
if ($this->popupMode) { |
||||||
|
$view = Yii::$app->getView(); |
||||||
|
ChoiceAsset::register($view); |
||||||
|
$view->registerJs("\$('#" . $this->getId() . "').authchoice();"); |
||||||
|
} |
||||||
|
$this->mainContainerHtmlOptions['id'] = $this->getId(); |
||||||
|
echo Html::beginTag('div', $this->mainContainerHtmlOptions); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Runs the widget. |
||||||
|
*/ |
||||||
|
public function run() |
||||||
|
{ |
||||||
|
if ($this->autoRender) { |
||||||
|
$this->renderMainContent(); |
||||||
|
} |
||||||
|
echo Html::endTag('div'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\authclient\widgets; |
||||||
|
|
||||||
|
use yii\web\AssetBundle; |
||||||
|
|
||||||
|
/** |
||||||
|
* ChoiceAsset is an asset bundle for [[Choice]] widget. |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class ChoiceAsset extends AssetBundle |
||||||
|
{ |
||||||
|
public $sourcePath = '@yii/authclient/widgets/assets'; |
||||||
|
public $js = [ |
||||||
|
'authchoice.js', |
||||||
|
]; |
||||||
|
public $css = [ |
||||||
|
'authchoice.css', |
||||||
|
]; |
||||||
|
public $depends = [ |
||||||
|
'yii\web\YiiAsset', |
||||||
|
]; |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
.clients { |
||||||
|
overflow:auto; |
||||||
|
} |
||||||
|
|
||||||
|
.auth-icon { |
||||||
|
display: block; |
||||||
|
width: 32px; |
||||||
|
height: 32px; |
||||||
|
background: url(authchoice.png) no-repeat; |
||||||
|
} |
||||||
|
|
||||||
|
.auth-icon.google, |
||||||
|
.auth-icon.google_openid, |
||||||
|
.auth-icon.google_oauth { |
||||||
|
background-position: 0 -34px; |
||||||
|
} |
||||||
|
.auth-icon.twitter { |
||||||
|
background-position: 0 -68px; |
||||||
|
} |
||||||
|
.auth-icon.yandex, |
||||||
|
.auth-icon.yandex_openid, |
||||||
|
.auth-icon.yandex_oauth { |
||||||
|
background-position: 0 -102px; |
||||||
|
} |
||||||
|
.auth-icon.vkontakte { |
||||||
|
background-position: 0 -136px; |
||||||
|
} |
||||||
|
.auth-icon.facebook { |
||||||
|
background-position: 0 -170px; |
||||||
|
} |
||||||
|
.auth-icon.mailru { |
||||||
|
background-position: 0 -204px; |
||||||
|
} |
||||||
|
.auth-icon.moikrug { |
||||||
|
background-position: 0 -238px; |
||||||
|
} |
||||||
|
.auth-icon.odnoklassniki { |
||||||
|
background-position: 0 -272px; |
||||||
|
} |
||||||
|
.auth-icon.linkedin { |
||||||
|
background-position: 0 -306px; |
||||||
|
} |
||||||
|
.auth-icon.github { |
||||||
|
background-position: 0 -340px; |
||||||
|
} |
||||||
|
.auth-icon.live { |
||||||
|
background-position: 0 -372px; |
||||||
|
} |
||||||
|
|
||||||
|
.auth-link:hover .auth-icon i, |
||||||
|
.auth-link:focus .auth-icon i { |
||||||
|
display: block; |
||||||
|
width: 32px; |
||||||
|
height: 32px; |
||||||
|
background: url(authchoice.png) 0 0 no-repeat; |
||||||
|
} |
||||||
|
|
||||||
|
.auth-clients { |
||||||
|
margin: 0 0 1em; |
||||||
|
list-style: none; |
||||||
|
overflow: auto; |
||||||
|
} |
||||||
|
|
||||||
|
.auth-client { |
||||||
|
float: left; |
||||||
|
margin: 0 1em 0 0; |
||||||
|
} |
||||||
|
|
||||||
|
.auth-clients .auth-client .auth-link { |
||||||
|
display: block; |
||||||
|
width: 58px; |
||||||
|
} |
||||||
|
|
||||||
|
.auth-client .auth-link .auth-icon { |
||||||
|
margin: 0 auto; |
||||||
|
} |
||||||
|
|
||||||
|
.auth-client .auth-link .auth-title { |
||||||
|
display: block; |
||||||
|
margin-top: 0.4em; |
||||||
|
text-align: center; |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
/** |
||||||
|
* Yii auth choice widget. |
||||||
|
* |
||||||
|
* This is the JavaScript widget used by the yii\authclient\widgets\Choice widget. |
||||||
|
* |
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
jQuery(function($) { |
||||||
|
$.fn.authchoice = function(options) { |
||||||
|
options = $.extend({ |
||||||
|
popup: { |
||||||
|
resizable: 'yes', |
||||||
|
scrollbars: 'no', |
||||||
|
toolbar: 'no', |
||||||
|
menubar: 'no', |
||||||
|
location: 'no', |
||||||
|
directories: 'no', |
||||||
|
status: 'yes', |
||||||
|
width: 450, |
||||||
|
height: 380 |
||||||
|
} |
||||||
|
}, options); |
||||||
|
|
||||||
|
return this.each(function() { |
||||||
|
var $container = $(this); |
||||||
|
|
||||||
|
$container.find('a').on('click', function(e) { |
||||||
|
e.preventDefault(); |
||||||
|
|
||||||
|
var authChoicePopup = null; |
||||||
|
|
||||||
|
if (authChoicePopup = $container.data('authChoicePopup')) { |
||||||
|
authChoicePopup.close(); |
||||||
|
} |
||||||
|
|
||||||
|
var url = this.href; |
||||||
|
var popupOptions = options.popup; |
||||||
|
|
||||||
|
var localPopupWidth = this.getAttribute('data-popup-width'); |
||||||
|
if (localPopupWidth) { |
||||||
|
popupOptions.width = localPopupWidth; |
||||||
|
} |
||||||
|
var localPopupHeight = this.getAttribute('data-popup-height'); |
||||||
|
if (localPopupWidth) { |
||||||
|
popupOptions.height = localPopupHeight; |
||||||
|
} |
||||||
|
|
||||||
|
popupOptions.left = (window.screen.width - options.popup.width) / 2; |
||||||
|
popupOptions.top = (window.screen.height - options.popup.height) / 2; |
||||||
|
|
||||||
|
var popupFeatureParts = []; |
||||||
|
for (var propName in popupOptions) { |
||||||
|
popupFeatureParts.push(propName + '=' + popupOptions[propName]); |
||||||
|
} |
||||||
|
var popupFeature = popupFeatureParts.join(','); |
||||||
|
|
||||||
|
authChoicePopup = window.open(url, 'yii_auth_choice', popupFeature); |
||||||
|
authChoicePopup.focus(); |
||||||
|
|
||||||
|
$container.data('authChoicePopup', authChoicePopup); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}; |
||||||
|
}); |
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,68 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit\extensions\authclient; |
||||||
|
|
||||||
|
|
||||||
|
use yii\authclient\AuthAction; |
||||||
|
|
||||||
|
class AuthActionTest extends TestCase |
||||||
|
{ |
||||||
|
protected function setUp() |
||||||
|
{ |
||||||
|
$config = [ |
||||||
|
'components' => [ |
||||||
|
'user' => [ |
||||||
|
'identityClass' => '\yii\web\IdentityInterface' |
||||||
|
], |
||||||
|
'request' => [ |
||||||
|
'hostInfo' => 'http://testdomain.com', |
||||||
|
'scriptUrl' => '/index.php', |
||||||
|
], |
||||||
|
] |
||||||
|
]; |
||||||
|
$this->mockApplication($config, '\yii\web\Application'); |
||||||
|
} |
||||||
|
|
||||||
|
public function testSetGet() |
||||||
|
{ |
||||||
|
$action = new AuthAction(null, null); |
||||||
|
|
||||||
|
$successUrl = 'http://test.success.url'; |
||||||
|
$action->setSuccessUrl($successUrl); |
||||||
|
$this->assertEquals($successUrl, $action->getSuccessUrl(), 'Unable to setup success URL!'); |
||||||
|
|
||||||
|
$cancelUrl = 'http://test.cancel.url'; |
||||||
|
$action->setCancelUrl($cancelUrl); |
||||||
|
$this->assertEquals($cancelUrl, $action->getCancelUrl(), 'Unable to setup cancel URL!'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetGet |
||||||
|
*/ |
||||||
|
public function testGetDefaultSuccessUrl() |
||||||
|
{ |
||||||
|
$action = new AuthAction(null, null); |
||||||
|
|
||||||
|
$this->assertNotEmpty($action->getSuccessUrl(), 'Unable to get default success URL!'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetGet |
||||||
|
*/ |
||||||
|
public function testGetDefaultCancelUrl() |
||||||
|
{ |
||||||
|
$action = new AuthAction(null, null); |
||||||
|
|
||||||
|
$this->assertNotEmpty($action->getSuccessUrl(), 'Unable to get default cancel URL!'); |
||||||
|
} |
||||||
|
|
||||||
|
public function testRedirect() |
||||||
|
{ |
||||||
|
$action = new AuthAction(null, null); |
||||||
|
|
||||||
|
$url = 'http://test.url'; |
||||||
|
$response = $action->redirect($url, true); |
||||||
|
|
||||||
|
$this->assertContains($url, $response->content); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit\extensions\authclient; |
||||||
|
|
||||||
|
use yii\authclient\BaseClient; |
||||||
|
|
||||||
|
class BaseClientTest extends TestCase |
||||||
|
{ |
||||||
|
public function testSetGet() |
||||||
|
{ |
||||||
|
$client = new Client(); |
||||||
|
|
||||||
|
$id = 'test_id'; |
||||||
|
$client->setId($id); |
||||||
|
$this->assertEquals($id, $client->getId(), 'Unable to setup id!'); |
||||||
|
|
||||||
|
$name = 'test_name'; |
||||||
|
$client->setName($name); |
||||||
|
$this->assertEquals($name, $client->getName(), 'Unable to setup name!'); |
||||||
|
|
||||||
|
$title = 'test_title'; |
||||||
|
$client->setTitle($title); |
||||||
|
$this->assertEquals($title, $client->getTitle(), 'Unable to setup title!'); |
||||||
|
|
||||||
|
$userAttributes = [ |
||||||
|
'attribute1' => 'value1', |
||||||
|
'attribute2' => 'value2', |
||||||
|
]; |
||||||
|
$client->setUserAttributes($userAttributes); |
||||||
|
$this->assertEquals($userAttributes, $client->getUserAttributes(), 'Unable to setup user attributes!'); |
||||||
|
|
||||||
|
$normalizeUserAttributeMap = [ |
||||||
|
'name' => 'some/name', |
||||||
|
'email' => 'some/email', |
||||||
|
]; |
||||||
|
$client->setNormalizeUserAttributeMap($normalizeUserAttributeMap); |
||||||
|
$this->assertEquals($normalizeUserAttributeMap, $client->getNormalizeUserAttributeMap(), 'Unable to setup normalize user attribute map!'); |
||||||
|
|
||||||
|
$viewOptions = [ |
||||||
|
'option1' => 'value1', |
||||||
|
'option2' => 'value2', |
||||||
|
]; |
||||||
|
$client->setViewOptions($viewOptions); |
||||||
|
$this->assertEquals($viewOptions, $client->getViewOptions(), 'Unable to setup view options!'); |
||||||
|
} |
||||||
|
|
||||||
|
public function testGetDefaults() |
||||||
|
{ |
||||||
|
$client = new Client(); |
||||||
|
|
||||||
|
$this->assertNotEmpty($client->getName(), 'Unable to get default name!'); |
||||||
|
$this->assertNotEmpty($client->getTitle(), 'Unable to get default title!'); |
||||||
|
$this->assertNotNull($client->getViewOptions(), 'Unable to get default view options!'); |
||||||
|
$this->assertNotNull($client->getNormalizeUserAttributeMap(), 'Unable to get default normalize user attribute map!'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetGet |
||||||
|
*/ |
||||||
|
public function testNormalizeUserAttributes() |
||||||
|
{ |
||||||
|
$client = new Client(); |
||||||
|
|
||||||
|
$normalizeUserAttributeMap = [ |
||||||
|
'raw/name' => 'name', |
||||||
|
'raw/email' => 'email', |
||||||
|
]; |
||||||
|
$client->setNormalizeUserAttributeMap($normalizeUserAttributeMap); |
||||||
|
$rawUserAttributes = [ |
||||||
|
'raw/name' => 'name value', |
||||||
|
'raw/email' => 'email value', |
||||||
|
]; |
||||||
|
$client->setUserAttributes($rawUserAttributes); |
||||||
|
$normalizedUserAttributes = $client->getUserAttributes(); |
||||||
|
$expectedNormalizedUserAttributes = array_combine(array_keys($normalizeUserAttributeMap), array_values($rawUserAttributes)); |
||||||
|
$this->assertEquals($expectedNormalizedUserAttributes, $normalizedUserAttributes); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Client extends BaseClient |
||||||
|
{ |
||||||
|
} |
@ -0,0 +1,251 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit\extensions\authclient; |
||||||
|
|
||||||
|
use yii\authclient\signature\PlainText; |
||||||
|
use yii\authclient\OAuthToken; |
||||||
|
use yiiunit\extensions\authclient\TestCase; |
||||||
|
use yii\authclient\BaseOAuth; |
||||||
|
|
||||||
|
class BaseOAuthTest extends TestCase |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Creates test OAuth client instance. |
||||||
|
* @return BaseOAuth oauth client. |
||||||
|
*/ |
||||||
|
protected function createOAuthClient() |
||||||
|
{ |
||||||
|
$oauthClient = $this->getMock(BaseOAuth::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 BaseOAuth $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 OAuthToken(); |
||||||
|
$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\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 OAuthToken(); |
||||||
|
$accessToken->setToken('test_access_token'); |
||||||
|
$accessToken->setExpireDuration(1000); |
||||||
|
$oauthClient->setAccessToken($accessToken); |
||||||
|
|
||||||
|
$oauthClient->apiBaseUrl = $apiBaseUrl; |
||||||
|
|
||||||
|
$this->assertEquals($expectedApiFullUrl, $oauthClient->api($apiSubUrl)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit\extensions\authclient; |
||||||
|
|
||||||
|
use yii\authclient\Collection; |
||||||
|
use yii\authclient\BaseClient; |
||||||
|
use yiiunit\extensions\authclient\TestCase; |
||||||
|
|
||||||
|
class CollectionTest extends TestCase |
||||||
|
{ |
||||||
|
// Tests : |
||||||
|
|
||||||
|
public function testSetGet() |
||||||
|
{ |
||||||
|
$collection = new Collection(); |
||||||
|
|
||||||
|
$clients = [ |
||||||
|
'testClient1' => new TestClient(), |
||||||
|
'testClient2' => new TestClient(), |
||||||
|
]; |
||||||
|
$collection->setClients($clients); |
||||||
|
$this->assertEquals($clients, $collection->getClients(), 'Unable to setup clients!'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetGet |
||||||
|
*/ |
||||||
|
public function testGetProviderById() |
||||||
|
{ |
||||||
|
$collection = new Collection(); |
||||||
|
|
||||||
|
$clientId = 'testClientId'; |
||||||
|
$client = new TestClient(); |
||||||
|
$clients = [ |
||||||
|
$clientId => $client |
||||||
|
]; |
||||||
|
$collection->setClients($clients); |
||||||
|
|
||||||
|
$this->assertEquals($client, $collection->getClient($clientId), 'Unable to get client by id!'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testGetProviderById |
||||||
|
*/ |
||||||
|
public function testCreateProvider() |
||||||
|
{ |
||||||
|
$collection = new Collection(); |
||||||
|
|
||||||
|
$clientId = 'testClientId'; |
||||||
|
$clientClassName = TestClient::className(); |
||||||
|
$clients = [ |
||||||
|
$clientId => [ |
||||||
|
'class' => $clientClassName |
||||||
|
] |
||||||
|
]; |
||||||
|
$collection->setClients($clients); |
||||||
|
|
||||||
|
$provider = $collection->getClient($clientId); |
||||||
|
$this->assertTrue(is_object($provider), 'Unable to create client by config!'); |
||||||
|
$this->assertTrue(is_a($provider, $clientClassName), 'Client has wrong class name!'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetGet |
||||||
|
*/ |
||||||
|
public function testHasProvider() |
||||||
|
{ |
||||||
|
$collection = new Collection(); |
||||||
|
|
||||||
|
$clientName = 'testClientName'; |
||||||
|
$clients = [ |
||||||
|
$clientName => [ |
||||||
|
'class' => 'TestClient1' |
||||||
|
], |
||||||
|
]; |
||||||
|
$collection->setClients($clients); |
||||||
|
|
||||||
|
$this->assertTrue($collection->hasClient($clientName), 'Existing client check fails!'); |
||||||
|
$this->assertFalse($collection->hasClient('unExistingClientName'), 'Not existing client check fails!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class TestClient extends BaseClient |
||||||
|
{ |
||||||
|
} |
@ -0,0 +1,109 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit\extensions\authclient\oauth; |
||||||
|
|
||||||
|
use yii\authclient\OAuth1; |
||||||
|
use yii\authclient\signature\PlainText; |
||||||
|
use yii\authclient\OAuthToken; |
||||||
|
use yiiunit\extensions\authclient\TestCase; |
||||||
|
|
||||||
|
class OAuth1Test extends TestCase |
||||||
|
{ |
||||||
|
protected function setUp() |
||||||
|
{ |
||||||
|
$this->mockApplication([], '\yii\web\Application'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Invokes the OAuth client method even if it is protected. |
||||||
|
* @param OAuth1 $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 OAuth1(); |
||||||
|
|
||||||
|
$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 OAuth1(); |
||||||
|
$authorizationHeader = $this->invokeOAuthClientMethod($oauthClient, 'composeAuthorizationHeader', [$params, $realm]); |
||||||
|
$this->assertEquals($expectedAuthorizationHeader, $authorizationHeader); |
||||||
|
} |
||||||
|
|
||||||
|
public function testBuildAuthUrl() { |
||||||
|
$oauthClient = new OAuth1(); |
||||||
|
$authUrl = 'http://test.auth.url'; |
||||||
|
$oauthClient->authUrl = $authUrl; |
||||||
|
|
||||||
|
$requestTokenToken = 'test_request_token'; |
||||||
|
$requestToken = new OAuthToken(); |
||||||
|
$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\OAuth2; |
||||||
|
use yiiunit\extensions\authclient\TestCase; |
||||||
|
|
||||||
|
class OAuth2Test extends TestCase |
||||||
|
{ |
||||||
|
protected function setUp() |
||||||
|
{ |
||||||
|
$this->mockApplication([], '\yii\web\Application'); |
||||||
|
} |
||||||
|
|
||||||
|
// Tests : |
||||||
|
|
||||||
|
public function testBuildAuthUrl() |
||||||
|
{ |
||||||
|
$oauthClient = new OAuth2(); |
||||||
|
$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,61 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit\extensions\authclient; |
||||||
|
|
||||||
|
use yii\authclient\OpenId; |
||||||
|
|
||||||
|
class OpenIdTest extends TestCase |
||||||
|
{ |
||||||
|
protected function setUp() |
||||||
|
{ |
||||||
|
$config = [ |
||||||
|
'components' => [ |
||||||
|
'request' => [ |
||||||
|
'hostInfo' => 'http://testdomain.com', |
||||||
|
'scriptUrl' => '/index.php', |
||||||
|
], |
||||||
|
] |
||||||
|
]; |
||||||
|
$this->mockApplication($config, '\yii\web\Application'); |
||||||
|
} |
||||||
|
|
||||||
|
// Tests : |
||||||
|
|
||||||
|
public function testSetGet() |
||||||
|
{ |
||||||
|
$client = new OpenId(); |
||||||
|
|
||||||
|
$trustRoot = 'http://trust.root'; |
||||||
|
$client->setTrustRoot($trustRoot); |
||||||
|
$this->assertEquals($trustRoot, $client->getTrustRoot(), 'Unable to setup trust root!'); |
||||||
|
|
||||||
|
$returnUrl = 'http://return.url'; |
||||||
|
$client->setReturnUrl($returnUrl); |
||||||
|
$this->assertEquals($returnUrl, $client->getReturnUrl(), 'Unable to setup return URL!'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetGet |
||||||
|
*/ |
||||||
|
public function testGetDefaults() |
||||||
|
{ |
||||||
|
$client = new OpenId(); |
||||||
|
|
||||||
|
$this->assertNotEmpty($client->getTrustRoot(), 'Unable to get default trust root!'); |
||||||
|
$this->assertNotEmpty($client->getReturnUrl(), 'Unable to get default return URL!'); |
||||||
|
} |
||||||
|
|
||||||
|
public function testDiscover() |
||||||
|
{ |
||||||
|
$url = 'https://www.google.com/accounts/o8/id'; |
||||||
|
$client = new OpenId(); |
||||||
|
$info = $client->discover($url); |
||||||
|
$this->assertNotEmpty($info); |
||||||
|
$this->assertNotEmpty($info['url']); |
||||||
|
$this->assertNotEmpty($info['identity']); |
||||||
|
$this->assertEquals(2, $info['version']); |
||||||
|
$this->assertArrayHasKey('identifier_select', $info); |
||||||
|
$this->assertArrayHasKey('ax', $info); |
||||||
|
$this->assertArrayHasKey('sreg', $info); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit\extensions\authclient; |
||||||
|
|
||||||
|
use yii\helpers\FileHelper; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
/** |
||||||
|
* TestCase for "authclient" extension. |
||||||
|
*/ |
||||||
|
class TestCase extends \yiiunit\TestCase |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Adds sphinx extension files to [[Yii::$classPath]], |
||||||
|
* avoiding the necessity of usage Composer autoloader. |
||||||
|
*/ |
||||||
|
public 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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
TestCase::loadClassMap(); |
@ -0,0 +1,133 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit\extensions\authclient\oauth; |
||||||
|
|
||||||
|
use yii\authclient\OAuthToken; |
||||||
|
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 OAuthToken($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 OAuthToken(); |
||||||
|
|
||||||
|
$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 OAuthToken(); |
||||||
|
|
||||||
|
$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 OAuthToken(); |
||||||
|
$oauthToken->setParams($params); |
||||||
|
$this->assertEquals($expectedExpireDuration, $oauthToken->getExpireDuration()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetupParamsShortcuts |
||||||
|
*/ |
||||||
|
public function testGetIsExpired() |
||||||
|
{ |
||||||
|
$oauthToken = new OAuthToken(); |
||||||
|
$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 OAuthToken(); |
||||||
|
$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\signature; |
||||||
|
|
||||||
|
use yiiunit\extensions\authclient\TestCase; |
||||||
|
|
||||||
|
class BaseMethodTest extends TestCase |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Creates test signature method instance. |
||||||
|
* @return \yii\authclient\signature\BaseMethod |
||||||
|
*/ |
||||||
|
protected function createTestSignatureMethod() |
||||||
|
{ |
||||||
|
$signatureMethod = $this->getMock('\yii\authclient\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\signature; |
||||||
|
|
||||||
|
use yii\authclient\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\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\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