2021-10-01 13:19:26 +02:00
< ? php
namespace App\Model\Behavior ;
use ArrayObject ;
use Cake\Datasource\EntityInterface ;
use Cake\Event\EventInterface ;
use Cake\ORM\Behavior ;
use Cake\ORM\Entity ;
use Cake\ORM\Query ;
use Cake\Utility\Text ;
2021-10-04 11:02:10 +02:00
use Cake\Utility\Security ;
2022-05-17 02:42:14 +02:00
use Cake\Utility\Hash ;
2021-10-01 13:19:26 +02:00
use \Cake\Http\Session ;
use Cake\Core\Configure ;
use Cake\Http\Client ;
use Cake\Http\Client\FormData ;
2022-05-17 02:42:14 +02:00
use Cake\Http\Exception\NotFoundException ;
2021-10-01 13:19:26 +02:00
class AuthKeycloakBehavior extends Behavior
{
public function getUser ( EntityInterface $profile , Session $session )
{
$userId = $session -> read ( 'Auth.User.id' );
if ( $userId ) {
return $this -> _table -> get ( $userId );
}
$raw_profile_payload = $profile -> access_token -> getJwt () -> getPayload ();
$user = $this -> extractProfileData ( $raw_profile_payload );
if ( ! $user ) {
2022-09-18 18:51:05 +02:00
throw new \RuntimeException ( 'Unable to authenticate user. The KeyCloak and Cerebrate states of the user differ. This could be due to a missing synchronisation of the data.' );
2021-10-01 13:19:26 +02:00
}
return $user ;
}
2022-11-09 14:10:54 +01:00
2021-10-01 13:19:26 +02:00
private function extractProfileData ( $profile_payload )
{
$mapping = Configure :: read ( 'keycloak.mapping' );
$fields = [
'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 ];
}
}
2022-09-21 10:07:51 +02:00
$existingUser = $this -> _table -> find ()
-> where ([ 'username' => $profile_payload [ $fields [ 'username' ]]])
-> contain ( 'Individuals' )
-> first ();
2022-12-12 16:49:52 +01:00
if ( mb_strtolower ( $existingUser [ 'individual' ][ 'email' ]) !== mb_strtolower ( $profile_payload [ $fields [ 'email' ]])) {
2022-09-18 18:51:05 +02:00
return false ;
2021-10-01 13:19:26 +02:00
}
return $existingUser ;
}
2022-05-17 02:42:14 +02:00
/*
* Run a rest query against keycloak
* Auto sets the headers and uses a sprintf string to build the URL , injecting the baseurl + realm into the $pathString
*/
private function restApiRequest ( string $pathString , array $payload , string $postRequestType = 'post' ) : Object
{
$token = $this -> getAdminAccessToken ();
$keycloakConfig = Configure :: read ( 'keycloak' );
$http = new Client ();
$url = sprintf (
$pathString ,
$keycloakConfig [ 'provider' ][ 'baseUrl' ],
$keycloakConfig [ 'provider' ][ 'realm' ]
);
return $http -> $postRequestType (
$url ,
json_encode ( $payload ),
[
'headers' => [
'Content-Type' => 'application/json' ,
'Authorization' => 'Bearer ' . $token
]
]
);
}
2022-11-11 15:10:04 +01:00
public function getUserIdByUsername ( string $username )
{
$response = $this -> restApiRequest (
'%s/admin/realms/%s/users/?username=' . urlencode ( $username ),
[],
'GET'
);
if ( ! $response -> isOk ()) {
$responseBody = json_decode ( $response -> getStringBody (), true );
$this -> _table -> auditLogs () -> insert ([
'request_action' => 'keycloakGetUser' ,
'model' => 'User' ,
'model_id' => 0 ,
'model_title' => __ ( 'Failed to fetch user ({0}) from keycloak' , $username ),
'changed' => [ 'error' => empty ( $responseBody [ 'errorMessage' ]) ? 'Unknown error.' : $responseBody [ 'errorMessage' ]]
]);
}
$responseBody = json_decode ( $response -> getStringBody (), true );
if ( empty ( $responseBody [ 0 ][ 'id' ])) {
return false ;
}
return $responseBody [ 0 ][ 'id' ];
}
public function deleteUser ( $data ) : bool
{
$userId = $this -> getUserIdByUsername ( $data [ 'username' ]);
if ( $userId === false ) {
$this -> _table -> auditLogs () -> insert ([
'request_action' => 'keycloakUserDeletion' ,
'model' => 'User' ,
'model_id' => 0 ,
'model_title' => __ ( 'User {0} not found in keycloak, deleting the user locally.' , $data [ 'username' ]),
'changed' => []
]);
return true ;
}
$response = $this -> restApiRequest (
'%s/admin/realms/%s/users/' . urlencode ( $userId ),
[],
'delete'
);
if ( ! $response -> isOk ()) {
$responseBody = json_decode ( $response -> getStringBody (), true );
$this -> _table -> auditLogs () -> insert ([
'request_action' => 'keycloakUserDeletion' ,
'model' => 'User' ,
'model_id' => 0 ,
'model_title' => __ ( 'Failed to delete user {0} ({1}) in keycloak' , $data [ 'username' ], $userId ),
'changed' => [ 'error' => empty ( $responseBody [ 'errorMessage' ]) ? 'Unknown error.' : $responseBody [ 'errorMessage' ]]
]);
return false ;
}
return true ;
}
2021-10-01 13:19:26 +02:00
public function enrollUser ( $data ) : bool
{
$roleConditions = [
'id' => $data [ 'role_id' ]
];
2022-05-17 04:01:10 +02:00
$user = [
2021-10-01 13:19:26 +02:00
'username' => $data [ 'username' ],
2022-05-17 04:01:10 +02:00
'disabled' => false ,
'individual' => $this -> _table -> Individuals -> find () -> where (
[
'id' => $data [ 'individual_id' ]
]
) -> first (),
'role' => $this -> _table -> Roles -> find () -> where ( $roleConditions ) -> first (),
'organisation' => $this -> _table -> Organisations -> find () -> where (
[
'id' => $data [ 'organisation_id' ]
]
) -> first ()
2021-10-01 13:19:26 +02:00
];
2022-05-17 04:01:10 +02:00
$clientId = $this -> getClientId ();
2022-10-31 11:31:38 +01:00
$newUserId = $this -> createUser ( $user , $clientId );
2022-10-25 10:57:18 +02:00
if ( ! $newUserId ) {
2022-05-17 10:16:47 +02:00
$logChange = [
'username' => $user [ 'username' ],
'individual_id' => $user [ 'individual' ][ 'id' ],
'role_id' => $user [ 'role' ][ 'id' ]
];
2022-02-18 11:47:33 +01:00
$this -> _table -> auditLogs () -> insert ([
'request_action' => 'enrollUser' ,
'model' => 'User' ,
'model_id' => 0 ,
2022-05-17 04:01:10 +02:00
'model_title' => __ ( 'Failed Keycloak enrollment for user {0}' , $user [ 'username' ]),
2022-02-18 11:47:33 +01:00
'changed' => $logChange
]);
} else {
2022-05-17 10:16:47 +02:00
$logChange = [
'username' => $user [ 'username' ],
'individual_id' => $user [ 'individual' ][ 'id' ],
'role_id' => $user [ 'role' ][ 'id' ]
];
2022-02-18 11:47:33 +01:00
$this -> _table -> auditLogs () -> insert ([
'request_action' => 'enrollUser' ,
'model' => 'User' ,
'model_id' => 0 ,
2022-05-17 04:01:10 +02:00
'model_title' => __ ( 'Successful Keycloak enrollment for user {0}' , $user [ 'username' ]),
2022-02-18 11:47:33 +01:00
'changed' => $logChange
]);
2022-10-25 10:57:18 +02:00
$response = $this -> restApiRequest (
'%s/admin/realms/%s/users/' . urlencode ( $newUserId ) . '/execute-actions-email' ,
[ 'UPDATE_PASSWORD' ],
'put'
);
if ( ! $response -> isOk ()) {
$responseBody = json_decode ( $response -> getStringBody (), true );
$this -> _table -> auditLogs () -> insert ([
'request_action' => 'keycloakWelcomeEmail' ,
'model' => 'User' ,
'model_id' => 0 ,
'model_title' => __ ( 'Failed to send welcome mail to user ({0}) in keycloak' , $user [ 'username' ]),
'changed' => [ 'error' => empty ( $responseBody [ 'errorMessage' ]) ? 'Unknown error.' : $responseBody [ 'errorMessage' ]]
]);
}
2022-02-18 11:47:33 +01:00
}
2021-10-01 13:19:26 +02:00
return true ;
}
2022-09-21 10:11:09 +02:00
/**
* handleUserUpdate
*
* @ param \App\Model\Entity\User $user
2022-10-31 11:31:38 +01:00
* @ return array Containing changes if successful
2022-09-21 10:11:09 +02:00
*/
2022-10-31 11:31:38 +01:00
public function handleUserUpdate ( \App\Model\Entity\User $user ) : array
2022-09-21 10:11:09 +02:00
{
$user [ 'individual' ] = $this -> _table -> Individuals -> find () -> where ([
'id' => $user [ 'individual_id' ]
]) -> first ();
$user [ 'role' ] = $this -> _table -> Roles -> find () -> where ([
'id' => $user [ 'role_id' ]
]) -> first ();
$user [ 'organisation' ] = $this -> _table -> Organisations -> find () -> where ([
'id' => $user [ 'organisation_id' ]
]) -> first ();
$users = [ $user -> toArray ()];
$clientId = $this -> getClientId ();
2022-10-31 13:26:12 +01:00
$changes = $this -> syncUsers ( $users , $clientId );
2022-10-31 11:31:38 +01:00
return $changes ;
2022-09-21 10:11:09 +02:00
}
2022-10-25 15:08:41 +02:00
public function keyCloaklogout () : string
{
$keycloakConfig = Configure :: read ( 'keycloak' );
$logoutUrl = sprintf (
'%s/realms/%s/protocol/openid-connect/logout?redirect_uri=%s' ,
$keycloakConfig [ 'provider' ][ 'baseUrl' ],
$keycloakConfig [ 'provider' ][ 'realm' ],
urlencode ( Configure :: read ( 'App.fullBaseUrl' ))
);
return $logoutUrl ;
}
2021-10-01 13:19:26 +02:00
private function getAdminAccessToken ()
{
$keycloakConfig = Configure :: read ( 'keycloak' );
$http = new Client ();
$tokenUrl = sprintf (
'%s/realms/%s/protocol/openid-connect/token' ,
$keycloakConfig [ 'provider' ][ 'baseUrl' ],
$keycloakConfig [ 'provider' ][ 'realm' ]
);
$response = $http -> post (
$tokenUrl ,
sprintf (
'grant_type=client_credentials&client_id=%s&client_secret=%s' ,
urlencode ( Configure :: read ( 'keycloak.provider.applicationId' )),
urlencode ( Configure :: read ( 'keycloak.provider.applicationSecret' ))
),
[
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded'
]
]
);
$parsedResponse = json_decode ( $response -> getStringBody (), true );
return $parsedResponse [ 'access_token' ];
}
2022-05-17 02:42:14 +02:00
private function getClientId () : string
{
$response = $this -> restApiRequest ( '%s/admin/realms/%s/clients?clientId=' . Configure :: read ( 'keycloak.provider.applicationId' ), [], 'get' );
$clientId = json_decode ( $response -> getStringBody (), true );
if ( ! empty ( $clientId [ 0 ][ 'id' ])) {
return $clientId [ 0 ][ 'id' ];
} else {
throw new NotFoundException ( __ ( 'Keycloak client ID not found or service account doesn\'t have the "view-clients" privilege.' ));
}
}
public function syncWithKeycloak () : array
{
2022-10-31 13:26:12 +01:00
$this -> updateMappers ();
2022-05-17 02:42:14 +02:00
$results = [];
2022-12-09 11:53:20 +01:00
$data [ 'Users' ] = $this -> getCerebrateUsers ();
2022-05-17 02:42:14 +02:00
$clientId = $this -> getClientId ();
2022-10-31 11:31:38 +01:00
return $this -> syncUsers ( $data [ 'Users' ], $clientId );
2022-05-17 02:42:14 +02:00
}
2022-10-31 11:31:38 +01:00
private function syncUsers ( array $users , $clientId ) : array
2022-12-09 11:53:20 +01:00
{
$keycloakUsersParsed = $this -> getParsedKeycloakUser ();
$changes = [
'created' => [],
'modified' => [],
];
foreach ( $users as & $user ) {
if ( empty ( $keycloakUsersParsed [ $user [ 'username' ]])) {
if ( $this -> createUser ( $user , $clientId )) {
$changes [ 'created' ][] = $user [ 'username' ];
}
} else {
if ( $this -> checkAndUpdateUser ( $keycloakUsersParsed [ $user [ 'username' ]], $user )) {
$changes [ 'modified' ][] = $user [ 'username' ];
}
}
}
return $changes ;
}
public function getParsedKeycloakUser () : array
2022-05-17 02:42:14 +02:00
{
$response = $this -> restApiRequest ( '%s/admin/realms/%s/users' , [], 'get' );
$keycloakUsers = json_decode ( $response -> getStringBody (), true );
$keycloakUsersParsed = [];
foreach ( $keycloakUsers as $u ) {
$keycloakUsersParsed [ $u [ 'username' ]] = [
'id' => $u [ 'id' ],
'username' => $u [ 'username' ],
'enabled' => $u [ 'enabled' ],
'firstName' => $u [ 'firstName' ],
'lastName' => $u [ 'lastName' ],
'email' => $u [ 'email' ],
2022-10-31 11:31:38 +01:00
'attributes' => [
'role_name' => $u [ 'attributes' ][ 'role_name' ][ 0 ] ? ? '' ,
'role_uuid' => $u [ 'attributes' ][ 'role_uuid' ][ 0 ] ? ? '' ,
'org_uuid' => $u [ 'attributes' ][ 'org_uuid' ][ 0 ] ? ? '' ,
'org_name' => $u [ 'attributes' ][ 'org_name' ][ 0 ] ? ? ''
]
2022-05-17 02:42:14 +02:00
];
}
2022-12-09 11:53:20 +01:00
return $keycloakUsersParsed ;
}
private function getCerebrateUsers () : array
{
return $this -> _table -> find () -> contain ([ 'Individuals' , 'Organisations' , 'Roles' ]) -> select ([
'id' ,
'uuid' ,
'username' ,
'disabled' ,
'Individuals.email' ,
'Individuals.first_name' ,
'Individuals.last_name' ,
'Individuals.uuid' ,
'Roles.name' ,
'Roles.uuid' ,
'Organisations.name' ,
'Organisations.uuid'
]) -> disableHydration () -> toArray ();
2022-05-17 02:42:14 +02:00
}
private function checkAndUpdateUser ( array $keycloakUser , array $user ) : bool
{
2022-12-12 16:49:52 +01:00
if ( $this -> checkKeycloakUserRequiresUpdate ( $keycloakUser , $user )) {
2022-05-17 02:42:14 +02:00
$change = [
'enabled' => ! $user [ 'disabled' ],
2022-05-17 04:01:10 +02:00
'firstName' => $user [ 'individual' ][ 'first_name' ],
'lastName' => $user [ 'individual' ][ 'last_name' ],
'email' => $user [ 'individual' ][ 'email' ],
2022-10-31 11:31:38 +01:00
'attributes' => [
'role_name' => $user [ 'role' ][ 'name' ],
'role_uuid' => $user [ 'role' ][ 'uuid' ],
'org_name' => $user [ 'organisation' ][ 'name' ],
'org_uuid' => $user [ 'organisation' ][ 'uuid' ]
]
2022-05-17 02:42:14 +02:00
];
$response = $this -> restApiRequest ( '%s/admin/realms/%s/users/' . $keycloakUser [ 'id' ], $change , 'put' );
2022-05-17 04:01:10 +02:00
if ( ! $response -> isOk ()) {
$this -> _table -> auditLogs () -> insert ([
'request_action' => 'keycloakUpdateUser' ,
'model' => 'User' ,
'model_id' => 0 ,
'model_title' => __ ( 'Failed to update user ({0}) in keycloak' , $user [ 'username' ]),
'changed' => [
'code' => $response -> getStatusCode (),
'error_body' => $response -> getStringBody ()
]
]);
} else {
return true ;
}
2022-05-17 02:42:14 +02:00
}
2022-05-17 04:01:10 +02:00
return false ;
2022-05-17 02:42:14 +02:00
}
2022-12-09 11:53:20 +01:00
public function checkKeycloakStatus ( array $users , array $keycloakUsers ) : array
{
$users = Hash :: combine ( $users , '{n}.username' , '{n}' );
$keycloakUsersParsed = Hash :: combine ( $keycloakUsers , '{n}.username' , '{n}' );
$status = [];
foreach ( $users as $username => $user ) {
$differences = [];
$requireUpdate = $this -> checkKeycloakUserRequiresUpdate ( $keycloakUsersParsed [ $username ], $user , $differences );
$status [ $user [ 'id' ]] = [
'require_update' => $requireUpdate ,
'differences' => $differences ,
];
}
return $status ;
}
private function checkKeycloakUserRequiresUpdate ( array $keycloakUser , array $user , array & $differences = []) : bool
{
2022-12-12 08:45:02 +01:00
$condEnabled = $keycloakUser [ 'enabled' ] == $user [ 'disabled' ];
2022-12-12 16:49:52 +01:00
$condFirstname = mb_strtolower ( $keycloakUser [ 'firstName' ]) !== mb_strtolower ( $user [ 'individual' ][ 'first_name' ]);
$condLastname = mb_strtolower ( $keycloakUser [ 'lastName' ]) !== mb_strtolower ( $user [ 'individual' ][ 'last_name' ]);
$condEmail = mb_strtolower ( $keycloakUser [ 'email' ]) !== mb_strtolower ( $user [ 'individual' ][ 'email' ]);
$condRolename = ( empty ( $keycloakUser [ 'attributes' ][ 'role_name' ]) || mb_strtolower ( $keycloakUser [ 'attributes' ][ 'role_name' ]) !== mb_strtolower ( $user [ 'role' ][ 'name' ]));
$condRoleuuid = ( empty ( $keycloakUser [ 'attributes' ][ 'role_uuid' ]) || mb_strtolower ( $keycloakUser [ 'attributes' ][ 'role_uuid' ]) !== mb_strtolower ( $user [ 'role' ][ 'uuid' ]));
$condOrgname = ( empty ( $keycloakUser [ 'attributes' ][ 'org_name' ]) || mb_strtolower ( $keycloakUser [ 'attributes' ][ 'org_name' ]) !== mb_strtolower ( $user [ 'organisation' ][ 'name' ]));
$condOrguuid = ( empty ( $keycloakUser [ 'attributes' ][ 'org_uuid' ]) || mb_strtolower ( $keycloakUser [ 'attributes' ][ 'org_uuid' ]) !== mb_strtolower ( $user [ 'organisation' ][ 'uuid' ]));
2022-12-12 08:45:02 +01:00
if ( $condEnabled || $condFirstname || $condLastname || $condEmail || $condRolename || $condRoleuuid || $condOrgname || $condOrguuid ) {
if ( $condEnabled ) {
$differences [ 'enabled' ] = [ 'keycloak' => $keycloakUser [ 'enabled' ], 'cerebrate' => $user [ 'disabled' ]];
2022-12-09 11:53:20 +01:00
}
2022-12-12 08:45:02 +01:00
if ( $condFirstname ) {
$differences [ 'first_name' ] = [ 'keycloak' => $keycloakUser [ 'firstName' ], 'cerebrate' => $user [ 'individual' ][ 'first_name' ]];
2022-12-09 11:53:20 +01:00
}
2022-12-12 08:45:02 +01:00
if ( $condLastname ) {
$differences [ 'last_name' ] = [ 'keycloak' => $keycloakUser [ 'lastName' ], 'cerebrate' => $user [ 'individual' ][ 'last_name' ]];
2022-12-09 11:53:20 +01:00
}
2022-12-12 08:45:02 +01:00
if ( $condEmail ) {
$differences [ 'email' ] = [ 'keycloak' => $keycloakUser [ 'email' ], 'cerebrate' => $user [ 'individual' ][ 'email' ]];
2022-12-09 11:53:20 +01:00
}
2022-12-12 08:45:02 +01:00
if ( $condRolename ) {
$differences [ 'role_name' ] = [ 'keycloak' => $keycloakUser [ 'attributes' ][ 'role_name' ], 'cerebrate' => $user [ 'role' ][ 'name' ]];
2022-12-09 11:53:20 +01:00
}
2022-12-12 08:45:02 +01:00
if ( $condRoleuuid ) {
$differences [ 'role_uuid' ] = [ 'keycloak' => $keycloakUser [ 'attributes' ][ 'role_uuid' ], 'cerebrate' => $user [ 'role' ][ 'uuid' ]];
2022-12-09 11:53:20 +01:00
}
2022-12-12 08:45:02 +01:00
if ( $condOrgname ) {
$differences [ 'org_name' ] = [ 'keycloak' => $keycloakUser [ 'attributes' ][ 'org_name' ], 'cerebrate' => $user [ 'organisation' ][ 'name' ]];
2022-12-09 11:53:20 +01:00
}
2022-12-12 08:45:02 +01:00
if ( $condOrguuid ) {
$differences [ 'org_uuid' ] = [ 'keycloak' => $keycloakUser [ 'attributes' ][ 'org_uuid' ], 'cerebrate' => $user [ 'organisation' ][ 'uuid' ]];
2022-12-09 11:53:20 +01:00
}
return true ;
}
return false ;
}
2022-10-31 11:31:38 +01:00
private function createUser ( array $user , string $clientId )
2022-05-17 02:42:14 +02:00
{
$newUser = [
'username' => $user [ 'username' ],
'enabled' => ! $user [ 'disabled' ],
'firstName' => $user [ 'individual' ][ 'first_name' ],
'lastName' => $user [ 'individual' ][ 'last_name' ],
2022-10-31 11:31:38 +01:00
'email' => $user [ 'individual' ][ 'email' ],
'attributes' => [
'role_name' => $user [ 'role' ][ 'name' ],
'role_uuid' => $user [ 'role' ][ 'uuid' ],
'org_name' => $user [ 'organisation' ][ 'name' ],
'org_uuid' => $user [ 'organisation' ][ 'uuid' ]
]
2022-05-17 02:42:14 +02:00
];
$response = $this -> restApiRequest ( '%s/admin/realms/%s/users' , $newUser , 'post' );
2022-05-17 04:01:10 +02:00
if ( ! $response -> isOk ()) {
$this -> _table -> auditLogs () -> insert ([
'request_action' => 'createUser' ,
'model' => 'User' ,
'model_id' => 0 ,
'model_title' => __ ( 'Failed to create user ({0}) in keycloak {0}' , $user [ 'username' ]),
'changed' => [
'code' => $response -> getStatusCode (),
'error_body' => $response -> getStringBody ()
]
]);
}
2022-08-23 11:05:07 +02:00
$newUser = $this -> restApiRequest (
'%s/admin/realms/%s/users?username=' . $this -> urlencodeEscapeForSprintf ( urlencode ( $user [ 'username' ])),
[],
'get'
);
2022-05-17 10:16:47 +02:00
$users = json_decode ( $newUser -> getStringBody (), true );
if ( empty ( $users [ 0 ][ 'id' ])) {
2022-05-17 04:01:10 +02:00
return false ;
}
2022-05-17 10:16:47 +02:00
if ( is_array ( $users [ 0 ][ 'id' ])) {
$users [ 0 ][ 'id' ] = $users [ 0 ][ 'id' ][ 0 ];
}
$user [ 'id' ] = $users [ 0 ][ 'id' ];
2022-10-25 10:57:18 +02:00
return $user [ 'id' ];
2022-05-17 02:42:14 +02:00
}
2022-08-23 11:05:07 +02:00
private function urlencodeEscapeForSprintf ( string $input ) : string
{
return str_replace ( '%' , '%%' , $input );
}
2022-10-31 13:26:12 +01:00
public function updateMappers () : bool
{
$clientId = $this -> getClientId ();
$response = $this -> restApiRequest ( '%s/admin/realms/%s/clients/' . $clientId . '/protocol-mappers/models?protocolMapper=oidc-usermodel-attribute-mapper' , [], 'get' );
if ( $response -> isOk ()) {
$mappers = json_decode ( $response -> getStringBody (), true );
} else {
return false ;
}
$enabledMappers = [];
$defaultMappers = [
'org_name' => 0 ,
'org_uuid' => 0 ,
'role_name' => 0 ,
'role_uuid' => 0
];
$mappersToEnable = explode ( ',' , Configure :: read ( 'keycloak.user_meta_mapping' ));
foreach ( $mappers as $mapper ) {
if ( $mapper [ 'protocolMapper' ] !== 'oidc-usermodel-attribute-mapper' ) {
continue ;
}
if ( in_array ( $mapper [ 'name' ], array_keys ( $defaultMappers ))) {
$defaultMappers [ $mapper [ 'name' ]] = 1 ;
continue ;
}
$enabledMappers [ $mapper [ 'name' ]] = $mapper ;
}
$payload = [];
foreach ( $mappersToEnable as $mapperToEnable ) {
$payload [] = [
'protocol' => 'openid-connect' ,
'name' => $mapperToEnable ,
'protocolMapper' => 'oidc-usermodel-attribute-mapper' ,
'config' => [
'id.token.claim' => true ,
'access.token.claim' => true ,
'userinfo.token.claim' => true ,
'user.attribute' => $mapperToEnable ,
'claim.name' => $mapperToEnable
]
];
}
2022-10-31 13:36:53 +01:00
foreach ( $defaultMappers as $defaultMapper => $enabled ) {
if ( ! $enabled ) {
$payload [] = [
'protocol' => 'openid-connect' ,
'name' => $defaultMapper ,
'protocolMapper' => 'oidc-usermodel-attribute-mapper' ,
'config' => [
'id.token.claim' => true ,
'access.token.claim' => true ,
'userinfo.token.claim' => true ,
'user.attribute' => $defaultMapper ,
'claim.name' => $defaultMapper
]
];
}
}
2022-10-31 13:26:12 +01:00
if ( ! empty ( $payload )) {
$response = $this -> restApiRequest ( '%s/admin/realms/%s/clients/' . $clientId . '/protocol-mappers/add-models' , $payload , 'post' );
if ( ! $response -> isOk ()) {
return false ;
}
}
return true ;
}
2021-10-01 13:19:26 +02:00
}