Skip to content

Commit

Permalink
Add toggles to disable recovery token types
Browse files Browse the repository at this point in the history
SMS or safe store recovery token types can be enabled and disabled. But
never can both be disabled.

See https://www.pivotaltracker.com/story/show/183636781
  • Loading branch information
MKodde committed Nov 1, 2022
1 parent 5360e24 commit e5ae959
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 4 deletions.
6 changes: 6 additions & 0 deletions config/legacy/parameters.yaml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -80,6 +80,7 @@ public function listAction()
'expirationHelper' => $expirationHelper,
'selfAssertedTokenRegistration' => $selfAssertedTokenRegistration,
'recoveryTokens' => $recoveryTokens,
'hasRemainingRecoveryTokens' => $hasRemainingTokenTypes,
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@
<p>{{ 'ss.second_factor.list.text.no_recovery_tokens'|trans }}</p>
{% endif %}

{% if hasRemainingRecoveryTokens %}
<p>
<a href="{{ path('ss_recovery_token_display_types') }}"
class="btn btn-primary pull-right">
{{ 'ss.second_factor.list.button.register_recovery_token'|trans }}
</a>
</p>

{% endif %}
<p>&nbsp;</p>
<p>&nbsp;</p>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/**
* Copyright 2022 SURFnet bv
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\Exception;

use Surfnet\StepupSelfService\SelfServiceBundle\Exception\RuntimeException;

class RecoveryTokenConfigurationException extends RuntimeException
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

/**
* Copyright 2022 SURFnet bv
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens;

use Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\Exception\RecoveryTokenConfigurationException;

class RecoveryTokenConfig
{
/**
* @var bool
*/
private $smsEnabled;

/**
* @var bool
*/
private $safeStoreCodeEnabled;

public function __construct(bool $smsEnabled, bool $safeStoreCodeEnabled)
{
if ($smsEnabled === false && $safeStoreCodeEnabled === false) {
throw new RecoveryTokenConfigurationException('The SMS or safe-store code recovery token must be enabled');
}
$this->smsEnabled = $smsEnabled;
$this->safeStoreCodeEnabled = $safeStoreCodeEnabled;
}

public function isSmsDisabled(): bool
{
return !$this->smsEnabled;
}

public function isSafeStoreCodeDisabled(): bool
{
return !$this->safeStoreCodeEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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)) {
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/**
* Copyright 2022 SURFnet bv
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Surfnet\StepupSelfService\SelfServiceBundle\Tests\Service\SelfAssertedTokens;

use PHPUnit\Framework\TestCase;
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\Exception\RecoveryTokenConfigurationException;
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SelfAssertedTokens\RecoveryTokenConfig;

class RecoveryTokenConfigTest extends TestCase
{
public function test_both_recovery_token_methods_can_be_enabled()
{
$config = new RecoveryTokenConfig(true, true);
self::assertFalse($config->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);
}
}

0 comments on commit e5ae959

Please sign in to comment.