diff --git a/ci/qa/phpstan-baseline.neon b/ci/qa/phpstan-baseline.neon index 1331b58ea..7e32dc337 100644 --- a/ci/qa/phpstan-baseline.neon +++ b/ci/qa/phpstan-baseline.neon @@ -66,12 +66,6 @@ parameters: count: 1 path: ../../src/Surfnet/Stepup/Configuration/Configuration.php - - - message: '#^Parameter \#2 \$emailTemplates of class Surfnet\\Stepup\\Configuration\\Event\\EmailTemplatesUpdatedEvent constructor expects array, mixed given\.$#' - identifier: argument.type - count: 1 - path: ../../src/Surfnet/Stepup/Configuration/Configuration.php - - message: '#^Parameter \#2 \$identityProviders of class Surfnet\\Stepup\\Configuration\\Event\\IdentityProvidersUpdatedEvent constructor expects array, mixed given\.$#' identifier: argument.type @@ -90,12 +84,6 @@ parameters: count: 1 path: ../../src/Surfnet/Stepup/Configuration/Configuration.php - - - message: '#^Parameter \#2 \$sraaList of class Surfnet\\Stepup\\Configuration\\Event\\SraaUpdatedEvent constructor expects array, mixed given\.$#' - identifier: argument.type - count: 1 - path: ../../src/Surfnet/Stepup/Configuration/Configuration.php - - message: '#^Property Surfnet\\Stepup\\Configuration\\Configuration\:\:\$configuration type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -4086,12 +4074,6 @@ parameters: count: 1 path: ../../src/Surfnet/StepupMiddleware/ManagementBundle/Validator/ConfigurationStructureValidator.php - - - message: '#^Method Surfnet\\StepupMiddleware\\ManagementBundle\\Validator\\ConfigurationStructureValidator\:\:validateSraaConfiguration\(\) has parameter \$configuration with no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: ../../src/Surfnet/StepupMiddleware/ManagementBundle/Validator/ConfigurationStructureValidator.php - - message: '#^Parameter \#1 \$configuration of method Surfnet\\StepupMiddleware\\ManagementBundle\\Validator\\ConfigurationStructureValidator\:\:validateRoot\(\) expects array, mixed given\.$#' identifier: argument.type diff --git a/config/openconext/email_templates/en_GB/confirm_email.html.twig b/config/openconext/email_templates/en_GB/confirm_email.html.twig new file mode 100644 index 000000000..52e218b8a --- /dev/null +++ b/config/openconext/email_templates/en_GB/confirm_email.html.twig @@ -0,0 +1,7 @@ +

Dear {{ commonName }},

+ +

Thank you for registering your token. Please visit this link to verify your email address:

+ +

{{ verificationUrl }}

+ +

If you can not click on the URL, please copy the link and paste it in the address bar of your browser.

diff --git a/config/openconext/email_templates/en_GB/recovery_token_created.html.twig b/config/openconext/email_templates/en_GB/recovery_token_created.html.twig new file mode 100644 index 000000000..e7a590fac --- /dev/null +++ b/config/openconext/email_templates/en_GB/recovery_token_created.html.twig @@ -0,0 +1,5 @@ +

Dear {{ commonName }},

+ +

Thank you for registering a recovery method. You can use this method if you want to reactivate a token that you have lost.

+ +

Always make sure you have at least one recovery method available.

diff --git a/config/openconext/email_templates/en_GB/recovery_token_revoked.html.twig b/config/openconext/email_templates/en_GB/recovery_token_revoked.html.twig new file mode 100644 index 000000000..d2cc162fd --- /dev/null +++ b/config/openconext/email_templates/en_GB/recovery_token_revoked.html.twig @@ -0,0 +1,13 @@ +

Dear {{ commonName }},

+ +

+{% if isRevokedByRa %} + Your recovery method was removed by an administrator. +{% else %} + Your recovery method has been removed. Please contact your institution's helpdesk immediately if you did not do this yourself, as this could mean that your account has been compromised. +{% endif %} +

+ +

You can no longer use this recovery method to activate a token.

+ +

Always make sure you have at least one recovery method available.

diff --git a/config/openconext/email_templates/en_GB/registration_code_with_ra_locations.html.twig b/config/openconext/email_templates/en_GB/registration_code_with_ra_locations.html.twig new file mode 100644 index 000000000..b8e8748c9 --- /dev/null +++ b/config/openconext/email_templates/en_GB/registration_code_with_ra_locations.html.twig @@ -0,0 +1,27 @@ +

Dear {{ commonName }},

+ +

Thank you for registering your token. Please visit one of the locations below within 14 days to get your token activated. After {{ expirationDate | format_date('full', locale=locale) }} your activation code is no longer valid.

+ +

Please bring the following:

+ + +

Activation code: {{ registrationCode }}

+ +

Location(s) to activate your token:

+{% if raLocations is empty %} +

No locations known.

+{% else %} + +{% endif %} diff --git a/config/openconext/email_templates/en_GB/registration_code_with_ras.html.twig b/config/openconext/email_templates/en_GB/registration_code_with_ras.html.twig new file mode 100644 index 000000000..08a2ba75d --- /dev/null +++ b/config/openconext/email_templates/en_GB/registration_code_with_ras.html.twig @@ -0,0 +1,27 @@ +

Dear {{ commonName }},

+ +

Thank you for registering your token. Please visit one of the locations below within 14 days to get your token activated. After {{ expirationDate | format_date('full', locale=locale) }} your activation code is no longer valid.

+ +

Please bring the following:

+ + +

Activation code: {{ registrationCode }}

+ +

Location(s) to activate your token:

+{% if ras is empty %} +

No RAs are known.

+{% else %} + +{% endif %} diff --git a/config/openconext/email_templates/en_GB/second_factor_revoked.html.twig b/config/openconext/email_templates/en_GB/second_factor_revoked.html.twig new file mode 100644 index 000000000..e53a15dd3 --- /dev/null +++ b/config/openconext/email_templates/en_GB/second_factor_revoked.html.twig @@ -0,0 +1,13 @@ +

Dear {{ commonName }},

+ +

+{% if isRevokedByRa %} + The registration of your {{ tokenType }} with ID {{ tokenIdentifier }} was deleted by an administrator. +{% else %} + You have deleted the registration of your {{ tokenType }} token with ID {{ tokenIdentifier }}. If you did not delete your token you must immediately contact the support desk of your institution, as this may indicate that your account has been compromised. +{% endif %} +

+ +

You can no longer use this token to access services that require two-step authentication.

+ +

Do you want to replace your token? Please visit {{ selfServiceUrl }} and register a new token.

diff --git a/config/openconext/email_templates/en_GB/second_factor_verification_reminder_with_ra_locations.html.twig b/config/openconext/email_templates/en_GB/second_factor_verification_reminder_with_ra_locations.html.twig new file mode 100644 index 000000000..56ab91724 --- /dev/null +++ b/config/openconext/email_templates/en_GB/second_factor_verification_reminder_with_ra_locations.html.twig @@ -0,0 +1,27 @@ +

Dear {{ commonName }},

+ +

You have registered, but not yet activated, a token. Please visit one of the locations below to get your token activated. After {{ expirationDate | format_date('full', locale=locale) }} your activation code is no longer valid.

+ +

Please bring the following:

+ + +

Activation code: {{ registrationCode }}

+ +

Location(s) to activate your token:

+{% if raLocations is empty %} +

No locations known.

+{% else %} + +{% endif %} diff --git a/config/openconext/email_templates/en_GB/second_factor_verification_reminder_with_ras.html.twig b/config/openconext/email_templates/en_GB/second_factor_verification_reminder_with_ras.html.twig new file mode 100644 index 000000000..fdaf75f07 --- /dev/null +++ b/config/openconext/email_templates/en_GB/second_factor_verification_reminder_with_ras.html.twig @@ -0,0 +1,27 @@ +

Dear {{ commonName }},

+ +

You have registered, but not yet activated, a token. Please visit one of the locations below to get your token activated. After {{ expirationDate | format_date('full', locale=locale) }} your activation code is no longer valid.

+ +

Please bring the following:

+ + +

Activation code: {{ registrationCode }}

+ +

Location(s) to activate your token:

+{% if ras is empty %} +

No RAs are known.

+{% else %} + +{% endif %} diff --git a/config/openconext/email_templates/en_GB/vetted.html.twig b/config/openconext/email_templates/en_GB/vetted.html.twig new file mode 100644 index 000000000..0e5f036b0 --- /dev/null +++ b/config/openconext/email_templates/en_GB/vetted.html.twig @@ -0,0 +1,19 @@ +

Dear {{ commonName }},

+ +

Thank you for registering your token. Your token is ready to use. You can use this token for services connected to SURFconext that require two-step authentication. This e-mail contains more info on how to use your token.

+ +

Handle your token with care

+ + +

Token lost?
+Did you lose your token? Please visit {{ selfServiceUrl }} and remove your token registration. This way no one can take advantage of your token.

+ +

Replace token
+Do you want to replace your token? Please visit {{ selfServiceUrl }}, remove your activated token and start the token registration process again.

+ +

Test token
+Do you want to test your token? Please visit {{ selfServiceUrl }} and select the "Test" button next to the token you want to test.

diff --git a/config/openconext/email_templates/nl_NL/confirm_email.html.twig b/config/openconext/email_templates/nl_NL/confirm_email.html.twig new file mode 100644 index 000000000..aaab3a54f --- /dev/null +++ b/config/openconext/email_templates/nl_NL/confirm_email.html.twig @@ -0,0 +1,7 @@ +

Beste {{ commonName }},

+ +

Bedankt voor het registreren van je token. Klik op onderstaande link om je e-mailadres te bevestigen:

+ +

{{ verificationUrl }}

+ +

Is klikken op de link niet mogelijk? Kopieer dan de link en plak deze in de adresbalk van je browser.

diff --git a/config/openconext/email_templates/nl_NL/recovery_token_created.html.twig b/config/openconext/email_templates/nl_NL/recovery_token_created.html.twig new file mode 100644 index 000000000..a0f1d6c42 --- /dev/null +++ b/config/openconext/email_templates/nl_NL/recovery_token_created.html.twig @@ -0,0 +1,5 @@ +

Beste {{ commonName }},

+ +

Bedankt voor het registreren een herstelmethode. Je kunt deze methode gebruiken wanneer je een token dat je verloren bent opnieuw wilt activeren.

+ +

Zorg er altijd voor dat je tenminste één herstelmethode beschikbaar hebt.

diff --git a/config/openconext/email_templates/nl_NL/recovery_token_revoked.html.twig b/config/openconext/email_templates/nl_NL/recovery_token_revoked.html.twig new file mode 100644 index 000000000..a980fbe23 --- /dev/null +++ b/config/openconext/email_templates/nl_NL/recovery_token_revoked.html.twig @@ -0,0 +1,13 @@ +

Beste {{ commonName }},

+ +

+{% if isRevokedByRa %} + Je herstelmethode is verwijderd door een beheerder. +{% else %} + Je herstelmethode is verwijderd. Neem direct contact op met de helpdesk van je instelling als je dit niet zelf gedaan hebt, omdat dit kan betekenen dat je account gecompromitteerd is. +{% endif %} +

+ +

Je kunt deze herstelmethode niet meer gebruiken om een token te activeren.

+ +

Zorg er altijd voor dat je tenminste één herstelmethode beschikbaar hebt.

diff --git a/config/openconext/email_templates/nl_NL/registration_code_with_ra_locations.html.twig b/config/openconext/email_templates/nl_NL/registration_code_with_ra_locations.html.twig new file mode 100644 index 000000000..f2c441195 --- /dev/null +++ b/config/openconext/email_templates/nl_NL/registration_code_with_ra_locations.html.twig @@ -0,0 +1,27 @@ +

Beste {{ commonName }},

+ +

Bedankt voor het registreren van je token. Ga binnen 14 dagen naar een van de onderstaande locaties om je token te laten activeren. Je activatiecode is geldig tot en met {{ expirationDate | format_date('full', locale=locale) }}.

+ +

Neem daarbij het volgende mee:

+ + +

Activatiecode: {{ registrationCode }}

+ +

Locatie(s) om je token te activeren:

+{% if raLocations is empty %} +

Er zijn geen Locaties bekend.

+{% else %} + +{% endif %} diff --git a/config/openconext/email_templates/nl_NL/registration_code_with_ras.html.twig b/config/openconext/email_templates/nl_NL/registration_code_with_ras.html.twig new file mode 100644 index 000000000..34045a5c7 --- /dev/null +++ b/config/openconext/email_templates/nl_NL/registration_code_with_ras.html.twig @@ -0,0 +1,27 @@ +

Beste {{ commonName }},

+ +

Bedankt voor het registreren van je token. Ga binnen 14 dagen naar een van de onderstaande locaties om je token te laten activeren. Je activatiecode is geldig tot en met {{ expirationDate | format_date('full', locale=locale) }}.

+ +

Neem daarbij het volgende mee:

+ + +

Activatiecode: {{ registrationCode }}

+ +

Locatie(s) om je token te activeren:

+{% if ras is empty %} +

Er zijn geen RAs bekend.

+{% else %} + +{% endif %} diff --git a/config/openconext/email_templates/nl_NL/second_factor_revoked.html.twig b/config/openconext/email_templates/nl_NL/second_factor_revoked.html.twig new file mode 100644 index 000000000..a9d859314 --- /dev/null +++ b/config/openconext/email_templates/nl_NL/second_factor_revoked.html.twig @@ -0,0 +1,13 @@ +

Beste {{ commonName }},

+ +

+{% if isRevokedByRa %} + De registratie van je {{ tokenType }} token met ID {{ tokenIdentifier }} is verwijderd door een beheerder. +{% else %} + Je hebt de registratie voor je {{ tokenType }} token met ID {{ tokenIdentifier }} verwijderd. Neem direct contact op met de helpdesk van je instelling als je dit zelf niet gedaan hebt, omdat dit kan betekenen dat je account gecompromitteerd is. +{% endif %} +

+ +

Je kunt dit token niet meer gebruiken om in te loggen bij services die een tweede inlogstap vereisen.

+ +

Wil je een nieuw token aanvragen? Ga dan naar {{ selfServiceUrl }} en doorloop het registratieproces opnieuw.

diff --git a/config/openconext/email_templates/nl_NL/second_factor_verification_reminder_with_ra_locations.html.twig b/config/openconext/email_templates/nl_NL/second_factor_verification_reminder_with_ra_locations.html.twig new file mode 100644 index 000000000..ff60ee1f8 --- /dev/null +++ b/config/openconext/email_templates/nl_NL/second_factor_verification_reminder_with_ra_locations.html.twig @@ -0,0 +1,27 @@ +

Beste {{ commonName }},

+ +

Je hebt een token geregistreerd, maar het nog niet laten activeren. Je kunt tot en met {{ expirationDate | format_date('full', locale=locale) }} bij een van de onderstaande locaties terecht om je token te laten activeren.

+ +

Neem daarbij het volgende mee:

+ + +

Activatiecode: {{ registrationCode }}

+ +

Locatie(s) om je token te activeren:

+{% if raLocations is empty %} +

Er zijn geen Locaties bekend.

+{% else %} + +{% endif %} diff --git a/config/openconext/email_templates/nl_NL/second_factor_verification_reminder_with_ras.html.twig b/config/openconext/email_templates/nl_NL/second_factor_verification_reminder_with_ras.html.twig new file mode 100644 index 000000000..1d988d703 --- /dev/null +++ b/config/openconext/email_templates/nl_NL/second_factor_verification_reminder_with_ras.html.twig @@ -0,0 +1,27 @@ +

Beste {{ commonName }},

+ +

Je hebt een token geregistreerd, maar het nog niet laten activeren. Je kunt tot en met {{ expirationDate | format_date('full', locale=locale) }} bij een van de onderstaande locaties terecht om je token te laten activeren.

+ +

Neem daarbij het volgende mee:

+ + +

Activatiecode: {{ registrationCode }}

+ +

Locatie(s) om je token te activeren:

+{% if ras is empty %} +

Er zijn geen RAs bekend.

+{% else %} + +{% endif %} diff --git a/config/openconext/email_templates/nl_NL/vetted.html.twig b/config/openconext/email_templates/nl_NL/vetted.html.twig new file mode 100644 index 000000000..53c849304 --- /dev/null +++ b/config/openconext/email_templates/nl_NL/vetted.html.twig @@ -0,0 +1,19 @@ +

Beste {{ commonName }},

+ +

Bedankt voor het registreren van je token. Je token is nu klaar voor gebruik. Je kunt dit token gebruiken wanneer op SURFconext aangesloten services een tweede inlogstap vereisen. In deze e-mail vind je meer informatie over het gebruik van je token.

+ +

Ga zorgvuldig om met je token

+ + +

Token verloren?
+Wat moet je doen als je jouw token verloren bent? Ga naar {{ selfServiceUrl }} en verwijder je tokenregistratie. Zo kan niemand misbruik maken van jouw token.

+ +

Nieuw token aanvragen
+Wil je jouw token vervangen? Log in op {{ selfServiceUrl }}, verwijder je geactiveerde token en doorloop het registratieproces opnieuw.

+ +

Token testen
+Wil je de werking van je token testen? Log in op {{ selfServiceUrl }} en selecteer de "Testen" knop naast het token dat je wil testen.

diff --git a/config/openconext/parameters.yaml.dist b/config/openconext/parameters.yaml.dist index c763d787a..c6bbe6c15 100644 --- a/config/openconext/parameters.yaml.dist +++ b/config/openconext/parameters.yaml.dist @@ -98,3 +98,7 @@ parameters: # This is the global, application wide default. The configuration consists of an array with second factors types # that will skip the prove possession step in RA. skip_prove_possession_second_factors: [] + + # List of name_ids for Super Registration Authority Administrators (SRAA). + # Replaces the sraa field previously pushed via the management API. + sraa: [] diff --git a/config/services.yaml b/config/services.yaml index 77270a418..aa5808fa6 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -39,7 +39,7 @@ services: class: Twig\Sandbox\SecurityPolicy arguments: - [ if, else, elseif, for ] # Allowed tags - - [ escape, localizeddate ] # Allowed filters + - [ escape, localizeddate, format_date ] # Allowed filters - # Allowed methods Surfnet\Stepup\Identity\Value\CommonName: - __toString diff --git a/src/Surfnet/Stepup/Configuration/Configuration.php b/src/Surfnet/Stepup/Configuration/Configuration.php index 5981eb8bc..b011f4b88 100644 --- a/src/Surfnet/Stepup/Configuration/Configuration.php +++ b/src/Surfnet/Stepup/Configuration/Configuration.php @@ -21,11 +21,9 @@ use Broadway\EventSourcing\EventSourcedAggregateRoot; use Surfnet\Stepup\Configuration\Api\Configuration as ConfigurationInterface; use Surfnet\Stepup\Configuration\Event\ConfigurationUpdatedEvent; -use Surfnet\Stepup\Configuration\Event\EmailTemplatesUpdatedEvent; use Surfnet\Stepup\Configuration\Event\IdentityProvidersUpdatedEvent; use Surfnet\Stepup\Configuration\Event\NewConfigurationCreatedEvent; use Surfnet\Stepup\Configuration\Event\ServiceProvidersUpdatedEvent; -use Surfnet\Stepup\Configuration\Event\SraaUpdatedEvent; use Surfnet\Stepup\Helper\JsonHelper; class Configuration extends EventSourcedAggregateRoot implements ConfigurationInterface @@ -52,6 +50,9 @@ public function update(string $newConfiguration): void { $decodedConfiguration = JsonHelper::decode($newConfiguration); + // sraa and email_templates are read from disk/parameters.yaml; ignore any values from the push + unset($decodedConfiguration['sraa'], $decodedConfiguration['email_templates']); + $this->apply( new ConfigurationUpdatedEvent( self::CONFIGURATION_ID, @@ -72,8 +73,6 @@ public function update(string $newConfiguration): void $decodedConfiguration['gateway']['identity_providers'], ), ); - $this->apply(new SraaUpdatedEvent(self::CONFIGURATION_ID, $decodedConfiguration['sraa'])); - $this->apply(new EmailTemplatesUpdatedEvent(self::CONFIGURATION_ID, $decodedConfiguration['email_templates'])); } public function getAggregateRootId(): string diff --git a/src/Surfnet/StepupMiddleware/ApiBundle/Identity/Service/IdentityService.php b/src/Surfnet/StepupMiddleware/ApiBundle/Identity/Service/IdentityService.php index 5f6e52e96..8300bd413 100644 --- a/src/Surfnet/StepupMiddleware/ApiBundle/Identity/Service/IdentityService.php +++ b/src/Surfnet/StepupMiddleware/ApiBundle/Identity/Service/IdentityService.php @@ -30,7 +30,6 @@ use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\IdentityRepository; use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\IdentitySelfAssertedTokenOptionsRepository; use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\RaListingRepository; -use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\SraaRepository; use Surfnet\StepupMiddleware\ApiBundle\Identity\Value\RegistrationAuthorityCredentials; /** @@ -42,7 +41,7 @@ public function __construct( private readonly IdentityRepository $repository, private readonly IdentitySelfAssertedTokenOptionsRepository $identitySelfAssertedTokensOptionsRepository, private readonly RaListingRepository $raListingRepository, - private readonly SraaRepository $sraaRepository, + private readonly SraaService $sraaService, ) { } @@ -111,7 +110,7 @@ public function findRegistrationAuthorityCredentialsByNameIdAndInstitution( private function findRegistrationAuthorityCredentialsByIdentity(Identity $identity): ?RegistrationAuthorityCredentials { $raListing = $this->raListingRepository->findByIdentityId(new IdentityId($identity->id)); - $sraa = $this->sraaRepository->findByNameId($identity->nameId); + $sraa = $this->sraaService->findByNameId($identity->nameId); if ($raListing !== []) { $credentials = RegistrationAuthorityCredentials::fromRaListings($raListing); diff --git a/src/Surfnet/StepupMiddleware/ApiBundle/Identity/Service/SraaService.php b/src/Surfnet/StepupMiddleware/ApiBundle/Identity/Service/SraaService.php index 5ab04a439..783b3b844 100644 --- a/src/Surfnet/StepupMiddleware/ApiBundle/Identity/Service/SraaService.php +++ b/src/Surfnet/StepupMiddleware/ApiBundle/Identity/Service/SraaService.php @@ -20,17 +20,23 @@ use Surfnet\Stepup\Identity\Value\NameId; use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\Sraa; -use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\SraaRepository; class SraaService { - public function __construct(private readonly SraaRepository $sraaRepository) + /** + * @param string[] $sraaNameIds list of name_id strings from parameters.yaml + */ + public function __construct(private readonly array $sraaNameIds) { } public function findByNameId(NameId $nameId): ?Sraa { - return $this->sraaRepository->findByNameId($nameId); + if (!in_array((string) $nameId, $this->sraaNameIds, true)) { + return null; + } + + return new Sraa($nameId); } /** @@ -38,11 +44,14 @@ public function findByNameId(NameId $nameId): ?Sraa */ public function findAll(): array { - return $this->sraaRepository->findAll(); + return array_map( + static fn(string $nameId): Sraa => new Sraa(new NameId($nameId)), + $this->sraaNameIds, + ); } public function contains(NameId $nameId): bool { - return $this->sraaRepository->contains($nameId); + return in_array((string) $nameId, $this->sraaNameIds, true); } } diff --git a/src/Surfnet/StepupMiddleware/ApiBundle/Resources/config/services.yml b/src/Surfnet/StepupMiddleware/ApiBundle/Resources/config/services.yml index 3a032f7f7..37f3d3770 100644 --- a/src/Surfnet/StepupMiddleware/ApiBundle/Resources/config/services.yml +++ b/src/Surfnet/StepupMiddleware/ApiBundle/Resources/config/services.yml @@ -105,17 +105,18 @@ services: - "@surfnet_stepup_middleware_api.repository.identity" - "@surfnet_stepup_middleware_api.repository.identity_self_asserted_token_options" - "@surfnet_stepup_middleware_api.repository.ra_listing" - - "@surfnet_stepup_middleware_api.repository.sraa" + - "@surfnet_stepup_middleware_api.service.sraa" surfnet_stepup_middleware_api.service.ra_listing: class: Surfnet\StepupMiddleware\ApiBundle\Identity\Service\RaListingService arguments: - "@surfnet_stepup_middleware_api.repository.ra_listing" - surfnet_stepup_middleware_api.service.sraa: - class: Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SraaService + Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SraaService: arguments: - - "@surfnet_stepup_middleware_api.repository.sraa" + - "%sraa%" + + surfnet_stepup_middleware_api.service.sraa: '@Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SraaService' surfnet_stepup_middleware_api.service.audit_log: class: Surfnet\StepupMiddleware\ApiBundle\Identity\Service\AuditLogService @@ -156,7 +157,7 @@ services: $eventSourcingRepository: '@surfnet_stepup.repository.identity' $apiRepository: '@surfnet_stepup_middleware_api.repository.identity' $logger: '@logger' - $sraaRepository: '@surfnet_stepup_middleware_api.repository.sraa' + $sraaService: '@surfnet_stepup_middleware_api.service.sraa' $raListingRepository: '@surfnet_stepup_middleware_api.repository.ra_listing' Surfnet\Stepup\Helper\RecoveryTokenSecretHelper: diff --git a/src/Surfnet/StepupMiddleware/ApiBundle/Service/DeprovisionService.php b/src/Surfnet/StepupMiddleware/ApiBundle/Service/DeprovisionService.php index 438043ae0..d90065c0b 100644 --- a/src/Surfnet/StepupMiddleware/ApiBundle/Service/DeprovisionService.php +++ b/src/Surfnet/StepupMiddleware/ApiBundle/Service/DeprovisionService.php @@ -28,7 +28,7 @@ use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\Identity; use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\IdentityRepository as ApiIdentityRepository; use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\RaListingRepository; -use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\SraaRepository; +use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SraaService; use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\ForgetIdentityCommand; use Surfnet\StepupMiddleware\CommandHandlingBundle\Pipeline\Pipeline; use function sprintf; @@ -43,7 +43,7 @@ public function __construct( private readonly IdentityRepository $eventSourcingRepository, private readonly ApiIdentityRepository $apiRepository, private readonly LoggerInterface $logger, - private readonly SraaRepository $sraaRepository, + private readonly SraaService $sraaService, private readonly RaListingRepository $raListingRepository, ) { } @@ -104,7 +104,7 @@ public function assertIsAllowed(string $collabPersonId): void throw new RuntimeException('Cannot forget an identity that does not exist.'); } - if ($this->sraaRepository->contains($identity->nameId)) { + if ($this->sraaService->contains($identity->nameId)) { throw new RuntimeException('Cannot forget an identity that is currently accredited as an SRAA'); } diff --git a/src/Surfnet/StepupMiddleware/ApiBundle/Tests/Identity/Service/SraaServiceTest.php b/src/Surfnet/StepupMiddleware/ApiBundle/Tests/Identity/Service/SraaServiceTest.php new file mode 100644 index 000000000..31d65604f --- /dev/null +++ b/src/Surfnet/StepupMiddleware/ApiBundle/Tests/Identity/Service/SraaServiceTest.php @@ -0,0 +1,85 @@ +findByNameId(new NameId('urn:collab:person:example.com:admin')); + + $this->assertInstanceOf(Sraa::class, $result); + $this->assertEquals('urn:collab:person:example.com:admin', (string) $result->nameId); + } + + #[Test] + public function it_returns_null_when_name_id_not_in_list(): void + { + $service = new SraaService(['urn:collab:person:example.com:admin']); + $result = $service->findByNameId(new NameId('urn:collab:person:example.com:unknown')); + + $this->assertNull($result); + } + + #[Test] + public function it_returns_null_for_empty_sraa_list(): void + { + $service = new SraaService([]); + $result = $service->findByNameId(new NameId('urn:collab:person:example.com:admin')); + + $this->assertNull($result); + } + + #[Test] + public function it_returns_all_sraas(): void + { + $nameIds = ['urn:collab:person:example.com:admin', 'urn:collab:person:example.com:other']; + $service = new SraaService($nameIds); + $result = $service->findAll(); + + $this->assertCount(2, $result); + $this->assertContainsOnlyInstancesOf(Sraa::class, $result); + } + + #[Test] + public function it_returns_empty_array_when_no_sraas_configured(): void + { + $service = new SraaService([]); + $result = $service->findAll(); + + $this->assertSame([], $result); + } + + #[Test] + public function it_checks_if_name_id_is_sraa(): void + { + $service = new SraaService(['urn:collab:person:example.com:admin']); + + $this->assertTrue($service->contains(new NameId('urn:collab:person:example.com:admin'))); + $this->assertFalse($service->contains(new NameId('urn:collab:person:example.com:other'))); + } +} diff --git a/src/Surfnet/StepupMiddleware/ApiBundle/Tests/Service/DeprovisionServiceTest.php b/src/Surfnet/StepupMiddleware/ApiBundle/Tests/Service/DeprovisionServiceTest.php index 27170c3c1..993778c14 100644 --- a/src/Surfnet/StepupMiddleware/ApiBundle/Tests/Service/DeprovisionServiceTest.php +++ b/src/Surfnet/StepupMiddleware/ApiBundle/Tests/Service/DeprovisionServiceTest.php @@ -31,7 +31,7 @@ use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\Identity; use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\IdentityRepository as ApiIdentityRepository; use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\RaListingRepository; -use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\SraaRepository; +use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SraaService; use Surfnet\StepupMiddleware\ApiBundle\Service\DeprovisionService; use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\ForgetIdentityCommand; use Surfnet\StepupMiddleware\CommandHandlingBundle\Pipeline\Pipeline; @@ -48,7 +48,7 @@ class DeprovisionServiceTest extends TestCase private MockInterface&IdentityRepository $eventRepo; - private MockInterface&SraaRepository $sraaRepo; + private MockInterface&SraaService $sraaRepo; private MockInterface&RaListingRepository $raListingRepo; @@ -57,7 +57,7 @@ protected function setUp(): void $this->pipeline = m::mock(Pipeline::class); $this->apiRepo = m::mock(ApiIdentityRepository::class); $this->eventRepo = m::mock(IdentityRepository::class); - $this->sraaRepo = m::mock(SraaRepository::class); + $this->sraaRepo = m::mock(SraaService::class); $this->raListingRepo = m::mock(RaListingRepository::class); $logger = m::mock(LoggerInterface::class); diff --git a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Cache/EmailTemplatesWarmer.php b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Cache/EmailTemplatesWarmer.php new file mode 100644 index 000000000..f6af8918e --- /dev/null +++ b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Cache/EmailTemplatesWarmer.php @@ -0,0 +1,83 @@ +locales as $locale) { + foreach (self::TEMPLATE_NAMES as $name) { + $path = sprintf('%s/%s/%s.html.twig', $this->templatesDir, $locale, $name); + + if (!file_exists($path)) { + throw new RuntimeException( + sprintf('Email template file missing: %s', $path), + ); + } + + $content = (string) file_get_contents($path); + + try { + $this->twig->createTemplate($content); + } catch (Throwable $e) { + throw new RuntimeException( + sprintf('Email template "%s" (locale "%s") failed to compile: %s', $name, $locale, $e->getMessage()), + 0, + $e, + ); + } + } + } + + return []; + } + + public function isOptional(): bool + { + return false; + } +} diff --git a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Identity/CommandHandler/RightToBeForgottenCommandHandler.php b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Identity/CommandHandler/RightToBeForgottenCommandHandler.php index 19aae954d..08a0d9735 100644 --- a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Identity/CommandHandler/RightToBeForgottenCommandHandler.php +++ b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Identity/CommandHandler/RightToBeForgottenCommandHandler.php @@ -25,7 +25,7 @@ use Surfnet\Stepup\Identity\Value\Institution; use Surfnet\Stepup\Identity\Value\NameId; use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\IdentityRepository as ApiIdentityRepository; -use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\SraaRepository; +use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SraaService; use Surfnet\StepupMiddleware\CommandHandlingBundle\Exception\RuntimeException; use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\ForgetIdentityCommand; use Surfnet\StepupMiddleware\CommandHandlingBundle\SensitiveData\Service\SensitiveDataService; @@ -36,7 +36,7 @@ public function __construct( private readonly IdentityRepository $repository, private readonly ApiIdentityRepository $apiIdentityRepository, private readonly SensitiveDataService $sensitiveDataService, - private readonly SraaRepository $sraaRepository, + private readonly SraaService $sraaService, ) { } @@ -44,7 +44,7 @@ public function handleForgetIdentityCommand(ForgetIdentityCommand $command): voi { $nameId = new NameId($command->nameId); - if ($this->sraaRepository->contains($nameId)) { + if ($this->sraaService->contains($nameId)) { throw new RuntimeException('Cannot forget an identity that is currently accredited as an SRAA'); } diff --git a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Resources/config/command_handlers.yml b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Resources/config/command_handlers.yml index 4c9c3eca6..3a2a99cb9 100644 --- a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Resources/config/command_handlers.yml +++ b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Resources/config/command_handlers.yml @@ -49,7 +49,7 @@ services: - "@surfnet_stepup.repository.identity" - "@surfnet_stepup_middleware_api.repository.identity" - "@surfnet_stepup_middleware_command_handling.service.sensitive_data" - - "@surfnet_stepup_middleware_api.repository.sraa" + - "@surfnet_stepup_middleware_api.service.sraa" tags: [ { name: command_bus.command_handler } ] surfnet_stepup_middleware_command_handling.command_handler.reminder_email: diff --git a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Cache/EmailTemplatesWarmerTest.php b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Cache/EmailTemplatesWarmerTest.php new file mode 100644 index 000000000..3cb705fd1 --- /dev/null +++ b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Cache/EmailTemplatesWarmerTest.php @@ -0,0 +1,137 @@ +templatesDir = sys_get_temp_dir() . '/email_warmer_test_' . uniqid(); + foreach (self::LOCALES as $locale) { + mkdir($this->templatesDir . '/' . $locale, 0777, true); + } + } + + protected function tearDown(): void + { + $this->removeDirectory($this->templatesDir); + } + + #[Test] + public function it_passes_when_all_templates_exist_and_compile(): void + { + $this->createAllTemplates('

Hello {{ name }}

'); + + $warmer = new EmailTemplatesWarmer($this->createTwig(), $this->templatesDir, self::LOCALES); + $warmer->warmUp('/tmp'); + + // No exception = pass + $this->addToAssertionCount(1); + } + + #[Test] + public function it_throws_when_template_file_is_missing(): void + { + $this->createAllTemplates('

Hello

'); + unlink($this->templatesDir . '/en_GB/confirm_email.html.twig'); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/missing/i'); + + $warmer = new EmailTemplatesWarmer($this->createTwig(), $this->templatesDir, self::LOCALES); + $warmer->warmUp('/tmp'); + } + + #[Test] + public function it_throws_when_template_has_invalid_twig_syntax(): void + { + $this->createAllTemplates('

Hello

'); + file_put_contents( + $this->templatesDir . '/en_GB/confirm_email.html.twig', + '{% unclosed block', + ); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/compile/i'); + + $warmer = new EmailTemplatesWarmer($this->createTwig(), $this->templatesDir, self::LOCALES); + $warmer->warmUp('/tmp'); + } + + #[Test] + public function it_is_not_optional(): void + { + $warmer = new EmailTemplatesWarmer($this->createTwig(), $this->templatesDir, self::LOCALES); + $this->assertFalse($warmer->isOptional()); + } + + private function createAllTemplates(string $content): void + { + foreach (self::LOCALES as $locale) { + foreach (self::TEMPLATE_NAMES as $name) { + file_put_contents( + sprintf('%s/%s/%s.html.twig', $this->templatesDir, $locale, $name), + $content, + ); + } + } + } + + private function createTwig(): Environment + { + return new Environment(new ArrayLoader([])); + } + + private function removeDirectory(string $dir): void + { + if (!is_dir($dir)) { + return; + } + foreach (scandir($dir) as $item) { + if ($item === '.' || $item === '..') { + continue; + } + $path = $dir . '/' . $item; + is_dir($path) ? $this->removeDirectory($path) : unlink($path); + } + rmdir($dir); + } +} diff --git a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Configuration/CommandHandler/ConfigurationCommandHandlerTest.php b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Configuration/CommandHandler/ConfigurationCommandHandlerTest.php index 3ffa73cad..079f30b3b 100644 --- a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Configuration/CommandHandler/ConfigurationCommandHandlerTest.php +++ b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Configuration/CommandHandler/ConfigurationCommandHandlerTest.php @@ -27,11 +27,9 @@ use RuntimeException; use Surfnet\Stepup\Configuration\Configuration; use Surfnet\Stepup\Configuration\Event\ConfigurationUpdatedEvent; -use Surfnet\Stepup\Configuration\Event\EmailTemplatesUpdatedEvent; use Surfnet\Stepup\Configuration\Event\IdentityProvidersUpdatedEvent; use Surfnet\Stepup\Configuration\Event\NewConfigurationCreatedEvent; use Surfnet\Stepup\Configuration\Event\ServiceProvidersUpdatedEvent; -use Surfnet\Stepup\Configuration\Event\SraaUpdatedEvent; use Surfnet\Stepup\Configuration\EventSourcing\ConfigurationRepository; use Surfnet\StepupMiddleware\CommandHandlingBundle\Configuration\Command\UpdateConfigurationCommand; use Surfnet\StepupMiddleware\CommandHandlingBundle\Configuration\CommandHandler\ConfigurationCommandHandler; @@ -169,12 +167,15 @@ private function createNewConfigurationCreatedEvent(): NewConfigurationCreatedEv */ private function createConfigurationUpdatedEvents(array $newConfiguration, array $oldConfiguration = null): array { + // sraa and email_templates are dropped before processing; strip them from expected events too + unset($newConfiguration['sraa'], $newConfiguration['email_templates']); + if ($oldConfiguration !== null) { + unset($oldConfiguration['sraa'], $oldConfiguration['email_templates']); + } return [ new ConfigurationUpdatedEvent(self::CID, $newConfiguration, $oldConfiguration), new ServiceProvidersUpdatedEvent(self::CID, $newConfiguration['gateway']['service_providers']), new IdentityProvidersUpdatedEvent(self::CID, $newConfiguration['gateway']['identity_providers']), - new SraaUpdatedEvent(self::CID, $newConfiguration['sraa']), - new EmailTemplatesUpdatedEvent(self::CID, $newConfiguration['email_templates']), ]; } } diff --git a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Identity/CommandHandler/RightToBeForgottenCommandHandlerTest.php b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Identity/CommandHandler/RightToBeForgottenCommandHandlerTest.php index 1c7dc34fc..ec85f7fee 100644 --- a/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Identity/CommandHandler/RightToBeForgottenCommandHandlerTest.php +++ b/src/Surfnet/StepupMiddleware/CommandHandlingBundle/Tests/Identity/CommandHandler/RightToBeForgottenCommandHandlerTest.php @@ -50,7 +50,7 @@ use Surfnet\Stepup\Identity\Value\YubikeyPublicId; use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\Identity; use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\IdentityRepository as ConcreteIdentityRepository; -use Surfnet\StepupMiddleware\ApiBundle\Identity\Repository\SraaRepository; +use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SraaService; use Surfnet\StepupMiddleware\CommandHandlingBundle\Exception\RuntimeException; use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\ForgetIdentityCommand; use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\CommandHandler\RightToBeForgottenCommandHandler; @@ -79,7 +79,7 @@ protected function createCommandHandler( ConcreteIdentityRepository::class, ); $this->sensitiveDataService = m::mock(SensitiveDataService::class); - $this->sraaRepository = m::mock(SraaRepository::class); + $this->sraaRepository = m::mock(SraaService::class); $logger = m::mock(LoggerInterface::class); $logger->shouldIgnoreMissing(); diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Configuration/Service/DiskEmailTemplateService.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Configuration/Service/DiskEmailTemplateService.php new file mode 100644 index 000000000..90506162d --- /dev/null +++ b/src/Surfnet/StepupMiddleware/ManagementBundle/Configuration/Service/DiskEmailTemplateService.php @@ -0,0 +1,45 @@ +templatesDir, $locale, $name); + if (file_exists($path)) { + $template = new EmailTemplate(); + $template->name = $name; + $template->locale = $locale; + $template->htmlContent = (string) file_get_contents($path); + return $template; + } + } + + return null; + } +} diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Resources/config/services.yml b/src/Surfnet/StepupMiddleware/ManagementBundle/Resources/config/services.yml index c8132f958..ee19217b2 100644 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Resources/config/services.yml +++ b/src/Surfnet/StepupMiddleware/ManagementBundle/Resources/config/services.yml @@ -22,7 +22,6 @@ services: class: Surfnet\StepupMiddleware\ManagementBundle\Validator\ConfigurationStructureValidator arguments: - "@surfnet_stepup_middleware_management.validator.gateway_configuration" - - "@surfnet_stepup_middleware_management.validator.email_templates_configuration" tags: - { name: validator.constraint_validator, alias: configuration_structure_validator } @@ -61,8 +60,17 @@ services: surfnet_stepup_middleware_management.repository.email_template: '@Surfnet\StepupMiddleware\ManagementBundle\Configuration\Repository\EmailTemplateRepository' surfnet_stepup_middleware_management.service.email_template: - class: Surfnet\StepupMiddleware\ManagementBundle\Configuration\Service\EmailTemplateService - arguments: [ "@surfnet_stepup_middleware_management.repository.email_template" ] + class: Surfnet\StepupMiddleware\ManagementBundle\Configuration\Service\DiskEmailTemplateService + arguments: + - '%kernel.project_dir%/config/openconext/email_templates' + + Surfnet\StepupMiddleware\CommandHandlingBundle\Cache\EmailTemplatesWarmer: + arguments: + - '@twig' + - '%kernel.project_dir%/config/openconext/email_templates' + - '%locales%' + tags: + - { name: kernel.cache_warmer } surfnet_stepup_middleware_management.dbal_connection_helper: class: Surfnet\StepupMiddleware\ManagementBundle\Service\DBALConnectionHelper diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Configuration/Service/DiskEmailTemplateServiceTest.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Configuration/Service/DiskEmailTemplateServiceTest.php new file mode 100644 index 000000000..863805fb3 --- /dev/null +++ b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Configuration/Service/DiskEmailTemplateServiceTest.php @@ -0,0 +1,105 @@ +templatesDir = sys_get_temp_dir() . '/disk_email_template_test_' . uniqid(); + mkdir($this->templatesDir . '/en_GB', 0777, true); + mkdir($this->templatesDir . '/nl_NL', 0777, true); + } + + protected function tearDown(): void + { + $this->removeDirectory($this->templatesDir); + } + + #[Test] + public function it_returns_template_for_preferred_locale(): void + { + file_put_contents($this->templatesDir . '/en_GB/confirm_email.html.twig', '

Hello {{ commonName }}

'); + file_put_contents($this->templatesDir . '/nl_NL/confirm_email.html.twig', '

Hallo {{ commonName }}

'); + + $service = new DiskEmailTemplateService($this->templatesDir); + $template = $service->findByName('confirm_email', 'en_GB', 'nl_NL'); + + $this->assertNotNull($template); + $this->assertEquals('confirm_email', $template->name); + $this->assertEquals('en_GB', $template->locale); + $this->assertStringContainsString('Hello', $template->htmlContent); + } + + #[Test] + public function it_falls_back_to_fallback_locale_when_preferred_missing(): void + { + file_put_contents($this->templatesDir . '/nl_NL/confirm_email.html.twig', '

Hallo {{ commonName }}

'); + + $service = new DiskEmailTemplateService($this->templatesDir); + $template = $service->findByName('confirm_email', 'en_GB', 'nl_NL'); + + $this->assertNotNull($template); + $this->assertEquals('nl_NL', $template->locale); + $this->assertStringContainsString('Hallo', $template->htmlContent); + } + + #[Test] + public function it_returns_null_when_template_missing_in_both_locales(): void + { + $service = new DiskEmailTemplateService($this->templatesDir); + $template = $service->findByName('confirm_email', 'en_GB', 'nl_NL'); + + $this->assertNull($template); + } + + #[Test] + public function it_returns_correct_html_content(): void + { + $content = '

Dear {{ commonName }}, your code is {{ registrationCode }}

'; + file_put_contents($this->templatesDir . '/en_GB/registration_code_with_ras.html.twig', $content); + + $service = new DiskEmailTemplateService($this->templatesDir); + $template = $service->findByName('registration_code_with_ras', 'en_GB', 'nl_NL'); + + $this->assertNotNull($template); + $this->assertEquals($content, $template->htmlContent); + } + + private function removeDirectory(string $dir): void + { + if (!is_dir($dir)) { + return; + } + foreach (scandir($dir) as $item) { + if ($item === '.' || $item === '..') { + continue; + } + $path = $dir . '/' . $item; + is_dir($path) ? $this->removeDirectory($path) : unlink($path); + } + rmdir($dir); + } +} diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Controller/ConfigurationControllerTest.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Controller/ConfigurationControllerTest.php index ccaf45985..748cb1207 100644 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Controller/ConfigurationControllerTest.php +++ b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Controller/ConfigurationControllerTest.php @@ -18,6 +18,10 @@ namespace Surfnet\StepupMiddleware\ManagementBundle\Tests\Controller; +use Broadway\EventStore\Dbal\DBALEventStore; +use Doctrine\DBAL\Connection; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Tools\SchemaTool; use Liip\TestFixturesBundle\Services\DatabaseToolCollection; use Liip\TestFixturesBundle\Services\DatabaseTools\AbstractDatabaseTool; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; @@ -52,6 +56,23 @@ public function setUp(): void $this->databaseTool->setExcludedDoctrineTables(['ra_candidate']); $this->databaseTool->loadFixtures([]); + // Broadway event store table is not managed by Doctrine ORM; create it manually for the test DB. + $eventStore = $this->client->getContainer()->get('surfnet_stepup.event_store.dbal'); + assert($eventStore instanceof DBALEventStore); + $connection = $this->client->getContainer()->get('doctrine.dbal.middleware_connection'); + assert($connection instanceof Connection); + $schemaManager = $connection->createSchemaManager(); + $table = $eventStore->configureTable(); + if (!$schemaManager->tablesExist(['event_stream'])) { + $schemaManager->createTable($table); + } + + // Gateway entity manager schema (saml_entity etc.) is a separate SQLite DB in test env. + $gatewayEm = $this->client->getContainer()->get('doctrine.orm.gateway_entity_manager'); + assert($gatewayEm instanceof EntityManagerInterface); + $schemaTool = new SchemaTool($gatewayEm); + $schemaTool->updateSchema($gatewayEm->getMetadataFactory()->getAllMetadata()); + $managementPassword = $this->client->getKernel()->getContainer()->getParameter('management_password'); if (!is_string($managementPassword)) { $this->fail('Unable to grab the management_password parameter from the container'); @@ -181,6 +202,97 @@ public function json_is_returned_from_the_configuration_api(): void ); } + #[Test] + #[Group('management')] + public function validPushWithOnlyGatewayIsAccepted(): void + { + $configuration = json_encode([ + 'gateway' => [ + 'identity_providers' => [], + 'service_providers' => [self::minimalServiceProvider()], + ], + ]); + assert(is_string($configuration)); + + $this->client->request( + 'POST', + '/management/configuration', + [], + [], + [ + 'HTTP_ACCEPT' => 'application/json', + 'CONTENT_TYPE' => 'application/json', + 'PHP_AUTH_USER' => 'management', + 'PHP_AUTH_PW' => $this->password, + ], + $configuration, + ); + + $this->assertSame( + Response::HTTP_OK, + $this->client->getResponse()->getStatusCode(), + (string) $this->client->getResponse()->getContent(), + ); + } + + #[Test] + #[Group('management')] + public function pushWithSraaAndEmailTemplatesIsSilentlyAccepted(): void + { + $configuration = json_encode([ + 'gateway' => [ + 'identity_providers' => [], + 'service_providers' => [self::minimalServiceProvider()], + ], + 'sraa' => ['urn:collab:person:example.com:admin'], + 'email_templates' => [ + 'confirm_email' => ['en_GB' => 'Verify {{ commonName }}'], + ], + ]); + assert(is_string($configuration)); + + $this->client->request( + 'POST', + '/management/configuration', + [], + [], + [ + 'HTTP_ACCEPT' => 'application/json', + 'CONTENT_TYPE' => 'application/json', + 'PHP_AUTH_USER' => 'management', + 'PHP_AUTH_PW' => $this->password, + ], + $configuration, + ); + + $this->assertSame( + Response::HTTP_OK, + $this->client->getResponse()->getStatusCode(), + (string) $this->client->getResponse()->getContent(), + ); + + $content = $this->client->getResponse()->getContent(); + assert(is_string($content)); + $response = json_decode($content, true); + assert(is_array($response)); + $this->assertEquals('OK', $response['status']); + } + + /** @return array */ + private static function minimalServiceProvider(): array + { + return [ + 'entity_id' => 'https://sp.example.com/metadata', + 'public_key' => 'MIIE...', + 'acs' => ['https://sp.example.com/acs'], + 'loa' => ['__default__' => 'https://gateway.example.com/authentication/loa2'], + 'second_factor_only' => false, + 'second_factor_only_nameid_patterns' => [], + 'assertion_encryption_enabled' => false, + 'blacklisted_encryption_algorithms' => [], + ]; + } + /** * Dataprovider for only_post_requests_are_accepted */ diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/ConfigurationValidationTest.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/ConfigurationValidationTest.php index c80db1905..619cea632 100644 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/ConfigurationValidationTest.php +++ b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/ConfigurationValidationTest.php @@ -28,7 +28,6 @@ use RuntimeException; use Surfnet\StepupMiddleware\ManagementBundle\Validator\ConfigurationStructureValidator; use Surfnet\StepupMiddleware\ManagementBundle\Validator\Constraints\HasValidConfigurationStructure; -use Surfnet\StepupMiddleware\ManagementBundle\Validator\EmailTemplatesConfigurationValidator; use Surfnet\StepupMiddleware\ManagementBundle\Validator\GatewayConfigurationValidator; use Surfnet\StepupMiddleware\ManagementBundle\Validator\IdentityProviderConfigurationValidator; use Surfnet\StepupMiddleware\ManagementBundle\Validator\ServiceProviderConfigurationValidator; @@ -81,7 +80,6 @@ public function it_rejects_invalid_configuration(array $configuration, string $e new IdentityProviderConfigurationValidator(), new ServiceProviderConfigurationValidator(), ), - new EmailTemplatesConfigurationValidator('en_GB'), ); $validator->initialize($context); $validator->validate(json_encode($configuration), new HasValidConfigurationStructure()); diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_email_template_locale.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_email_template_locale.php deleted file mode 100644 index 3fe626880..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_email_template_locale.php +++ /dev/null @@ -1,52 +0,0 @@ - 'email_templates.confirm_email[9]', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - "entity_id" => "https://entity.tld/id", - "public_key" => "MIIE...", - "acs" => ["https://entity.tld/consume-assertion"], - "loa" => [ - "__default__" => "https://entity.tld/authentication/loa2", - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => ['20394-4320423-439248324'], - 'email_templates' => [ - 'confirm_email' => ['en_GB' => 'Verify {{ commonName }}', 9 => ''], - 'registration_code_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'registration_code_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'second_factor_verification_reminder_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'second_factor_verification_reminder_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'vetted' => ['en_GB' => 'Vetted {{ commonName }}'], - 'second_factor_revoked' => ['en_GB' => 'Revoked token for {{ commonName }}'], - 'recovery_token_created' => ['en_GB' => 'Code {{ commonName }}'], - 'recovery_token_revoked' => ['en_GB' => 'Code {{ commonName }}'], - ], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_sraa.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_sraa.php deleted file mode 100644 index 9cf861103..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_sraa.php +++ /dev/null @@ -1,50 +0,0 @@ - 'sraa[0]', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - "entity_id" => "https://entity.tld/id", - "public_key" => "MIIE...", - "acs" => ["https://entity.tld/consume-assertion"], - "loa" => [ - "__default__" => "https://entity.tld/authentication/loa2", - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => [9], - 'email_templates' => [ - 'confirm_email' => ['en_GB' => 'Verify {{ commonName }}'], - 'registration_code_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'registration_code_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'vetted' => ['en_GB' => 'Vetted {{ commonName }}'], - 'second_factor_revoked' => ['en_GB' => 'Revoked token for {{ commonName }}'], - 'second_factor_verification_reminder_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'second_factor_verification_reminder_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - ], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_sraas.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_sraas.php deleted file mode 100644 index 3b5d3b96c..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/invalid_sraas.php +++ /dev/null @@ -1,50 +0,0 @@ - 'sraa', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - "entity_id" => "https://entity.tld/id", - "public_key" => "MIIE...", - "acs" => ["https://entity.tld/consume-assertion"], - "loa" => [ - "__default__" => "https://entity.tld/authentication/loa2", - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => 9, - 'email_templates' => [ - 'confirm_email' => ['en_GB' => 'Verify {{ commonName }}'], - 'registration_code_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'registration_code_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'vetted' => ['en_GB' => 'Vetted {{ commonName }}'], - 'second_factor_revoked' => ['en_GB' => 'Revoked token for {{ commonName }}'], - 'second_factor_verification_reminder_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'second_factor_verification_reminder_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - ], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_confirm_email.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_confirm_email.php deleted file mode 100644 index 3c9cea46a..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_confirm_email.php +++ /dev/null @@ -1,49 +0,0 @@ - 'email_templates', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - "entity_id" => "https://entity.tld/id", - "public_key" => "MIIE...", - "acs" => ["https://entity.tld/consume-assertion"], - "loa" => [ - "__default__" => "https://entity.tld/authentication/loa2", - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => ['20394-4320423-439248324'], - 'email_templates' => [ - 'registration_code_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'registration_code_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'vetted' => ['en_GB' => 'Vetted {{ commonName }}'], - 'second_factor_revoked' => ['en_GB' => 'Revoked token for {{ commonName }}'], - 'second_factor_verification_reminder_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'second_factor_verification_reminder_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - ], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_locale.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_locale.php deleted file mode 100644 index e8581de28..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_locale.php +++ /dev/null @@ -1,53 +0,0 @@ - 'email_templates.confirm_email', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - "entity_id" => "https://entity.tld/id", - "public_key" => "MIIE...", - "acs" => ["https://entity.tld/consume-assertion"], - "loa" => [ - "__default__" => "https://entity.tld/authentication/loa2", - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - - 'sraa' => ['20394-4320423-439248324'], - 'email_templates' => [ - 'confirm_email' => ['nl_NL' => 'Verify {{ commonName }}'], - 'registration_code_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'registration_code_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'vetted' => ['en_GB' => 'Vetted {{ commonName }}'], - 'second_factor_revoked' => ['en_GB' => 'Revoked token for {{ commonName }}'], - 'second_factor_verification_reminder_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'second_factor_verification_reminder_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'recovery_token_created' => ['en_GB' => 'Code {{ commonName }}'], - 'recovery_token_revoked' => ['en_GB' => 'Code {{ commonName }}'], - ], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_registration_code.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_registration_code.php deleted file mode 100644 index 98cbdb2b6..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_registration_code.php +++ /dev/null @@ -1,46 +0,0 @@ - 'email_templates', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - "entity_id" => "https://entity.tld/id", - "public_key" => "MIIE...", - "acs" => ["https://entity.tld/consume-assertion"], - "loa" => [ - "__default__" => "https://entity.tld/authentication/loa2", - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => ['20394-4320423-439248324'], - 'email_templates' => [ - 'confirm_email' => ['en_GB' => 'Verify {{ commonName }}'], - 'vetted' => ['en_GB' => 'Vetted {{ commonName }}'], - 'second_factor_revoked' => ['en_GB' => 'Revoked token for {{ commonName }}'], - ], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_second_factor_revoked.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_second_factor_revoked.php deleted file mode 100644 index 9ad984d75..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/missing_email_template_second_factor_revoked.php +++ /dev/null @@ -1,47 +0,0 @@ - 'email_templates', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - "entity_id" => "https://entity.tld/id", - "public_key" => "MIIE...", - "acs" => ["https://entity.tld/consume-assertion"], - "loa" => [ - "__default__" => "https://entity.tld/authentication/loa2", - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => ['20394-4320423-439248324'], - 'email_templates' => [ - 'confirm_email' => ['en_GB' => 'Verify {{ commonName }}'], - 'registration_code_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'registration_code_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'vetted' => ['en_GB' => 'Vetted {{ commonName }}'], - ], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_email_templates.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_email_templates.php deleted file mode 100644 index 3cd10dc10..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_email_templates.php +++ /dev/null @@ -1,25 +0,0 @@ - '(root)', - 'configuration' => [ - 'gateway' => [], - 'sraa' => [], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_sraa.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_sraa.php deleted file mode 100644 index ecce9fab5..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_sraa.php +++ /dev/null @@ -1,24 +0,0 @@ - '(root)', - 'configuration' => [ - 'gateway' => [], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_superfluous_keys_email_template.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_superfluous_keys_email_template.php deleted file mode 100644 index 8bfb9ae62..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/no_superfluous_keys_email_template.php +++ /dev/null @@ -1,51 +0,0 @@ - 'email_templates', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - "entity_id" => "https://entity.tld/id", - "public_key" => "MIIE...", - "acs" => ["https://entity.tld/consume-assertion"], - "loa" => [ - "__default__" => "https://entity.tld/authentication/loa2", - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => ['20394-4320423-439248324'], - 'email_templates' => [ - 'superfluous_key' => 'lemon', - 'confirm_email' => ['en_GB' => 'Verify {{ commonName }}'], - 'registration_code_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'registration_code_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - 'vetted' => ['en_GB' => 'Vetted {{ commonName }}'], - 'second_factor_revoked' => ['en_GB' => 'Revoked token for {{ commonName }}'], - 'second_factor_verification_reminder_with_ras' => ['en_GB' => 'Code {{ commonName }}'], - 'second_factor_verification_reminder_with_ra_locations' => ['en_GB' => 'Code {{ commonName }}'], - ], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_array_email_templates.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_array_email_templates.php deleted file mode 100644 index 4cd6698a0..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_array_email_templates.php +++ /dev/null @@ -1,42 +0,0 @@ - 'email_templates', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - 'entity_id' => 'http://entity.tld/metadata', - 'public_key' => 'MIIEEE...', - 'acs' => ['http://entity.tld/consume-assertion'], - 'loa' => [ - '__default__' => 'http://gateway.tld/loa/1', - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => [], - 'email_templates' => null, - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_array_sraa.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_array_sraa.php deleted file mode 100644 index b0f3b1822..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_array_sraa.php +++ /dev/null @@ -1,42 +0,0 @@ - 'sraa', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - 'entity_id' => 'http://entity.tld/metadata', - 'public_key' => 'MIIEEE...', - 'acs' => ['http://entity.tld/consume-assertion'], - 'loa' => [ - '__default__' => 'http://gateway.tld/loa/1', - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => null, - 'email_templates' => [], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_strings_sraa.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_strings_sraa.php deleted file mode 100644 index bc5c4cce9..000000000 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Tests/Validator/Fixtures/invalid_configuration/not_strings_sraa.php +++ /dev/null @@ -1,44 +0,0 @@ - 'sraa[0]', - 'configuration' => [ - 'gateway' => [ - 'identity_providers' => [], - 'service_providers' => [ - [ - 'entity_id' => 'http://entity.tld/metadata', - 'public_key' => 'MIIEEE...', - 'acs' => ['http://entity.tld/consume-assertion'], - 'loa' => [ - '__default__' => 'http://gateway.tld/loa/1', - ], - "second_factor_only" => false, - "second_factor_only_nameid_patterns" => [], - "assertion_encryption_enabled" => false, - "blacklisted_encryption_algorithms" => [], - ], - ], - ], - 'sraa' => [ - 9, - ], - 'email_templates' => [], - ], -]; diff --git a/src/Surfnet/StepupMiddleware/ManagementBundle/Validator/ConfigurationStructureValidator.php b/src/Surfnet/StepupMiddleware/ManagementBundle/Validator/ConfigurationStructureValidator.php index 9d9d38cb3..578d4e73f 100644 --- a/src/Surfnet/StepupMiddleware/ManagementBundle/Validator/ConfigurationStructureValidator.php +++ b/src/Surfnet/StepupMiddleware/ManagementBundle/Validator/ConfigurationStructureValidator.php @@ -19,7 +19,6 @@ namespace Surfnet\StepupMiddleware\ManagementBundle\Validator; use Assert\Assertion; -use Assert\AssertionFailedException; use Assert\InvalidArgumentException as AssertionException; use InvalidArgumentException as CoreInvalidArgumentException; use Surfnet\Stepup\Helper\JsonHelper; @@ -37,7 +36,6 @@ class ConfigurationStructureValidator extends ConstraintValidator { public function __construct( private readonly GatewayConfigurationValidator $gatewayConfigurationValidator, - private readonly EmailTemplatesConfigurationValidator $emailTemplatesConfigurationValidator, ) { } @@ -70,17 +68,16 @@ private function decodeJson(string $rawValue): mixed public function validateRoot(array $configuration): void { - $acceptedProperties = ['gateway', 'sraa', 'email_templates']; - StepupAssert::keysMatch( + // sraa and email_templates are accepted for backward compatibility but ignored; only gateway is required + StepupAssert::requiredAndOptionalOptions( $configuration, - $acceptedProperties, - sprintf("Expected only properties '%s'", implode(',', $acceptedProperties)), + ['gateway'], + ['sraa', 'email_templates'], + "Expected only properties 'gateway', optional 'sraa', 'email_templates'", '(root)', ); $this->validateGatewayConfiguration($configuration, 'gateway'); - $this->validateSraaConfiguration($configuration, 'sraa'); - $this->validateEmailTemplatesConfiguration($configuration, 'email_templates'); } private function validateGatewayConfiguration(array $configuration, string $propertyPath): void @@ -89,36 +86,4 @@ private function validateGatewayConfiguration(array $configuration, string $prop $this->gatewayConfigurationValidator->validate($configuration['gateway'], $propertyPath); } - - private function validateSraaConfiguration(array $configuration, string $propertyPath): void - { - Assertion::isArray( - $configuration['sraa'], - 'Property sraa must have an array of name_ids (string) as value', - $propertyPath, - ); - - foreach ($configuration['sraa'] as $index => $value) { - Assertion::string( - $value, - 'value must be a string (the name_id of the SRAA)', - $propertyPath . '[' . $index . ']', - ); - } - } - - /** - * @param array $configuration - * @throws AssertionFailedException - */ - private function validateEmailTemplatesConfiguration(array $configuration, string $propertyPath): void - { - Assertion::isArray( - $configuration['email_templates'], - 'Property "email_templates" must have an object as value', - $propertyPath, - ); - - $this->emailTemplatesConfigurationValidator->validate($configuration['email_templates'], $propertyPath); - } }