diff --git a/app/config/config.yml b/app/config/config.yml index b04ca496b..97c64858d 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -162,3 +162,6 @@ jms_translation: excluded_names: ['*TestCase.php', '*Test.php'] excluded_dirs: [cache, data, logs, Tests] extractors: [] + +surfnet_stepup_self_service_self_service: + enabled_second_factors: %enabled_second_factors% diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index 9376134d7..6071d640a 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -44,3 +44,7 @@ parameters: stepup_loa_loa3: https://gateway.tld/authentication/loa3 logout_redirect_url: https://www.surf.nl/over-surf/werkmaatschappijen/surfnet + + enabled_second_factors: + - sms + - yubikey diff --git a/composer.json b/composer.json index b9c39f5bb..148c4085b 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ "symfony/swiftmailer-bundle": "~2.3" }, "require-dev": { + "matthiasnoback/symfony-config-test": "^1.2.0", "mockery/mockery": "~0.9.0", "sensio/generator-bundle": "~2.3", "ibuildings/qa-tools": "~1.1,>=1.1.27", diff --git a/composer.lock b/composer.lock index 93f9fe877..c2d43c3bc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "08e429320ee0805b6367ec25809f582a", + "hash": "b1feb8d102ba3368c0586eac4127644c", "packages": [ { "name": "beberlei/assert", @@ -1190,7 +1190,7 @@ }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phiamo/MopaBootstrapBundle/zipball/c34671a55b2585e20a35ab5c6e1ad13a7e220b01", + "url": "https://api.github.com/repos/phiamo/MopaBootstrapBundle/zipball/cc093b4f10f5598f9c5d77acd365c0e61283e8e7", "reference": "818b0f47ebd352559950e9a64431ff9472e8a9dd", "shasum": "" }, @@ -1744,12 +1744,12 @@ "source": { "type": "git", "url": "https://github.com/SURFnet/Stepup-bundle.git", - "reference": "ac1513d9ddfde02849896e10f4c517a81642bcda" + "reference": "1e15e4adf96144f470ec7660b02c2faf2b5cc9d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SURFnet/Stepup-bundle/zipball/ac1513d9ddfde02849896e10f4c517a81642bcda", - "reference": "ac1513d9ddfde02849896e10f4c517a81642bcda", + "url": "https://api.github.com/repos/SURFnet/Stepup-bundle/zipball/1e15e4adf96144f470ec7660b02c2faf2b5cc9d0", + "reference": "1e15e4adf96144f470ec7660b02c2faf2b5cc9d0", "shasum": "" }, "require": { @@ -1758,7 +1758,7 @@ "graylog2/gelf-php": "~1.1", "guzzlehttp/guzzle": "~4", "monolog/monolog": "~1.11", - "php": "~5.4|^7", + "php": ">=5.4,<8.0-dev", "sensio/framework-extra-bundle": "~3", "symfony/config": "^2.7", "symfony/dependency-injection": "^2.7", @@ -1789,7 +1789,7 @@ "suaas", "surfnet" ], - "time": "2015-08-26 09:22:28" + "time": "2015-09-09 09:07:14" }, { "name": "surfnet/stepup-middleware-client-bundle", @@ -1801,7 +1801,7 @@ }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SURFnet/Stepup-Middleware-clientbundle/zipball/f10eaa326cbc2d04e61ff4e34f03c6ebe180230b", + "url": "https://api.github.com/repos/SURFnet/Stepup-Middleware-clientbundle/zipball/2230cbd536b8c7912b7850f5516d99b028ad0ee4", "reference": "f10eaa326cbc2d04e61ff4e34f03c6ebe180230b", "shasum": "" }, @@ -1850,7 +1850,7 @@ }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SURFnet/Stepup-saml-bundle/zipball/53b7fd0198a1e9de2504a3762af499f744ad222d", + "url": "https://api.github.com/repos/SURFnet/Stepup-saml-bundle/zipball/62ac63e0f7bd15257aa919d0d6885f76cdcaea43", "reference": "53b7fd0198a1e9de2504a3762af499f744ad222d", "shasum": "" }, @@ -3157,6 +3157,54 @@ ], "time": "2014-10-28 10:33:21" }, + { + "name": "matthiasnoback/symfony-config-test", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/matthiasnoback/SymfonyConfigTest.git", + "reference": "9e1d553cc5b3900b48e8d4074d84cc7a02c958d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/matthiasnoback/SymfonyConfigTest/zipball/9e1d553cc5b3900b48e8d4074d84cc7a02c958d1", + "reference": "9e1d553cc5b3900b48e8d4074d84cc7a02c958d1", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "symfony/config": "2.*" + }, + "require-dev": { + "phpunit/phpunit": ">=3.7", + "sebastian/exporter": "1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matthias\\SymfonyConfigTest\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthias Noback", + "email": "matthiasnoback@gmail.com", + "homepage": "http://php-and-symfony.matthiasnoback.nl" + } + ], + "description": "Library for testing user classes related to the Symfony Config Component", + "homepage": "https://github.com/matthiasnoback/SymfonyConfigTest", + "keywords": [ + "config", + "phpunit", + "symfony" + ], + "time": "2015-04-20 08:58:05" + }, { "name": "mockery/mockery", "version": "0.9.4", diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Controller.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Controller.php index 0e1dc750b..a39c11505 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Controller.php +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Controller.php @@ -48,4 +48,16 @@ protected function getIdentity() return $user; } + + /** + * @param string $type + */ + protected function assertSecondFactorEnabled($type) + { + if (!in_array($type, $this->getParameter('ss.enabled_second_factors'))) { + $this->get('logger')->warning('A controller action was called for a disabled second factor'); + + throw $this->createNotFoundException(); + } + } } diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/GssfController.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/GssfController.php index a28e6c76c..aa4804baa 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/GssfController.php +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/GssfController.php @@ -38,6 +38,8 @@ final class GssfController extends Controller */ public function initiateAction($provider) { + $this->assertSecondFactorEnabled($provider); + return $this->renderInitiateForm($provider); } @@ -47,6 +49,8 @@ public function initiateAction($provider) */ public function authenticateAction($provider) { + $this->assertSecondFactorEnabled($provider); + $provider = $this->getProvider($provider); $authnRequest = AuthnRequestFactory::createNewRequest( @@ -77,6 +81,8 @@ public function authenticateAction($provider) */ public function consumeAssertionAction(Request $httpRequest, $provider) { + $this->assertSecondFactorEnabled($provider); + $provider = $this->getProvider($provider); $this->get('logger')->notice( @@ -145,6 +151,8 @@ public function consumeAssertionAction(Request $httpRequest, $provider) */ public function metadataAction($provider) { + $this->assertSecondFactorEnabled($provider); + $provider = $this->getProvider($provider); /** @var \Surfnet\SamlBundle\Metadata\MetadataFactory $factory */ diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/SmsController.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/SmsController.php index 073dfbc7c..d15fb2402 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/SmsController.php +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/SmsController.php @@ -33,6 +33,8 @@ class SmsController extends Controller */ public function sendChallengeAction(Request $request) { + $this->assertSecondFactorEnabled('sms'); + $identity = $this->getIdentity(); $command = new SendSmsChallengeCommand(); @@ -71,6 +73,8 @@ public function sendChallengeAction(Request $request) */ public function provePossessionAction(Request $request) { + $this->assertSecondFactorEnabled('sms'); + /** @var SmsSecondFactorService $service */ $service = $this->get('surfnet_stepup_self_service_self_service.service.sms_second_factor'); diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/YubikeyController.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/YubikeyController.php index 5240d9cb2..20499e79b 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/YubikeyController.php +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/Registration/YubikeyController.php @@ -32,6 +32,8 @@ class YubikeyController extends Controller */ public function provePossessionAction(Request $request) { + $this->assertSecondFactorEnabled('yubikey'); + $identity = $this->getIdentity(); $command = new VerifyYubikeyOtpCommand(); diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/RegistrationController.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/RegistrationController.php index c0428d260..c2792ce33 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/RegistrationController.php +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Controller/RegistrationController.php @@ -31,7 +31,12 @@ class RegistrationController extends Controller */ public function displaySecondFactorTypesAction() { - return ['commonName' => $this->getIdentity()->commonName]; + $enabledSecondFactors = $this->getParameter('ss.enabled_second_factors'); + + return [ + 'commonName' => $this->getIdentity()->commonName, + 'enabledSecondFactors' => array_combine($enabledSecondFactors, $enabledSecondFactors), + ]; } /** diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/DependencyInjection/Configuration.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/DependencyInjection/Configuration.php new file mode 100644 index 000000000..856d2b273 --- /dev/null +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/DependencyInjection/Configuration.php @@ -0,0 +1,59 @@ +root('surfnet_stepup_self_service_self_service') + ->children() + ->arrayNode('enabled_second_factors') + ->isRequired() + ->prototype('scalar') + ->validate() + ->ifTrue(function ($type) { + try { + new SecondFactorType($type); + } catch (InvalidArgumentException $e) { + return true; + } catch (DomainException $e) { + return true; + } + }) + ->thenInvalid( + 'Enabled second factor type "%s" is not one of the valid types. See SecondFactorType' + ) + ->end() + ->end() + ->end() + ->end(); + + return $treeBuilder; + } +} diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/DependencyInjection/SurfnetStepupSelfServiceSelfServiceExtension.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/DependencyInjection/SurfnetStepupSelfServiceSelfServiceExtension.php index 37ad19666..42d3dbc80 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/DependencyInjection/SurfnetStepupSelfServiceSelfServiceExtension.php +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/DependencyInjection/SurfnetStepupSelfServiceSelfServiceExtension.php @@ -35,11 +35,16 @@ class SurfnetStepupSelfServiceSelfServiceExtension extends Extension */ public function load(array $configs, ContainerBuilder $container) { + $configuration = new Configuration(); + $config = $this->processConfiguration($configuration, $configs); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); $container->getDefinition('self_service.locale.request_stack_locale_provider') ->replaceArgument(1, $container->getParameter('default_locale')) ->replaceArgument(2, $container->getParameter('locales')); + + $container->setParameter('ss.enabled_second_factors', $config['enabled_second_factors']); } } diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/views/Registration/displaySecondFactorTypes.html.twig b/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/views/Registration/displaySecondFactorTypes.html.twig index f67c02633..b61d0c3c2 100644 --- a/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/views/Registration/displaySecondFactorTypes.html.twig +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Resources/views/Registration/displaySecondFactorTypes.html.twig @@ -12,22 +12,26 @@

{{ block('page_title') }}

- {% include 'SurfnetStepupSelfServiceSelfServiceBundle::Registration/partial/secondFactor.html.twig' with { - 'type': 'sms', - 'security': 2, - 'url': path('ss_registration_sms_send_challenge') - } only %} - {# - {% include 'SurfnetStepupSelfServiceSelfServiceBundle::Registration/partial/secondFactor.html.twig' with { - 'type': 'tiqr', - 'security': 2, - 'url': path('ss_registration_gssf_initiate', {'provider': 'tiqr'}) - } only %} - #} - {% include 'SurfnetStepupSelfServiceSelfServiceBundle::Registration/partial/secondFactor.html.twig' with { - 'type': 'yubikey', - 'security': 3, - 'url': path('ss_registration_yubikey_prove_possession') - } only %} + {% if enabledSecondFactors.sms is defined %} + {% include 'SurfnetStepupSelfServiceSelfServiceBundle::Registration/partial/secondFactor.html.twig' with { + 'type': 'sms', + 'security': 2, + 'url': path('ss_registration_sms_send_challenge') + } only %} + {% endif %} + {% if enabledSecondFactors.tiqr is defined %} + {% include 'SurfnetStepupSelfServiceSelfServiceBundle::Registration/partial/secondFactor.html.twig' with { + 'type': 'tiqr', + 'security': 2, + 'url': path('ss_registration_gssf_initiate', {'provider': 'tiqr'}) + } only %} + {% endif %} + {% if enabledSecondFactors.yubikey is defined %} + {% include 'SurfnetStepupSelfServiceSelfServiceBundle::Registration/partial/secondFactor.html.twig' with { + 'type': 'yubikey', + 'security': 3, + 'url': path('ss_registration_yubikey_prove_possession') + } only %} + {% endif %}
{% endblock %} diff --git a/src/Surfnet/StepupSelfService/SelfServiceBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Surfnet/StepupSelfService/SelfServiceBundle/Tests/DependencyInjection/ConfigurationTest.php new file mode 100644 index 000000000..5c522cb77 --- /dev/null +++ b/src/Surfnet/StepupSelfService/SelfServiceBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -0,0 +1,82 @@ +assertConfigurationIsInvalid([$configuration], 'must be configured'); + } + + /** + * @test + * @group configuration + */ + public function it_allows_one_enabled_second_factor() + { + $configuration = ['enabled_second_factors' => ['sms']]; + $expectedProcessedConfiguration = [ + 'enabled_second_factors' => ['sms'], + ]; + + $this->assertProcessedConfigurationEquals([$configuration], $expectedProcessedConfiguration); + } + + /** + * @test + * @group configuration + */ + public function it_allows_two_enabled_second_factors() + { + $configuration = ['enabled_second_factors' => ['sms', 'yubikey']]; + $expectedProcessedConfiguration = [ + 'enabled_second_factors' => ['sms', 'yubikey'], + ]; + + $this->assertProcessedConfigurationEquals([$configuration], $expectedProcessedConfiguration); + } + + /** + * @test + * @group configuration + */ + public function it_rejects_invalid_second_factor_types() + { + $configuration = ['enabled_second_factors' => ['passport']]; + + $this->assertConfigurationIsInvalid([$configuration], 'not one of the valid types'); + } + + protected function getConfiguration() + { + return new Configuration(); + } +}