From de9008a14d1cee1766a9497b6bb83de37c9e7938 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Tue, 4 Aug 2020 15:49:25 +0200 Subject: [PATCH] Parse EU Access attributes. --- composer.json | 1 + .../Core/User/EuLoginUserProviderSpec.php | 25 ++- .../Security/Core/User/EuLoginUserSpec.php | 160 ++++++++++++------ src/Security/Core/User/EuLoginUser.php | 32 ++-- .../Core/User/EuLoginUserInterface.php | 2 + 5 files changed, 158 insertions(+), 62 deletions(-) diff --git a/composer.json b/composer.json index f32dbc5..e122a20 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "ext-simplexml": "*", "ecphp/cas-bundle": "2.2.*", "ecphp/ecas": "2.1.*", + "loophp/collection": "^2.0", "symfony/framework-bundle": "^5.1" }, "require-dev": { diff --git a/spec/EcPhp/EuLoginBundle/Security/Core/User/EuLoginUserProviderSpec.php b/spec/EcPhp/EuLoginBundle/Security/Core/User/EuLoginUserProviderSpec.php index b283885..9b7ac89 100644 --- a/spec/EcPhp/EuLoginBundle/Security/Core/User/EuLoginUserProviderSpec.php +++ b/spec/EcPhp/EuLoginBundle/Security/Core/User/EuLoginUserProviderSpec.php @@ -54,6 +54,12 @@ public function it_can_load_a_user_from_a_response(ResponseInterface $response) group1 group2 + + + rex + snoopy + + EOF; @@ -77,11 +83,17 @@ public function it_can_load_a_user_from_a_response(ResponseInterface $response) 'group2', ], ], + 'extendedAttributes' => [ + 'http://stork.eu/motherInLawDogName' => [ + 'rex', + 'snoopy', + ], + ], ]); $this ->loadUserByResponse($response) - ->getUser() + ->getUsername() ->shouldReturn('username'); $this @@ -92,6 +104,17 @@ public function it_can_load_a_user_from_a_response(ResponseInterface $response) 'group2', 'ROLE_CAS_AUTHENTICATED', ]); + + $this->loadUserByResponse($response) + ->getExtendedAttributes() + ->shouldReturn( + [ + 'http://stork.eu/motherInLawDogName' => [ + 'rex', + 'snoopy', + ], + ] + ); } public function it_can_refresh_a_user(EuLoginUserInterface $user) diff --git a/spec/EcPhp/EuLoginBundle/Security/Core/User/EuLoginUserSpec.php b/spec/EcPhp/EuLoginBundle/Security/Core/User/EuLoginUserSpec.php index a26e72f..0019260 100644 --- a/spec/EcPhp/EuLoginBundle/Security/Core/User/EuLoginUserSpec.php +++ b/spec/EcPhp/EuLoginBundle/Security/Core/User/EuLoginUserSpec.php @@ -6,27 +6,47 @@ use EcPhp\CasBundle\Security\Core\User\CasUser; use EcPhp\CasBundle\Security\Core\User\CasUserInterface; +use EcPhp\CasLib\Introspection\Introspector; use EcPhp\EuLoginBundle\Security\Core\User\EuLoginUser; +use Nyholm\Psr7\Response; use PhpSpec\ObjectBehavior; class EuLoginUserSpec extends ObjectBehavior { public function it_can_get_groups_when_no_groups_are_available() { - $attributes = $this->getAttributesData(); - unset($attributes['groups']); - - $data = [ - 'user' => 'user', - 'proxyGrantingTicket' => 'proxyGrantingTicket', - 'proxies' => [ - 'proxy1', - ], - 'attributes' => $attributes, - ]; + $body = <<<'EOF' + + + username + bar + + foo + + + + group1 + group2 + + + + rex + snoopy + + + + + +EOF; + + $response = new Response(200, ['Content-Type' => 'application/xml'], $body); + $data = (new Introspector())->parse($response)['serviceResponse']['authenticationSuccess']; + unset($data['attributes']['groups']); + + $casUser = new CasUser($data); $this - ->beConstructedWith(new CasUser($data)); + ->beConstructedWith($casUser); $this ->getGroups() @@ -37,11 +57,11 @@ public function it_can_get_specific_attribute() { $this ->getAssuranceLevel() - ->shouldReturn('assuranceLevel'); + ->shouldReturn('40'); $this ->getAuthenticationFactors() - ->shouldReturn(['foobar']); + ->shouldReturn(['ecphp@ec.europa.eu']); $this ->getDepartmentNumber() @@ -73,7 +93,10 @@ public function it_can_get_specific_attribute() $this ->getGroups() - ->shouldReturn(['foo']); + ->shouldReturn([ + 'group1', + 'group2', + ]); $this ->getLastName() @@ -114,28 +137,14 @@ public function it_can_get_specific_attribute() $this ->getUid() ->shouldReturn('uid'); + + $this + ->getAttributes() + ->shouldReturn($this->getAttributesData()); } public function it_can_get_the_attributes_only(CasUserInterface $user) { - $data = [ - 'user' => 'user', - 'proxyGrantingTicket' => 'proxyGrantingTicket', - 'proxies' => [ - 'proxy1', - ], - 'attributes' => $this->getAttributesData(), - ]; - - $user - ->getAttributes() - ->willReturn($this->getAttributesData()); - - $user - ->beConstructedWith($data); - $this - ->beConstructedWith($user); - $this ->getAttributes() ->shouldReturn($this->getAttributesData()); @@ -148,26 +157,64 @@ public function it_is_initializable() public function let(CasUserInterface $user) { - $data = [ - 'user' => 'user', - 'proxyGrantingTicket' => 'proxyGrantingTicket', - 'proxies' => [ - 'proxy1', - ], - 'attributes' => $this->getAttributesData(), - ]; + $body = <<<'EOF' + + + username + bar + + foo + + + + + ecphp@ec.europa.eu + + + 40 + + group1 + group2 + + + + rex + snoopy + + + + + +EOF; + + $response = new Response(200, ['Content-Type' => 'application/json'], $body); + $data = (new Introspector())->parse($response)['serviceResponse']['authenticationSuccess']; $user ->beConstructedWith($data); + $user + ->getAttribute('extendedAttributes', []) + ->willReturn([ + 'extendedAttribute' => [ + 'attributeValue' => [ + 'value1', + 'value2', + ], + '@attributes' => [ + 'name' => 'attr1', + ], + ], + ]); + $user ->getAttribute('assuranceLevel') - ->willReturn('assuranceLevel'); + ->willReturn($data['attributes']['assuranceLevel']); $user ->getAttribute('authenticationFactors', []) ->willReturn([ - 'foobar', + 'ecphp@ec.europa.eu', ]); $user @@ -199,9 +246,15 @@ public function let(CasUserInterface $user) ->willReturn('firstName'); $user - ->getAttribute('groups', []) + ->getAttribute('groups', ['group' => []]) ->willReturn([ - 'foo', + 'group' => [ + 'group1', + 'group2', + ], + '@attributes' => [ + 'number' => 2, + ], ]); $user @@ -246,6 +299,10 @@ public function let(CasUserInterface $user) ->getAttribute('uid') ->willReturn('uid'); + $user + ->getAttributes() + ->willReturn($this->getAttributesData()); + $this ->beConstructedWith($user); } @@ -257,24 +314,31 @@ private function getAttributesData(): array 'email' => 'email', 'employeeNumber' => 'employeeNumber', 'employeeType' => 'employeeType', + 'extendedAttributes' => [ + 'attr1' => [ + 'value1', + 'value2', + ], + ], 'firstName' => 'firstName', 'lastName' => 'lastName', 'domain' => 'domain', 'domainUsername' => 'domainUsername', 'telephoneNumber' => 'telephoneNumber', 'locale' => 'locale', - 'assuranceLevel' => 'assuranceLevel', + 'assuranceLevel' => '40', 'uid' => 'uid', 'orgId' => 'orgId', 'teleworkingPriority' => 'teleworkingPriority', 'groups' => [ - 'foo', + 'group1', + 'group2', ], 'strengths' => [ 'bar', ], 'authenticationFactors' => [ - 'foobar', + 'ecphp@ec.europa.eu', ], 'loginDate' => 'loginDate', 'sso' => 'sso', diff --git a/src/Security/Core/User/EuLoginUser.php b/src/Security/Core/User/EuLoginUser.php index 087c55a..60e5f1c 100644 --- a/src/Security/Core/User/EuLoginUser.php +++ b/src/Security/Core/User/EuLoginUser.php @@ -5,9 +5,7 @@ namespace EcPhp\EuLoginBundle\Security\Core\User; use EcPhp\CasBundle\Security\Core\User\CasUserInterface; - -use function array_key_exists; -use function is_array; +use loophp\collection\Collection; final class EuLoginUser implements EuLoginUserInterface { @@ -16,9 +14,6 @@ final class EuLoginUser implements EuLoginUserInterface */ private $user; - /** - * EuLoginUser constructor. - */ public function __construct(CasUserInterface $user) { $this->user = $user; @@ -61,7 +56,10 @@ public function getAttribute(string $key, $default = null) */ public function getAttributes(): array { - return $this->user->getAttributes(); + $attributes = $this->user->getAttributes(); + $attributes['extendedAttributes'] = $this->getExtendedAttributes(); + + return $attributes; } /** @@ -120,6 +118,18 @@ public function getEmployeeType(): ?string return $this->user->getAttribute('employeeType'); } + public function getExtendedAttributes(): array + { + return Collection::fromIterable($this->user->getAttribute('extendedAttributes', [])) + ->map( + static function (array $item): array { + return [$item['@attributes']['name'] => $item['attributeValue']]; + } + ) + ->unwrap() + ->all(); + } + /** * {@inheritdoc} */ @@ -133,7 +143,7 @@ public function getFirstName(): ?string */ public function getGroups(): array { - return $this->user->getAttribute('groups', []); + return $this->user->getAttribute('groups', ['group' => []])['group']; } /** @@ -191,11 +201,7 @@ public function getRoles() { $default = ['ROLE_CAS_AUTHENTICATED']; - if (([] !== $roles = $this->getGroups()) && (array_key_exists('group', $roles) && is_array($roles['group']))) { - return array_merge($roles['group'], $default); - } - - return $default; + return array_merge($this->getGroups(), $default); } /** diff --git a/src/Security/Core/User/EuLoginUserInterface.php b/src/Security/Core/User/EuLoginUserInterface.php index 97d41b5..71a198f 100644 --- a/src/Security/Core/User/EuLoginUserInterface.php +++ b/src/Security/Core/User/EuLoginUserInterface.php @@ -27,6 +27,8 @@ public function getEmployeeNumber(): ?string; public function getEmployeeType(): ?string; + public function getExtendedAttributes(): array; + public function getFirstName(): ?string; /**