From 55e47c942124a6038c7a2c499afb06083c6a4526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= <marko.ivancic@srce.hr> Date: Thu, 6 Jul 2023 15:39:46 +0200 Subject: [PATCH] WIP --- src/Entities/Bases/AbstractProvider.php | 28 +++++--- src/Entities/Interfaces/ProviderInterface.php | 6 +- .../Providers/Bases/AbstractSaml2Provider.php | 69 +++++++++++++++++++ src/Entities/Providers/Identity/Oidc.php | 5 ++ src/Entities/Providers/Identity/Saml2.php | 37 ++-------- src/Entities/Providers/Service/Oidc.php | 5 ++ src/Entities/Providers/Service/Saml2.php | 40 ++--------- .../Entities/Bases/AbstractProviderTest.php | 5 ++ .../Entities/Providers/Identity/Saml2Test.php | 2 + .../Entities/Providers/Service/Saml2Test.php | 2 + tests/src/Helpers/ProviderResolverTest.php | 2 + 11 files changed, 119 insertions(+), 82 deletions(-) create mode 100644 src/Entities/Providers/Bases/AbstractSaml2Provider.php diff --git a/src/Entities/Bases/AbstractProvider.php b/src/Entities/Bases/AbstractProvider.php index 9e63abd..c4b66b6 100755 --- a/src/Entities/Bases/AbstractProvider.php +++ b/src/Entities/Bases/AbstractProvider.php @@ -18,23 +18,28 @@ abstract class AbstractProvider implements ProviderInterface $this->entityId = $this->resolveEntityId(); } - protected function resolveOptionallyLocalizedString(string $key, string $locale = 'en'): ?string - { - if (!isset($this->metadata[$key])) { + protected function resolveOptionallyLocalizedString( + string $key, + string $locale = self::DEFAULT_LOCALE, + array $metadataOverride = null + ): ?string { + $metadata = $metadataOverride ?? $this->metadata; + + if (!isset($metadata[$key])) { return null; } // Check for non-localized version. - if (is_string($this->metadata[$key])) { - return $this->metadata[$key]; + if (is_string($metadata[$key])) { + return $metadata[$key]; } if ( - is_array($this->metadata[$key]) && - !empty($this->metadata[$key][$locale]) && - is_string($this->metadata[$key][$locale]) + is_array($metadata[$key]) && + !empty($metadata[$key][$locale]) && + is_string($metadata[$key][$locale]) ) { - return $this->metadata[$key][$locale]; + return $metadata[$key][$locale]; } return null; @@ -50,8 +55,9 @@ abstract class AbstractProvider implements ProviderInterface return $this->entityId; } - abstract public function getName(string $locale = 'en'): ?string; - abstract public function getDescription(string $locale = 'en'): ?string; + abstract public function getName(string $locale = self::DEFAULT_LOCALE): ?string; + abstract public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string; abstract protected function resolveEntityId(): string; abstract public function getProtocol(): AuthenticationProtocolInterface; + abstract protected function getProviderDescription(): string; } diff --git a/src/Entities/Interfaces/ProviderInterface.php b/src/Entities/Interfaces/ProviderInterface.php index c82a179..a5957a5 100755 --- a/src/Entities/Interfaces/ProviderInterface.php +++ b/src/Entities/Interfaces/ProviderInterface.php @@ -9,9 +9,11 @@ use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload; interface ProviderInterface { + public const DEFAULT_LOCALE = 'en'; + public function getMetadata(): array; - public function getName(string $locale = 'en'): ?string; + public function getName(string $locale = self::DEFAULT_LOCALE): ?string; public function getEntityId(): string; - public function getDescription(string $locale = 'en'): ?string; + public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string; public function getProtocol(): AuthenticationProtocolInterface; } diff --git a/src/Entities/Providers/Bases/AbstractSaml2Provider.php b/src/Entities/Providers/Bases/AbstractSaml2Provider.php new file mode 100644 index 0000000..0a5fd98 --- /dev/null +++ b/src/Entities/Providers/Bases/AbstractSaml2Provider.php @@ -0,0 +1,69 @@ +<?php + +namespace SimpleSAML\Module\accounting\Entities\Providers\Bases; + +use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider; +use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; +use SimpleSAML\Module\accounting\Exceptions\MetadataException; +use SimpleSAML\Module\accounting\Entities\Authentication; + +abstract class AbstractSaml2Provider extends AbstractProvider +{ + public const METADATA_KEY_ENTITY_ID = 'entityid'; + public const METADATA_KEY_NAME = 'name'; + public const METADATA_KEY_DESCRIPTION = 'description'; + public const METADATA_KEY_UI_INFO = 'UIInfo'; + public const METADATA_KEY_UI_INFO_DESCRIPTION = 'Description'; + public const METADATA_KEY_UI_INFO_DISPLAY_NAME = 'DisplayName'; + + protected function getEntityInfoString(string $key, string $locale = self::DEFAULT_LOCALE): ?string + { + return $this->resolveOptionallyLocalizedString($key, $locale); + } + + protected function getEntityUiInfoString(string $key, string $locale = self::DEFAULT_LOCALE): ?string + { + if ( + isset($this->metadata[self::METADATA_KEY_UI_INFO]) && + is_array($this->metadata[self::METADATA_KEY_UI_INFO]) + ) { + return $this->resolveOptionallyLocalizedString( + $key, + $locale, + $this->metadata[self::METADATA_KEY_UI_INFO] + ); + } + + return null; + } + + public function getName(string $locale = self::DEFAULT_LOCALE): ?string + { + return $this->getEntityInfoString(self::METADATA_KEY_NAME, $locale) ?? + $this->getEntityUiInfoString(self::METADATA_KEY_UI_INFO_DISPLAY_NAME, $locale); + } + + public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string + { + return $this->getEntityInfoString(self::METADATA_KEY_DESCRIPTION, $locale) ?? + $this->getEntityUiInfoString(self::METADATA_KEY_UI_INFO_DESCRIPTION, $locale); + } + + /** + * @throws MetadataException + */ + protected function resolveEntityId(): string + { + if (empty($entityId = $this->getEntityInfoString(self::METADATA_KEY_ENTITY_ID))) { + $message = sprintf('Provider metadata does not contain entity ID (%s).', $this->getProviderDescription()); + throw new MetadataException($message); + } + + return $entityId; + } + + public function getProtocol(): AuthenticationProtocolInterface + { + return new Authentication\Protocol\Saml2(); + } +} diff --git a/src/Entities/Providers/Identity/Oidc.php b/src/Entities/Providers/Identity/Oidc.php index c662f78..9bc3784 100755 --- a/src/Entities/Providers/Identity/Oidc.php +++ b/src/Entities/Providers/Identity/Oidc.php @@ -43,4 +43,9 @@ class Oidc extends AbstractProvider implements IdentityProviderInterface { return new Authentication\Protocol\Oidc(); } + + protected function getProviderDescription(): string + { + return $this->getProtocol()->getDesignation() . ' OpenID Provider'; + } } diff --git a/src/Entities/Providers/Identity/Saml2.php b/src/Entities/Providers/Identity/Saml2.php index 0476863..8bef30d 100755 --- a/src/Entities/Providers/Identity/Saml2.php +++ b/src/Entities/Providers/Identity/Saml2.php @@ -5,44 +5,15 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities\Providers\Identity; use SimpleSAML\Module\accounting\Entities\Authentication; -use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider; use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface; +use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider; use SimpleSAML\Module\accounting\Exceptions\MetadataException; -class Saml2 extends AbstractProvider implements IdentityProviderInterface +class Saml2 extends AbstractSaml2Provider implements IdentityProviderInterface { - public const METADATA_KEY_NAME = 'name'; - public const METADATA_KEY_ENTITY_ID = 'entityid'; - public const METADATA_KEY_DESCRIPTION = 'description'; - - public function getName(string $locale = 'en'): ?string - { - return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_NAME, $locale); - } - - public function getDescription(string $locale = 'en'): ?string - { - return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_DESCRIPTION, $locale); - } - - /** - * @throws MetadataException - */ - protected function resolveEntityId(): string - { - if ( - !empty($this->metadata[self::METADATA_KEY_ENTITY_ID]) && - is_string($this->metadata[self::METADATA_KEY_ENTITY_ID]) - ) { - return $this->metadata[self::METADATA_KEY_ENTITY_ID]; - } - - throw new MetadataException('Identity provider metadata does not contain entity ID.'); - } - - public function getProtocol(): AuthenticationProtocolInterface + protected function getProviderDescription(): string { - return new Authentication\Protocol\Saml2(); + return $this->getProtocol()->getDesignation() . ' Identity Provider'; } } diff --git a/src/Entities/Providers/Service/Oidc.php b/src/Entities/Providers/Service/Oidc.php index 5f5ff82..c683718 100755 --- a/src/Entities/Providers/Service/Oidc.php +++ b/src/Entities/Providers/Service/Oidc.php @@ -45,4 +45,9 @@ class Oidc extends AbstractProvider implements ServiceProviderInterface { return new Authentication\Protocol\Oidc(); } + + protected function getProviderDescription(): string + { + return $this->getProtocol()->getDesignation() . ' Relying Party'; + } } diff --git a/src/Entities/Providers/Service/Saml2.php b/src/Entities/Providers/Service/Saml2.php index d0dfd4a..deeb307 100755 --- a/src/Entities/Providers/Service/Saml2.php +++ b/src/Entities/Providers/Service/Saml2.php @@ -4,45 +4,13 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities\Providers\Service; -use SimpleSAML\Module\accounting\Entities\Authentication; -use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider; -use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface; -use SimpleSAML\Module\accounting\Exceptions\MetadataException; +use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider; -class Saml2 extends AbstractProvider implements ServiceProviderInterface +class Saml2 extends AbstractSaml2Provider implements ServiceProviderInterface { - public const METADATA_KEY_ENTITY_ID = 'entityid'; - public const METADATA_KEY_NAME = 'name'; - public const METADATA_KEY_DESCRIPTION = 'description'; - - public function getName(string $locale = 'en'): ?string - { - return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_NAME, $locale); - } - - public function getDescription(string $locale = 'en'): ?string - { - return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_DESCRIPTION, $locale); - } - - /** - * @throws MetadataException - */ - protected function resolveEntityId(): string - { - if ( - !empty($this->metadata[self::METADATA_KEY_ENTITY_ID]) && - is_string($this->metadata[self::METADATA_KEY_ENTITY_ID]) - ) { - return $this->metadata[self::METADATA_KEY_ENTITY_ID]; - } - - throw new MetadataException('Service provider metadata does not contain entity ID.'); - } - - public function getProtocol(): AuthenticationProtocolInterface + protected function getProviderDescription(): string { - return new Authentication\Protocol\Saml2(); + return $this->getProtocol()->getDesignation() . ' Service Provider'; } } diff --git a/tests/src/Entities/Bases/AbstractProviderTest.php b/tests/src/Entities/Bases/AbstractProviderTest.php index e8d8a27..e858379 100755 --- a/tests/src/Entities/Bases/AbstractProviderTest.php +++ b/tests/src/Entities/Bases/AbstractProviderTest.php @@ -112,6 +112,11 @@ class AbstractProviderTest extends TestCase } }; } + + protected function getProviderDescription(): string + { + return 'provider description'; + } }; } } diff --git a/tests/src/Entities/Providers/Identity/Saml2Test.php b/tests/src/Entities/Providers/Identity/Saml2Test.php index 7c99595..5c4db09 100755 --- a/tests/src/Entities/Providers/Identity/Saml2Test.php +++ b/tests/src/Entities/Providers/Identity/Saml2Test.php @@ -12,6 +12,8 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays; /** * @covers \SimpleSAML\Module\accounting\Entities\Providers\Identity\Saml2 * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider + * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider + * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2 */ class Saml2Test extends TestCase { diff --git a/tests/src/Entities/Providers/Service/Saml2Test.php b/tests/src/Entities/Providers/Service/Saml2Test.php index c4475d7..225c92a 100755 --- a/tests/src/Entities/Providers/Service/Saml2Test.php +++ b/tests/src/Entities/Providers/Service/Saml2Test.php @@ -9,6 +9,8 @@ use SimpleSAML\Module\accounting\Exceptions\MetadataException; /** * @covers \SimpleSAML\Module\accounting\Entities\Providers\Service\Saml2 * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider + * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider + * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2 */ class Saml2Test extends TestCase { diff --git a/tests/src/Helpers/ProviderResolverTest.php b/tests/src/Helpers/ProviderResolverTest.php index 3661701..1e7f3fe 100755 --- a/tests/src/Helpers/ProviderResolverTest.php +++ b/tests/src/Helpers/ProviderResolverTest.php @@ -21,6 +21,8 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays; * @uses \SimpleSAML\Module\accounting\Entities\Providers\Identity\Oidc * @uses \SimpleSAML\Module\accounting\Entities\Providers\Service\Saml2 * @uses \SimpleSAML\Module\accounting\Entities\Providers\Service\Oidc + * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider + * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2 */ class ProviderResolverTest extends TestCase { -- GitLab