├── Resources
├── config
│ ├── routing.yml
│ ├── services.yml
│ ├── services
│ │ ├── model-repository.yml
│ │ ├── model-manager.yml
│ │ ├── model-gateway.yml
│ │ ├── model.yml
│ │ └── components.yml
│ └── doctrine
│ │ └── Session.orm.yml
├── views
│ ├── home.html.twig
│ └── login.html.twig
├── doc
│ ├── index.md
│ ├── configuration_reference.md
│ └── install.md
└── meta
│ └── LICENSE
├── Tests
├── Functional
│ ├── app
│ │ ├── config
│ │ │ ├── config_dev.yml
│ │ │ ├── config_prod.yml
│ │ │ ├── config_test.yml
│ │ │ ├── routing_dev.yml
│ │ │ ├── routing.yml
│ │ │ ├── ccdn
│ │ │ │ └── user-security.yml
│ │ │ └── config.yml
│ │ ├── console
│ │ └── AppKernel.php
│ ├── src
│ │ ├── Resources
│ │ │ └── config
│ │ │ │ └── doctrine
│ │ │ │ └── User.orm.yml
│ │ └── Entity
│ │ │ └── User.php
│ └── bootstrap.php
├── Manager
│ └── SessionManagerTest.php
├── Repository
│ └── SessionRepositoryTest.php
└── TestBase.php
├── .gitignore
├── .php_cs
├── Component
├── Listener
│ ├── AccessDeniedExceptionFactoryInterface.php
│ ├── AccessDeniedExceptionFactory.php
│ ├── DeferLoginListener.php
│ └── BlockingLoginListener.php
├── Authorisation
│ ├── SecurityManagerInterface.php
│ ├── Voter
│ │ └── ClientLoginVoter.php
│ └── SecurityManager.php
└── Authentication
│ ├── Tracker
│ └── LoginFailureTracker.php
│ └── Handler
│ └── LoginFailureHandler.php
├── script_phpunit.sh
├── script_behat.sh
├── behat.yml
├── CCDNUserSecurityBundle.php
├── .travis.yml
├── Controller
└── TestLoginController.php
├── phpunit.xml.dist
├── composer.json
├── features
├── bootstrap
│ ├── WebUser.php
│ ├── FeatureContext.php
│ └── DataContext.php
└── user_login.feature
├── Model
├── Component
│ ├── Repository
│ │ ├── SessionRepository.php
│ │ ├── RepositoryInterface.php
│ │ └── BaseRepository.php
│ ├── Manager
│ │ ├── SessionManager.php
│ │ ├── ManagerInterface.php
│ │ └── BaseManager.php
│ └── Gateway
│ │ ├── GatewayInterface.php
│ │ ├── BaseGateway.php
│ │ └── SessionGateway.php
└── FrontModel
│ ├── SessionModel.php
│ ├── ModelInterface.php
│ └── BaseModel.php
├── Entity
└── Session.php
├── README.md
└── DependencyInjection
├── CCDNUserSecurityExtension.php
└── Configuration.php
/Resources/config/routing.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Tests/Functional/app/config/config_dev.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config.yml }
3 |
--------------------------------------------------------------------------------
/Tests/Functional/app/config/config_prod.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config.yml }
3 |
--------------------------------------------------------------------------------
/Tests/Functional/app/config/config_test.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config.yml }
3 |
--------------------------------------------------------------------------------
/Tests/Functional/app/config/routing_dev.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: routing.yml }
3 |
--------------------------------------------------------------------------------
/Resources/config/services.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 |
3 | # Service Parameters defined in app/config
4 |
5 | services:
6 |
--------------------------------------------------------------------------------
/Resources/views/home.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hi on this test home page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Tests/Functional/src/Resources/config/doctrine/User.orm.yml:
--------------------------------------------------------------------------------
1 | CCDNUser\SecurityBundle\Tests\Functional\src\Entity\User:
2 | type: entity
3 | table: cc_user
4 | id:
5 | id:
6 | type: integer
7 | generator: { strategy: AUTO }
8 |
--------------------------------------------------------------------------------
/Tests/Functional/src/Entity/User.php:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
--------------------------------------------------------------------------------
/Resources/config/doctrine/Session.orm.yml:
--------------------------------------------------------------------------------
1 | CCDNUser\SecurityBundle\Entity\Session:
2 | type: entity
3 | table: cc_security_session
4 | id:
5 | id:
6 | type: integer
7 | generator: { strategy: AUTO }
8 | fields:
9 | ipAddress:
10 | type: string
11 | column: ip_address
12 | length: 50
13 | loginAttemptDate:
14 | type: datetime
15 | column: login_attempt_date
16 | loginAttemptUsername:
17 | type: text
18 | column: login_attempt_username
19 |
--------------------------------------------------------------------------------
/Resources/doc/index.md:
--------------------------------------------------------------------------------
1 | CCDNUser SecurityBundle Documentation.
2 | ======================================
3 |
4 | ### Translations
5 |
6 | If you wish to use default texts provided in this bundle, you have to make sure you have translator enabled in your config.
7 |
8 | ``` yaml
9 | # app/config/config.yml
10 |
11 | framework:
12 | translator: ~
13 | ```
14 |
15 | For more information about translations, check [Symfony documentation](http://symfony.com/doc/current/book/translation.html).
16 |
17 | ## Installation Documentation:
18 |
19 | - [Installing CCDNUser SecurityBundle for Symfony](install.md).
20 | - [Configuration Reference](configuration_reference.md).
21 |
--------------------------------------------------------------------------------
/.php_cs:
--------------------------------------------------------------------------------
1 | notName('LICENSE')
7 | ->notName('README.md')
8 | ->notName('.php_cs')
9 | ->notName('composer.*')
10 | ->notName('phpunit.xml*')
11 | ->notName('*.phar')
12 | ->exclude(
13 | array(
14 | 'vendor',
15 | 'Resources/meta',
16 | 'Resources/doc',
17 | 'Resources/public',
18 | 'Tests',
19 | )
20 | )
21 | ->in(__DIR__)
22 | ;
23 |
24 | return Symfony\CS\Config\Config::create()
25 | ->fixers(FixerInterface::ALL_LEVEL)
26 | ->finder($finder)
27 | ;
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Tests/Functional/bootstrap.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | use Doctrine\Common\Annotations\AnnotationRegistry;
15 |
16 | if (!file_exists($file = __DIR__.'/../../vendor/autoload.php')) {
17 | throw new \RuntimeException('Install the dependencies to run the test suite.');
18 | }
19 |
20 | $loader = require $file;
21 | AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
22 |
--------------------------------------------------------------------------------
/Component/Listener/AccessDeniedExceptionFactoryInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Component\Listener;
15 |
16 | interface AccessDeniedExceptionFactoryInterface
17 | {
18 | /**
19 | * Create exception thrown when a ip is blocked
20 | *
21 | * @return \Exception
22 | */
23 | public function createAccessDeniedException();
24 | }
25 |
--------------------------------------------------------------------------------
/Component/Listener/AccessDeniedExceptionFactory.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Component\Listener;
15 |
16 | use Symfony\Component\HttpKernel\Exception\HttpException;
17 |
18 | class AccessDeniedExceptionFactory implements AccessDeniedExceptionFactoryInterface
19 | {
20 | public function createAccessDeniedException()
21 | {
22 | return new HttpException(500, 'flood control - login blocked');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/script_phpunit.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | rm -rRf ./Tests/Functional/app/cache/*
4 | rm -rRf ./Tests/Functional/app/logs/*
5 |
6 | rm -f ./Tests/Functional/app/config/parameters.yml
7 | echo 'parameters:
8 | database_driver: pdo_mysql
9 | database_host: 127.0.0.1
10 | database_port: null
11 | database_name: ccdn_test
12 | database_user: ccdnroot
13 | database_password: root
14 | locale: en
15 |
16 | ' > ./Tests/Functional/app/config/parameters.yml
17 |
18 | composer install --dev
19 |
20 | php ./Tests/Functional/app/console --env=test doctrine:database:drop --force
21 | php ./Tests/Functional/app/console --env=test doctrine:database:create
22 | php ./Tests/Functional/app/console --env=test doctrine:schema:create
23 | php ./Tests/Functional/app/console --env=test doctrine:schema:update --force
24 |
25 | ./vendor/phpunit/phpunit/phpunit.php -c ./ --testdox
26 |
--------------------------------------------------------------------------------
/Tests/Functional/app/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
18 | $debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
19 |
20 | $kernel = new AppKernel($env, $debug);
21 | $application = new Application($kernel);
22 | $application->run($input);
23 |
--------------------------------------------------------------------------------
/script_behat.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | rm -rRf ./Tests/Functional/app/cache/*
4 | rm -rRf ./Tests/Functional/app/logs/*
5 |
6 | rm -f ./Tests/Functional/app/config/parameters.yml
7 | echo 'parameters:
8 | database_driver: pdo_mysql
9 | database_host: 127.0.0.1
10 | database_port: null
11 | database_name: ccdn_test
12 | database_user: ccdnroot
13 | database_password: root
14 | locale: en
15 |
16 | ' > ./Tests/Functional/app/config/parameters.yml
17 |
18 | composer install --dev --prefer-dist
19 |
20 | php ./Tests/Functional/app/console --env=test doctrine:database:drop --force
21 | php ./Tests/Functional/app/console --env=test doctrine:database:create
22 | php ./Tests/Functional/app/console --env=test doctrine:schema:create
23 | php ./Tests/Functional/app/console --env=test doctrine:schema:update --force
24 |
25 | ./vendor/behat/behat/bin/behat "@CCDNUserSecurityBundle" --config ./behat.yml
26 |
--------------------------------------------------------------------------------
/Tests/Functional/app/config/routing.yml:
--------------------------------------------------------------------------------
1 |
2 | fos_user_security:
3 | resource: "@FOSUserBundle/Resources/config/routing/security.xml"
4 |
5 | fos_user_profile:
6 | resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
7 | prefix: /profile
8 |
9 | fos_user_register:
10 | resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
11 | prefix: /register
12 |
13 | fos_user_resetting:
14 | resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
15 | prefix: /resetting
16 |
17 | fos_user_change_password:
18 | resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
19 | prefix: /profile
20 |
21 | ccdn_user_security_circumvent_login:
22 | pattern: /circumvent_login
23 | defaults: { _controller: CCDNUserSecurityBundle:TestLogin:circumvent }
24 |
25 | home:
26 | path: /
27 | defaults:
28 | _controller: FrameworkBundle:Template:template
29 | template: 'CCDNUserSecurityBundle::home.html.twig'
30 |
--------------------------------------------------------------------------------
/Resources/meta/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2011-2012 CodeConsortium
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
--------------------------------------------------------------------------------
/behat.yml:
--------------------------------------------------------------------------------
1 | default:
2 | formatter:
3 | name: progress
4 | parameters:
5 | decorated: true
6 | verbose: false
7 | time: true
8 | language: en
9 | output_path: null
10 | multiline_arguments: true
11 | paths:
12 | features: features
13 | bootstrap: %behat.paths.features%/Context
14 | context:
15 | class: CCDNUser\SecurityBundle\features\bootstrap\FeatureContext
16 | extensions:
17 | Behat\Symfony2Extension\Extension:
18 | mink_driver: true
19 | context:
20 | path_suffix: features
21 | class_suffix: features\bootstrap
22 | kernel:
23 | env: test
24 | debug: true
25 | path: Tests/Functional/app/AppKernel.php
26 | bootstrap: Tests/Functional/bootstrap.php
27 | Behat\MinkExtension\Extension:
28 | default_session: 'symfony2'
29 | goutte: ~
30 | selenium2: ~
31 | # base_url: http://ccdn.local/
32 |
--------------------------------------------------------------------------------
/CCDNUserSecurityBundle.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle;
15 |
16 | use Symfony\Component\HttpKernel\Bundle\Bundle;
17 | use Symfony\Component\DependencyInjection\ContainerBuilder;
18 |
19 | /**
20 | *
21 | * @category CCDNUser
22 | * @package SecurityBundle
23 | *
24 | * @author Reece Fowell
25 | * @license http://opensource.org/licenses/MIT MIT
26 | * @version Release: 1.0
27 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
28 | *
29 | */
30 | class CCDNUserSecurityBundle extends Bundle
31 | {
32 | /**
33 | *
34 | * @access public
35 | * @param ContainerBuilder $container
36 | */
37 | public function build(ContainerBuilder $container)
38 | {
39 | parent::build($container);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | # - hhvm
5 | - 5.3
6 | - 5.4
7 | - 5.5
8 |
9 | matrix:
10 | allow_failures:
11 | - php: 5.3
12 |
13 | before_script:
14 | - echo 'date.timezone = "Europe/London"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
15 | - mysql -e 'CREATE DATABASE ccdn_test'
16 | - >
17 | echo 'parameters:
18 | database_driver: pdo_mysql
19 | database_host: 127.0.0.1
20 | database_port: null
21 | database_name: ccdn_test
22 | database_user: root
23 | database_password: ~
24 | locale: en
25 |
26 | ' > ./Tests/Functional/app/config/parameters.yml
27 | - curl -s http://getcomposer.org/installer | php
28 | - php composer.phar install --dev --prefer-dist
29 | - php ./Tests/Functional/app/console doctrine:schema:create
30 | - php ./Tests/Functional/app/console doctrine:schema:update --force
31 |
32 | script:
33 | - 'php ./vendor/bin/phpunit -c ./ --testdox'
34 | - 'php ./vendor/bin/behat'
35 |
36 | after_script:
37 | - mysql -e 'DROP DATABASE ccdn_test;'
38 |
39 | notifications:
40 | email: status@codeconsortium.com
41 |
42 |
--------------------------------------------------------------------------------
/Tests/Manager/SessionManagerTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Tests\Manager;
15 |
16 | use CCDNUser\SecurityBundle\Tests\TestBase;
17 |
18 | /**
19 | *
20 | * @category CCDNUser
21 | * @package SecurityBundle
22 | *
23 | * @author Reece Fowell
24 | * @license http://opensource.org/licenses/MIT MIT
25 | * @version Release: 1.0
26 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
27 | *
28 | */
29 | class SessionManagerTest extends TestBase
30 | {
31 | public function testNewRecord()
32 | {
33 | $this->addFixturesForUsers();
34 | $ipAddress = '127.0.0.1';
35 | $this->getSessionModel()->newRecord($ipAddress, 'tom');
36 | $timeLimit = new \DateTime('-' . 1 . ' minutes');
37 | $sessions = $this->getSessionModel()->findAllByIpAddressAndLoginAttemptDate($ipAddress, $timeLimit);
38 |
39 | $this->assertCount(1, $sessions);
40 | $this->assertInstanceOf('CCDNUser\SecurityBundle\Entity\Session', $sessions[0]);
41 | }
42 | }
--------------------------------------------------------------------------------
/Controller/TestLoginController.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Controller;
15 |
16 | use Symfony\Component\DependencyInjection\ContainerAware;
17 |
18 | /**
19 | *
20 | * This controller is only for testing the POST request circumvention of login
21 | * protection and is not used during prod environment. Routes are only imported
22 | * during the test env for Behat under Tests/Functional/app/config
23 | *
24 | * @category CCDNUser
25 | * @package SecurityBundle
26 | *
27 | * @author Reece Fowell
28 | * @license http://opensource.org/licenses/MIT MIT
29 | * @version Release: 2.0
30 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
31 | *
32 | */
33 | class TestLoginController extends ContainerAware
34 | {
35 | public function circumventAction()
36 | {
37 | $csrfToken = $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate');
38 |
39 | return $this->container->get('templating')->renderResponse('CCDNUserSecurityBundle::login.html.twig', array('csrf_token' => $csrfToken));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Tests/Repository/SessionRepositoryTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Tests\Repository;
15 |
16 | use CCDNUser\SecurityBundle\Tests\TestBase;
17 |
18 | /**
19 | *
20 | * @category CCDNUser
21 | * @package SecurityBundle
22 | *
23 | * @author Reece Fowell
24 | * @license http://opensource.org/licenses/MIT MIT
25 | * @version Release: 1.0
26 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
27 | *
28 | */
29 | class SessionRepositoryTest extends TestBase
30 | {
31 | public function testFindAllByIpAddressAndLoginAttemptDate()
32 | {
33 | $this->addFixturesForUsers();
34 | $ipAddress = '127.0.0.1';
35 | $this->getSessionModel()->newRecord($ipAddress, 'tom');
36 | $this->getSessionModel()->newRecord($ipAddress, 'tom');
37 | $this->getSessionModel()->newRecord($ipAddress, 'tom');
38 | $this->getSessionModel()->newRecord($ipAddress, 'tom');
39 |
40 | $timeLimit = new \DateTime('-' . 1 . ' minutes');
41 | $sessions = $this->getSessionModel()->findAllByIpAddressAndLoginAttemptDate($ipAddress, $timeLimit);
42 |
43 | $this->assertCount(4, $sessions);
44 | }
45 | }
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
17 |
18 | ./Tests/Repository
19 | ./Tests/Manager
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ./Tests
30 |
31 | ./Resources
32 | ./vendor
33 |
34 |
35 |
36 | cache
37 | config
38 | data
39 | log
40 | vendor
41 | lib/vendor
42 | plugins
43 | web
44 | Resources
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "codeconsortium/ccdn-user-security-bundle",
3 | "description": "CCDN User Security Bundle",
4 | "keywords": ["ccdn", "codeconsortium", "user", "security", "brute force", "dictionary attack", "login"],
5 | "homepage": "http://github.com/codeconsortium/CCDNUserSecurityBundle",
6 | "type": "symfony-bundle",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Reece Fowell",
11 | "email": "reece@codeconsortium.com",
12 | "homepage": "http://www.reecefowell.com"
13 | }
14 | ],
15 | "minimum-stability": "dev",
16 | "require": {
17 | "php": ">=5.3.3",
18 | "symfony/symfony": "~2.5",
19 | "doctrine/orm": "~2.2,>=2.2.3",
20 | "doctrine/doctrine-bundle": "~1.2"
21 | },
22 | "require-dev": {
23 | "symfony/swiftmailer-bundle": "~2.3",
24 | "symfony/monolog-bundle": "~2.4",
25 | "doctrine/doctrine-fixtures-bundle": "dev-master",
26 | "behat/behat": "2.5.*@stable",
27 | "behat/mink": "v1.5.0",
28 | "behat/mink-goutte-driver": "*",
29 | "behat/mink-browserkit-driver": "*",
30 | "behat/mink-selenium2-driver": "*",
31 | "behat/mink-extension": "*",
32 | "behat/symfony2-extension": "*",
33 | "phpunit/phpunit": "3.7.*",
34 | "raulfraile/ladybug-bundle": "dev-master",
35 | "friendsofsymfony/user-bundle": "~2.0@dev"
36 | },
37 | "autoload": {
38 | "psr-0": { "CCDNUser\\SecurityBundle": "" }
39 | },
40 | "target-dir": "CCDNUser/SecurityBundle"
41 | }
42 |
--------------------------------------------------------------------------------
/features/bootstrap/WebUser.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\features\bootstrap;
15 |
16 | use Behat\MinkExtension\Context\MinkContext;
17 | use Behat\Symfony2Extension\Context\KernelAwareInterface;
18 | use Symfony\Component\HttpKernel\KernelInterface;
19 | use CCDNUser\SecurityBundle\features\bootstrap\DataContext;
20 |
21 | /**
22 | *
23 | * Web user context.
24 | *
25 | * @category CCDNUser
26 | * @package SecurityBundle
27 | *
28 | * @author Reece Fowell
29 | * @license http://opensource.org/licenses/MIT MIT
30 | * @version Release: 2.0
31 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
32 | *
33 | */
34 | class WebUser extends MinkContext implements KernelAwareInterface
35 | {
36 | /**
37 | *
38 | * Kernel.
39 | *
40 | * @var KernelInterface
41 | */
42 | protected $kernel;
43 |
44 | /**
45 | *
46 | * Constructor.
47 | */
48 | public function __construct()
49 | {
50 | // Bundle data creation context.
51 | $this->useContext('data', new DataContext());
52 | }
53 |
54 | /**
55 | *
56 | * {@inheritdoc}
57 | */
58 | public function setKernel(KernelInterface $kernel)
59 | {
60 | $this->kernel = $kernel;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Component/Authorisation/SecurityManagerInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Component\Authorisation;
15 |
16 | use Symfony\Component\HttpFoundation\RequestStack;
17 | use CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker;
18 |
19 | interface SecurityManagerInterface
20 | {
21 | const ACCESS_ALLOWED = 0;
22 | const ACCESS_DENIED_DEFER = 1;
23 | const ACCESS_DENIED_BLOCK = 2;
24 |
25 | /**
26 | * Constructor
27 | *
28 | * @access public
29 | * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
30 | * @param \CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker $loginFailureTracker
31 | * @param array $routeLogin
32 | * @param array $forceAccountRecovery
33 | * @param array $blockPages
34 | */
35 | public function __construct(RequestStack $requestStack, LoginFailureTracker $loginFailureTracker, $routeLogin, $forceAccountRecovery, $blockPages);
36 |
37 | /**
38 | * @access public
39 | * @return int
40 | */
41 | public function vote();
42 | }
43 |
--------------------------------------------------------------------------------
/Model/Component/Repository/SessionRepository.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Repository;
15 |
16 | /**
17 | *
18 | * SessionRepository
19 | *
20 | * @category CCDNUser
21 | * @package SecurityBundle
22 | *
23 | * @author Reece Fowell
24 | * @license http://opensource.org/licenses/MIT MIT
25 | * @version Release: 2.0
26 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
27 | *
28 | */
29 | class SessionRepository extends BaseRepository implements RepositoryInterface
30 | {
31 | /**
32 | *
33 | * @access public
34 | * @param string $ipAddress
35 | * @param string $timeLimit
36 | * @return \Doctrine\Common\Collections\ArrayCollection
37 | */
38 | public function findAllByIpAddressAndLoginAttemptDate($ipAddress, $timeLimit)
39 | {
40 | $qb = $this->createSelectQuery(array('s'));
41 |
42 | $params = array('1' => $ipAddress, '2' => $timeLimit);
43 |
44 | $qb
45 | ->where(
46 | $qb->expr()->andx(
47 | $qb->expr()->eq('s.ipAddress', '?1'),
48 | $qb->expr()->gt('s.loginAttemptDate', '?2')
49 | )
50 | )
51 | ;
52 |
53 | return $this->gateway->findSessions($qb, $params);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Model/Component/Manager/SessionManager.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Manager;
15 |
16 | use CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface;
17 | use CCDNUser\SecurityBundle\Model\Component\Manager\BaseManager;
18 |
19 | use CCDNUser\SecurityBundle\Entity\Session;
20 |
21 | /**
22 | *
23 | * @category CCDNUser
24 | * @package SecurityBundle
25 | *
26 | * @author Reece Fowell
27 | * @license http://opensource.org/licenses/MIT MIT
28 | * @version Release: 2.0
29 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
30 | *
31 | */
32 | class SessionManager extends BaseManager implements ManagerInterface
33 | {
34 | /**
35 | *
36 | * @access public
37 | * @param string $ipAddress
38 | * @param string $username
39 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\SessionManager
40 | */
41 | public function newRecord($ipAddress, $username)
42 | {
43 | $session = new Session();
44 |
45 | $session->setIpAddress($ipAddress);
46 | $session->setLoginAttemptUsername($username);
47 | $session->setLoginAttemptDate(new \DateTime('now'));
48 |
49 | $this
50 | ->persist($session)
51 | ->flush()
52 | ;
53 |
54 | return $this;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Model/FrontModel/SessionModel.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\FrontModel;
15 |
16 | use CCDNUser\SecurityBundle\Model\FrontModel\BaseModel;
17 | use CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface;
18 |
19 | /**
20 | *
21 | * @category CCDNUser
22 | * @package SecurityBundle
23 | *
24 | * @author Reece Fowell
25 | * @license http://opensource.org/licenses/MIT MIT
26 | * @version Release: 2.0
27 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
28 | *
29 | */
30 | class SessionModel extends BaseModel implements ModelInterface
31 | {
32 | /**
33 | *
34 | * @access public
35 | * @param string $ipAddress
36 | * @param string $timeLimit
37 | * @return \Doctrine\Common\Collections\ArrayCollection
38 | */
39 | public function findAllByIpAddressAndLoginAttemptDate($ipAddress, $timeLimit)
40 | {
41 | return $this->getRepository()->findAllByIpAddressAndLoginAttemptDate($ipAddress, $timeLimit);
42 | }
43 |
44 | /**
45 | *
46 | * @access public
47 | * @param string $ipAddress
48 | * @param string $username
49 | * @return \CCDNUser\SecurityBundle\Model\FrontModel\SessionModel
50 | */
51 | public function newRecord($ipAddress, $username)
52 | {
53 | return $this->getManager()->newRecord($ipAddress, $username);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Model/FrontModel/ModelInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\FrontModel;
15 |
16 | use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17 | use CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface;
18 | use CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface;
19 |
20 | /**
21 | *
22 | * @category CCDNUser
23 | * @package SecurityBundle
24 | *
25 | * @author Reece Fowell
26 | * @license http://opensource.org/licenses/MIT MIT
27 | * @version Release: 2.0
28 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
29 | *
30 | * @abstract
31 | */
32 | interface ModelInterface
33 | {
34 | /**
35 | *
36 | * @access public
37 | * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
38 | * @param \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface $repository
39 | * @param \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface $manager
40 | */
41 | public function __construct(EventDispatcherInterface $dispatcher, RepositoryInterface $repository, ManagerInterface $manager);
42 |
43 | /**
44 | *
45 | * @access public
46 | * @return \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface
47 | */
48 | public function getRepository();
49 |
50 | /**
51 | *
52 | * @access public
53 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
54 | */
55 | public function getManager();
56 | }
57 |
--------------------------------------------------------------------------------
/features/user_login.feature:
--------------------------------------------------------------------------------
1 | Feature: Check Blocking Functionalities
2 | In order to determine forced account recovery and page blocking as an User.
3 |
4 | Background:
5 | And there are following users defined:
6 | | name | email | password | enabled | role |
7 | | user1 | user1@foo.com | root | 1 | ROLE_USER |
8 | | user2 | user2@foo.com | root | 1 | ROLE_USER |
9 | | user3 | user3@foo.com | root | 1 | ROLE_USER |
10 |
11 | Scenario: I login successfully
12 | Given I am on "/login"
13 | And I fill in "username" with "user1@foo.com"
14 | And I fill in "password" with "root"
15 | And I press "_submit"
16 | And I should be logged in
17 | And I logout
18 |
19 | Scenario: I fail to login and am forced to recover my account
20 | Given I am on "/login"
21 | And I fill in "username" with "user1@foo.com"
22 | And I fill in "password" with "wrongpass"
23 | And I press "_submit"
24 | And I should not be logged in
25 | And I fill in "username" with "user1@foo.com"
26 | And I fill in "password" with "wrongpass"
27 | And I press "_submit"
28 | And I should not be logged in
29 | And I should be on "/resetting/request"
30 |
31 | Scenario: I fail to login too many times and am blocked from the account pages
32 | Given I am on "/login"
33 | And I circumvent login with "user1@foo.com" and "wrongpass"
34 | And I should not be logged in
35 | And I circumvent login with "user1@foo.com" and "wrongpass"
36 | And I should not be logged in
37 | And I circumvent login with "user1@foo.com" and "wrongpass"
38 | And I should not be logged in
39 | And I circumvent login with "user1@foo.com" and "wrongpass"
40 | Then I should be blocked
41 | And I go to "/login"
42 | Then I should be blocked
43 | And I circumvent login with "user1@foo.com" and "root"
44 | Then I should be blocked
45 | And I go to "/"
46 | Then I should not be logged in
47 |
--------------------------------------------------------------------------------
/Tests/Functional/app/config/ccdn/user-security.yml:
--------------------------------------------------------------------------------
1 | ccdn_user_security:
2 | entity:
3 | user:
4 | class: CCDNUser\SecurityBundle\Tests\Functional\src\Entity\User
5 | route_referer:
6 | enabled: false
7 | route_ignore_list:
8 | - fos_user_security_login
9 | - fos_user_security_check
10 | - fos_user_security_logout
11 | - fos_user_registration_register
12 | - fos_user_registration_check_email
13 | - fos_user_registration_confirm
14 | - fos_user_registration_confirmed
15 | - fos_user_resetting_request
16 | - fos_user_resetting_send_email
17 | - fos_user_resetting_check_email
18 | - fos_user_resetting_reset
19 | - fos_user_change_password
20 | login_shield:
21 | route_login:
22 | name: fos_user_security_login
23 | params: []
24 | force_account_recovery: # Specify all routes to block after attempt limit is reached, and account recovery route to force browser redirect.
25 | enabled: true
26 | after_attempts: 2
27 | duration_in_minutes: 1
28 | route_recover_account:
29 | name: fos_user_resetting_request
30 | params: []
31 | routes:
32 | - fos_user_security_login
33 | - fos_user_security_check
34 | - fos_user_security_logout
35 | block_pages: # Specify all routes to block after attempt limit is reached.
36 | enabled: true
37 | after_attempts: 4
38 | duration_in_minutes: 2
39 | routes:
40 | - fos_user_security_login
41 | - fos_user_security_check
42 | - fos_user_security_logout
43 | - fos_user_registration_register
44 | - fos_user_registration_check_email
45 | - fos_user_registration_confirm
46 | - fos_user_registration_confirmed
47 | - fos_user_resetting_request
48 | - fos_user_resetting_send_email
49 |
--------------------------------------------------------------------------------
/Component/Authentication/Tracker/LoginFailureTracker.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Component\Authentication\Tracker;
15 |
16 | use CCDNUser\SecurityBundle\Model\FrontModel\SessionModel;
17 |
18 | /**
19 | *
20 | * @category CCDNUser
21 | * @package SecurityBundle
22 | *
23 | * @author Reece Fowell
24 | * @license http://opensource.org/licenses/MIT MIT
25 | * @version Release: 2.0
26 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
27 | *
28 | */
29 | class LoginFailureTracker
30 | {
31 | /**
32 | *
33 | * @access protected
34 | * @var \CCDNUser\SecurityBundle\Model\FrontModel\SessionModel $sessionModel
35 | */
36 | protected $sessionModel;
37 |
38 | /**
39 | *
40 | * @access public
41 | * @param \CCDNUser\SecurityBundle\Model\FrontModel\SessionModel $sessionModel
42 | */
43 | public function __construct(SessionModel $sessionModel)
44 | {
45 | $this->sessionModel = $sessionModel;
46 | }
47 |
48 | /**
49 | *
50 | * @access public
51 | * @param string $ipAddress
52 | * @param int $blockingPeriod
53 | * @return array
54 | */
55 | public function getAttempts($ipAddress, $blockingPeriod)
56 | {
57 | // Set a limit on how far back we want to look at failed login attempts.
58 | $timeLimit = new \DateTime('-' . $blockingPeriod . ' minutes');
59 | $attempts = $this->sessionModel->findAllByIpAddressAndLoginAttemptDate($ipAddress, $timeLimit);
60 |
61 | return $attempts;
62 | }
63 |
64 | /**
65 | *
66 | * @access public
67 | * @param string $ipAddress
68 | * @param string $username
69 | */
70 | public function addAttempt($ipAddress, $username)
71 | {
72 | // Make a note of the failed login.
73 | $this->sessionModel->newRecord($ipAddress, $username);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Component/Listener/DeferLoginListener.php:
--------------------------------------------------------------------------------
1 | router = $router;
45 | $this->securityManager = $securityManager;
46 | $this->forceAccountRecovery = $forceAccountRecovery;
47 | }
48 |
49 | public function onKernelRequest(GetResponseEvent $event)
50 | {
51 | if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
52 | return;
53 | }
54 |
55 | $securityManager = $this->securityManager; // Avoid the silly cryptic error 'T_PAAMAYIM_NEKUDOTAYIM'
56 | $result = $securityManager->vote();
57 |
58 | if ($result === $securityManager::ACCESS_DENIED_DEFER) {
59 | $event->stopPropagation();
60 |
61 | $redirectUrl = $this->router->generate(
62 | $this->forceAccountRecovery['route_recover_account']['name'],
63 | $this->forceAccountRecovery['route_recover_account']['params']
64 | );
65 |
66 | $event->setResponse(new RedirectResponse($redirectUrl));
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Resources/doc/configuration_reference.md:
--------------------------------------------------------------------------------
1 | CCDNUser SecurityBundle Configuration Reference.
2 | ================================================
3 |
4 | All available configuration options are listed below with their default values.
5 |
6 | ``` yml
7 | #
8 | # for CCDNUser SecurityBundle
9 | #
10 | ccdn_user_security:
11 | entity:
12 | user:
13 | class: Acme\YourUserBundle\Entity\User # Required
14 | login_shield:
15 | route_login:
16 | name: fos_user_security_login
17 | params: []
18 | force_account_recovery: # Specify all routes to block after attempt limit is reached, and account recovery route to force browser redirect.
19 | enabled: true
20 | after_attempts: 2
21 | duration_in_minutes: 1
22 | route_recover_account:
23 | name: fos_user_resetting_request
24 | params: []
25 | routes:
26 | - fos_user_security_login
27 | - fos_user_security_check
28 | - fos_user_security_logout
29 | block_pages: # Specify all routes to block after attempt limit is reached.
30 | enabled: true
31 | after_attempts: 4
32 | duration_in_minutes: 2
33 | routes:
34 | - fos_user_security_login
35 | - fos_user_security_check
36 | - fos_user_security_logout
37 | - fos_user_registration_register
38 | - fos_user_registration_check_email
39 | - fos_user_registration_confirm
40 | - fos_user_registration_confirmed
41 | - fos_user_resetting_request
42 | - fos_user_resetting_send_email
43 | ```
44 |
45 | Please note that for either 'force_account_recovery' or 'block_pages' to function, you need to specify the 'route_login' config, also you must specify the route for the account recovery page.
46 |
47 | Once you have enabled either 'force_account_recovery' or 'block_pages', you must specify the routes that you want blocked once the number of attempts has been reached.
48 |
49 | In order that the forced account recovery process works, the limit must be set lower than the block_pages process, otherwise page blocking will supersede this and prevent it from working.
50 |
51 | Replace Acme\YourUserBundle\Entity\User with the user class of your chosen user bundle.
52 |
53 | - [Return back to the docs index](index.md).
54 |
--------------------------------------------------------------------------------
/Tests/Functional/app/AppKernel.php:
--------------------------------------------------------------------------------
1 | load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
34 | }
35 |
36 | /**
37 | * @return string
38 | */
39 | public function getCacheDir()
40 | {
41 | return sys_get_temp_dir().'/CCDNUserSecurityBundle/cache/' . $this->getEnvironment();
42 | }
43 |
44 | /**
45 | * @return string
46 | */
47 | public function getLogDir()
48 | {
49 | return sys_get_temp_dir().'/CCDNUserSecurityBundle/logs';
50 | }
51 |
52 | /**
53 | *
54 | * @link http://kriswallsmith.net/post/27979797907/get-fast-an-easy-symfony2-phpunit-optimization
55 | * (does not work)
56 | */
57 | // protected function initializeContainer()
58 | // {
59 | // static $first = true;
60 | //
61 | // if ('test' !== $this->getEnvironment()) {
62 | // parent::initializeContainer();
63 | // return;
64 | // }
65 | //
66 | // $debug = $this->debug;
67 | //
68 | // if (!$first) {
69 | // // disable debug mode on all but the first initialization
70 | // $this->debug = false;
71 | // }
72 | //
73 | // // will not work with --process-isolation
74 | // $first = false;
75 | //
76 | // try {
77 | // parent::initializeContainer();
78 | // } catch (\Exception $e) {
79 | // $this->debug = $debug;
80 | // throw $e;
81 | // }
82 | //
83 | // $this->debug = $debug;
84 | // }
85 | }
--------------------------------------------------------------------------------
/Component/Listener/BlockingLoginListener.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Component\Listener;
15 |
16 | use CCDNUser\SecurityBundle\Component\Authorisation\SecurityManagerInterface;
17 | use Symfony\Component\HttpKernel\Event\GetResponseEvent;
18 |
19 | /**
20 | *
21 | * @category CCDNUser
22 | * @package SecurityBundle
23 | *
24 | * @author Reece Fowell
25 | * @license http://opensource.org/licenses/MIT MIT
26 | * @version Release: 2.0
27 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
28 | *
29 | */
30 | class BlockingLoginListener
31 | {
32 | /**
33 | *
34 | * @access protected
35 | * @var \CCDNUser\SecurityBundle\Component\Authorisation\SecurityManagerInterface $securityManager
36 | */
37 | protected $securityManager;
38 |
39 | /**
40 | * @var AccessDeniedExceptionFactoryInterface
41 | */
42 | protected $exceptionFactory;
43 |
44 | /**
45 | *
46 | * @access public
47 | * @param \CCDNUser\SecurityBundle\Component\Authorisation\SecurityManagerInterface $securityManager
48 | * @param \CCDNUser\SecurityBundle\Component\Listener\AccessDeniedExceptionFactoryInterface $exceptionFactory
49 | */
50 | public function __construct(SecurityManagerInterface $securityManager, AccessDeniedExceptionFactoryInterface $exceptionFactory)
51 | {
52 | $this->securityManager = $securityManager;
53 | $this->exceptionFactory = $exceptionFactory;
54 | }
55 |
56 | /**
57 | *
58 | * If you have failed to login too many times,
59 | * a log of this will be present in the databse.
60 | *
61 | * @access public
62 | * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
63 | */
64 | public function onKernelRequest(GetResponseEvent $event)
65 | {
66 | if ($event->getRequestType() !== \Symfony\Component\HttpKernel\HttpKernel::MASTER_REQUEST) {
67 | return;
68 | }
69 |
70 | $securityManager = $this->securityManager; // Avoid the silly cryptic error 'T_PAAMAYIM_NEKUDOTAYIM'
71 | $result = $securityManager->vote();
72 |
73 | if ($result == $securityManager::ACCESS_ALLOWED) {
74 | return;
75 | }
76 |
77 | if ($result == $securityManager::ACCESS_DENIED_BLOCK) {
78 | $event->stopPropagation();
79 |
80 | throw $this->exceptionFactory->createAccessDeniedException();
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Model/FrontModel/BaseModel.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\FrontModel;
15 |
16 | use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17 | use CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface;
18 | use CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface;
19 |
20 | /**
21 | *
22 | * @category CCDNUser
23 | * @package SecurityBundle
24 | *
25 | * @author Reece Fowell
26 | * @license http://opensource.org/licenses/MIT MIT
27 | * @version Release: 2.0
28 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
29 | *
30 | * @abstract
31 | */
32 | abstract class BaseModel
33 | {
34 | /**
35 | *
36 | * @access protected
37 | * @var \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface
38 | */
39 | protected $repository;
40 |
41 | /**
42 | *
43 | * @access protected
44 | * @var \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
45 | */
46 | protected $manager;
47 |
48 | /**
49 | *
50 | * @access protected
51 | * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
52 | */
53 | protected $dispatcher;
54 |
55 | /**
56 | *
57 | * @access public
58 | * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
59 | * @param \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface $repository
60 | * @param \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface $manager
61 | */
62 | public function __construct(EventDispatcherInterface $dispatcher, RepositoryInterface $repository, ManagerInterface $manager)
63 | {
64 | $this->dispatcher = $dispatcher;
65 |
66 | $repository->setModel($this);
67 | $this->repository = $repository;
68 |
69 | $manager->setModel($this);
70 | $this->manager = $manager;
71 | }
72 |
73 | /**
74 | *
75 | * @access public
76 | * @return \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface
77 | */
78 | public function getRepository()
79 | {
80 | return $this->repository;
81 | }
82 |
83 | /**
84 | *
85 | * @access public
86 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
87 | */
88 | public function getManager()
89 | {
90 | return $this->manager;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/Model/Component/Repository/RepositoryInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Repository;
15 |
16 | use Doctrine\ORM\QueryBuilder;
17 | use CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface;
18 | use CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface;
19 |
20 | /**
21 | *
22 | * @category CCDNUser
23 | * @package SecurityBundle
24 | *
25 | * @author Reece Fowell
26 | * @license http://opensource.org/licenses/MIT MIT
27 | * @version Release: 2.0
28 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
29 | *
30 | */
31 | interface RepositoryInterface
32 | {
33 | /**
34 | *
35 | * @access public
36 | * @param \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface $gateway
37 | */
38 | public function __construct(GatewayInterface $gateway);
39 |
40 | /**
41 | *
42 | * @access public
43 | * @param \CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface $model
44 | * @return \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface
45 | */
46 | public function setModel(ModelInterface $model);
47 |
48 | /**
49 | *
50 | * @access public
51 | * @return \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface
52 | */
53 | public function getGateway();
54 |
55 | /**
56 | *
57 | * @access public
58 | * @return \Doctrine\ORM\QueryBuilder
59 | */
60 | public function getQueryBuilder();
61 |
62 | /**
63 | *
64 | * @access public
65 | * @param string $column = null
66 | * @param Array $aliases = null
67 | * @return \Doctrine\Common\Collections\ArrayCollection
68 | */
69 | public function createCountQuery($column = null, Array $aliases = null);
70 |
71 | /**
72 | *
73 | * @access public
74 | * @param Array $aliases = null
75 | * @return \Doctrine\Common\Collections\ArrayCollection
76 | */
77 | public function createSelectQuery(Array $aliases = null);
78 |
79 | /**
80 | *
81 | * @access public
82 | * @param \Doctrine\ORM\QueryBuilder $qb
83 | * @return \Doctrine\Common\Collections\ArrayCollection
84 | */
85 | public function one(QueryBuilder $qb);
86 |
87 | /**
88 | *
89 | * @access public
90 | * @param \Doctrine\ORM\QueryBuilder $qb
91 | * @return \Doctrine\ORM\QueryBuilder
92 | */
93 | public function all(QueryBuilder $qb);
94 | }
95 |
--------------------------------------------------------------------------------
/Component/Authentication/Handler/LoginFailureHandler.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Component\Authentication\Handler;
15 |
16 | use Symfony\Component\Routing\RouterInterface;
17 | use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
18 | use Symfony\Component\Security\Core\Exception\AuthenticationException;
19 | use Symfony\Component\Security\Core\SecurityContext;
20 | use Symfony\Component\HttpFoundation\RedirectResponse;
21 | use Symfony\Component\HttpFoundation\Request;
22 | use Symfony\Component\HttpFoundation\Response;
23 |
24 | use CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker;
25 | use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler;
26 |
27 | /**
28 | *
29 | * @category CCDNUser
30 | * @package SecurityBundle
31 | *
32 | * @author Reece Fowell
33 | * @license http://opensource.org/licenses/MIT MIT
34 | * @version Release: 2.0
35 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
36 | *
37 | */
38 | class LoginFailureHandler extends DefaultAuthenticationFailureHandler
39 | {
40 | /**
41 | *
42 | * @access protected
43 | * @var \CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker $loginFailureTracker
44 | */
45 | protected $loginFailureTracker;
46 |
47 | /**
48 | *
49 | * @access public
50 | * @param \CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker $loginFailureTracker
51 | */
52 | public function setLoginFailureTracker(LoginFailureTracker $loginFailureTracker)
53 | {
54 | $this->loginFailureTracker = $loginFailureTracker;
55 | }
56 |
57 | /**
58 | *
59 | * @access public
60 | * @param \Symfony\Component\HttpFoundation\Request $request
61 | * @param \Symfony\Component\Security\Core\Exception\AuthenticationException $exception
62 | * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
63 | */
64 | public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
65 | {
66 | // Get the visitors IP address and attempted username.
67 | $ipAddress = $request->getClientIp();
68 | if ($request->request->has('_username')) {
69 | $username = $request->request->get('_username');
70 | } else {
71 | $username = '';
72 | }
73 |
74 | // Make a note of the failed login.
75 | $this->loginFailureTracker->addAttempt($ipAddress, $username);
76 |
77 | // Let Symfony decide what to do next
78 | return parent::onAuthenticationFailure($request, $exception);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Tests/TestBase.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Tests;
15 |
16 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
17 | use Doctrine\Common\DataFixtures\Purger\ORMPurger;
18 | use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
19 |
20 | use CCDNUser\SecurityBundle\Tests\Functional\src\Entity\User;
21 | use CCDNUser\SecurityBundle\Entity\Security;
22 |
23 | class TestBase extends WebTestCase
24 | {
25 | /**
26 | *
27 | * @var \Doctrine\ORM\EntityManager
28 | */
29 | protected $em;
30 |
31 | /**
32 | *
33 | * @var $container
34 | */
35 | private $container;
36 |
37 | /**
38 | *
39 | * @access public
40 | */
41 | public function setUp()
42 | {
43 | $kernel = static::createKernel();
44 |
45 | $kernel->boot();
46 |
47 | $this->container = $kernel->getContainer();
48 |
49 | $this->em = $this->container->get('doctrine.orm.entity_manager');
50 |
51 | $this->purge();
52 | }
53 |
54 | /*
55 | *
56 | * Close doctrine connections to avoid having a 'too many connections'
57 | * message when running many tests
58 | */
59 | public function tearDown(){
60 | if($this->container !== null){
61 | $this->container->get('doctrine')->getConnection()->close();
62 | }
63 |
64 | parent::tearDown();
65 | }
66 |
67 | protected function purge()
68 | {
69 | $purger = new ORMPurger($this->em);
70 | $executor = new ORMExecutor($this->em, $purger);
71 | $executor->purge();
72 | }
73 |
74 | protected function addNewUser($username, $email, $password)
75 | {
76 | $user = new User();
77 |
78 | $user->setUsername($username);
79 | $user->setEmail($email);
80 | $user->setPlainPassword($password);
81 |
82 | $this->em->persist($user);
83 |
84 | return $user;
85 | }
86 |
87 | protected function addFixturesForUsers()
88 | {
89 | $userNames = array('admin', 'tom', 'dick', 'harry');
90 | $users = array();
91 |
92 | foreach ($userNames as $username) {
93 | $users[$username] = $this->addNewUser($username, $username . '@foobar.com', 'password');
94 | }
95 |
96 | $this->em->flush();
97 |
98 | return $users;
99 | }
100 |
101 | /**
102 | *
103 | * @var \CCDNUser\SecurityBundle\Model\FrontModel\SessionModel $sessionModel
104 | */
105 | private $sessionModel;
106 |
107 | /**
108 | *
109 | * @access protected
110 | * @return \CCDNUser\SecurityBundle\Model\FrontModel\SessionModel
111 | */
112 | protected function getSessionModel()
113 | {
114 | if (null == $this->sessionModel) {
115 | $this->sessionModel = $this->container->get('ccdn_user_security.model.session');
116 | }
117 |
118 | return $this->sessionModel;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Model/Component/Gateway/GatewayInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Gateway;
15 |
16 | use Doctrine\Common\Persistence\ObjectManager;
17 | use Doctrine\ORM\QueryBuilder;
18 |
19 | /**
20 | *
21 | * @category CCDNUser
22 | * @package SecurityBundle
23 | *
24 | * @author Reece Fowell
25 | * @license http://opensource.org/licenses/MIT MIT
26 | * @version Release: 2.0
27 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
28 | *
29 | */
30 | interface GatewayInterface
31 | {
32 | /**
33 | *
34 | * @access public
35 | * @param \Doctrine\Common\Persistence\ObjectManager $em
36 | * @param string $entityClass
37 | */
38 | public function __construct(ObjectManager $em, $entityClass);
39 |
40 | /**
41 | *
42 | * @access public
43 | * @return string
44 | */
45 | public function getEntityClass();
46 |
47 | /**
48 | *
49 | * @access public
50 | * @return \Doctrine\ORM\QueryBuilder
51 | */
52 | public function getQueryBuilder();
53 |
54 | /**
55 | *
56 | * @access public
57 | * @param \Doctrine\ORM\QueryBuilder $qb
58 | * @param Array $parameters
59 | * @return \Doctrine\Common\Collections\ArrayCollection
60 | */
61 | public function one(QueryBuilder $qb, $parameters = array());
62 |
63 | /**
64 | *
65 | * @access public
66 | * @param \Doctrine\ORM\QueryBuilder $qb
67 | * @param Array $parameters
68 | * @return \Doctrine\Common\Collections\ArrayCollection
69 | */
70 | public function all(QueryBuilder $qb, $parameters = array());
71 |
72 | /**
73 | *
74 | * @access public
75 | * @param Object $entity
76 | * @return \CCDNUser\SecurityBundle\Gateway\BaseGatewayInterface
77 | */
78 | public function persist($entity);
79 |
80 | /**
81 | *
82 | * @access public
83 | * @param Object $entity
84 | * @return \CCDNUser\SecurityBundle\Gateway\BaseGatewayInterface
85 | */
86 | public function remove($entity);
87 |
88 | /**
89 | *
90 | * @access public
91 | * @return \CCDNUser\SecurityBundle\Gateway\BaseGatewayInterface
92 | */
93 | public function flush();
94 |
95 | /**
96 | *
97 | * @access public
98 | * @param Object $entity
99 | * @return \CCDNUser\SecurityBundle\Gateway\BaseGatewayInterface
100 | */
101 | public function refresh($entity);
102 | }
103 |
--------------------------------------------------------------------------------
/Entity/Session.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Entity;
15 |
16 | /**
17 | *
18 | * @category CCDNUser
19 | * @package SecurityBundle
20 | *
21 | * @author Reece Fowell
22 | * @license http://opensource.org/licenses/MIT MIT
23 | * @version Release: 2.0
24 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
25 | *
26 | */
27 | class Session
28 | {
29 | /**
30 | *
31 | * @var int $id
32 | */
33 | protected $id;
34 |
35 | /**
36 | *
37 | * @var string $ipAddress
38 | */
39 | protected $ipAddress;
40 |
41 | /**
42 | *
43 | * @var \Datetime $loginAttemptDate
44 | */
45 | protected $loginAttemptDate;
46 |
47 | /**
48 | *
49 | * @var string $loginAttemptUsername
50 | */
51 | protected $loginAttemptUsername;
52 |
53 | /**
54 | * Get id
55 | *
56 | * @return integer
57 | */
58 | public function getId()
59 | {
60 | return $this->id;
61 | }
62 |
63 | /**
64 | * Set ipAddress
65 | *
66 | * @param string $ipAddress
67 | * @return \CCDNUser\SecurityBundle\Entity\Session
68 | */
69 | public function setIpAddress($ipAddress)
70 | {
71 | $this->ipAddress = $ipAddress;
72 |
73 | return $this;
74 | }
75 |
76 | /**
77 | * Get ipAddress
78 | *
79 | * @return string
80 | */
81 | public function getIpAddress()
82 | {
83 | return $this->ipAddress;
84 | }
85 |
86 | /**
87 | * Set loginAttemptDate
88 | *
89 | * @param integer $loginAttemptDate
90 | * @return \CCDNUser\SecurityBundle\Entity\Session
91 | */
92 | public function setLoginAttemptDate($loginAttemptDate)
93 | {
94 | $this->loginAttemptDate = $loginAttemptDate;
95 |
96 | return $this;
97 | }
98 |
99 | /**
100 | * Get loginAttemptDate
101 | *
102 | * @return integer
103 | */
104 | public function getLoginAttemptDate()
105 | {
106 | return $this->loginAttemptDate;
107 | }
108 |
109 | /**
110 | * Set loginUsername
111 | *
112 | * @param string $loginUsername
113 | * @return \CCDNUser\SecurityBundle\Entity\Session
114 | */
115 | public function setLoginAttemptUsername($loginAttemptUsername)
116 | {
117 | $this->loginAttemptUsername = $loginAttemptUsername;
118 |
119 | return $this;
120 | }
121 |
122 | /**
123 | * Get loginUsername
124 | *
125 | * @return string
126 | */
127 | public function getLoginAttemptUsername()
128 | {
129 | return $this->loginAttemptUsername;
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/Resources/config/services/components.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 |
3 | # Service Parameters defined in app/config
4 |
5 | services:
6 |
7 | #
8 | # Login/Logout Success/Failure Handlers.
9 | #
10 | ccdn_user_security.component.authentication.handler.login_failure_handler:
11 | class: %ccdn_user_security.component.authentication.handler.login_failure_handler.class%
12 | parent: security.authentication.failure_handler
13 | calls:
14 | - [setLoginFailureTracker, ['@ccdn_user_security.component.authentication.tracker.login_failure_tracker']]
15 |
16 | ccdn_user_security.component.authentication.tracker.login_failure_tracker:
17 | class: %ccdn_user_security.component.authentication.tracker.login_failure_tracker.class%
18 | arguments:
19 | - @ccdn_user_security.model.session
20 |
21 | #
22 | # Access Decision Manager
23 | #
24 | ccdn_user_security.component.authorisation.security_manager:
25 | class: %ccdn_user_security.component.authorisation.security_manager.class%
26 | arguments:
27 | - @request_stack
28 | - @ccdn_user_security.component.authentication.tracker.login_failure_tracker
29 | - %ccdn_user_security.login_shield.route_login%
30 | - %ccdn_user_security.login_shield.force_account_recovery%
31 | - %ccdn_user_security.login_shield.block_pages%
32 |
33 | #
34 | # Authorisation Voter
35 | #
36 | ccdn_user_security.component.authorisation.voter.client_login_voter:
37 | class: %ccdn_user_security.component.authorisation.voter.client_login_voter.class%
38 | arguments:
39 | - @ccdn_user_security.component.authorisation.security_manager
40 | tags:
41 | - { name: security.voter }
42 |
43 | #
44 | # Blocking login Listener.
45 | #
46 | ccdn_user_security.component.listener.blocking_login_listener:
47 | class: %ccdn_user_security.component.listener.blocking_login_listener.class%
48 | arguments:
49 | - @ccdn_user_security.component.authorisation.security_manager
50 | - @ccdn_user_security.component.access_denied_exception_factory
51 | tags:
52 | - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 9 }
53 | ccdn_user_security.component.access_denied_exception_factory:
54 | class: %ccdn_user_security.component.access_denied_exception_factory.class%
55 |
56 | #
57 | # Defer login Listener.
58 | #
59 | ccdn_user_security.component.listener.defer_login_listener:
60 | class: %ccdn_user_security.component.listener.defer_login_listener.class%
61 | arguments:
62 | - @router
63 | - @ccdn_user_security.component.authorisation.security_manager
64 | - %ccdn_user_security.login_shield.force_account_recovery%
65 | tags:
66 | - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
67 |
68 | #
69 | # For legacy compatibility, we alias deprecated listeners
70 | #
71 | ccdn_user_security.component.authentication.handler.login_success_handler:
72 | parent: security.authentication.success_handler
73 |
74 | ccdn_user_security.component.authentication.handler.logout_success_handler:
75 | parent: security.logout.success_handler
76 |
--------------------------------------------------------------------------------
/Component/Authorisation/Voter/ClientLoginVoter.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Component\Authorisation\Voter;
15 |
16 | use CCDNUser\SecurityBundle\Component\Authorisation\SecurityManagerInterface;
17 | use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
18 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
19 |
20 | /**
21 | *
22 | * @category CCDNUser
23 | * @package SecurityBundle
24 | *
25 | * @author Reece Fowell
26 | * @license http://opensource.org/licenses/MIT MIT
27 | * @version Release: 2.0
28 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
29 | *
30 | */
31 | class ClientLoginVoter implements VoterInterface
32 | {
33 | /**
34 | *
35 | * @access protected
36 | * @var \CCDNUser\SecurityBundle\Component\Authorisation\SecurityManagerInterface $securityManager
37 | */
38 | protected $securityManager;
39 |
40 | /**
41 | *
42 | * @access public
43 | * @param \CCDNUser\SecurityBundle\Component\Authorisation\SecurityManagerInterface $securityManager
44 | */
45 | public function __construct(SecurityManagerInterface $securityManager)
46 | {
47 | $this->securityManager = $securityManager;
48 | }
49 |
50 | /**
51 | *
52 | * @access public
53 | * @param $attribute
54 | * @return bool
55 | */
56 | public function supportsAttribute($attribute)
57 | {
58 | // we won't check against a user attribute, so we return true
59 | return true;
60 | }
61 |
62 | /**
63 | *
64 | * @access public
65 | * @param $class
66 | * @return bool
67 | */
68 | public function supportsClass($class)
69 | {
70 | // our voter supports all type of token classes, so we return true
71 | return true;
72 | }
73 |
74 | /**
75 | *
76 | * @access public
77 | * @param \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token
78 | * @param object $object
79 | * @param array $attributes
80 | * @return int
81 | */
82 | public function vote(TokenInterface $token, $object, array $attributes)
83 | {
84 | $securityManager = $this->securityManager; // Avoid the silly cryptic error 'T_PAAMAYIM_NEKUDOTAYIM'
85 | $result = $securityManager->vote();
86 |
87 | if ($result == $securityManager::ACCESS_ALLOWED) {
88 | return VoterInterface::ACCESS_ABSTAIN;
89 | }
90 |
91 | if ($result == $securityManager::ACCESS_DENIED_DEFER) {
92 | return VoterInterface::ACCESS_ABSTAIN;
93 | }
94 |
95 | if ($result == $securityManager::ACCESS_DENIED_BLOCK) {
96 | return VoterInterface::ACCESS_DENIED;
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/Model/Component/Repository/BaseRepository.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Repository;
15 |
16 | use Doctrine\ORM\QueryBuilder;
17 | use CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface;
18 | use CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface;
19 |
20 | /**
21 | *
22 | * @category CCDNUser
23 | * @package SecurityBundle
24 | *
25 | * @author Reece Fowell
26 | * @license http://opensource.org/licenses/MIT MIT
27 | * @version Release: 2.0
28 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
29 | *
30 | * @abstract
31 | *
32 | */
33 | abstract class BaseRepository
34 | {
35 | /**
36 | *
37 | * @access protected
38 | * @var \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface $gateway
39 | */
40 | protected $gateway;
41 |
42 | /**
43 | *
44 | * @access protected
45 | * @var \CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface $model
46 | */
47 | protected $model;
48 |
49 | /**
50 | *
51 | * @access public
52 | * @param \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface $gateway
53 | */
54 | public function __construct(GatewayInterface $gateway)
55 | {
56 | $this->gateway = $gateway;
57 | }
58 |
59 | /**
60 | *
61 | * @access public
62 | * @param \CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface $model
63 | * @return \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface
64 | */
65 | public function setModel(ModelInterface $model)
66 | {
67 | $this->model = $model;
68 |
69 | return $this;
70 | }
71 |
72 | /**
73 | *
74 | * @access public
75 | * @return \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface
76 | */
77 | public function getGateway()
78 | {
79 | return $this->gateway;
80 | }
81 |
82 | /**
83 | *
84 | * @access public
85 | * @return \Doctrine\ORM\QueryBuilder
86 | */
87 | public function getQueryBuilder()
88 | {
89 | return $this->gateway->getQueryBuilder();
90 | }
91 |
92 | /**
93 | *
94 | * @access public
95 | * @param string $column = null
96 | * @param Array $aliases = null
97 | * @return \Doctrine\Common\Collections\ArrayCollection
98 | */
99 | public function createCountQuery($column = null, Array $aliases = null)
100 | {
101 | return $this->gateway->createCountQuery($column, $aliases);
102 | }
103 |
104 | /**
105 | *
106 | * @access public
107 | * @param Array $aliases = null
108 | * @return \Doctrine\Common\Collections\ArrayCollection
109 | */
110 | public function createSelectQuery(Array $aliases = null)
111 | {
112 | return $this->gateway->createSelectQuery($aliases);
113 | }
114 |
115 | /**
116 | *
117 | * @access public
118 | * @param \Doctrine\ORM\QueryBuilder $qb
119 | * @return \Doctrine\Common\Collections\ArrayCollection
120 | */
121 | public function one(QueryBuilder $qb)
122 | {
123 | return $this->gateway->one($qb);
124 | }
125 |
126 | /**
127 | *
128 | * @access public
129 | * @param \Doctrine\ORM\QueryBuilder $qb
130 | * @return \Doctrine\ORM\QueryBuilder
131 | */
132 | public function all(QueryBuilder $qb)
133 | {
134 | return $this->gateway->all($qb);
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Model/Component/Manager/ManagerInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Manager;
15 |
16 | use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17 | use Doctrine\ORM\QueryBuilder;
18 | use CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface;
19 | use CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface;
20 |
21 | /**
22 | *
23 | * @category CCDNUser
24 | * @package SecurityBundle
25 | *
26 | * @author Reece Fowell
27 | * @license http://opensource.org/licenses/MIT MIT
28 | * @version Release: 2.0
29 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
30 | *
31 | */
32 | interface ManagerInterface
33 | {
34 | /**
35 | *
36 | * @access public
37 | * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
38 | * @param \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface $gateway
39 | */
40 | public function __construct(EventDispatcherInterface $dispatcher, GatewayInterface $gateway);
41 |
42 | /**
43 | *
44 | * @access public
45 | * @param \CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface $model
46 | * @return \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface
47 | */
48 | public function setModel(ModelInterface $model);
49 |
50 | /**
51 | *
52 | * @access public
53 | * @return \CCDNUser\SecurityBundle\Gateway\GatewayInterface
54 | */
55 | public function getGateway();
56 |
57 | /**
58 | *
59 | * @access public
60 | * @return \Doctrine\ORM\QueryBuilder
61 | */
62 | public function getQueryBuilder();
63 |
64 | /**
65 | *
66 | * @access public
67 | * @param string $column = null
68 | * @param Array $aliases = null
69 | * @return \Doctrine\Common\Collections\ArrayCollection
70 | */
71 | public function createCountQuery($column = null, Array $aliases = null);
72 |
73 | /**
74 | *
75 | * @access public
76 | * @param Array $aliases = null
77 | * @return \Doctrine\Common\Collections\ArrayCollection
78 | */
79 | public function createSelectQuery(Array $aliases = null);
80 |
81 | /**
82 | *
83 | * @access public
84 | * @param \Doctrine\ORM\QueryBuilder $qb
85 | * @return \Doctrine\Common\Collections\ArrayCollection
86 | */
87 | public function one(QueryBuilder $qb);
88 |
89 | /**
90 | *
91 | * @access public
92 | * @param \Doctrine\ORM\QueryBuilder $qb
93 | * @return \Doctrine\ORM\QueryBuilder
94 | */
95 | public function all(QueryBuilder $qb);
96 |
97 | /**
98 | *
99 | * @access public
100 | * @param Object $entity
101 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
102 | */
103 | public function persist($entity);
104 |
105 | /**
106 | *
107 | * @access public
108 | * @param Object $entity
109 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
110 | */
111 | public function remove($entity);
112 |
113 | /**
114 | *
115 | * @access public
116 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
117 | */
118 | public function flush();
119 |
120 | /**
121 | *
122 | * @access public
123 | * @param Object $entity
124 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
125 | */
126 | public function refresh($entity);
127 | }
128 |
--------------------------------------------------------------------------------
/features/bootstrap/FeatureContext.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\features\bootstrap;
15 |
16 | use Behat\MinkExtension\Context\RawMinkContext;
17 | use Behat\Symfony2Extension\Context\KernelAwareInterface;
18 | use Doctrine\Common\DataFixtures\Purger\ORMPurger;
19 | use Symfony\Component\HttpKernel\KernelInterface;
20 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
21 | use CCDNUser\SecurityBundle\features\bootstrap\WebUser;
22 |
23 | /**
24 | *
25 | * Features context.
26 | *
27 | * @category CCDNUser
28 | * @package SecurityBundle
29 | *
30 | * @author Reece Fowell
31 | * @license http://opensource.org/licenses/MIT MIT
32 | * @version Release: 2.0
33 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
34 | *
35 | */
36 | class FeatureContext extends RawMinkContext implements KernelAwareInterface
37 | {
38 | /**
39 | *
40 | * Kernel.
41 | *
42 | * @var KernelInterface
43 | */
44 | private $kernel;
45 |
46 | /**
47 | *
48 | * Parameters.
49 | *
50 | * @var array
51 | */
52 | private $parameters;
53 |
54 | /**
55 | *
56 | * Initializes context.
57 | * Every scenario gets it's own context object.
58 | *
59 | * @param array $parameters context parameters (set them up through behat.yml)
60 | */
61 | public function __construct(array $parameters)
62 | {
63 | // Initialize your context here
64 | $this->parameters = $parameters;
65 |
66 | // Web user context.
67 | $this->useContext('web-user', new WebUser());
68 | }
69 |
70 | /**
71 | *
72 | * {@inheritdoc}
73 | */
74 | public function setKernel(KernelInterface $kernel)
75 | {
76 | $this->kernel = $kernel;
77 | }
78 |
79 | /**
80 | *
81 | * @BeforeScenario
82 | */
83 | public function purgeDatabase()
84 | {
85 | $entityManager = $this->kernel->getContainer()->get('doctrine.orm.entity_manager');
86 |
87 | $purger = new ORMPurger($entityManager);
88 | $purger->purge();
89 | }
90 |
91 | /**
92 | *
93 | * @Given /^I am logged in as "([^"]*)"$/
94 | */
95 | public function iAmLoggedInAs($user)
96 | {
97 | $session = $this->getMainContext()->getSession();
98 | $session->setBasicAuth($user . '@foo.com', 'root');
99 | }
100 |
101 | /**
102 | * @Given /^I logout$/
103 | */
104 | public function iLogout()
105 | {
106 | $this->kernel->getContainer()->get('security.context')->getToken()->eraseCredentials();
107 | }
108 |
109 | /**
110 | * @Given /^I should be logged in$/
111 | */
112 | public function iShouldBeLoggedIn()
113 | {
114 | WebTestCase::assertTrue($this->kernel->getContainer()->get('security.context')->getToken()->getUser() instanceof \Symfony\Component\Security\Core\User\UserInterface);
115 | }
116 |
117 | /**
118 | * @Given /^I should not be logged in$/
119 | */
120 | public function iShouldNotBeLoggedIn()
121 | {
122 | WebTestCase::assertFalse($this->kernel->getContainer()->get('security.context')->getToken()->getUser() instanceof \Symfony\Component\Security\Core\User\UserInterface);
123 | }
124 |
125 | /**
126 | * @Given /^I circumvent login with "([^"]*)" and "([^"]*)"$/
127 | */
128 | public function iCircumventLoginWithAnd($username, $password)
129 | {
130 | $this->getMainContext()->getSession()->visit('/circumvent_login');
131 | $this->getMainContext()->getSession()->getPage()->fillField('_username', $username);
132 | $this->getMainContext()->getSession()->getPage()->fillField('_password', $password);
133 | $this->getMainContext()->getSession()->getPage()->pressButton('Login');
134 | }
135 |
136 | /**
137 | * @Given /^I should be blocked$/
138 | */
139 | public function iShouldBeBlocked()
140 | {
141 | WebTestCase::assertSame(500, $this->getMainContext()->getSession()->getStatusCode());
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/Model/Component/Gateway/BaseGateway.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Gateway;
15 |
16 | use Doctrine\Common\Persistence\ObjectManager;
17 | use Doctrine\ORM\QueryBuilder;
18 |
19 | /**
20 | *
21 | * @category CCDNUser
22 | * @package SecurityBundle
23 | *
24 | * @author Reece Fowell
25 | * @license http://opensource.org/licenses/MIT MIT
26 | * @version Release: 2.0
27 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
28 | * @abstract
29 | *
30 | */
31 | abstract class BaseGateway
32 | {
33 | /**
34 | *
35 | * @access protected
36 | * @var \Doctrine\ORM\EntityManager $em
37 | */
38 | protected $em;
39 |
40 | /**
41 | *
42 | * @access private
43 | * @var string $entityClass
44 | */
45 | protected $entityClass;
46 |
47 | /**
48 | *
49 | * @access public
50 | * @param \Doctrine\Common\Persistence\ObjectManager $em
51 | * @param string $entityClass
52 | */
53 | public function __construct(ObjectManager $em, $entityClass)
54 | {
55 | if (null == $entityClass) {
56 | throw new \Exception('Entity class for gateway must be specified!');
57 | }
58 |
59 | $this->entityClass = $entityClass;
60 | $this->em = $em;
61 | }
62 |
63 | /**
64 | *
65 | * @access public
66 | * @return string
67 | */
68 | public function getEntityClass()
69 | {
70 | return $this->entityClass;
71 | }
72 |
73 | /**
74 | *
75 | * @access public
76 | * @return \Doctrine\ORM\QueryBuilder
77 | */
78 | public function getQueryBuilder()
79 | {
80 | return $this->em->createQueryBuilder();
81 | }
82 |
83 | /**
84 | *
85 | * @access public
86 | * @param \Doctrine\ORM\QueryBuilder $qb
87 | * @param Array $parameters
88 | * @return \Doctrine\Common\Collections\ArrayCollection
89 | */
90 | public function one(QueryBuilder $qb, $parameters = array())
91 | {
92 | if (count($parameters)) {
93 | $qb->setParameters($parameters);
94 | }
95 |
96 | try {
97 | return $qb->getQuery()->getSingleResult();
98 | } catch (\Doctrine\ORM\NoResultException $e) {
99 | return null;
100 | }
101 | }
102 |
103 | /**
104 | *
105 | * @access public
106 | * @param \Doctrine\ORM\QueryBuilder $qb
107 | * @param Array $parameters
108 | * @return \Doctrine\Common\Collections\ArrayCollection
109 | */
110 | public function all(QueryBuilder $qb, $parameters = array())
111 | {
112 | if (count($parameters)) {
113 | $qb->setParameters($parameters);
114 | }
115 |
116 | try {
117 | return $qb->getQuery()->getResult();
118 | } catch (\Doctrine\ORM\NoResultException $e) {
119 | return null;
120 | }
121 | }
122 |
123 | /**
124 | *
125 | * @access public
126 | * @param Object $entity
127 | * @return \CCDNUser\SecurityBundle\Gateway\BaseGatewayInterface
128 | */
129 | public function persist($entity)
130 | {
131 | $this->em->persist($entity);
132 |
133 | return $this;
134 | }
135 |
136 | /**
137 | *
138 | * @access public
139 | * @param Object $entity
140 | * @return \CCDNUser\SecurityBundle\Gateway\BaseGatewayInterface
141 | */
142 | public function remove($entity)
143 | {
144 | $this->em->remove($entity);
145 |
146 | return $this;
147 | }
148 |
149 | /**
150 | *
151 | * @access public
152 | * @return \CCDNUser\SecurityBundle\Gateway\BaseGatewayInterface
153 | */
154 | public function flush()
155 | {
156 | $this->em->flush();
157 |
158 | return $this;
159 | }
160 |
161 | /**
162 | *
163 | * @access public
164 | * @param Object $entity
165 | * @return \CCDNUser\SecurityBundle\Gateway\BaseGatewayInterface
166 | */
167 | public function refresh($entity)
168 | {
169 | $this->em->refresh($entity);
170 |
171 | return $this;
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/Component/Authorisation/SecurityManager.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Component\Authorisation;
15 |
16 | use Symfony\Component\HttpFoundation\RequestStack;
17 | use CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker;
18 |
19 | /**
20 | *
21 | * @category CCDNUser
22 | * @package SecurityBundle
23 | *
24 | * @author Reece Fowell
25 | * @license http://opensource.org/licenses/MIT MIT
26 | * @version Release: 2.0
27 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
28 | *
29 | */
30 | class SecurityManager implements SecurityManagerInterface
31 | {
32 | /**
33 | *
34 | * @access protected
35 | * @var \Symfony\Component\HttpFoundation\RequestStack $requestStack
36 | */
37 | protected $requestStack;
38 |
39 | /**
40 | *
41 | * @access protected
42 | * @var \CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker $loginFailureTracker
43 | */
44 | protected $loginFailureTracker;
45 |
46 | /**
47 | *
48 | * @access protected
49 | * @var array $routeLogin
50 | */
51 | protected $routeLogin;
52 |
53 | /**
54 | *
55 | * @access protected
56 | * @var array $forceAccountRecovery
57 | */
58 | protected $forceAccountRecovery;
59 |
60 | /**
61 | *
62 | * @access protected
63 | * @var array $blockPages
64 | */
65 | protected $blockPages;
66 |
67 | /**
68 | *
69 | * @access public
70 | * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
71 | * @param \CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker $loginFailureTracker
72 | * @param array $routeLogin
73 | * @param array $forceAccountRecovery
74 | * @param array $blockPages
75 | */
76 | public function __construct(RequestStack $requestStack, LoginFailureTracker $loginFailureTracker, $routeLogin, $forceAccountRecovery, $blockPages)
77 | {
78 | $this->requestStack = $requestStack;
79 | $this->loginFailureTracker = $loginFailureTracker;
80 | $this->routeLogin = $routeLogin;
81 | $this->forceAccountRecovery = $forceAccountRecovery;
82 | $this->blockPages = $blockPages;
83 | }
84 |
85 | /**
86 | * If you have failed to login too many times, a log of this will be present
87 | * in your session and the databse (incase session is dropped the record remains).
88 | *
89 | * @access public
90 | * @return int
91 | */
92 | public function vote()
93 | {
94 | $request = $this->requestStack->getMasterRequest();
95 | if (($this->forceAccountRecovery['enabled'] || $this->blockPages['enabled']) && $request) {
96 | $route = $request->get('_route');
97 | $ipAddress = $request->getClientIp();
98 |
99 | $this->blockPages['routes'][] = $this->routeLogin['name'];
100 | if ($this->blockPages['enabled'] && in_array($route, $this->blockPages['routes'])) {
101 | // Get number of failed login attempts.
102 | $attempts = $this->loginFailureTracker->getAttempts($ipAddress, $this->blockPages['duration_in_minutes']);
103 |
104 | if (count($attempts) >= $this->blockPages['after_attempts']) {
105 | // You have too many failed login attempts, login access is temporarily blocked.
106 | return self::ACCESS_DENIED_BLOCK;
107 | }
108 | }
109 |
110 | $this->forceAccountRecovery['routes'][] = $this->routeLogin['name'];
111 | if ($this->forceAccountRecovery['enabled'] && in_array($route, $this->forceAccountRecovery['routes'])) {
112 | // Get number of failed login attempts.
113 | $attempts = $this->loginFailureTracker->getAttempts($ipAddress, $this->forceAccountRecovery['duration_in_minutes']);
114 |
115 | if (count($attempts) >= $this->forceAccountRecovery['after_attempts']) {
116 | // You have too many failed login attempts, login access is temporarily blocked, go recover your account.
117 | return self::ACCESS_DENIED_DEFER;
118 | }
119 | }
120 | }
121 |
122 | return self::ACCESS_ALLOWED;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [NO LONGER SUPPORTED] CCDNUser SecurityBundle README.
2 | ===============================
3 |
4 | [](https://insight.sensiolabs.com/projects/bc552d3d-50ea-4287-8398-ed165db32f78) [](https://travis-ci.org/codeconsortium/CCDNUserSecurityBundle) [](https://scrutinizer-ci.com/g/codeconsortium/CCDNUserSecurityBundle/) [](https://scrutinizer-ci.com/g/codeconsortium/CCDNUserSecurityBundle/) [](https://packagist.org/packages/codeconsortium/ccdn-user-security-bundle) [](https://packagist.org/packages/codeconsortium/ccdn-user-security-bundle) [](https://waffle.io/codeconsortium/ccdnusersecuritybundle)
5 |
6 | ## Notes:
7 |
8 | This is no longer supported or worked on. If you wish to continue using this and wish to take over let me know.
9 |
10 | This bundle is for the symfony framework and requires Symfony ~2.4 and PHP >=5.3.2
11 |
12 | This project uses Doctrine >=2.1 and so does not require any specific database.
13 |
14 | This file is part of the CCDNUser bundles(s)
15 |
16 | © CCDN © [CodeConsortium](http://www.codeconsortium.com/)
17 |
18 | Available on:
19 | * [Github](http://www.github.com/codeconsortium/CCDNUserSecurityBundle)
20 | * [Packagist](https://packagist.org/packages/codeconsortium/ccdn-user-security-bundle)
21 |
22 | For the full copyright and license information, please view the [LICENSE](http://github.com/codeconsortium/CCDNUserSecurityBundle/blob/master/Resources/meta/LICENSE) file that was distributed with this source code.
23 |
24 | [](https://insight.sensiolabs.com/projects/bc552d3d-50ea-4287-8398-ed165db32f78)
25 | [](http://knpbundles.com/codeconsortium/CCDNUserSecurityBundle)
26 |
27 | ## Description:
28 |
29 | Use this bundle to mitigate brute force dictionary attacks on your sites. Excessive failed logins will force users to recover their account, additional attempts
30 | to circumvent that will block the user from specified webpages by returning an HTTP 500 response on all specified routes.
31 |
32 | ### You can use this bundle with any User Bundle you like.
33 |
34 | > This bundle does *NOT* provide user registration/login/logout etc features. This bundle is for brute force dictionary attack mitigation only. Use this bundle in conjunction with your preferred user bundle.
35 |
36 | ## Features.
37 |
38 | SecurityBundle Provides the following features:
39 |
40 | 1. Prevent brute force attacks being carried out by limiting number of login attempts:
41 | 1. When first limit is reached, redirect to an account recovery page.
42 | 2. When secondary limit is reached, return an HTTP 500 status to block login pages etc.
43 | 3. All limits are configurable.
44 | 4. Routes to block are configurable.
45 | 5. Route for account recovery page is configurable.
46 | 6. Decoupled from UserBundle specifics. You can use this with any user bundle you like.
47 | 6. Redirect user to last page they were on upon successful login.
48 | 7. Redirect user to last page they were on upon successful logout.
49 |
50 | ## Documentation.
51 |
52 | Documentation can be found in the `Resources/doc/index.md` file in this bundle:
53 |
54 | [Read the Documentation](http://github.com/codeconsortium/CCDNUserSecurityBundle/blob/master/Resources/doc/index.md).
55 |
56 | ## Installation.
57 |
58 | All the installation instructions are located in [documentation](http://github.com/codeconsortium/CCDNUserSecurityBundle/blob/master/Resources/doc/install.md).
59 |
60 | ## License.
61 |
62 | This software is licensed under the MIT license. See the complete license file in the bundle:
63 |
64 | Resources/meta/LICENSE
65 |
66 | [Read the License](http://github.com/codeconsortium/CCDNUserSecurityBundle/blob/master/Resources/meta/LICENSE).
67 |
68 | ## About.
69 |
70 | [CCDNUser SecurityBundle](http://github.com/codeconsortium/CCDNUserSecurityBundle) is free software from [Code Consortium](http://www.codeconsortium.com).
71 | See also the list of [contributors](http://github.com/codeconsortium/CCDNUserSecurityBundle/contributors).
72 |
73 | ## Reporting an issue or feature request.
74 |
75 | Issues and feature requests are tracked in the [Github issue tracker](http://github.com/codeconsortium/CCDNUserSecurityBundle/issues).
76 |
77 | Discussions and debates on the project can be further discussed at [Code Consortium](http://www.codeconsortium.com).
78 |
--------------------------------------------------------------------------------
/Tests/Functional/app/config/config.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: parameters.yml }
3 | - { resource: ccdn/user-security.yml }
4 |
5 | framework:
6 | test: ~
7 | #esi: ~
8 | translator: { fallback: "%locale%" }
9 | translator: ~
10 | secret: "secret"
11 | router:
12 | resource: "%kernel.root_dir%/config/routing.yml"
13 | strict_requirements: "%kernel.debug%"
14 | form: true
15 | csrf_protection: true
16 | validation: { enable_annotations: true }
17 | templating:
18 | engines: ['twig']
19 | #assets_version: SomeVersionScheme
20 | default_locale: "%locale%"
21 | trusted_proxies: ~
22 | session:
23 | storage_id: session.storage.mock_file
24 | fragments: ~
25 | http_method_override: true
26 | profiler: { only_exceptions: false }
27 |
28 | monolog:
29 | handlers:
30 | main:
31 | type: test
32 | # main:
33 | # type: stream
34 | # path: "%kernel.logs_dir%/%kernel.environment%.log"
35 | # level: debug
36 | # firephp:
37 | # type: firephp
38 | # level: info
39 |
40 | # Twig Configuration
41 | twig:
42 | debug: "%kernel.debug%"
43 | strict_variables: "%kernel.debug%"
44 | form:
45 | resources: ~
46 |
47 | # Doctrine Configuration
48 | doctrine:
49 | dbal:
50 | driver: "%database_driver%"
51 | host: "%database_host%"
52 | port: "%database_port%"
53 | dbname: "%database_name%"
54 | user: "%database_user%"
55 | password: "%database_password%"
56 | charset: UTF8
57 | orm:
58 | default_entity_manager: default
59 | auto_generate_proxy_classes: "%kernel.debug%"
60 | #auto_mapping: true
61 | resolve_target_entities:
62 | # For testing purposes only
63 | 'Symfony\Component\Security\Core\User\UserInterface': 'CCDNUser\SecurityBundle\Tests\Functional\src\Entity\User'
64 | entity_managers:
65 | default:
66 | mappings:
67 | CCDNUserSecurityBundle:
68 | mapping: true
69 | type: yml
70 | dir: "Resources/config/doctrine"
71 | alias: ~
72 | prefix: CCDNUser\SecurityBundle\Entity
73 | is_bundle: true
74 | CCDNUserSecurityBundleUserEntity:
75 | mapping: true
76 | type: yml
77 | dir: "Tests/Functional/src/Resources/config/doctrine"
78 | alias: ~
79 | prefix: CCDNUser\SecurityBundle\Tests\Functional\src\Entity
80 | is_bundle: false
81 |
82 | security:
83 | role_hierarchy:
84 | ROLE_USER: ROLE_USER
85 | ROLE_MODERATOR: [ROLE_USER]
86 | ROLE_ADMIN: [ROLE_USER, ROLE_MODERATOR]
87 | ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_MODERATOR, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
88 | encoders:
89 | FOS\UserBundle\Model\UserInterface: sha512
90 | providers:
91 | fos_userbundle:
92 | id: fos_user.user_provider.username_email
93 | # in_memory:
94 | # memory:
95 | # users:
96 | # user: { password: root, roles: [ 'ROLE_USER' ] }
97 | # moderator: { password: root, roles: [ 'ROLE_MODERATOR' ] }
98 | # admin: { password: root, roles: [ 'ROLE_ADMIN' ] }
99 | firewalls:
100 | main:
101 | switch_user: true
102 | pattern: ^/
103 | form_login:
104 | provider: fos_userbundle
105 | login_path: /login
106 | use_forward: false
107 | check_path: /login_check
108 | success_handler: ccdn_user_security.component.authentication.handler.login_success_handler
109 | failure_handler: ccdn_user_security.component.authentication.handler.login_failure_handler
110 | failure_path: null
111 | csrf_provider: form.csrf_provider
112 | #success_handler:
113 | logout:
114 | path: /logout
115 | target: /
116 | success_handler: ccdn_user_security.component.authentication.handler.logout_success_handler
117 | anonymous: true
118 | http_basic:
119 | #switch_user: true
120 | #pattern: ^/
121 | #logout:
122 | #anonymous: true
123 | dev:
124 | pattern: ^/(_(Securityr|wdt)|css|images|js)/
125 | security: false
126 | remember_me:
127 | key: secret
128 | lifetime: 604800
129 | access_control:
130 | #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
131 | # You must uncomment the two following rules to restrict access to paths
132 | # starting with the /_internal prefix to only localhost
133 | #- { path: ^/_internal/secure, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
134 | #- { path: ^/_internal/secure, roles: ROLE_NO_ACCESS }
135 |
136 | fos_user:
137 | db_driver: orm # other valid values are 'mongodb', 'couchdb' and 'propel'
138 | firewall_name: main
139 | user_class: CCDNUser\SecurityBundle\Tests\Functional\src\Entity\User
140 |
141 |
--------------------------------------------------------------------------------
/Model/Component/Gateway/SessionGateway.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Gateway;
15 |
16 | use Doctrine\ORM\QueryBuilder;
17 | use CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface;
18 | use CCDNUser\SecurityBundle\Model\Component\Gateway\BaseGateway;
19 | use CCDNUser\SecurityBundle\Entity\Session;
20 |
21 | /**
22 | *
23 | * @category CCDNUser
24 | * @package SecurityBundle
25 | *
26 | * @author Reece Fowell
27 | * @license http://opensource.org/licenses/MIT MIT
28 | * @version Release: 2.0
29 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
30 | *
31 | */
32 | class SessionGateway extends BaseGateway implements GatewayInterface
33 | {
34 | /**
35 | *
36 | * @access private
37 | * @var string $queryAlias
38 | */
39 | private $queryAlias = 's';
40 |
41 | /**
42 | *
43 | * @access public
44 | * @param \Doctrine\ORM\QueryBuilder $qb
45 | * @param Array $parameters
46 | * @return \Symfony\Component\Security\Core\User\UserInterface
47 | */
48 | public function findSession(QueryBuilder $qb = null, $parameters = null)
49 | {
50 | if (null == $qb) {
51 | $qb = $this->createSelectQuery();
52 | }
53 |
54 | return $this->one($qb, $parameters);
55 | }
56 |
57 | /**
58 | *
59 | * @access public
60 | * @param \Doctrine\ORM\QueryBuilder $qb
61 | * @param Array $parameters
62 | * @return \Doctrine\Common\Collections\ArrayCollection
63 | */
64 | public function findSessions(QueryBuilder $qb = null, $parameters = null)
65 | {
66 | if (null == $qb) {
67 | $qb = $this->createSelectQuery();
68 | }
69 |
70 | return $this->all($qb, $parameters);
71 | }
72 |
73 | /**
74 | *
75 | * @access public
76 | * @param \Doctrine\ORM\QueryBuilder $qb
77 | * @param Array $parameters
78 | * @return int
79 | */
80 | public function countSessions(QueryBuilder $qb = null, $parameters = null)
81 | {
82 | if (null == $qb) {
83 | $qb = $this->createCountQuery();
84 | }
85 |
86 | if (null == $parameters) {
87 | $parameters = array();
88 | }
89 |
90 | $qb->setParameters($parameters);
91 |
92 | try {
93 | return $qb->getQuery()->getSingleScalarResult();
94 | } catch (\Doctrine\ORM\NoResultException $e) {
95 | return 0;
96 | }
97 | }
98 |
99 | /**
100 | *
101 | * @access public
102 | * @param string $column = null
103 | * @param Array $aliases = null
104 | * @return \Doctrine\ORM\QueryBuilder
105 | */
106 | public function createCountQuery($column = null, Array $aliases = null)
107 | {
108 | if (null == $column) {
109 | $column = 'count(' . $this->queryAlias . '.id)';
110 | }
111 |
112 | if (null == $aliases || ! is_array($aliases)) {
113 | $aliases = array($column);
114 | }
115 |
116 | if (! in_array($column, $aliases)) {
117 | $aliases = array($column) + $aliases;
118 | }
119 |
120 | return $this->getQueryBuilder()->select($aliases)->from($this->entityClass, $this->queryAlias);
121 | }
122 |
123 | /**
124 | *
125 | * @access public
126 | * @param Array $aliases = null
127 | * @return \Doctrine\ORM\QueryBuilder
128 | */
129 | public function createSelectQuery(Array $aliases = null)
130 | {
131 | if (null == $aliases || ! is_array($aliases)) {
132 | $aliases = array($this->queryAlias);
133 | }
134 |
135 | if (! in_array($this->queryAlias, $aliases)) {
136 | $aliases = array($this->queryAlias) + $aliases;
137 | }
138 |
139 | return $this->getQueryBuilder()->select($aliases)->from($this->entityClass, $this->queryAlias);
140 | }
141 |
142 | /**
143 | *
144 | * @access public
145 | * @param \CCDNUser\SecurityBundle\Entity\Session $session
146 | * @return \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface
147 | */
148 | public function persistSession(Session $session)
149 | {
150 | $this->persist($session)->flush();
151 |
152 | return $this;
153 | }
154 |
155 | /**
156 | *
157 | * @access public
158 | * @param \CCDNUser\SecurityBundle\Entity\Session $session
159 | * @return \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface
160 | */
161 | public function updateSession(Session $session)
162 | {
163 | $this->persist($session)->flush();
164 |
165 | return $this;
166 | }
167 |
168 | /**
169 | *
170 | * @access public
171 | * @param \CCDNUser\SecurityBundle\Entity\Session $session
172 | * @return \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface
173 | */
174 | public function deleteSession(Session $session)
175 | {
176 | $this->remove($session)->flush();
177 |
178 | return $this;
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/Model/Component/Manager/BaseManager.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\Model\Component\Manager;
15 |
16 | use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17 | use Doctrine\ORM\QueryBuilder;
18 | use CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface;
19 | use CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface;
20 |
21 | /**
22 | *
23 | * @category CCDNUser
24 | * @package SecurityBundle
25 | *
26 | * @author Reece Fowell
27 | * @license http://opensource.org/licenses/MIT MIT
28 | * @version Release: 2.0
29 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
30 | *
31 | */
32 | abstract class BaseManager
33 | {
34 | /**
35 | *
36 | * @access protected
37 | * @var \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface $gateway
38 | */
39 | protected $gateway;
40 |
41 | /**
42 | *
43 | * @access protected
44 | * @var \CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface $model
45 | */
46 | protected $model;
47 |
48 | /**
49 | *
50 | * @access protected
51 | * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
52 | */
53 | protected $dispatcher;
54 |
55 | /**
56 | *
57 | * @access public
58 | * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
59 | * @param \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface $gateway
60 | */
61 | public function __construct(EventDispatcherInterface $dispatcher, GatewayInterface $gateway)
62 | {
63 | $this->dispatcher = $dispatcher;
64 | $this->gateway = $gateway;
65 | }
66 |
67 | /**
68 | *
69 | * @access public
70 | * @param \CCDNUser\SecurityBundle\Model\FrontModel\ModelInterface $model
71 | * @return \CCDNUser\SecurityBundle\Model\Component\Repository\RepositoryInterface
72 | */
73 | public function setModel(ModelInterface $model)
74 | {
75 | $this->model = $model;
76 |
77 | return $this;
78 | }
79 |
80 | /**
81 | *
82 | * @access public
83 | * @return \CCDNUser\SecurityBundle\Model\Component\Gateway\GatewayInterface
84 | */
85 | public function getGateway()
86 | {
87 | return $this->gateway;
88 | }
89 |
90 | /**
91 | *
92 | * @access public
93 | * @return \Doctrine\ORM\QueryBuilder
94 | */
95 | public function getQueryBuilder()
96 | {
97 | return $this->gateway->getQueryBuilder();
98 | }
99 |
100 | /**
101 | *
102 | * @access public
103 | * @param string $column = null
104 | * @param Array $aliases = null
105 | * @return \Doctrine\Common\Collections\ArrayCollection
106 | */
107 | public function createCountQuery($column = null, Array $aliases = null)
108 | {
109 | return $this->gateway->createCountQuery($column, $aliases);
110 | }
111 |
112 | /**
113 | *
114 | * @access public
115 | * @param Array $aliases = null
116 | * @return \Doctrine\Common\Collections\ArrayCollection
117 | */
118 | public function createSelectQuery(Array $aliases = null)
119 | {
120 | return $this->gateway->createSelectQuery($aliases);
121 | }
122 |
123 | /**
124 | *
125 | * @access public
126 | * @param \Doctrine\ORM\QueryBuilder $qb
127 | * @return \Doctrine\Common\Collections\ArrayCollection
128 | */
129 | public function one(QueryBuilder $qb)
130 | {
131 | return $this->gateway->one($qb);
132 | }
133 |
134 | /**
135 | *
136 | * @access public
137 | * @param \Doctrine\ORM\QueryBuilder $qb
138 | * @return \Doctrine\ORM\QueryBuilder
139 | */
140 | public function all(QueryBuilder $qb)
141 | {
142 | return $this->gateway->all($qb);
143 | }
144 |
145 | /**
146 | *
147 | * @access public
148 | * @param Object $entity
149 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
150 | */
151 | public function persist($entity)
152 | {
153 | $this->gateway->persist($entity);
154 |
155 | return $this;
156 | }
157 |
158 | /**
159 | *
160 | * @access public
161 | * @param Object $entity
162 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
163 | */
164 | public function remove($entity)
165 | {
166 | $this->gateway->remove($entity);
167 |
168 | return $this;
169 | }
170 |
171 | /**
172 | *
173 | * @access public
174 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
175 | */
176 | public function flush()
177 | {
178 | $this->gateway->flush();
179 |
180 | return $this;
181 | }
182 |
183 | /**
184 | *
185 | * @access public
186 | * @param Object $entity
187 | * @return \CCDNUser\SecurityBundle\Model\Component\Manager\ManagerInterface
188 | */
189 | public function refresh($entity)
190 | {
191 | $this->gateway->refresh($entity);
192 |
193 | return $this;
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/features/bootstrap/DataContext.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\features\bootstrap;
15 |
16 | use Behat\Behat\Context\BehatContext;
17 | use Behat\Gherkin\Node\TableNode;
18 | use Behat\Symfony2Extension\Context\KernelAwareInterface;
19 | use Symfony\Component\HttpKernel\KernelInterface;
20 |
21 | use CCDNUser\SecurityBundle\Tests\Functional\src\Entity\User;
22 | use CCDNUser\SecurityBundle\Entity\Profile;
23 |
24 | /**
25 | *
26 | * Features context.
27 | *
28 | * @category CCDNUser
29 | * @package SecurityBundle
30 | *
31 | * @author Reece Fowell
32 | * @license http://opensource.org/licenses/MIT MIT
33 | * @version Release: 2.0
34 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
35 | *
36 | */
37 | class DataContext extends BehatContext implements KernelAwareInterface
38 | {
39 | /**
40 | *
41 | * Kernel.
42 | *
43 | * @var KernelInterface
44 | */
45 | protected $kernel;
46 |
47 | /**
48 | *
49 | * {@inheritdoc}
50 | */
51 | public function setKernel(KernelInterface $kernel)
52 | {
53 | $this->kernel = $kernel;
54 | }
55 |
56 | /**
57 | *
58 | * Get entity manager.
59 | *
60 | * @return EntityManager
61 | */
62 | public function getEntityManager()
63 | {
64 | return $this->getContainer()->get('doctrine')->getManager();
65 | }
66 |
67 | /**
68 | *
69 | * Returns Container instance.
70 | *
71 | * @return ContainerInterface
72 | */
73 | protected function getContainer()
74 | {
75 | return $this->kernel->getContainer();
76 | }
77 |
78 | /**
79 | *
80 | * Get service by id.
81 | *
82 | * @param string $id
83 | *
84 | * @return object
85 | */
86 | protected function getService($id)
87 | {
88 | return $this->getContainer()->get($id);
89 | }
90 |
91 | protected $users = array();
92 |
93 | /**
94 | *
95 | * @Given /^there are following users defined:$/
96 | */
97 | public function thereAreFollowingUsersDefined(TableNode $table)
98 | {
99 | foreach ($table->getHash() as $data) {
100 | $username = isset($data['name']) ? $data['name'] : sha1(uniqid(mt_rand(), true));
101 |
102 | $this->users[$username] = $this->thereIsUser(
103 | $username,
104 | isset($data['email']) ? $data['email'] : sha1(uniqid(mt_rand(), true)),
105 | isset($data['password']) ? $data['password'] : 'password',
106 | isset($data['role']) ? $data['role'] : 'ROLE_USER',
107 | isset($data['enabled']) ? $data['enabled'] : true
108 | );
109 | }
110 |
111 | $this->getEntityManager()->flush();
112 | }
113 |
114 | public function thereIsUser($username, $email, $password, $role = 'ROLE_USER', $enabled = true)
115 | {
116 | $user = new User();
117 |
118 | $user->setUsername($username);
119 | $user->setEmail($email);
120 | $user->setEnabled($enabled);
121 | $user->setPlainPassword($password);
122 |
123 | if (null !== $role) {
124 | $user->addRole($role);
125 | }
126 |
127 | $this->getEntityManager()->persist($user);
128 |
129 | return $user;
130 | }
131 |
132 | protected $profiles = array();
133 |
134 | /**
135 | *
136 | * @Given /^there are following profiles defined:$/
137 | */
138 | public function thereAreFollowingProfilesDefined(TableNode $table)
139 | {
140 | foreach ($table->getHash() as $data) {
141 | $username = isset($data['user']) ? $data['user'] : sha1(uniqid(mt_rand(), true));
142 |
143 | if (isset($this->users[$username])) {
144 | $this->profiles[$username] = $this->thereIsProfile(
145 | $this->users[$username],
146 | isset($data['country']) ? $data['country'] : null,
147 | isset($data['city']) ? $data['city'] : null,
148 | isset($data['real_name']) ? $data['real_name'] : null,
149 | isset($data['birthday']) ? new \Datetime($data['birthday']) : null,
150 | isset($data['company']) ? $data['company'] : null,
151 | isset($data['position']) ? $data['position'] : null,
152 | isset($data['bio']) ? $data['bio'] : null,
153 | isset($data['signature']) ? $data['signature'] : null,
154 | isset($data['msn']) ? $data['msn'] : null,
155 | isset($data['aim']) ? $data['aim'] : null,
156 | isset($data['yahoo']) ? $data['yahoo'] : null,
157 | isset($data['icq']) ? $data['icq'] : true
158 | );
159 | }
160 | }
161 |
162 | $this->getEntityManager()->flush();
163 | }
164 |
165 | public function thereIsProfile(User $user, $country, $city, $realName, \Datetime $birthday, $company, $position, $bio, $signature, $msn, $aim, $yahoo, $icq)
166 | {
167 | $profile = new Profile();
168 |
169 | $profile->setUser($user);
170 | $profile->setLocationCountry($country);
171 | $profile->setLocationCity($city);
172 | $profile->setRealName($realName);
173 | $profile->setBirthDate($birthday);
174 | $profile->setCompany($company);
175 | $profile->setPosition($position);
176 | $profile->setBio($bio);
177 | $profile->setSignature($signature);
178 | $profile->setMsn($msn);
179 | $profile->setMsnPublic(true);
180 | $profile->setAim($aim);
181 | $profile->setAimPublic(true);
182 | $profile->setYahoo($yahoo);
183 | $profile->setYahooPublic(true);
184 | $profile->setIcq($icq);
185 | $profile->setIcqPublic(true);
186 |
187 | $this->getEntityManager()->persist($profile);
188 |
189 | return $user;
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/Resources/doc/install.md:
--------------------------------------------------------------------------------
1 | Installing CCDNUser SecurityBundle.
2 | ===================================
3 |
4 | ## Dependencies:
5 |
6 | > Note you will need a User Bundle so that you can map the UserInterface to your own User entity. You can use whatever User Bundle you prefer. FOSUserBundle is highly rated.
7 |
8 | ## Installation:
9 |
10 | Installation takes only 5 steps:
11 |
12 | 1. Download and install dependencies via Composer.
13 | 2. Register bundles with AppKernel.php.
14 | 3. Update your app/config/config.yml.
15 | 4. enable handlers
16 | 5. Update your database schema.
17 |
18 | ### Step 1: Download and install dependencies via Composer.
19 |
20 | Append the following to end of your applications composer.json file (found in the root of your Symfony2 installation):
21 |
22 | ``` js
23 | // composer.json
24 | {
25 | // ...
26 | "require": {
27 | // ...
28 | "codeconsortium/ccdn-user-security-bundle": "dev-master"
29 | }
30 | }
31 | ```
32 |
33 | NOTE: Please replace ``dev-master`` in the snippet above with the latest stable branch, for example ``2.0.*``.
34 |
35 | Then, you can install the new dependencies by running Composer's ``update``
36 | command from the directory where your ``composer.json`` file is located:
37 |
38 | ``` bash
39 | $ php composer.phar update
40 | ```
41 |
42 | ### Step 2: Register bundles with AppKernel.php.
43 |
44 | Now, Composer will automatically download all required files, and install them
45 | for you. All that is left to do is to update your ``AppKernel.php`` file, and
46 | register the new bundle:
47 |
48 | ``` php
49 | // app/AppKernel.php
50 | public function registerBundles()
51 | {
52 | $bundles = array(
53 | new CCDNUser\SecurityBundle\CCDNUserSecurityBundle(),
54 | // ...
55 | );
56 | }
57 | ```
58 |
59 | ### Step 3: Update your app/config/config.yml.
60 |
61 | In your app/config/config.yml add:
62 |
63 | ``` yml
64 | #
65 | # for CCDNUser SecurityBundle
66 | #
67 | ccdn_user_security:
68 | entity:
69 | user:
70 | class: Acme\YourUserBundle\Entity\User # Required
71 | login_shield:
72 | route_login:
73 | name: fos_user_security_login
74 | params: []
75 | force_account_recovery: # Specify all routes to block after attempt limit is reached, and account recovery route to force browser redirect.
76 | enabled: true
77 | after_attempts: 2
78 | duration_in_minutes: 1
79 | route_recover_account:
80 | name: fos_user_resetting_request
81 | params: []
82 | routes:
83 | - fos_user_security_login
84 | - fos_user_security_check
85 | - fos_user_security_logout
86 | block_pages: # Specify all routes to block after attempt limit is reached.
87 | enabled: true
88 | after_attempts: 4
89 | duration_in_minutes: 2
90 | routes:
91 | - fos_user_security_login
92 | - fos_user_security_check
93 | - fos_user_security_logout
94 | - fos_user_registration_register
95 | - fos_user_registration_check_email
96 | - fos_user_registration_confirm
97 | - fos_user_registration_confirmed
98 | - fos_user_resetting_request
99 | - fos_user_resetting_send_email
100 | ```
101 |
102 | > Routes added are for FOSUserBundle and are added as an example only, choose the correct routes for the user bundle of your choice. If however you are using FOSUserBundle then the routes shown above should work for you.
103 |
104 | Replace Acme\YourUserBundle\Entity\User with the user class of your chosen user bundle.
105 |
106 | Add or remove routes as you see fit to the ignore list or list of routes to block when denied.
107 |
108 | Use the ignore list for routes you do not want to track for the redirect path after a successful login.
109 |
110 | >Please note that for either 'force_account_recovery' or 'block_pages' to function, you need to specify the 'route_login' config, also you must specify the route for the account recovery page.
111 | >Once you have enabled either 'force_account_recovery' or 'block_pages', you must specify the routes that you want blocked once the number of attempts has been reached.
112 | >In order that the forced account recovery process works, the limit must be set lower than the block_pages process, otherwise page blocking will supersede this and prevent it from working and the route must be provided for the account recovery page.
113 |
114 | ### Step 4: enable handlers
115 |
116 | You have to enable your login-/logout-handlers via app/config/security.yml:
117 |
118 | ```
119 | security:
120 | firewalls:
121 | main:
122 | form_login:
123 | provider: fos_userbundle
124 | login_path: /login
125 | use_forward: false
126 | check_path: /login_check
127 | failure_handler: ccdn_user_security.component.authentication.handler.login_failure_handler
128 | logout:
129 | path: /logout
130 | ```
131 |
132 |
133 | ### Step 5: Update your database schema.
134 |
135 | Make sure to add the SecurityBundle to doctrines mapping configuration:
136 |
137 | ```
138 | # app/config/config.yml
139 | # Doctrine Configuration
140 | doctrine:
141 | orm:
142 | default_entity_manager: default
143 | auto_generate_proxy_classes: "%kernel.debug%"
144 | entity_managers:
145 | default:
146 | mappings:
147 | CCDNUserSecurityBundle:
148 | mapping: true
149 | type: yml
150 | dir: "Resources/config/doctrine"
151 | alias: ~
152 | prefix: CCDNUser\SecurityBundle\Entity
153 | is_bundle: true
154 | ```
155 |
156 | From your projects root Symfony directory on the command line run:
157 |
158 | ``` bash
159 | $ php app/console doctrine:schema:update --dump-sql
160 | ```
161 |
162 | Take the SQL that is output and update your database manually.
163 |
164 | **Warning:**
165 |
166 | > Please take care when updating your database, check the output SQL before applying it.
167 |
168 | ## Next Steps.
169 |
170 | Installation should now be complete!
171 |
172 | If you need further help/support, have suggestions or want to contribute please join the community at [Code Consortium](http://www.codeconsortium.com)
173 |
174 | - [Return back to the docs index](index.md).
175 | - [Configuration Reference](configuration_reference.md).
176 |
--------------------------------------------------------------------------------
/DependencyInjection/CCDNUserSecurityExtension.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\DependencyInjection;
15 |
16 | use Symfony\Component\DependencyInjection\Reference;
17 | use Symfony\Component\HttpKernel\DependencyInjection\Extension;
18 | use Symfony\Component\DependencyInjection\ContainerBuilder;
19 | use Symfony\Component\DependencyInjection\Loader;
20 | use Symfony\Component\Config\FileLocator;
21 |
22 | /**
23 | * This is the class that loads and manages your bundle configuration
24 | *
25 | * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
26 | *
27 | * @category CCDNUser
28 | * @package SecurityBundle
29 | *
30 | * @author Reece Fowell
31 | * @license http://opensource.org/licenses/MIT MIT
32 | * @version Release: 2.0
33 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
34 | *
35 | */
36 | class CCDNUserSecurityExtension extends Extension
37 | {
38 | /**
39 | *
40 | * @access public
41 | * @return string
42 | */
43 | public function getAlias()
44 | {
45 | return 'ccdn_user_security';
46 | }
47 |
48 | /**
49 | *
50 | * @access public
51 | * @param array $config
52 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
53 | */
54 | public function load(array $configs, ContainerBuilder $container)
55 | {
56 | $configuration = new Configuration();
57 | $config = $this->processConfiguration($configuration, $configs);
58 |
59 | // Class file namespaces.
60 | $this->getEntitySection($container, $config);
61 | $this->getGatewaySection($container, $config);
62 | $this->getRepositorySection($container, $config);
63 | $this->getManagerSection($container, $config);
64 | $this->getModelSection($container, $config);
65 | $this->getComponentSection($container, $config);
66 |
67 | // Configuration stuff.
68 | $this->getLoginShieldSection($container, $config);
69 |
70 | // Load Service definitions.
71 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
72 | $loader->load('services.yml');
73 | $loader->load('services/components.yml');
74 | $loader->load('services/model-gateway.yml');
75 | $loader->load('services/model-repository.yml');
76 | $loader->load('services/model-manager.yml');
77 | $loader->load('services/model.yml');
78 | }
79 |
80 | /**
81 | *
82 | * @access private
83 | * @param array $config
84 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
85 | * @return \CCDNUser\SecurityBundle\DependencyInjection\CCDNUserSecurityExtension
86 | */
87 | private function getEntitySection(ContainerBuilder $container, $config)
88 | {
89 | $container->setParameter('ccdn_user_security.entity.user.class', $config['entity']['user']['class']);
90 | $container->setParameter('ccdn_user_security.entity.session.class', $config['entity']['session']['class']);
91 |
92 | return $this;
93 | }
94 |
95 | /**
96 | *
97 | * @access private
98 | * @param array $config
99 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
100 | * @return \CCDNUser\SecurityBundle\DependencyInjection\CCDNUserSecurityExtension
101 | */
102 | private function getGatewaySection(ContainerBuilder $container, $config)
103 | {
104 | $container->setParameter('ccdn_user_security.gateway.session.class', $config['gateway']['session']['class']);
105 |
106 | return $this;
107 | }
108 |
109 | /**
110 | *
111 | * @access private
112 | * @param array $config
113 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
114 | * @return \CCDNUser\SecurityBundle\DependencyInjection\CCDNUserSecurityExtension
115 | */
116 | private function getRepositorySection(ContainerBuilder $container, $config)
117 | {
118 | $container->setParameter('ccdn_user_security.repository.session.class', $config['repository']['session']['class']);
119 |
120 | return $this;
121 | }
122 |
123 | /**
124 | *
125 | * @access private
126 | * @param array $config
127 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
128 | * @return \CCDNUser\SecurityBundle\DependencyInjection\CCDNUserSecurityExtension
129 | */
130 | private function getManagerSection(ContainerBuilder $container, $config)
131 | {
132 | $container->setParameter('ccdn_user_security.manager.session.class', $config['manager']['session']['class']);
133 |
134 | return $this;
135 | }
136 |
137 | /**
138 | *
139 | * @access private
140 | * @param array $config
141 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
142 | * @return \CCDNUser\SecurityBundle\DependencyInjection\CCDNUserSecurityExtension
143 | */
144 | private function getModelSection(ContainerBuilder $container, $config)
145 | {
146 | $container->setParameter('ccdn_user_security.model.session.class', $config['model']['session']['class']);
147 |
148 | return $this;
149 | }
150 |
151 | /**
152 | *
153 | * @access private
154 | * @param array $config
155 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
156 | * @return \CCDNUser\SecurityBundle\DependencyInjection\CCDNUserSecurityExtension
157 | */
158 | private function getComponentSection(ContainerBuilder $container, $config)
159 | {
160 | $container->setParameter('ccdn_user_security.component.authentication.handler.login_failure_handler.class', $config['component']['authentication']['handler']['login_failure_handler']['class']);
161 | $container->setParameter('ccdn_user_security.component.authentication.tracker.login_failure_tracker.class', $config['component']['authentication']['tracker']['login_failure_tracker']['class']);
162 |
163 | $container->setParameter('ccdn_user_security.component.authorisation.security_manager.class', $config['component']['authorisation']['security_manager']['class']);
164 | $container->setParameter('ccdn_user_security.component.authorisation.voter.client_login_voter.class', $config['component']['authorisation']['voter']['client_login_voter']['class']);
165 |
166 | $container->setParameter('ccdn_user_security.component.listener.blocking_login_listener.class', $config['component']['listener']['blocking_login_listener']['class']);
167 | $container->setParameter('ccdn_user_security.component.listener.defer_login_listener.class', $config['component']['listener']['defer_login_listener']['class']);
168 | $container->setParameter('ccdn_user_security.component.access_denied_exception_factory.class', $config['component']['listener']['blocking_login_listener']['access_denied_exception_factory']);
169 |
170 | return $this;
171 | }
172 |
173 | /**
174 | *
175 | * @access private
176 | * @param array $config
177 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
178 | * @return \CCDNUser\SecurityBundle\DependencyInjection\CCDNUserSecurityExtension
179 | */
180 | private function getLoginShieldSection(ContainerBuilder $container, $config)
181 | {
182 | $container->setParameter('ccdn_user_security.login_shield.route_login', $config['login_shield']['route_login']);
183 | $container->setParameter('ccdn_user_security.login_shield.force_account_recovery', $config['login_shield']['force_account_recovery']);
184 | $container->setParameter('ccdn_user_security.login_shield.block_pages', $config['login_shield']['block_pages']);
185 |
186 | return $this;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/DependencyInjection/Configuration.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Available on github
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace CCDNUser\SecurityBundle\DependencyInjection;
15 |
16 | use Symfony\Component\Config\Definition\ConfigurationInterface;
17 | use Symfony\Component\Config\Definition\Builder\TreeBuilder;
18 | use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
19 |
20 | /**
21 | * This is the class that validates and merges configuration from your app/config files
22 | *
23 | * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
24 | *
25 | * @category CCDNUser
26 | * @package SecurityBundle
27 | *
28 | * @author Reece Fowell
29 | * @license http://opensource.org/licenses/MIT MIT
30 | * @version Release: 2.0
31 | * @link https://github.com/codeconsortium/CCDNUserSecurityBundle
32 | *
33 | */
34 | class Configuration implements ConfigurationInterface
35 | {
36 | /**
37 | *
38 | * @access public
39 | * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder
40 | */
41 | public function getConfigTreeBuilder()
42 | {
43 | $treeBuilder = new TreeBuilder();
44 | $rootNode = $treeBuilder->root('ccdn_user_security');
45 |
46 | // Class file namespaces.
47 | $this->addEntitySection($rootNode);
48 | $this->addGatewaySection($rootNode);
49 | $this->addRepositorySection($rootNode);
50 | $this->addManagerSection($rootNode);
51 | $this->addModelSection($rootNode);
52 | $this->addComponentSection($rootNode);
53 |
54 | // Configuration stuff.
55 | $this->addLoginShieldSection($rootNode);
56 | $this->addRouteRefererSection($rootNode);
57 |
58 | return $treeBuilder;
59 | }
60 |
61 | /**
62 | *
63 | * @access private
64 | * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
65 | * @return \CCDNUser\SecurityBundle\DependencyInjection\Configuration
66 | */
67 | private function addEntitySection(ArrayNodeDefinition $node)
68 | {
69 | $node
70 | ->isRequired()
71 | ->cannotBeEmpty()
72 | ->children()
73 | ->arrayNode('entity')
74 | ->isRequired()
75 | ->cannotBeEmpty()
76 | ->children()
77 | ->arrayNode('user')
78 | ->isRequired()
79 | ->cannotBeEmpty()
80 | ->children()
81 | ->scalarNode('class')
82 | ->isRequired()
83 | ->cannotBeEmpty()
84 | ->end()
85 | ->end()
86 | ->end()
87 | ->arrayNode('session')
88 | ->addDefaultsIfNotSet()
89 | ->canBeUnset()
90 | ->children()
91 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Entity\Session')->end()
92 | ->end()
93 | ->end()
94 | ->end()
95 | ->end()
96 | ->end()
97 | ;
98 |
99 | return $this;
100 | }
101 |
102 | /**
103 | *
104 | * @access private
105 | * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
106 | * @return \CCDNUser\SecurityBundle\DependencyInjection\Configuration
107 | */
108 | private function addGatewaySection(ArrayNodeDefinition $node)
109 | {
110 | $node
111 | ->addDefaultsIfNotSet()
112 | ->children()
113 | ->arrayNode('gateway')
114 | ->addDefaultsIfNotSet()
115 | ->canBeUnset()
116 | ->children()
117 | ->arrayNode('session')
118 | ->addDefaultsIfNotSet()
119 | ->canBeUnset()
120 | ->children()
121 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Model\Component\Gateway\SessionGateway')->end()
122 | ->end()
123 | ->end()
124 | ->end()
125 | ->end()
126 | ->end()
127 | ;
128 |
129 | return $this;
130 | }
131 |
132 | /**
133 | *
134 | * @access private
135 | * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
136 | * @return \CCDNUser\SecurityBundle\DependencyInjection\Configuration
137 | */
138 | private function addRepositorySection(ArrayNodeDefinition $node)
139 | {
140 | $node
141 | ->addDefaultsIfNotSet()
142 | ->children()
143 | ->arrayNode('repository')
144 | ->addDefaultsIfNotSet()
145 | ->canBeUnset()
146 | ->children()
147 | ->arrayNode('session')
148 | ->addDefaultsIfNotSet()
149 | ->canBeUnset()
150 | ->children()
151 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Model\Component\Repository\SessionRepository')->end()
152 | ->end()
153 | ->end()
154 | ->end()
155 | ->end()
156 | ->end()
157 | ;
158 |
159 | return $this;
160 | }
161 |
162 | /**
163 | *
164 | * @access private
165 | * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
166 | * @return \CCDNUser\SecurityBundle\DependencyInjection\Configuration
167 | */
168 | private function addManagerSection(ArrayNodeDefinition $node)
169 | {
170 | $node
171 | ->addDefaultsIfNotSet()
172 | ->children()
173 | ->arrayNode('manager')
174 | ->addDefaultsIfNotSet()
175 | ->canBeUnset()
176 | ->children()
177 | ->arrayNode('session')
178 | ->addDefaultsIfNotSet()
179 | ->canBeUnset()
180 | ->children()
181 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Model\Component\Manager\SessionManager')->end()
182 | ->end()
183 | ->end()
184 | ->end()
185 | ->end()
186 | ->end()
187 | ;
188 |
189 | return $this;
190 | }
191 |
192 | /**
193 | *
194 | * @access private
195 | * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
196 | * @return \CCDNUser\SecurityBundle\DependencyInjection\Configuration
197 | */
198 | private function addModelSection(ArrayNodeDefinition $node)
199 | {
200 | $node
201 | ->addDefaultsIfNotSet()
202 | ->children()
203 | ->arrayNode('model')
204 | ->addDefaultsIfNotSet()
205 | ->canBeUnset()
206 | ->children()
207 | ->arrayNode('session')
208 | ->addDefaultsIfNotSet()
209 | ->canBeUnset()
210 | ->children()
211 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Model\FrontModel\SessionModel')->end()
212 | ->end()
213 | ->end()
214 | ->end()
215 | ->end()
216 | ->end()
217 | ;
218 |
219 | return $this;
220 | }
221 |
222 | /**
223 | *
224 | * @access private
225 | * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
226 | * @return \CCDNUser\SecurityBundle\DependencyInjection\Configuration
227 | */
228 | private function addRouteRefererSection(ArrayNodeDefinition $node)
229 | {
230 | $node
231 | ->children()
232 | ->arrayNode('route_referer')
233 | ->canBeUnset()
234 | ->ignoreExtraKeys()
235 | // we just skip that array!
236 | ->end()
237 | ->end()
238 | ;
239 |
240 | return $this;
241 | }
242 |
243 | /**
244 | *
245 | * @access private
246 | * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
247 | * @return \CCDNUser\SecurityBundle\DependencyInjection\Configuration
248 | */
249 | private function addComponentSection(ArrayNodeDefinition $node)
250 | {
251 | $node
252 | ->addDefaultsIfNotSet()
253 | ->children()
254 | ->arrayNode('component')
255 | ->addDefaultsIfNotSet()
256 | ->canBeUnset()
257 | ->children()
258 | ->arrayNode('authentication')
259 | ->addDefaultsIfNotSet()
260 | ->canBeUnset()
261 | ->children()
262 | ->arrayNode('handler')
263 | ->addDefaultsIfNotSet()
264 | ->canBeUnset()
265 | ->children()
266 | ->arrayNode('login_failure_handler')
267 | ->addDefaultsIfNotSet()
268 | ->canBeUnset()
269 | ->children()
270 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Authentication\Handler\LoginFailureHandler')->end()
271 | ->end()
272 | ->end()
273 | ->arrayNode('login_success_handler')
274 | ->addDefaultsIfNotSet()
275 | ->canBeUnset()
276 | ->children()
277 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Authentication\Handler\LoginSuccessHandler')->end()
278 | ->end()
279 | ->end()
280 | ->arrayNode('logout_success_handler')
281 | ->addDefaultsIfNotSet()
282 | ->canBeUnset()
283 | ->children()
284 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Authentication\Handler\LogoutSuccessHandler')->end()
285 | ->end()
286 | ->end()
287 | ->end()
288 | ->end()
289 | ->arrayNode('tracker')
290 | ->addDefaultsIfNotSet()
291 | ->canBeUnset()
292 | ->children()
293 | ->arrayNode('login_failure_tracker')
294 | ->addDefaultsIfNotSet()
295 | ->canBeUnset()
296 | ->children()
297 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Authentication\Tracker\LoginFailureTracker')->end()
298 | ->end()
299 | ->end()
300 | ->end()
301 | ->end()
302 | ->end()
303 | ->end()
304 | ->arrayNode('authorisation')
305 | ->addDefaultsIfNotSet()
306 | ->canBeUnset()
307 | ->children()
308 | ->arrayNode('security_manager')
309 | ->addDefaultsIfNotSet()
310 | ->canBeUnset()
311 | ->children()
312 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Authorisation\SecurityManager')->end()
313 | ->end()
314 | ->end()
315 | ->arrayNode('voter')
316 | ->addDefaultsIfNotSet()
317 | ->canBeUnset()
318 | ->children()
319 | ->arrayNode('client_login_voter')
320 | ->addDefaultsIfNotSet()
321 | ->canBeUnset()
322 | ->children()
323 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Authorisation\Voter\ClientLoginVoter')->end()
324 | ->end()
325 | ->end()
326 | ->end()
327 | ->end()
328 | ->end()
329 | ->end()
330 | ->arrayNode('listener')
331 | ->addDefaultsIfNotSet()
332 | ->canBeUnset()
333 | ->children()
334 | ->arrayNode('route_referer_listener')
335 | ->addDefaultsIfNotSet()
336 | ->canBeUnset()
337 | ->children()
338 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Listener\RouteRefererListener')->end()
339 | ->end()
340 | ->end()
341 | ->arrayNode('defer_login_listener')
342 | ->addDefaultsIfNotSet()
343 | ->canBeUnset()
344 | ->children()
345 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Listener\DeferLoginListener')->end()
346 | ->end()
347 | ->end()
348 | ->arrayNode('blocking_login_listener')
349 | ->addDefaultsIfNotSet()
350 | ->canBeUnset()
351 | ->children()
352 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Listener\BlockingLoginListener')->end()
353 | ->scalarNode('access_denied_exception_factory')->defaultValue('CCDNUser\SecurityBundle\Component\Listener\AccessDeniedExceptionFactory')->end()
354 | ->end()
355 | ->end()
356 | ->end()
357 | ->end()
358 | ->arrayNode('route_referer_ignore')
359 | ->addDefaultsIfNotSet()
360 | ->canBeUnset()
361 | ->children()
362 | ->arrayNode('chain')
363 | ->addDefaultsIfNotSet()
364 | ->canBeUnset()
365 | ->children()
366 | ->scalarNode('class')->defaultValue('CCDNUser\SecurityBundle\Component\Listener\Chain\RouteRefererIgnoreChain')->end()
367 | ->end()
368 | ->end()
369 | ->end()
370 | ->end()
371 | ->end()
372 | ->end()
373 | ->end()
374 | ;
375 |
376 | return $this;
377 | }
378 |
379 | /**
380 | *
381 | * @access private
382 | * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
383 | * @return \CCDNUser\SecurityBundle\DependencyInjection\Configuration
384 | */
385 | private function addLoginShieldSection(ArrayNodeDefinition $node)
386 | {
387 | $node
388 | ->addDefaultsIfNotSet()
389 | ->canBeUnset()
390 | ->children()
391 | ->arrayNode('login_shield')
392 | ->addDefaultsIfNotSet()
393 | ->canBeUnset()
394 | ->children()
395 | ->arrayNode('route_login')
396 | ->children()
397 | ->scalarNode('name')->end()
398 | ->scalarNode('path')->end()
399 | ->arrayNode('params')
400 | ->prototype('scalar')
401 | ->end()
402 | ->end()
403 | ->end()
404 | ->end()
405 |
406 | ->arrayNode('force_account_recovery')
407 | ->children()
408 | ->booleanNode('enabled')->defaultFalse()->end()
409 | ->scalarNode('after_attempts')->defaultValue(15)->end()
410 | ->scalarNode('duration_in_minutes')->defaultValue(10)->end()
411 | ->arrayNode('route_recover_account')
412 | ->children()
413 | ->scalarNode('name')->end()
414 | ->arrayNode('params')
415 | ->prototype('scalar')
416 | ->end()
417 | ->end()
418 | ->end()
419 | ->end()
420 | ->arrayNode('routes')
421 | ->prototype('scalar')
422 | ->end()
423 | ->end()
424 | ->end()
425 | ->end()
426 |
427 | ->arrayNode('block_pages')
428 | ->children()
429 | ->booleanNode('enabled')->defaultFalse()->end()
430 | ->scalarNode('after_attempts')->defaultValue(15)->end()
431 | ->scalarNode('duration_in_minutes')->defaultValue(10)->end()
432 | ->arrayNode('routes')
433 | ->prototype('scalar')
434 | ->end()
435 | ->end()
436 | ->end()
437 | ->end()
438 |
439 | ->end()
440 | ->end()
441 | ->end()
442 | ;
443 |
444 | return $this;
445 | }
446 | }
447 |
--------------------------------------------------------------------------------