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:
+
+ - Your token
+ - A valid proof of identity (passport, drivers license or national ID-card)
+ - The activation code from this e-mail
+
+
+Activation code: {{ registrationCode }}
+
+Location(s) to activate your token:
+{% if raLocations is empty %}
+ No locations known.
+{% else %}
+
+ {% for ra in raLocations %}
+ -
+ {{ ra.name }}
+ {{ ra.location }}
+ {{ ra.contactInformation }}
+
+ {% endfor %}
+
+{% 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:
+
+ - Your token
+ - A valid proof of identity (passport, drivers license or national ID-card)
+ - The activation code from this e-mail
+
+
+Activation code: {{ registrationCode }}
+
+Location(s) to activate your token:
+{% if ras is empty %}
+ No RAs are known.
+{% else %}
+
+ {% for ra in ras %}
+ -
+ {{ ra.commonName }}
+ {{ ra.location }}
+ {{ ra.contactInformation }}
+
+ {% endfor %}
+
+{% 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:
+
+ - Your token
+ - A valid proof of identity (passport, drivers license or national ID-card)
+ - The activation code from this e-mail
+
+
+Activation code: {{ registrationCode }}
+
+Location(s) to activate your token:
+{% if raLocations is empty %}
+ No locations known.
+{% else %}
+
+ {% for ra in raLocations %}
+ -
+ {{ ra.name }}
+ {{ ra.location }}
+ {{ ra.contactInformation }}
+
+ {% endfor %}
+
+{% 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:
+
+ - Your token
+ - A valid proof of identity (passport, drivers license or national ID-card).
+ - The activation code from this e-mail
+
+
+Activation code: {{ registrationCode }}
+
+Location(s) to activate your token:
+{% if ras is empty %}
+ No RAs are known.
+{% else %}
+
+ {% for ra in ras %}
+ -
+ {{ ra.commonName }}
+ {{ ra.location }}
+ {{ ra.contactInformation }}
+
+ {% endfor %}
+
+{% 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
+
+ - Your token is private, do not share your token with others
+ - Never leave your token unattended
+ - Lock your phone, e.g. with a code or fingerprint
+
+
+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:
+
+ - Je token
+ - Een geldig legitimatiebewijs (paspoort, rijbewijs of nationale ID-kaart)
+ - De activatiecode uit deze e-mail
+
+
+Activatiecode: {{ registrationCode }}
+
+Locatie(s) om je token te activeren:
+{% if raLocations is empty %}
+ Er zijn geen Locaties bekend.
+{% else %}
+
+ {% for ra in raLocations %}
+ -
+ {{ ra.name }}
+ {{ ra.location }}
+ {{ ra.contactInformation }}
+
+ {% endfor %}
+
+{% 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:
+
+ - Je token
+ - Een geldig legitimatiebewijs (paspoort, rijbewijs of nationale ID-kaart)
+ - De activatiecode uit deze e-mail
+
+
+Activatiecode: {{ registrationCode }}
+
+Locatie(s) om je token te activeren:
+{% if ras is empty %}
+ Er zijn geen RAs bekend.
+{% else %}
+
+ {% for ra in ras %}
+ -
+ {{ ra.commonName }}
+ {{ ra.location }}
+ {{ ra.contactInformation }}
+
+ {% endfor %}
+
+{% 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:
+
+ - Je token
+ - Een geldig legitimatiebewijs (paspoort, rijbewijs of nationale ID-kaart)
+ - De activatiecode uit deze e-mail
+
+
+Activatiecode: {{ registrationCode }}
+
+Locatie(s) om je token te activeren:
+{% if raLocations is empty %}
+ Er zijn geen Locaties bekend.
+{% else %}
+
+ {% for ra in raLocations %}
+ -
+ {{ ra.name }}
+ {{ ra.location }}
+ {{ ra.contactInformation }}
+
+ {% endfor %}
+
+{% 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:
+
+ - Je token
+ - Een geldig legitimatiebewijs (paspoort, rijbewijs of nationale ID-kaart)
+ - De activatiecode uit deze e-mail
+
+
+Activatiecode: {{ registrationCode }}
+
+Locatie(s) om je token te activeren:
+{% if ras is empty %}
+ Er zijn geen RAs bekend.
+{% else %}
+
+ {% for ra in ras %}
+ -
+ {{ ra.commonName }}
+ {{ ra.location }}
+ {{ ra.contactInformation }}
+
+ {% endfor %}
+
+{% 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
+
+ - Je token is persoonlijk, deel deze niet met anderen
+ - Laat je token nooit onbeheerd achter
+ - Vergrendel je telefoon met bijvoorbeeld een code of vingerafdruk
+
+
+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);
- }
}