From 1aedc1962fac50669ca9b8e35c47906972de48eb Mon Sep 17 00:00:00 2001 From: Luke Briner Date: Tue, 22 May 2018 20:21:07 +0100 Subject: [PATCH 1/7] Fix OpenIdConnect provider call to UserInfo yiisoft/yii2-authclient#220 --- src/OpenIdConnect.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/OpenIdConnect.php b/src/OpenIdConnect.php index 7a0c349..a32b212 100644 --- a/src/OpenIdConnect.php +++ b/src/OpenIdConnect.php @@ -260,6 +260,15 @@ protected function initUserAttributes() { return $this->api($this->getConfigParam('userinfo_endpoint'), 'GET'); } + + /** + * {@inheritdoc} + */ + public function applyAccessTokenToRequest($request, $accessToken) + { + // OpenID Connect requires bearer token auth for the user info endpoint + $request->getHeaders()->set('Authorization', "Bearer ".$accessToken->getToken()); + } /** * {@inheritdoc} From e81762910d145f769f6afbc011aeaa7942c20936 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Fri, 25 May 2018 02:29:19 +0300 Subject: [PATCH 2/7] Fixed formatting [skip ci] --- src/OpenIdConnect.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenIdConnect.php b/src/OpenIdConnect.php index a32b212..baf3033 100644 --- a/src/OpenIdConnect.php +++ b/src/OpenIdConnect.php @@ -261,13 +261,13 @@ protected function initUserAttributes() return $this->api($this->getConfigParam('userinfo_endpoint'), 'GET'); } - /** + /** * {@inheritdoc} */ public function applyAccessTokenToRequest($request, $accessToken) { - // OpenID Connect requires bearer token auth for the user info endpoint - $request->getHeaders()->set('Authorization', "Bearer ".$accessToken->getToken()); + // OpenID Connect requires bearer token auth for the user info endpoint + $request->getHeaders()->set('Authorization', 'Bearer ' . $accessToken->getToken()); } /** @@ -397,4 +397,4 @@ protected function generateAuthNonce() { return Yii::$app->security->generateRandomString(); } -} \ No newline at end of file +} From e8f979f05615fd280f2e5c3424e2df43b4e0dfe9 Mon Sep 17 00:00:00 2001 From: Luke Briner Date: Sat, 26 May 2018 10:11:46 +0100 Subject: [PATCH 3/7] Update changelog for #220 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 445f5c7..d26c6c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Yii Framework 2 authclient extension Change Log - Enh #203: Updated VKontakte client to use API version 5.0 (Shketkol) - Bug #211: `RsaSha` was not passing `$key` to `openssl_pkey_get_private()` in `generateSignature()` (cfhodges) +- Bug #220: Make `OpenIdConnect` client send token as bearer auth instead of querystring parameter (lukos) 2.1.5 February 08, 2018 From f4e89fb8ee45ef3179163234105d4c537ffeaec3 Mon Sep 17 00:00:00 2001 From: Luke Briner Date: Sat, 26 May 2018 11:02:48 +0100 Subject: [PATCH 4/7] Make use of AuthHandler clearer #222 --- docs/guide/quick-start.md | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/docs/guide/quick-start.md b/docs/guide/quick-start.md index 1bc968e..456af6f 100644 --- a/docs/guide/quick-start.md +++ b/docs/guide/quick-start.md @@ -4,7 +4,7 @@ Quick Start ## Adding action to controller Next step is to add [[yii\authclient\AuthAction]] to a web controller and provide a `successCallback` implementation, -which is suitable for your needs. Typically final controller code may look like following: +which is suitable for your needs. Typically, the final controller code will look like the following: ```php use app\components\AuthHandler; @@ -28,9 +28,25 @@ class SiteController extends Controller } ``` -Note that it's important for `auth` action to be public accessible, so make sure it's not denied by access control filter. - -Where AuthHandler implementation could be like this: +> Note that it's important for the `auth` action to be publically accessible, so make sure it's not denied by access control filter. + +The following code shows an example AuthHandler, which will need modifying for your app. + +Notes +* The namespaces for Auth and User reflect the basic app template. Put e.g. `use common\models\Auth;` for the advanced template. +* The attribute names `email`, `sub` and `nickname` at the start of `function handle()` are defined by OpenIdConnect. +If your provider is OAuth, these names might be different. +* You might need to set a specific `scope` value in your provider config to get back the required attributes. For OpenIdConnect, +you will need a scope of `openid email profile` to get the claims below returned. If not using nickname, you can use `openid email`. +Other providers will have unique scope to claim mappings. +* This code demonstrates a custom field `github` in the User which is both set and updated by `function updateUserInfo(User $user)` +when the user is created and every time they login to ensure it stays up to date. The example migration does not include this +custom field, if you don't need it, remove it. +* Different Auth clients may require different approaches while handling authentication success. For example: Twitter +does not return the user email, so you have to deal with this somehow. +* This code does not handle a new user having a username (nickname) that matches an existing user account (where the emails +are different) and the database insert will fail. You can code it to generate a unique id in this case or otherwise redirect the +user to a page to allow them to set a username. ```php client->getUserAttributes(); $email = ArrayHelper::getValue($attributes, 'email'); - $id = ArrayHelper::getValue($attributes, 'id'); - $nickname = ArrayHelper::getValue($attributes, 'login'); + $id = ArrayHelper::getValue($attributes, 'sub'); + $nickname = ArrayHelper::getValue($attributes, 'nickname'); /* @var Auth $auth */ $auth = Auth::find()->where([ @@ -177,9 +193,6 @@ we can retrieve information received. In our case we'd like to: - If user is guest and record not found in auth then create new user and make a record in auth table. Then log in. - If user is logged in and record not found in auth then try connecting additional account (save its data into auth table). -> Note: different Auth clients may require different approaches while handling authentication success. For example: Twitter - does not allow returning of the user email, so you have to deal with this somehow. - ### Auth client basic structure Although, all clients are different they shares same basic interface [[yii\authclient\ClientInterface]], From d9e3ed58ac1ef956ad0d60f85b5e0e3a23d11ed8 Mon Sep 17 00:00:00 2001 From: Luke Briner Date: Sat, 26 May 2018 11:11:22 +0100 Subject: [PATCH 5/7] Revert "Make use of AuthHandler clearer #222" This reverts commit f4e89fb8ee45ef3179163234105d4c537ffeaec3. --- docs/guide/quick-start.md | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/docs/guide/quick-start.md b/docs/guide/quick-start.md index 456af6f..1bc968e 100644 --- a/docs/guide/quick-start.md +++ b/docs/guide/quick-start.md @@ -4,7 +4,7 @@ Quick Start ## Adding action to controller Next step is to add [[yii\authclient\AuthAction]] to a web controller and provide a `successCallback` implementation, -which is suitable for your needs. Typically, the final controller code will look like the following: +which is suitable for your needs. Typically final controller code may look like following: ```php use app\components\AuthHandler; @@ -28,25 +28,9 @@ class SiteController extends Controller } ``` -> Note that it's important for the `auth` action to be publically accessible, so make sure it's not denied by access control filter. - -The following code shows an example AuthHandler, which will need modifying for your app. - -Notes -* The namespaces for Auth and User reflect the basic app template. Put e.g. `use common\models\Auth;` for the advanced template. -* The attribute names `email`, `sub` and `nickname` at the start of `function handle()` are defined by OpenIdConnect. -If your provider is OAuth, these names might be different. -* You might need to set a specific `scope` value in your provider config to get back the required attributes. For OpenIdConnect, -you will need a scope of `openid email profile` to get the claims below returned. If not using nickname, you can use `openid email`. -Other providers will have unique scope to claim mappings. -* This code demonstrates a custom field `github` in the User which is both set and updated by `function updateUserInfo(User $user)` -when the user is created and every time they login to ensure it stays up to date. The example migration does not include this -custom field, if you don't need it, remove it. -* Different Auth clients may require different approaches while handling authentication success. For example: Twitter -does not return the user email, so you have to deal with this somehow. -* This code does not handle a new user having a username (nickname) that matches an existing user account (where the emails -are different) and the database insert will fail. You can code it to generate a unique id in this case or otherwise redirect the -user to a page to allow them to set a username. +Note that it's important for `auth` action to be public accessible, so make sure it's not denied by access control filter. + +Where AuthHandler implementation could be like this: ```php client->getUserAttributes(); $email = ArrayHelper::getValue($attributes, 'email'); - $id = ArrayHelper::getValue($attributes, 'sub'); - $nickname = ArrayHelper::getValue($attributes, 'nickname'); + $id = ArrayHelper::getValue($attributes, 'id'); + $nickname = ArrayHelper::getValue($attributes, 'login'); /* @var Auth $auth */ $auth = Auth::find()->where([ @@ -193,6 +177,9 @@ we can retrieve information received. In our case we'd like to: - If user is guest and record not found in auth then create new user and make a record in auth table. Then log in. - If user is logged in and record not found in auth then try connecting additional account (save its data into auth table). +> Note: different Auth clients may require different approaches while handling authentication success. For example: Twitter + does not allow returning of the user email, so you have to deal with this somehow. + ### Auth client basic structure Although, all clients are different they shares same basic interface [[yii\authclient\ClientInterface]], From d9ce4dc97a2890f814eccbe341c7d26d1459ac44 Mon Sep 17 00:00:00 2001 From: Luke Briner Date: Sat, 26 May 2018 11:36:27 +0100 Subject: [PATCH 6/7] Make use of AuthHandler clearer #222 --- docs/guide/quick-start.md | 54 +++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/docs/guide/quick-start.md b/docs/guide/quick-start.md index 1bc968e..ce402fa 100644 --- a/docs/guide/quick-start.md +++ b/docs/guide/quick-start.md @@ -4,7 +4,7 @@ Quick Start ## Adding action to controller Next step is to add [[yii\authclient\AuthAction]] to a web controller and provide a `successCallback` implementation, -which is suitable for your needs. Typically final controller code may look like following: +which is suitable for your needs. Typically, the final controller code will look like the following: ```php use app\components\AuthHandler; @@ -28,9 +28,26 @@ class SiteController extends Controller } ``` -Note that it's important for `auth` action to be public accessible, so make sure it's not denied by access control filter. - -Where AuthHandler implementation could be like this: +> Note that it's important for the `auth` action to be publically accessible, so make sure it's not denied by access control filter. + +The following code shows an example AuthHandler, which will need modifying for your app. + +Notes +* The namespaces for models `Auth` and `User` reflect the basic app template. Put e.g. `use common\models\Auth;` for the advanced template. +* You need to generate the `Auth` model from the table mentioned [here](installation.md) +* The attribute names `email`, `sub` and `nickname` at the start of `function handle()` are defined by OpenIdConnect. +If your provider is OAuth, these names might be different. +* You might need to set a specific `scope` value in your provider config to get back the required attributes. For OpenIdConnect, +you will need a scope of `openid email profile` to get the claims below returned. If not using nickname, you can use `openid email`. +Other providers will have unique scope to claim mappings. +* This code demonstrates a custom field `github` in `User` which is both set and updated by `function updateUserInfo(User $user)` +when the user is created and every time they login to ensure it stays up to date. The example migration does not include this +custom field, if you don't need it, remove the code below. +* Different Auth clients may require different approaches while handling authentication success. For example: Twitter +does not return the user email, so you have to deal with this somehow. +* This code does not handle a new user having a username (nickname) that matches an existing username (where the emails +are different) and the database insert will fail. You can code it to generate a unique id in this case (see below for example) or +otherwise redirect the user to a page to allow them to set a username. ```php client->getUserAttributes(); $email = ArrayHelper::getValue($attributes, 'email'); - $id = ArrayHelper::getValue($attributes, 'id'); - $nickname = ArrayHelper::getValue($attributes, 'login'); + $id = ArrayHelper::getValue($attributes, 'sub'); + $nickname = ArrayHelper::getValue($attributes, 'nickname'); /* @var Auth $auth */ $auth = Auth::find()->where([ @@ -177,8 +194,29 @@ we can retrieve information received. In our case we'd like to: - If user is guest and record not found in auth then create new user and make a record in auth table. Then log in. - If user is logged in and record not found in auth then try connecting additional account (save its data into auth table). -> Note: different Auth clients may require different approaches while handling authentication success. For example: Twitter - does not allow returning of the user email, so you have to deal with this somehow. +### Generate unique username in AuthHandler + +If you do not want the user to interact with your system when their external nickname matches an existing username in the database, +you can use the following code snippet to add a number onto the end until a unique username is found. This code is just before +`$user = new User`. + +```php +if ( !isset($nickname) ) +{ + // Provider might not return a suitable nickname + // so start by taking the part before the @ sign as a nickname + $nickname = substr($email,0,strpos($email,'@')); +} +// If this username already exists, create another one with a number on the end +if ( User::find()->where(['username'=>$nickname])->exists() ) +{ + $index = 1; + // Check username is not already taken + while ( User::find()->where(['username'=>$nickname.$index])->exists()) { ++$index; } + $nickname = $nickname.$index; +} +$user = new User([ +``` ### Auth client basic structure From 7b1118e259801a777e10538c904e78f5a5acaf80 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Fri, 1 Jun 2018 20:57:41 +0300 Subject: [PATCH 7/7] Update quick-start.md --- docs/guide/quick-start.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/guide/quick-start.md b/docs/guide/quick-start.md index ce402fa..82447c3 100644 --- a/docs/guide/quick-start.md +++ b/docs/guide/quick-start.md @@ -28,24 +28,24 @@ class SiteController extends Controller } ``` -> Note that it's important for the `auth` action to be publically accessible, so make sure it's not denied by access control filter. +> Note that it is important for the `auth` action to be publically accessible, so make sure it is not denied by access control filter. -The following code shows an example AuthHandler, which will need modifying for your app. +The following code shows an example `AuthHandler`, which will need modifying for your app. -Notes -* The namespaces for models `Auth` and `User` reflect the basic app template. Put e.g. `use common\models\Auth;` for the advanced template. -* You need to generate the `Auth` model from the table mentioned [here](installation.md) -* The attribute names `email`, `sub` and `nickname` at the start of `function handle()` are defined by OpenIdConnect. +Notes: + +- The namespaces for models `Auth` and `User` reflect the basic project template. For the advanced template you need to adjust namespace to `common\models\Auth;`. +- You need to generate the `Auth` model from the table mentioned [here](installation.md). +- The attribute names `email`, `sub` and `nickname` at the start of `function handle()` are defined by OpenIdConnect. If your provider is OAuth, these names might be different. -* You might need to set a specific `scope` value in your provider config to get back the required attributes. For OpenIdConnect, +- You might need to set a specific `scope` value in your provider config to get back the required attributes. For OpenIdConnect, you will need a scope of `openid email profile` to get the claims below returned. If not using nickname, you can use `openid email`. Other providers will have unique scope to claim mappings. -* This code demonstrates a custom field `github` in `User` which is both set and updated by `function updateUserInfo(User $user)` +- This code demonstrates a custom field `github` in `User` which is both set and updated by `function updateUserInfo(User $user)` when the user is created and every time they login to ensure it stays up to date. The example migration does not include this custom field, if you don't need it, remove the code below. -* Different Auth clients may require different approaches while handling authentication success. For example: Twitter -does not return the user email, so you have to deal with this somehow. -* This code does not handle a new user having a username (nickname) that matches an existing username (where the emails +- Different Auth clients may require different approaches while handling authentication success. +- This code does not handle a new user having a username (nickname) that matches an existing username (where the emails are different) and the database insert will fail. You can code it to generate a unique id in this case (see below for example) or otherwise redirect the user to a page to allow them to set a username.