diff --git a/extensions/yii/authclient/provider/OAuth1.php b/extensions/yii/authclient/provider/OAuth1.php new file mode 100644 index 0000000..4220c39 --- /dev/null +++ b/extensions/yii/authclient/provider/OAuth1.php @@ -0,0 +1,51 @@ + + * @since 2.0 + */ +class OAuth1 extends \yii\authclient\OAuth1 implements ProviderInterface +{ + use ProviderTrait; + + /** + * @inheritdoc + */ + public function authenticate() + { + // 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 = $this->fetchRequestToken(); + // Get authorization URL. + $url = $this->buildAuthUrl($requestToken); + // Redirect to authorization URL. + return Yii::$app->getResponse()->redirect($url); + } else { + // Upgrade to access token. + $accessToken = $this->fetchAccessToken(); + $this->isAuthenticated = true; + } + + return $this->isAuthenticated; + } +} \ No newline at end of file diff --git a/extensions/yii/authclient/provider/OAuth2.php b/extensions/yii/authclient/provider/OAuth2.php new file mode 100644 index 0000000..e55328e --- /dev/null +++ b/extensions/yii/authclient/provider/OAuth2.php @@ -0,0 +1,58 @@ + + * @since 2.0 + */ +class OAuth2 extends \yii\authclient\OAuth2 implements ProviderInterface +{ + use ProviderTrait; + + /** + * @inheritdoc + */ + public function authenticate() + { + 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 = $this->fetchAccessToken($code); + if (!empty($token)) { + $this->isAuthenticated = true; + } + } else { + $url = $this->buildAuthUrl(); + return Yii::$app->getResponse()->redirect($url); + } + + return $this->isAuthenticated; + } +} \ No newline at end of file diff --git a/extensions/yii/authclient/provider/OpenId.php b/extensions/yii/authclient/provider/OpenId.php index ad00a39..ff1985c 100644 --- a/extensions/yii/authclient/provider/OpenId.php +++ b/extensions/yii/authclient/provider/OpenId.php @@ -7,7 +7,9 @@ namespace yii\authclient\provider; -use yii\authclient\openid\Client; +use Yii; +use yii\base\Exception; +use yii\web\HttpException; /** * Class OpenId @@ -15,16 +17,58 @@ use yii\authclient\openid\Client; * @author Paul Klimov * @since 2.0 */ -class OpenId extends Client implements ProviderInterface +class OpenId extends \yii\authclient\OpenId implements ProviderInterface { use ProviderTrait; /** - * Authenticate the user. - * @return boolean whether user was successfully authenticated. + * @inheritdoc */ public function authenticate() { - // TODO: Implement authenticate() method. + if (!empty($_REQUEST['openid_mode'])) { + switch ($_REQUEST['openid_mode']) { + case 'id_res': + if ($this->validate()) { + $attributes = array( + 'id' => $this->identity + ); + $rawAttributes = $this->getAttributes(); + foreach ($this->getRequiredAttributes() as $openIdAttributeName) { + if (isset($rawAttributes[$openIdAttributeName])) { + $attributes[$openIdAttributeName] = $rawAttributes[$openIdAttributeName]; + } else { + throw new Exception('Unable to complete the authentication because the required data was not received.'); + } + } + $this->setAttributes($attributes); + $this->isAuthenticated = true; + return true; + } else { + throw new Exception('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 { + $this->identity = $this->authUrl; // Setting identifier + $this->required = []; // Try to get info from openid provider + foreach ($this->getRequiredAttributes() as $openIdAttributeName) { + $this->required[] = $openIdAttributeName; + } + $request = Yii::$app->getRequest(); + $this->realm = $request->getHostInfo(); + $this->returnUrl = $this->realm . $request->getUrl(); // getting return URL + + $url = $this->authUrl(); + return Yii::$app->getResponse()->redirect($url); + } + + return false; } } \ No newline at end of file diff --git a/extensions/yii/authclient/provider/ProviderInterface.php b/extensions/yii/authclient/provider/ProviderInterface.php index 9be8a2f..b3f2b27 100644 --- a/extensions/yii/authclient/provider/ProviderInterface.php +++ b/extensions/yii/authclient/provider/ProviderInterface.php @@ -67,7 +67,7 @@ interface ProviderInterface /** * Authenticate the user. - * @return boolean whether user was successfully authenticated. + * @return \yii\web\Response|boolean response instance or whether user was successfully authenticated. */ public function authenticate(); } \ No newline at end of file diff --git a/extensions/yii/authclient/provider/ProviderTrait.php b/extensions/yii/authclient/provider/ProviderTrait.php index 5926302..129fa0d 100644 --- a/extensions/yii/authclient/provider/ProviderTrait.php +++ b/extensions/yii/authclient/provider/ProviderTrait.php @@ -173,4 +173,49 @@ trait ProviderTrait { return Yii::$app->getRequest()->getAbsoluteUrl(); } + + /** + * 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) + { + $viewData = [ + 'url' => $url, + 'enforceRedirect' => $enforceRedirect, + ]; + $viewFile = __DIR__ . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'redirect.php'; + + $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); + } } \ No newline at end of file diff --git a/extensions/yii/authclient/provider/views/redirect.php b/extensions/yii/authclient/provider/views/redirect.php new file mode 100644 index 0000000..e85aa46 --- /dev/null +++ b/extensions/yii/authclient/provider/views/redirect.php @@ -0,0 +1,38 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/unit/extensions/authclient/TestCase.php b/tests/unit/extensions/authclient/TestCase.php index 30fe5de..3a033b4 100644 --- a/tests/unit/extensions/authclient/TestCase.php +++ b/tests/unit/extensions/authclient/TestCase.php @@ -10,16 +10,11 @@ use Yii; */ class TestCase extends \yiiunit\TestCase { - public static function setUpBeforeClass() - { - static::loadClassMap(); - } - /** * Adds sphinx extension files to [[Yii::$classPath]], * avoiding the necessity of usage Composer autoloader. */ - protected static function loadClassMap() + public static function loadClassMap() { $baseNameSpace = 'yii/authclient'; $basePath = realpath(__DIR__. '/../../../../extensions/yii/authclient'); @@ -30,4 +25,6 @@ class TestCase extends \yiiunit\TestCase Yii::$classMap[$classFullName] = $file; } } -} \ No newline at end of file +} + +TestCase::loadClassMap(); \ No newline at end of file diff --git a/tests/unit/extensions/authclient/provider/ProviderTraitTest.php b/tests/unit/extensions/authclient/provider/ProviderTraitTest.php new file mode 100644 index 0000000..8289eb3 --- /dev/null +++ b/tests/unit/extensions/authclient/provider/ProviderTraitTest.php @@ -0,0 +1,90 @@ + [ + 'user' => [ + 'identityClass' => '\yii\web\IdentityInterface' + ], + 'request' => [ + 'hostInfo' => 'http://testdomain.com', + 'scriptUrl' => '/index.php', + ], + ] + ]; + $this->mockApplication($config, '\yii\web\Application'); + } + + public function testSetGet() + { + $provider = new Provider(); + + $id = 'test_service_id'; + $provider->setId($id); + $this->assertEquals($id, $provider->getId(), 'Unable to setup id!'); + + $successUrl = 'http://test.success.url'; + $provider->setSuccessUrl($successUrl); + $this->assertEquals($successUrl, $provider->getSuccessUrl(), 'Unable to setup success URL!'); + + $cancelUrl = 'http://test.cancel.url'; + $provider->setCancelUrl($cancelUrl); + $this->assertEquals($cancelUrl, $provider->getCancelUrl(), 'Unable to setup cancel URL!'); + } + + public function testGetDescriptiveData() + { + $provider = new Provider(); + + $this->assertNotEmpty($provider->getName(), 'Unable to get name!'); + $this->assertNotEmpty($provider->getTitle(), 'Unable to get title!'); + } + + /** + * @depends testSetGet + */ + public function testGetDefaultSuccessUrl() + { + $provider = new Provider(); + + $this->assertNotEmpty($provider->getSuccessUrl(), 'Unable to get default success URL!'); + } + + /** + * @depends testSetGet + */ + public function testGetDefaultCancelUrl() + { + $provider = new Provider(); + + $this->assertNotEmpty($provider->getSuccessUrl(), 'Unable to get default cancel URL!'); + } + + public function testRedirect() + { + $provider = new Provider(); + + $url = 'http://test.url'; + $response = $provider->redirect($url, true); + + $this->assertContains($url, $response->content); + } +} + +class Provider extends Object implements ProviderInterface +{ + use ProviderTrait; + + public function authenticate() {} +} \ No newline at end of file