new: [keycloak auth] wip version 1 added
- authenticate via keycloak (on demand only at the moment) - check if user from JWT token exists - if yes: - check if role needs to be updated - do so if need be - check if organisation needs to be updated - (currently only captures, not aligned yet!) - if no: - create user - set role (if set, otherwise fall back to default configuration) - capture organisation - (currently not aligned yet!)keycloak
parent
78f193cb5c
commit
efe3765609
|
@ -7,6 +7,11 @@ use Cake\ORM\Table;
|
|||
use Cake\Validation\Validator;
|
||||
use Cake\ORM\RulesChecker;
|
||||
use Cake\ORM\TableRegistry;
|
||||
use \Cake\Datasource\EntityInterface;
|
||||
use \Cake\Http\Session;
|
||||
use Cake\Http\Client;
|
||||
use Cake\Utility\Security;
|
||||
use Cake\Core\Configure;
|
||||
|
||||
class UsersTable extends AppTable
|
||||
{
|
||||
|
@ -93,4 +98,121 @@ class UsersTable extends AppTable
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function extractKeycloakProfileData($profile_payload)
|
||||
{
|
||||
$mapping = Configure::read('keycloak.mapping');
|
||||
$fields = [
|
||||
'org_uuid' => 'org_uuid',
|
||||
'role_name' => 'role_name',
|
||||
'username' => 'preferred_username',
|
||||
'email' => 'email',
|
||||
'first_name' => 'given_name',
|
||||
'last_name' => 'family_name'
|
||||
];
|
||||
foreach ($fields as $field => $default) {
|
||||
if (!empty($mapping[$field])) {
|
||||
$fields[$field] = $mapping[$field];
|
||||
}
|
||||
}
|
||||
$user = [
|
||||
'individual' => [
|
||||
'email' => $profile_payload[$fields['email']],
|
||||
'first_name' => $profile_payload[$fields['first_name']],
|
||||
'last_name' => $profile_payload[$fields['last_name']]
|
||||
],
|
||||
'user' => [
|
||||
'username' => $profile_payload[$fields['username']],
|
||||
],
|
||||
'organisation' => [
|
||||
'uuid' => $profile_payload[$fields['org_uuid']],
|
||||
],
|
||||
'role' => [
|
||||
'name' => $profile_payload[$fields['role_name']],
|
||||
]
|
||||
];
|
||||
$user['user']['individual_id'] = $this->captureIndividual($user);
|
||||
$user['user']['role_id'] = $this->captureRole($user);
|
||||
$existingUser = $this->find()->where(['username' => $user['user']['username']])->first();
|
||||
if (empty($existingUser)) {
|
||||
$user['user']['password'] = Security::randomString(16);
|
||||
$existingUser = $this->newEntity($user['user']);
|
||||
if (!$this->save($existingUser)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$dirty = false;
|
||||
if ($user['user']['individual_id'] != $existingUser['individual_id']) {
|
||||
$existingUser['individual_id'] = $user['user']['individual_id'];
|
||||
$dirty = true;
|
||||
}
|
||||
if ($user['user']['role_id'] != $existingUser['role_id']) {
|
||||
$existingUser['role_id'] = $user['user']['role_id'];
|
||||
$dirty = true;
|
||||
}
|
||||
$existingUser;
|
||||
if ($dirty) {
|
||||
if (!$this->save($existingUser)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $existingUser;
|
||||
}
|
||||
|
||||
private function captureIndividual($user)
|
||||
{
|
||||
$individual = $this->Individuals->find()->where(['email' => $user['individual']['email']])->first();
|
||||
if (empty($individual)) {
|
||||
$individual = $this->Individuals->newEntity($user['individual']);
|
||||
if (!$this->Individuals->save($individual)) {
|
||||
throw new BadRequestException(__('Could not save the associated individual'));
|
||||
}
|
||||
}
|
||||
return $individual->id;
|
||||
}
|
||||
|
||||
private function captureOrganisation($user)
|
||||
{
|
||||
$organisation = $this->Organisations->find()->where(['uuid' => $user['organisation']['uuid']])->first();
|
||||
if (empty($organisation)) {
|
||||
$user['organisation']['name'] = $user['organisation']['uuid'];
|
||||
$organisation = $this->Organisations->newEntity($user['organisation']);
|
||||
if (!$this->Organisations->save($organisation)) {
|
||||
throw new BadRequestException(__('Could not save the associated organisation'));
|
||||
}
|
||||
}
|
||||
return $organisation->id;
|
||||
}
|
||||
|
||||
private function captureRole($user)
|
||||
{
|
||||
$role = $this->Roles->find()->where(['name' => $user['role']['name']])->first();
|
||||
if (empty($role)) {
|
||||
if (!empty(Configure::read('keycloak.default_role_name'))) {
|
||||
$default_role_name = Configure::read('keycloak.default_role_name');
|
||||
$role = $this->Roles->find()->where(['name' => $default_role_name])->first();
|
||||
}
|
||||
if (empty($role)) {
|
||||
throw new NotFoundException(__('Invalid role'));
|
||||
}
|
||||
}
|
||||
return $role->id;
|
||||
}
|
||||
|
||||
public function getUser(EntityInterface $profile, Session $session)
|
||||
{
|
||||
$userId = $session->read('Auth.User.id');
|
||||
if ($userId) {
|
||||
return $this->get($userId);
|
||||
}
|
||||
|
||||
$raw_profile_payload = $profile->access_token->getJwt()->getPayload();
|
||||
$user = $this->extractKeycloakProfileData($raw_profile_payload);
|
||||
if (!$user) {
|
||||
throw new \RuntimeException('Unable to save new user');
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,5 +7,16 @@
|
|||
echo $this->Form->submit(__('Submit'), ['class' => 'btn btn-lg btn-primary btn-block']);
|
||||
echo $this->Form->end();
|
||||
echo '</div>';
|
||||
echo $this->Form->postLink(
|
||||
'Login with Keycloak',
|
||||
[
|
||||
'prefix' => false,
|
||||
'plugin' => 'ADmad/SocialAuth',
|
||||
'controller' => 'Auth',
|
||||
'action' => 'login',
|
||||
'provider' => 'keycloak',
|
||||
'?' => ['redirect' => $this->request->getQuery('redirect')]
|
||||
]
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue