diff --git a/src/Model/Table/UsersTable.php b/src/Model/Table/UsersTable.php index 09a142e..e8f8812 100644 --- a/src/Model/Table/UsersTable.php +++ b/src/Model/Table/UsersTable.php @@ -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; + } } diff --git a/templates/Users/login.php b/templates/Users/login.php index d787594..41b03d4 100644 --- a/templates/Users/login.php +++ b/templates/Users/login.php @@ -7,5 +7,16 @@ echo $this->Form->submit(__('Submit'), ['class' => 'btn btn-lg btn-primary btn-block']); echo $this->Form->end(); echo ''; + echo $this->Form->postLink( + 'Login with Keycloak', + [ + 'prefix' => false, + 'plugin' => 'ADmad/SocialAuth', + 'controller' => 'Auth', + 'action' => 'login', + 'provider' => 'keycloak', + '?' => ['redirect' => $this->request->getQuery('redirect')] + ] + ); ?>