diff --git a/composer.lock b/composer.lock index bd70a06a4..7ef55ff4e 100644 --- a/composer.lock +++ b/composer.lock @@ -7629,16 +7629,16 @@ }, { "name": "twig/twig", - "version": "v2.15.1", + "version": "v2.15.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "3b7cedb2f736899a7dbd0ba3d6da335a015f5cc4" + "reference": "ab402673db8746cb3a4c46f3869d6253699f614a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3b7cedb2f736899a7dbd0ba3d6da335a015f5cc4", - "reference": "3b7cedb2f736899a7dbd0ba3d6da335a015f5cc4", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/ab402673db8746cb3a4c46f3869d6253699f614a", + "reference": "ab402673db8746cb3a4c46f3869d6253699f614a", "shasum": "" }, "require": { @@ -7693,7 +7693,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v2.15.1" + "source": "https://github.com/twigphp/Twig/tree/v2.15.3" }, "funding": [ { @@ -7705,7 +7705,7 @@ "type": "tidelift" } ], - "time": "2022-05-17T05:46:24+00:00" + "time": "2022-09-28T08:40:08+00:00" }, { "name": "ua-parser/uap-php", diff --git a/config/legacy/parameters.yaml.dist b/config/legacy/parameters.yaml.dist index efd6a1c0d..7260420d4 100644 --- a/config/legacy/parameters.yaml.dist +++ b/config/legacy/parameters.yaml.dist @@ -64,3 +64,9 @@ parameters: preferred_activation_flow_name: activate preferred_activation_flow_options: [ra, self] + # Self-asserted tokens: enable/disable recovery methods + # + # One of the two options should be enabled to have a fully functioning + # Self-asserted token registration process. + recovery_method_sms_enabled: true + recovery_method_safe_store_code_enabled: true diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/SecondFactorController.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/SecondFactorController.php index 739f1e3ad..e8a6ab2ee 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/SecondFactorController.php +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/SecondFactorController.php @@ -61,7 +61,7 @@ public function listAction() $authorizationService = $this->get(AuthorizationService::class); $recoveryTokensAllowed = $authorizationService->mayRegisterRecoveryTokens($identity); $selfAssertedTokenRegistration = $options->allowSelfAssertedTokens === true && $recoveryTokensAllowed; - + $hasRemainingTokenTypes = count($recoveryTokenService->getRemainingTokenTypes($identity)) > 0; $recoveryTokens = []; if ($selfAssertedTokenRegistration && $recoveryTokensAllowed) { $recoveryTokens = $recoveryTokenService->getRecoveryTokensForIdentity($identity); @@ -80,6 +80,7 @@ public function listAction() 'expirationHelper' => $expirationHelper, 'selfAssertedTokenRegistration' => $selfAssertedTokenRegistration, 'recoveryTokens' => $recoveryTokens, + 'hasRemainingRecoveryTokens' => $hasRemainingTokenTypes, ]; } diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/config/services.yml b/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/config/services.yml index 0c50ae232..ccf11e677 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/config/services.yml +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/config/services.yml @@ -147,11 +147,17 @@ services: - '@Surfnet\StepupMiddlewareClientBundle\Identity\Service\VettingTypeHintService' - '@logger' + Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\RecoveryTokenConfig: + arguments: + - '%recovery_method_sms_enabled%' + - '%recovery_method_safe_store_code_enabled%' + Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\RecoveryTokenService: arguments: - '@Surfnet\StepupMiddlewareClientBundle\Identity\Service\RecoveryTokenService' - '@Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\SafeStoreService' - '@Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\RecoveryTokenState' + - '@Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\RecoveryTokenConfig' - '@logger' Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\SafeStoreState: diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/views/registration/partial/crud_list.html.twig b/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/views/registration/partial/crud_list.html.twig index 5e270b59f..be80a03ba 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/views/registration/partial/crud_list.html.twig +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/views/registration/partial/crud_list.html.twig @@ -38,13 +38,14 @@
{{ 'ss.second_factor.list.text.no_recovery_tokens'|trans }}
{% endif %} + {% if hasRemainingRecoveryTokens %}{{ 'ss.second_factor.list.button.register_recovery_token'|trans }}
- + {% endif %}
diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Service/SelfAssertedTokens/Exception/RecoveryTokenConfigurationException.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Service/SelfAssertedTokens/Exception/RecoveryTokenConfigurationException.php new file mode 100644 index 000000000..cfb539514 --- /dev/null +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Service/SelfAssertedTokens/Exception/RecoveryTokenConfigurationException.php @@ -0,0 +1,25 @@ +smsEnabled = $smsEnabled; + $this->safeStoreCodeEnabled = $safeStoreCodeEnabled; + } + + public function isSmsDisabled(): bool + { + return !$this->smsEnabled; + } + + public function isSafeStoreCodeDisabled(): bool + { + return !$this->safeStoreCodeEnabled; + } +} diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Service/SelfAssertedTokens/RecoveryTokenService.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Service/SelfAssertedTokens/RecoveryTokenService.php index eabe1c3fd..e2d9fbd6b 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Service/SelfAssertedTokens/RecoveryTokenService.php +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Service/SelfAssertedTokens/RecoveryTokenService.php @@ -48,15 +48,22 @@ class RecoveryTokenService */ private $stateStore; + /** + * @var RecoveryTokenConfig + */ + private $config; + public function __construct( MiddlewareRecoveryTokenService $recoveryTokenService, SafeStoreService $safeStoreService, RecoveryTokenState $recoveryTokenState, + RecoveryTokenConfig $config, LoggerInterface $logger ) { $this->recoveryTokenService = $recoveryTokenService; $this->safeStoreService = $safeStoreService; $this->stateStore = $recoveryTokenState; + $this->config = $config; $this->logger = $logger; } @@ -78,10 +85,13 @@ public function getRecoveryTokensForIdentity(Identity $identity): array return $this->recoveryTokenService->findAllFor($identity); } - public function getRemainingTokenTypes(Identity $identity) + public function getRemainingTokenTypes(Identity $identity): array { $tokens = $this->getRecoveryTokensForIdentity($identity); - $tokenTypes = $this->recoveryTokenService->getAvailableRecoveryTokenTypes(); + $tokenTypes = $this->excludeDisabledRecoveryTokens( + $this->recoveryTokenService->getAvailableRecoveryTokenTypes() + ); + /** @var RecoveryToken $token */ foreach ($tokens as $token) { if (in_array($token->type, $tokenTypes)) { @@ -173,4 +183,17 @@ public function resetStepUpGiven() { $this->stateStore->resetStepUpGiven(); } + + private function excludeDisabledRecoveryTokens(array $availableRecoveryTokenTypes): array + { + foreach ($availableRecoveryTokenTypes as $identifier => $token) { + if ($token === 'sms' && $this->config->isSmsDisabled()) { + unset($availableRecoveryTokenTypes[$identifier]); + } + if ($token === 'safe-store' && $this->config->isSafeStoreCodeDisabled()) { + unset($availableRecoveryTokenTypes[$identifier]); + } + } + return $availableRecoveryTokenTypes; + } } diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Tests/Service/SelfAssertedTokens/RecoveryTokenConfigTest.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Tests/Service/SelfAssertedTokens/RecoveryTokenConfigTest.php new file mode 100644 index 000000000..15f2e5b6f --- /dev/null +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Tests/Service/SelfAssertedTokens/RecoveryTokenConfigTest.php @@ -0,0 +1,54 @@ +isSafeStoreCodeDisabled()); + self::assertFalse($config->isSmsDisabled()); + } + + public function test_only_sms_can_be_enabled() + { + $config = new RecoveryTokenConfig(true, false); + self::assertTrue($config->isSafeStoreCodeDisabled()); + self::assertFalse($config->isSmsDisabled()); + } + + public function test_only_safe_store_can_be_enabled() + { + $config = new RecoveryTokenConfig(false, true); + self::assertFalse($config->isSafeStoreCodeDisabled()); + self::assertTrue($config->isSmsDisabled()); + } + + public function test_not_allowed_to_disable_both() + { + self::expectException(RecoveryTokenConfigurationException::class); + self::expectExceptionMessage('The SMS or safe-store code recovery token must be enabled'); + new RecoveryTokenConfig(false, false); + } +}