-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 316b3b1
Showing
4 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Yii2 usuario keycloak client | ||
|
||
### Installation and Setup | ||
|
||
For the installation and setup see [usuario docs](https://yii2-usuario.readthedocs.io/en/latest/) | ||
|
||
Install the package via composer | ||
```bash | ||
composer require dmstr/yii2-usuario-keycloak | ||
``` | ||
|
||
Update your yii2 app config | ||
```php | ||
use bizley\jwt\Jwt; | ||
use dmstr\tokenManager\components\TokenManager; | ||
use dmstr\usuario\keycloak\Bootstrap; | ||
use Lcobucci\Clock\SystemClock; | ||
use Lcobucci\JWT\Validation\Constraint\IssuedBy; | ||
use Lcobucci\JWT\Validation\Constraint\LooseValidAt; | ||
use Lcobucci\JWT\Validation\Constraint\SignedWith; | ||
|
||
return [ | ||
... | ||
'bootstrap' => [ | ||
[ | ||
'class' => Bootstrap::class, | ||
'clientAuthUrl' => getenv('KEYCLOAK_AUTH_URL'), | ||
'clientIssuerUrl' => getenv('KEYCLOAK_ISSUER_URL'), | ||
'clientClientId' => getenv('KEYCLOAK_CLIENT'), | ||
'clientClientSecret' => getenv('KEYCLOAK_CLIENT_SECRET') | ||
] | ||
], | ||
'components' => [ | ||
'jwt' => [ // example | ||
'class' => Jwt::class, | ||
'signer' => Jwt::RS256, | ||
'signingKey' => [ | ||
'key' => getenv('JWT_PUBLIC_KEY_FILE'), | ||
'method' => Jwt::METHOD_FILE, | ||
], | ||
'verifyingKey' => [ | ||
'key' => getenv('JWT_PUBLIC_KEY_FILE'), | ||
'method' => Jwt::METHOD_FILE, | ||
], | ||
'validationConstraints' => function ($jwt) { | ||
$config = $jwt->getConfiguration(); | ||
return [ | ||
new SignedWith($config->signer(), $config->signingKey()), | ||
new IssuedBy(getenv('JWT_TOKEN_ISSUER')), | ||
new LooseValidAt(SystemClock::fromUTC()), | ||
]; | ||
} | ||
], | ||
'tokenManager' => [ | ||
'class' => TokenManager::class | ||
] | ||
], | ||
'modules' => [ | ||
'user' => [ | ||
'enableRegistration' => true | ||
] | ||
] | ||
... | ||
]; | ||
``` | ||
|
||
After logging in to an account via social account login you can access to token like this | ||
|
||
```php | ||
use dmstr\tokenManager\components\TokenManager; | ||
|
||
$token = Yii::$app->tokenManager->getToken(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"name": "dmstr/yii2-usuario-keycloak", | ||
"description": "Yii2 usuario keycloak plugin", | ||
"authors": [ | ||
{ | ||
"name": "Andres Klapper", | ||
"email": "a.klapper@herzogkommunikation.de" | ||
}, | ||
{ | ||
"name": "Elias Luhr", | ||
"email": "e.luhr@herzogkommunikation.de" | ||
} | ||
], | ||
"require": { | ||
"yiisoft/yii2-authclient": "^2.2", | ||
"2amigos/yii2-usuario": "^1.5.1", | ||
"web-token/jwt-checker": ">=1.0 <3.0", | ||
"web-token/jwt-signature": ">=1.0 <3.0", | ||
"web-token/jwt-signature-algorithm-hmac": ">=1.0 <3.0", | ||
"web-token/jwt-signature-algorithm-ecdsa": ">=1.0 <3.0", | ||
"web-token/jwt-signature-algorithm-rsa": ">=1.0 <3.0", | ||
"web-token/jwt-key-mgmt": ">=1.0 <3.0", | ||
"dmstr/yii2-token-manager": "^1.0", | ||
"bizley/jwt": "^3.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
<?php | ||
|
||
namespace dmstr\usuario\keycloak; | ||
|
||
use bizley\jwt\Jwt; | ||
use Da\User\Controller\SecurityController; | ||
use Da\User\Event\SocialNetworkAuthEvent; | ||
use dmstr\tokenManager\components\TokenManager; | ||
use dmstr\usuario\keycloak\clients\Keycloak; | ||
use Lcobucci\JWT\Token; | ||
use Lcobucci\JWT\UnencryptedToken; | ||
use yii\authclient\OAuthToken; | ||
use yii\base\BootstrapInterface; | ||
use yii\base\Event; | ||
use yii\helpers\VarDumper; | ||
use yii\web\BadRequestHttpException; | ||
use Yii; | ||
|
||
/** | ||
* --- PROPERTIES --- | ||
* | ||
* @author Elias Luhr | ||
*/ | ||
class Bootstrap implements BootstrapInterface | ||
{ | ||
public string $clientName; | ||
public string $clientTitle; | ||
public string $clientAuthUrl; | ||
public string $clientTokenUrl; | ||
public string $clientIssuerUrl; | ||
public string $clientClientId; | ||
public string $clientClientSecret; | ||
|
||
public string $jwtComponentId = 'jwt'; | ||
public string $tokenManagerComponentId = 'tokenManager'; | ||
|
||
public function __construct() | ||
{ | ||
$this->clientName = getenv('KEYCLOAK_CLIENT_ID'); | ||
$this->clientTitle = getenv('KEYCLOAK_CLIENT_TITLE'); | ||
} | ||
|
||
/** | ||
* @param \yii\base\Application $app | ||
* @return void | ||
*/ | ||
public function bootstrap($app) | ||
{ | ||
// Configure keycloak client | ||
$clients = $app->authClientCollection->getClients(); | ||
$clients[$this->clientName] = [ | ||
'class' => Keycloak::class, | ||
'authUrl' => $this->clientAuthUrl, | ||
'issuerUrl' => $this->clientIssuerUrl, | ||
'tokenUrl' => $this->clientTokenUrl, | ||
'clientId' => $this->clientClientId, | ||
'clientSecret' => $this->clientClientSecret, | ||
'name' => $this->clientName, | ||
'title' => $this->clientTitle | ||
]; | ||
$app->authClientCollection->setClients($clients); | ||
|
||
|
||
// Create/update attached account | ||
Event::on(SecurityController::class, SocialNetworkAuthEvent::EVENT_BEFORE_AUTHENTICATE, function (SocialNetworkAuthEvent $event) { | ||
if ($event->getClient()->getName() === $this->clientName) { | ||
$event->account->save(false); | ||
} | ||
}); | ||
|
||
// Retrieve and process and save token | ||
Event::on(SecurityController::class, SocialNetworkAuthEvent::EVENT_AFTER_AUTHENTICATE, function (SocialNetworkAuthEvent $event) { | ||
$oauthAccessToken = $event->getClient()->getAccessToken(); | ||
// check ig access token is in expected format | ||
if ($oauthAccessToken instanceof OAuthToken) { | ||
// get token as string | ||
$token = $oauthAccessToken->getToken(); | ||
/** @var Jwt $jwtComponent */ | ||
$jwtComponent = Yii::$app->get($this->jwtComponentId); | ||
// parse string representation of the token to a token object | ||
$parsedToken = $jwtComponent->getParser()->parse($token); | ||
// validate the token | ||
if ($jwtComponent->validate($parsedToken)) { | ||
/** @var TokenManager $tokenManager */ | ||
$tokenManager = Yii::$app->get($this->tokenManagerComponentId); | ||
// save parsed token via token manager | ||
$tokenManager->setToken($parsedToken); | ||
return; // get out of here | ||
} | ||
|
||
} | ||
Yii::$app->getUser()->logout(); | ||
throw new BadRequestHttpException(\Yii::t('usuario.keycloak','Invalid token')); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?php | ||
|
||
namespace dmstr\usuario\keycloak\clients; | ||
|
||
use Da\User\Contracts\AuthClientInterface; | ||
use yii\authclient\OpenIdConnect; | ||
use yii\web\HttpException; | ||
|
||
/** | ||
* --- PROPERTIES --- | ||
* | ||
* @author Elias Luhr | ||
*/ | ||
class Keycloak extends OpenIdConnect implements AuthClientInterface | ||
{ | ||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function initUserAttributes() | ||
{ | ||
$token = $this->getAccessToken()->getToken(); | ||
return $this->loadJws($token); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getEmail() | ||
{ | ||
return $this->getUserAttributes()['email'] ?? null; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getUsername() | ||
{ | ||
// returns the e-mail as it corresponds with the username | ||
return $this->getEmail(); | ||
} | ||
|
||
/** | ||
* @throws HttpException | ||
* @return mixed | ||
*/ | ||
public function getRealmAccess(): mixed | ||
{ | ||
$accessToken = $this->getAccessToken(); | ||
if ($accessToken) { | ||
$token = $accessToken->getToken(); | ||
return $this->loadJws($token)['realm_access'] ?? null; | ||
} | ||
return null; | ||
} | ||
} |