From 8b72a04c9a0c6cc983e2d72cd03e8ff5744af4d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ANDRE=20s=C3=A9bastien?= <sandre@afi-sa.fr> Date: Thu, 1 Jun 2023 12:41:20 +0000 Subject: [PATCH] hotline : #178931 : default_id_bib before id_site in cas V3 --- VERSIONS_HOTLINE/178931 | 1 + library/Class/WebService/Cas2.php | 8 +- library/Class/WebService/Cas3.php | 17 +- ...IdentityProviderAuthenticationCas3Test.php | 404 ++++++++++++++---- .../IdentityProvider/cas3withoutsitecode.xml | 15 + .../IdentityProvider/cas3withsitecode.xml | 16 + 6 files changed, 369 insertions(+), 92 deletions(-) create mode 100644 VERSIONS_HOTLINE/178931 create mode 100644 tests/scenarios/IdentityProvider/cas3withoutsitecode.xml create mode 100644 tests/scenarios/IdentityProvider/cas3withsitecode.xml diff --git a/VERSIONS_HOTLINE/178931 b/VERSIONS_HOTLINE/178931 new file mode 100644 index 00000000000..8d28449d010 --- /dev/null +++ b/VERSIONS_HOTLINE/178931 @@ -0,0 +1 @@ + - correctif #178931 : Fournisseur d'identité : Cas3 la bibliothèque par défaut est prioritaire sur l'Id bibliothèque \ No newline at end of file diff --git a/library/Class/WebService/Cas2.php b/library/Class/WebService/Cas2.php index 6c8d39b0477..2270c025da3 100644 --- a/library/Class/WebService/Cas2.php +++ b/library/Class/WebService/Cas2.php @@ -50,10 +50,10 @@ class Class_WebService_Cas2 extends Class_WebService_IdentityProvider { } - protected function _getMappingValue( string $body, string $key) : string{ - if (! $result=(new SimpleXMLElement($body))->xpath('//cas:'. $key)) - return ''; - return (string)array_shift($result); + protected function _getMappingValue(string $body, string $key) : string { + return ($result = (new SimpleXMLElement($body))->xpath('//cas:' . $key)) + ? (string) array_shift($result) + : ''; } diff --git a/library/Class/WebService/Cas3.php b/library/Class/WebService/Cas3.php index bfa23383fcc..bfa69648b30 100644 --- a/library/Class/WebService/Cas3.php +++ b/library/Class/WebService/Cas3.php @@ -22,18 +22,33 @@ class Class_WebService_Cas3 extends Class_WebService_Cas2 { use Trait_TimeSource; + protected $_user_attributes = []; protected function _mappingResponse(string $body) :self { foreach (array_merge(Class_IdentityProvider_Cas3::getDefaultMapping(), $this->_provider->getMapping()) as $function_name => $key) - $this->_user_attributes[$function_name] = $this->_getMappingValue($body, $key); + $this->_user_attributes[$function_name] = ('id_site' === $function_name) + ? $this->_getValueForIdSite($body, $key) + : $this->_getMappingValue($body, $key); return $this; } + protected function _getValueForIdSite(string $body, string $key) : string { + if ($id = $this->_provider->getDefaultIdBib()) + return (string) $id; + + $id = $this->_getMappingValue($body, $key); + + return Class_Bib::find($id) + ? $id + : ''; + } + + public function updateUser(Class_Users $user) : self { foreach ($this->_user_attributes as $function_name => $value) $user->callSetterByAttributeName($function_name, $this->_validateValue($value, $function_name)) ; diff --git a/tests/scenarios/IdentityProvider/IdentityProviderAuthenticationCas3Test.php b/tests/scenarios/IdentityProvider/IdentityProviderAuthenticationCas3Test.php index 3433f32ef64..c56a98053a5 100644 --- a/tests/scenarios/IdentityProvider/IdentityProviderAuthenticationCas3Test.php +++ b/tests/scenarios/IdentityProvider/IdentityProviderAuthenticationCas3Test.php @@ -20,14 +20,19 @@ */ -abstract class IdentityProviderAuthenticationCas3BokehToBokehTestCase extends AbstractControllerTestCase { +abstract class IdentityProviderAuthenticationCas3BokehToBokehTestCase + extends AbstractControllerTestCase { + protected $_provider; public function setUp() { parent::setUp(); + Class_Users::setTimeSource(new TimeSourceForTest('2023-01-01')); Class_User_Log::setTimeSource(new TimeSourceForTest('2023-01-01 10:00:00')); + Class_AdminVar::set('ENABLE_IDENTITY_PROVIDERS', 1); + $this->fixture(Class_Bib::class, ['id' => 3, 'libelle' => 'Annecy', @@ -35,16 +40,18 @@ abstract class IdentityProviderAuthenticationCas3BokehToBokehTestCase extends Ab 'url_web' => 'cran.com', 'visibilite' => Class_Bib::V_DATA]); - $this->_provider = $this->fixture('Class_IdentityProvider', + $this->_provider = $this->fixture(Class_IdentityProvider::class, ['id' => 1, 'label' => 'Médiathèque Deauville', 'type' => 'cas3', - 'config' => json_encode($this->_identityProviderConfig()) - ]); + 'config' => json_encode($this->_identityProviderConfig())]); ZendAfi_Auth::getInstance()->clearIdentity(); + $response = $this->mock() - ->whenCalled('isError')->answers(false) + + ->whenCalled('isError') + ->answers(false) ->whenCalled('getBody') ->answers($this->_getAnswer()); @@ -55,31 +62,36 @@ abstract class IdentityProviderAuthenticationCas3BokehToBokehTestCase extends Ab } + public function tearDown() { + Class_Users::setTimeSource(null); + Class_User_Log::setTimeSource(null); + parent::tearDown(); + } + + protected function _getAnswer() { - return file_get_contents(__DIR__.'/cas3ticket.xml'); + return file_get_contents(__DIR__ . '/cas3ticket.xml'); } - protected function _identityProviderConfig(){ + protected function _identityProviderConfig() { return ['url' => 'http://moncompte.server.com/cas-server-v3/', 'auto_create_users' => 1, - 'role_level'=> ZendAfi_Acl_AdminControllerRoles::ABONNE, + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE, 'default_id_bib' => 3, - 'mapping' => $this->_getMapping()]; + 'mapping' => $this->_getMapping()]; } protected function _getMapping() { - return [ - 'nom' => 'lastname', - 'prenom' => 'firstname', - 'mail' => 'mail', - 'id_site' => 'site_code' - ]; + return ['nom' => 'lastname', + 'prenom' => 'firstname', + 'mail' => 'mail', + 'id_site' => 'site_code']; } - protected function _addPdJames(){ + protected function _addPdJames() { $this->fixture(Class_Users::class, ['id' => 98134, 'login' => 'mysuperid', @@ -89,18 +101,18 @@ abstract class IdentityProviderAuthenticationCas3BokehToBokehTestCase extends Ab 'civilite' => "1", 'date_naissance' => '2022-12-08', 'role_level' => ZendAfi_Acl_AdminControllerRoles::INVITE, - 'id_site' => 1 - ]); + 'id_site' => 1]); } abstract public function mappingDatas(); + /** * @test * @dataProvider mappingDatas */ - public function userShouldGetMapping($key, $value) { + public function userShouldGetMapping(string $key, $value) { $this->assertEquals($value, Class_Users::getIdentity()->{'get' . $key}()); } } @@ -108,27 +120,27 @@ abstract class IdentityProviderAuthenticationCas3BokehToBokehTestCase extends Ab -class IdentityProviderAuthenticationCas3WrongMappingTest extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { +class IdentityProviderAuthenticationCas3WrongMappingTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { public function setUp() { parent::setUp(); + $this->dispatch('/auth/login/provider/1?ticket=testticket'); } - protected function _identityProviderConfig(){ + protected function _identityProviderConfig() { return ['url' => 'http://moncompte.server.com/cas-server-v3/', 'auto_create_users' => 1, - 'role_level'=> ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL, - 'mapping' => $this->_getMapping()]; + 'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL, + 'mapping' => $this->_getMapping()]; } protected function _getMapping() { - return [ - 'nom' => 'badlastname', - 'prenom' => 'firstname', - ]; + return ['nom' => 'badlastname', + 'prenom' => 'firstname']; } @@ -137,8 +149,8 @@ class IdentityProviderAuthenticationCas3WrongMappingTest extends IdentityProvide ['Nom', ''], ['Prenom' , 'Tom'], ['Idabon' , '123XPE'], - [ 'LibraryId', ''], - [ 'LibelleBib', ''], + ['LibraryId', ''], + ['LibelleBib', ''], ]; } @@ -146,14 +158,15 @@ class IdentityProviderAuthenticationCas3WrongMappingTest extends IdentityProvide /** @test */ public function userShouldBeRemotelyLoggedAsModoPortail() { - $this->assertEquals('modo_portail',Class_Users::getIdentity()->getNomRole()); + $this->assertEquals('modo_portail', Class_Users::getIdentity()->getNomRole()); } } -class IdentityProviderAuthenticationCas3Bokeh2BokehWithUTCDateTest extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { +class IdentityProviderAuthenticationCas3Bokeh2BokehWithUTCDateTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { public function setUp() { parent::setUp(); @@ -163,27 +176,20 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehWithUTCDateTest extends Ident protected function _getAnswer() { - return file_get_contents(__DIR__.'/cas3archimed.xml'); - } - - - /** @test */ - public function userShouldBeRemotelyLogged() { - $this->assertTrue($this->_provider->isRemotelyLogged()); + return file_get_contents(__DIR__ . '/cas3archimed.xml'); } public function mappingDatas() : array { return [ ['Nom', 'Pouce'], - ['Prenom' , 'Tom'], + ['Prenom', 'Tom'], ['Mail', 'tom@pouce.fr'], ['IdSigb', '22345'], ['NomRole', 'abonne'], ['LibraryId', '3'], ['LibelleBib', 'Annecy'], ['DateFin', '2023-02-15'], - ['LibelleBib', 'Annecy'], ['Naissance', '1972-02-14'], ['CodePostal', '38123'], ['Ville', 'Laval'], @@ -191,19 +197,17 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehWithUTCDateTest extends Ident } - /** - * @test - * @dataProvider mappingDatas - */ - public function userShouldGetMapping($key, $value) { - $this->assertEquals($value, Class_Users::getIdentity()->{'get' . $key}()); + /** @test */ + public function userShouldBeRemotelyLogged() { + $this->assertTrue($this->_provider->isRemotelyLogged()); } } -class IdentityProviderAuthenticationCas3Bokeh2BokehTest extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { +class IdentityProviderAuthenticationCas3Bokeh2BokehTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { public function setUp() { parent::setUp(); @@ -212,18 +216,6 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehTest extends IdentityProvider } - /** @test */ - public function userShouldBeRemotelyLogged() { - $this->assertTrue($this->_provider->isRemotelyLogged()); - } - - - /** @test */ - public function groupMediathequeDeauvilleShouldBeCreated() { - $this->assertEquals('Groupe manuel pour Médiathèque Deauville', Class_UserGroup::find(1)->getLibelle()); - } - - public function mappingDatas() : array { return [ ['Nom', 'Pouce'], @@ -234,7 +226,6 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehTest extends IdentityProvider ['LibraryId', '3'], ['LibelleBib', 'Annecy'], ['DateFin', '2020-02-12'], - ['LibelleBib', 'Annecy'], ['Naissance', '1978-08-02'], ['CodePostal', '38123'], ['Ville', 'Laval'], @@ -242,12 +233,16 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehTest extends IdentityProvider } - /** - * @test - * @dataProvider mappingDatas - */ - public function userShouldGetMapping($key, $value) { - $this->assertEquals($value, Class_Users::getIdentity()->{'get' . $key}()); + /** @test */ + public function userShouldBeRemotelyLogged() { + $this->assertTrue($this->_provider->isRemotelyLogged()); + } + + + /** @test */ + public function groupMediathequeDeauvilleShouldBeCreated() { + $this->assertEquals('Groupe manuel pour Médiathèque Deauville', + Class_UserGroup::find(1)->getLibelle()); } @@ -260,7 +255,8 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehTest extends IdentityProvider -class IdentityProviderAuthenticationCas3PMBToBokehTest extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { +class IdentityProviderAuthenticationCas3PMBToBokehTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { public function setUp() { parent::setUp(); @@ -271,9 +267,9 @@ class IdentityProviderAuthenticationCas3PMBToBokehTest extends IdentityProviderA protected function _getMapping() { return [ - 'nom' => 'nom', - 'prenom' => 'firstname', - 'mail' => 'mail', + 'nom' => 'nom', + 'prenom' => 'firstname', + 'mail' => 'mail', 'id_site' => 'site_code', 'naissance' => 'year' ]; @@ -311,7 +307,8 @@ class IdentityProviderAuthenticationCas3PMBToBokehTest extends IdentityProviderA -class IdentityProviderAuthenticationCas3Bokeh2BokehWithoutAutoCreateUsersTest extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { +class IdentityProviderAuthenticationCas3Bokeh2BokehWithoutAutoCreateUsersTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { public function setUp() { parent::setUp(); @@ -321,13 +318,13 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehWithoutAutoCreateUsersTest ex } - protected function _identityProviderConfig(){ + protected function _identityProviderConfig() { return ['url' => 'http://moncompte.server.com/cas-server-v3/', 'associate_on_login' => 1, 'auto_create_users' => 0, - 'role_level'=> ZendAfi_Acl_AdminControllerRoles::ABONNE, + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE, 'default_id_bib' => 3, - 'mapping' => $this->_getMapping()]; + 'mapping' => $this->_getMapping()]; } @@ -348,7 +345,8 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehWithoutAutoCreateUsersTest ex -class IdentityProviderAuthenticationCas3Bokeh2BokehWithAutoUpdateUsersTest extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { +class IdentityProviderAuthenticationCas3Bokeh2BokehWithAutoUpdateUsersTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { public function setUp() { parent::setUp(); @@ -366,31 +364,28 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehWithAutoUpdateUsersTest exten } - protected function _identityProviderConfig(){ + protected function _identityProviderConfig() { return ['url' => 'http://moncompte.server.com/cas-server-v3/', 'associate_on_login' => 1, 'auto_create_users' => 1, 'auto_update_users' => 1, - 'role_level'=> ZendAfi_Acl_AdminControllerRoles::ABONNE, - 'default_id_bib' => 3, - 'mapping' => $this->_getMapping()]; + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE, + 'mapping' => $this->_getMapping()]; } - protected function _getMapping(){ - return [ - 'nom' => 'lastname', - 'prenom' => 'firstname', - 'mail' => 'mail', + protected function _getMapping() { + return ['nom' => 'lastname', + 'prenom' => 'firstname', + 'mail' => 'mail', 'date_naissance' => 'birth_date', 'idabon' => 'card_number', 'id_sigb' => 'ils_number', - 'mail' => 'mail' - ]; + 'mail' => 'mail']; } - public function mappingDatas(){ + public function mappingDatas() { return [ ['Id', '98134'], ['Nom', 'Pouce'], @@ -408,3 +403,238 @@ class IdentityProviderAuthenticationCas3Bokeh2BokehWithAutoUpdateUsersTest exten $this->assertTrue($this->_provider->isRemotelyLogged()); } } + + + + +class IdentityProviderAuthenticationCas3AnswerSiteCodeWithDefaultLibraryWithoutSiteCodeTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { + + public function setUp() { + parent::setUp(); + + $this->fixture(Class_Bib::class, + ['id' => 5, + 'libelle' => 'Meythet', + 'ville' => 'Meythet', + 'url_web' => 'cran.com', + 'visibilite' => Class_Bib::V_DATA]); + + $this->dispatch('/auth/login/provider/1?ticket=testticket'); + } + + + protected function _getAnswer() { + return file_get_contents(__DIR__ . '/cas3withsitecode.xml'); + } + + + protected function _getMapping() { + return ['nom' => 'lastname', + 'prenom' => 'firstname', + 'mail' => 'mail']; + } + + + public function mappingDatas() : array { + return [ + ['Nom', 'Pouce'], + ['Prenom', 'Tom'], + ['Mail', 'tom@pouce.fr'], + ['LibraryId', '3'], + ['LibelleBib', 'Annecy'], + ]; + } +} + + + + +class IdentityProviderAuthenticationCas3AnswerSiteCodeWithoutDefaultLibraryWithSiteCodeTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { + + public function setUp() { + parent::setUp(); + + $this->fixture(Class_Bib::class, + ['id' => 5, + 'libelle' => 'Meythet', + 'ville' => 'Meythet', + 'url_web' => 'cran.com', + 'visibilite' => Class_Bib::V_DATA]); + + $this->dispatch('/auth/login/provider/1?ticket=testticket'); + } + + + protected function _getAnswer() { + return file_get_contents(__DIR__ . '/cas3withsitecode.xml'); + } + + + protected function _identityProviderConfig() { + return ['url' => 'http://moncompte.server.com/cas-server-v3/', + 'auto_create_users' => 1, + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE, + 'mapping' => $this->_getMapping()]; + } + + + protected function _getMapping() { + return ['nom' => 'lastname', + 'prenom' => 'firstname', + 'mail' => 'mail', + 'id_site' => 'sitecode']; + } + + + public function mappingDatas() : array { + return [ + ['Nom', 'Pouce'], + ['Prenom', 'Tom'], + ['Mail', 'tom@pouce.fr'], + ['LibraryId', '5'], + ['LibelleBib', 'Meythet'], + ]; + } +} + + + + +class IdentityProviderAuthenticationCas3AnswerWithoutSiteCodeWithDefaultLibraryWithoutSiteCodeTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { + + public function setUp() { + parent::setUp(); + + $this->fixture(Class_Bib::class, + ['id' => 5, + 'libelle' => 'Meythet', + 'ville' => 'Meythet', + 'url_web' => 'cran.com', + 'visibilite' => Class_Bib::V_DATA]); + + $this->dispatch('/auth/login/provider/1?ticket=testticket'); + } + + + protected function _getAnswer() { + return file_get_contents(__DIR__ . '/cas3withoutsitecode.xml'); + } + + + protected function _getMapping() { + return ['nom' => 'lastname', + 'prenom' => 'firstname', + 'mail' => 'mail']; + } + + + public function mappingDatas() : array { + return [ + ['Nom', 'Pouce'], + ['Prenom', 'Tom'], + ['Mail', 'tom@pouce.fr'], + ['LibraryId', '3'], + ['LibelleBib', 'Annecy'], + ]; + } +} + + + + +class IdentityProviderAuthenticationCas3AnswerWithoutSiteCodeWithoutDefaultLibraryWithSiteCodeTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { + + public function setUp() { + parent::setUp(); + + $this->fixture(Class_Bib::class, + ['id' => 5, + 'libelle' => 'Meythet', + 'ville' => 'Meythet', + 'url_web' => 'cran.com', + 'visibilite' => Class_Bib::V_DATA]); + + $this->dispatch('/auth/login/provider/1?ticket=testticket'); + } + + + protected function _getAnswer() { + return file_get_contents(__DIR__ . '/cas3withoutsitecode.xml'); + } + + + protected function _identityProviderConfig() { + return ['url' => 'http://moncompte.server.com/cas-server-v3/', + 'auto_create_users' => 1, + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE, + 'mapping' => $this->_getMapping()]; + } + + + protected function _getMapping() { + return ['nom' => 'lastname', + 'prenom' => 'firstname', + 'mail' => 'mail', + 'id_site' => 'sitecode']; + } + + + public function mappingDatas() : array { + return [ + ['Nom', 'Pouce'], + ['Prenom', 'Tom'], + ['Mail', 'tom@pouce.fr'], + ['LibraryId', ''], + ['LibelleBib', ''], + ]; + } +} + + + + +class IdentityProviderAuthenticationCas3SiteCodeWithoutExistingBibTest + extends IdentityProviderAuthenticationCas3BokehToBokehTestCase { + + public function setUp() { + parent::setUp(); + + $this->dispatch('/auth/login/provider/1?ticket=testticket'); + } + + + protected function _getAnswer() { + return file_get_contents(__DIR__ . '/cas3withsitecode.xml'); + } + + + protected function _identityProviderConfig() { + return ['url' => 'http://moncompte.server.com/cas-server-v3/', + 'auto_create_users' => 1, + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE, + 'mapping' => $this->_getMapping()]; + } + + + protected function _getMapping() { + return ['nom' => 'lastname', + 'prenom' => 'firstname', + 'mail' => 'mail', + 'id_site' => 'sitecode']; + } + + + public function mappingDatas() : array { + return [ + ['Nom', 'Pouce'], + ['Prenom', 'Tom'], + ['Mail', 'tom@pouce.fr'], + ['LibraryId', ''], + ['LibelleBib', ''], + ]; + } +} diff --git a/tests/scenarios/IdentityProvider/cas3withoutsitecode.xml b/tests/scenarios/IdentityProvider/cas3withoutsitecode.xml new file mode 100644 index 00000000000..6f4915766f5 --- /dev/null +++ b/tests/scenarios/IdentityProvider/cas3withoutsitecode.xml @@ -0,0 +1,15 @@ +<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas"> + <cas:authenticationSuccess> + <cas:user>mysuperid</cas:user> + <cas:proxyGrantingTicket>ST-a51b1ae3e8b2319bba4e90841a40cf4b</cas:proxyGrantingTicket> + <cas:attributes> + <cas:lastname>Pouce</cas:lastname> + <cas:firstname>Tom</cas:firstname> + <cas:mail>tom@pouce.fr</cas:mail> + <cas:expire_at>20230215000000.0Z</cas:expire_at> + <cas:card_number>123XPE</cas:card_number> + <cas:affiliation>supremes</cas:affiliation> + <cas:affiliation>temptations</cas:affiliation> + </cas:attributes> + </cas:authenticationSuccess> +</cas:serviceResponse> diff --git a/tests/scenarios/IdentityProvider/cas3withsitecode.xml b/tests/scenarios/IdentityProvider/cas3withsitecode.xml new file mode 100644 index 00000000000..2ec8c8f62d3 --- /dev/null +++ b/tests/scenarios/IdentityProvider/cas3withsitecode.xml @@ -0,0 +1,16 @@ +<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas"> + <cas:authenticationSuccess> + <cas:user>mysuperid</cas:user> + <cas:proxyGrantingTicket>ST-a51b1ae3e8b2319bba4e90841a40cf4b</cas:proxyGrantingTicket> + <cas:attributes> + <cas:lastname>Pouce</cas:lastname> + <cas:firstname>Tom</cas:firstname> + <cas:mail>tom@pouce.fr</cas:mail> + <cas:expire_at>20230215000000.0Z</cas:expire_at> + <cas:card_number>123XPE</cas:card_number> + <cas:sitecode>5</cas:sitecode> + <cas:affiliation>supremes</cas:affiliation> + <cas:affiliation>temptations</cas:affiliation> + </cas:attributes> + </cas:authenticationSuccess> +</cas:serviceResponse> -- GitLab