mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-23 12:10:54 +08:00
OpenId client "authUrl" field added, identity/claimedId processing refactored.
This commit is contained in:
@ -192,30 +192,30 @@ class AuthAction extends Action
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param OpenId $provider provider instance.
|
* @param OpenId $client provider instance.
|
||||||
* @return \yii\web\Response action response.
|
* @return \yii\web\Response action response.
|
||||||
* @throws Exception on failure
|
* @throws Exception on failure
|
||||||
* @throws \yii\web\HttpException
|
* @throws \yii\web\HttpException
|
||||||
*/
|
*/
|
||||||
protected function authOpenId($provider)
|
protected function authOpenId($client)
|
||||||
{
|
{
|
||||||
if (!empty($_REQUEST['openid_mode'])) {
|
if (!empty($_REQUEST['openid_mode'])) {
|
||||||
switch ($_REQUEST['openid_mode']) {
|
switch ($_REQUEST['openid_mode']) {
|
||||||
case 'id_res':
|
case 'id_res':
|
||||||
if ($provider->validate()) {
|
if ($client->validate()) {
|
||||||
$attributes = array(
|
$attributes = [
|
||||||
'id' => $provider->identity
|
'id' => $client->getClaimedId()
|
||||||
);
|
];
|
||||||
$rawAttributes = $provider->fetchAttributes();
|
$rawAttributes = $client->fetchAttributes();
|
||||||
foreach ($provider->requiredAttributes as $openIdAttributeName) {
|
foreach ($client->requiredAttributes as $openIdAttributeName) {
|
||||||
if (isset($rawAttributes[$openIdAttributeName])) {
|
if (isset($rawAttributes[$openIdAttributeName])) {
|
||||||
$attributes[$openIdAttributeName] = $rawAttributes[$openIdAttributeName];
|
$attributes[$openIdAttributeName] = $rawAttributes[$openIdAttributeName];
|
||||||
} else {
|
} else {
|
||||||
throw new Exception('Unable to complete the authentication because the required data was not received.');
|
throw new Exception('Unable to complete the authentication because the required data was not received.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$provider->setUserAttributes($attributes);
|
$client->setUserAttributes($attributes);
|
||||||
return $this->authSuccess($provider);
|
return $this->authSuccess($client);
|
||||||
} else {
|
} else {
|
||||||
throw new Exception('Unable to complete the authentication because the required data was not received.');
|
throw new Exception('Unable to complete the authentication because the required data was not received.');
|
||||||
}
|
}
|
||||||
@ -228,8 +228,7 @@ class AuthAction extends Action
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//$provider->identity = $provider->authUrl; // Setting identifier
|
$url = $client->buildAuthUrl();
|
||||||
$url = $provider->buildAuthUrl();
|
|
||||||
return Yii::$app->getResponse()->redirect($url);
|
return Yii::$app->getResponse()->redirect($url);
|
||||||
}
|
}
|
||||||
return $this->redirectCancel();
|
return $this->redirectCancel();
|
||||||
|
@ -17,7 +17,7 @@ use Yii;
|
|||||||
* @see http://openid.net/
|
* @see http://openid.net/
|
||||||
*
|
*
|
||||||
* @property string $returnUrl authentication return URL.
|
* @property string $returnUrl authentication return URL.
|
||||||
* @property mixed $identity ???
|
* @property string $claimedId claimed identifier (identity).
|
||||||
* @property string $trustRoot client trust root (realm), by default [[\yii\web\Request::hostInfo]] value will be used.
|
* @property string $trustRoot client trust root (realm), by default [[\yii\web\Request::hostInfo]] value will be used.
|
||||||
*
|
*
|
||||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||||
@ -25,6 +25,11 @@ use Yii;
|
|||||||
*/
|
*/
|
||||||
class OpenId extends BaseClient implements ClientInterface
|
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.
|
* @var array list of attributes, which always should be returned from server.
|
||||||
*/
|
*/
|
||||||
@ -53,9 +58,9 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
* @var string authentication return URL.
|
* @var string authentication return URL.
|
||||||
*/
|
*/
|
||||||
private $_returnUrl;
|
private $_returnUrl;
|
||||||
|
/**
|
||||||
private $_identity;
|
* @var string claimed identifier (identity)
|
||||||
|
*/
|
||||||
private $_claimedId;
|
private $_claimedId;
|
||||||
/**
|
/**
|
||||||
* @var string client trust root (realm), by default [[\yii\web\Request::hostInfo]] value will be used.
|
* @var string client trust root (realm), by default [[\yii\web\Request::hostInfo]] value will be used.
|
||||||
@ -91,27 +96,26 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setIdentity($value)
|
/**
|
||||||
|
* @param string $claimedId claimed identifier (identity).
|
||||||
|
*/
|
||||||
|
public function setClaimedId($claimedId)
|
||||||
{
|
{
|
||||||
if (strlen($value = trim((String) $value))) {
|
$this->_claimedId = $claimedId;
|
||||||
if (preg_match('#^xri:/*#i', $value, $m)) {
|
|
||||||
$value = substr($value, strlen($m[0]));
|
|
||||||
} elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) {
|
|
||||||
$value = "http://$value";
|
|
||||||
}
|
|
||||||
if (preg_match('#^https?://[^/]+$#i', $value, $m)) {
|
|
||||||
$value .= '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->_identity = $value;
|
|
||||||
$this->_claimedId = $value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getIdentity()
|
/**
|
||||||
|
* @return string claimed identifier (identity).
|
||||||
|
*/
|
||||||
|
public function getClaimedId()
|
||||||
{
|
{
|
||||||
/* We return claimed_id instead of identity,
|
if ($this->_claimedId === null) {
|
||||||
because the developer should see the claimed identifier,
|
if (isset($this->data['openid_claimed_id'])) {
|
||||||
i.e. what he set as identity, not the op-local identifier (which is what we verify)*/
|
$this->_claimedId = $this->data['openid_claimed_id'];
|
||||||
|
} elseif (isset($this->data['openid_identity'])) {
|
||||||
|
$this->_claimedId = $this->data['openid_identity'];
|
||||||
|
}
|
||||||
|
}
|
||||||
return $this->_claimedId;
|
return $this->_claimedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,13 +238,6 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
$name = strtolower(trim(substr($header, 0, $pos)));
|
$name = strtolower(trim(substr($header, 0, $pos)));
|
||||||
$headers[$name] = trim(substr($header, $pos+1));
|
$headers[$name] = trim(substr($header, $pos+1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updating claimed_id in case of redirections.
|
|
||||||
$effectiveUrl = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
|
|
||||||
if ($effectiveUrl != $url) {
|
|
||||||
$this->_identity = $this->_claimedId = $effectiveUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $headers;
|
return $headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,23 +310,6 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
$pos = strpos($header, ':');
|
$pos = strpos($header, ':');
|
||||||
$name = strtolower(trim(substr($header, 0, $pos)));
|
$name = strtolower(trim(substr($header, 0, $pos)));
|
||||||
$headers[$name] = trim(substr($header, $pos + 1));
|
$headers[$name] = trim(substr($header, $pos + 1));
|
||||||
|
|
||||||
/* Following possible redirections. The point is just to have
|
|
||||||
claimed_id change with them, because get_headers() will
|
|
||||||
follow redirections automatically.
|
|
||||||
We ignore redirections with relative paths.
|
|
||||||
If any known provider uses them, file a bug report.*/
|
|
||||||
if ($name == 'location') {
|
|
||||||
if (strpos($headers[$name], 'http') === 0) {
|
|
||||||
$this->_identity = $this->_claimedId = $headers[$name];
|
|
||||||
} elseif($headers[$name][0] == '/') {
|
|
||||||
$parsedUrl = parse_url($this->_claimedId);
|
|
||||||
$this->_identity =
|
|
||||||
$this->_claimedId = $parsedUrl['scheme'] . '://'
|
|
||||||
. $parsedUrl['host']
|
|
||||||
. $headers[$name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// and restore them
|
// and restore them
|
||||||
@ -660,8 +640,8 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
/* If we have an openid.delegate that is different from our claimed id,
|
/* If we have an openid.delegate that is different from our claimed id,
|
||||||
we need to somehow preserve the claimed id between requests.
|
we need to somehow preserve the claimed id between requests.
|
||||||
The simplest way is to just send it along with the return_to url.*/
|
The simplest way is to just send it along with the return_to url.*/
|
||||||
if ($serverInfo['identity'] != $this->_claimedId) {
|
if ($serverInfo['identity'] != $this->getClaimedId()) {
|
||||||
$returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->_claimedId;
|
$returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->getClaimedId();
|
||||||
}
|
}
|
||||||
|
|
||||||
$params = array_merge(
|
$params = array_merge(
|
||||||
@ -707,7 +687,7 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
$params['openid.claimed_id']= $url;
|
$params['openid.claimed_id']= $url;
|
||||||
} else {
|
} else {
|
||||||
$params['openid.identity'] = $serverInfo['identity'];
|
$params['openid.identity'] = $serverInfo['identity'];
|
||||||
$params['openid.claimed_id'] = $this->_claimedId;
|
$params['openid.claimed_id'] = $this->getClaimedId();
|
||||||
}
|
}
|
||||||
return $this->buildUrl(parse_url($serverInfo['url']), ['query' => http_build_query($params, '', '&')]);
|
return $this->buildUrl(parse_url($serverInfo['url']), ['query' => http_build_query($params, '', '&')]);
|
||||||
}
|
}
|
||||||
@ -720,7 +700,12 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
*/
|
*/
|
||||||
public function buildAuthUrl($identifierSelect = null)
|
public function buildAuthUrl($identifierSelect = null)
|
||||||
{
|
{
|
||||||
$serverInfo = $this->discover($this->_identity);
|
$authUrl = $this->authUrl;
|
||||||
|
$claimedId = $this->getClaimedId();
|
||||||
|
if (empty($claimedId)) {
|
||||||
|
$this->setClaimedId($authUrl);
|
||||||
|
}
|
||||||
|
$serverInfo = $this->discover($authUrl);
|
||||||
if ($serverInfo['version'] == 2) {
|
if ($serverInfo['version'] == 2) {
|
||||||
if ($identifierSelect !== null) {
|
if ($identifierSelect !== null) {
|
||||||
$serverInfo['identifier_select'] = $identifierSelect;
|
$serverInfo['identifier_select'] = $identifierSelect;
|
||||||
@ -733,11 +718,13 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
/**
|
/**
|
||||||
* Performs OpenID verification with the OP.
|
* Performs OpenID verification with the OP.
|
||||||
* @return boolean whether the verification was successful.
|
* @return boolean whether the verification was successful.
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public function validate()
|
public function validate()
|
||||||
{
|
{
|
||||||
$this->_claimedId = isset($this->data['openid_claimed_id']) ? $this->data['openid_claimed_id'] : $this->data['openid_identity'];
|
$claimedId = $this->getClaimedId();
|
||||||
|
if (empty($claimedId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$params = [
|
$params = [
|
||||||
'openid.assoc_handle' => $this->data['openid_assoc_handle'],
|
'openid.assoc_handle' => $this->data['openid_assoc_handle'],
|
||||||
'openid.signed' => $this->data['openid_signed'],
|
'openid.signed' => $this->data['openid_signed'],
|
||||||
@ -751,27 +738,20 @@ class OpenId extends BaseClient implements ClientInterface
|
|||||||
$params['openid.ns'] = 'http://specs.openid.net/auth/2.0';
|
$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']) {
|
} 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,
|
// If it's an OpenID 1 provider, and we've got claimed_id,
|
||||||
// we have to append it to the returnUrl, like authUrl_v1 does.
|
// we have to append it to the returnUrl, like authUrlV1 does.
|
||||||
$this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->_claimedId;
|
$this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $claimedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->data['openid_return_to'] != $this->returnUrl) {
|
if ($this->data['openid_return_to'] != $this->returnUrl) {
|
||||||
// The return_to url must match the url of current request.
|
// The return_to url must match the url of current request.
|
||||||
// I'm assuing that noone will set the returnUrl to something that doesn't make sense.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$serverInfo = $this->discover($this->_claimedId);
|
$serverInfo = $this->discover($claimedId);
|
||||||
|
|
||||||
foreach (explode(',', $this->data['openid_signed']) as $item) {
|
foreach (explode(',', $this->data['openid_signed']) as $item) {
|
||||||
/* Checking whether magic_quotes_gpc is turned on, because
|
|
||||||
the function may fail if it is. For example, when fetching
|
|
||||||
AX namePerson, it might containg an apostrophe, which will be escaped.
|
|
||||||
In such case, validation would fail, since we'd send different data than OP
|
|
||||||
wants to verify. stripslashes() should solve that problem, but we can't
|
|
||||||
use it when magic_quotes is off.*/
|
|
||||||
$value = $this->data['openid_' . str_replace('.', '_', $item)];
|
$value = $this->data['openid_' . str_replace('.', '_', $item)];
|
||||||
$params['openid.' . $item] = get_magic_quotes_gpc() ? stripslashes($value) : $value;
|
$params['openid.' . $item] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$params['openid.mode'] = 'check_authentication';
|
$params['openid.mode'] = 'check_authentication';
|
||||||
|
@ -20,17 +20,16 @@ class GoogleOpenId extends OpenId
|
|||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public function init()
|
public $authUrl = 'https://www.google.com/accounts/o8/id';
|
||||||
{
|
/**
|
||||||
parent::init();
|
* @inheritdoc
|
||||||
$this->setIdentity('https://www.google.com/accounts/o8/id');
|
*/
|
||||||
$this->requiredAttributes = [
|
public $requiredAttributes = [
|
||||||
'namePerson/first',
|
'namePerson/first',
|
||||||
'namePerson/last',
|
'namePerson/last',
|
||||||
'contact/email',
|
'contact/email',
|
||||||
'pref/language',
|
'pref/language',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
|
@ -20,15 +20,14 @@ class YandexOpenId extends OpenId
|
|||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public function init()
|
public $authUrl = 'http://openid.yandex.ru';
|
||||||
{
|
/**
|
||||||
parent::init();
|
* @inheritdoc
|
||||||
$this->setIdentity('http://openid.yandex.ru');
|
*/
|
||||||
$this->requiredAttributes = [
|
public $requiredAttributes = [
|
||||||
'namePerson',
|
'namePerson',
|
||||||
'contact/email',
|
'contact/email',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
|
Reference in New Issue
Block a user