├── .gitignore ├── .php_cs ├── .travis.yml ├── CCDNUserSecurityBundle.php ├── Component ├── Authentication │ ├── Handler │ │ └── LoginFailureHandler.php │ └── Tracker │ │ └── LoginFailureTracker.php ├── Authorisation │ ├── SecurityManager.php │ ├── SecurityManagerInterface.php │ └── Voter │ │ └── ClientLoginVoter.php └── Listener │ ├── AccessDeniedExceptionFactory.php │ ├── AccessDeniedExceptionFactoryInterface.php │ ├── BlockingLoginListener.php │ └── DeferLoginListener.php ├── Controller └── TestLoginController.php ├── DependencyInjection ├── CCDNUserSecurityExtension.php └── Configuration.php ├── Entity └── Session.php ├── Model ├── Component │ ├── Gateway │ │ ├── BaseGateway.php │ │ ├── GatewayInterface.php │ │ └── SessionGateway.php │ ├── Manager │ │ ├── BaseManager.php │ │ ├── ManagerInterface.php │ │ └── SessionManager.php │ └── Repository │ │ ├── BaseRepository.php │ │ ├── RepositoryInterface.php │ │ └── SessionRepository.php └── FrontModel │ ├── BaseModel.php │ ├── ModelInterface.php │ └── SessionModel.php ├── README.md ├── Resources ├── config │ ├── doctrine │ │ └── Session.orm.yml │ ├── routing.yml │ ├── services.yml │ └── services │ │ ├── components.yml │ │ ├── model-gateway.yml │ │ ├── model-manager.yml │ │ ├── model-repository.yml │ │ └── model.yml ├── doc │ ├── configuration_reference.md │ ├── index.md │ └── install.md ├── meta │ └── LICENSE └── views │ ├── home.html.twig │ └── login.html.twig ├── Tests ├── Functional │ ├── app │ │ ├── AppKernel.php │ │ ├── config │ │ │ ├── ccdn │ │ │ │ └── user-security.yml │ │ │ ├── config.yml │ │ │ ├── config_dev.yml │ │ │ ├── config_prod.yml │ │ │ ├── config_test.yml │ │ │ ├── routing.yml │ │ │ └── routing_dev.yml │ │ └── console │ ├── bootstrap.php │ └── src │ │ ├── Entity │ │ └── User.php │ │ └── Resources │ │ └── config │ │ └── doctrine │ │ └── User.orm.yml ├── Manager │ └── SessionManagerTest.php ├── Repository │ └── SessionRepositoryTest.php └── TestBase.php ├── behat.yml ├── composer.json ├── features ├── bootstrap │ ├── DataContext.php │ ├── FeatureContext.php │ └── WebUser.php └── user_login.feature ├── phpunit.xml.dist ├── script_behat.sh └── script_phpunit.sh /.gitignore: -------------------------------------------------------------------------------- 1 | app/config/parameters.yml 2 | app/config/parameters.ini 3 | logs/ 4 | cache/ 5 | vendor/ 6 | vendor/* 7 | web/bundles/ 8 | .idea/ 9 | Propel/om/* 10 | Propel/map/* 11 | composer.lock 12 | phpunit.xml 13 | Tests/autoload.php 14 | catalog.xml 15 | 16 | *.log 17 | *.db 18 | *.DS_Store 19 | *.DS_Store? 20 | ._* 21 | .Spotlight-V100 22 | .Trashes 23 | Icon? 24 | ehthumbs.db 25 | Thumbs.db 26 | 27 | Tests/Functional/app/config/parameters.yml 28 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [NO LONGER SUPPORTED] CCDNUser SecurityBundle README. 2 | =============================== 3 | 4 | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/bc552d3d-50ea-4287-8398-ed165db32f78/mini.png)](https://insight.sensiolabs.com/projects/bc552d3d-50ea-4287-8398-ed165db32f78) [![Build Status](https://secure.travis-ci.org/codeconsortium/CCDNUserSecurityBundle.png)](https://travis-ci.org/codeconsortium/CCDNUserSecurityBundle) [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/codeconsortium/CCDNUserSecurityBundle/badges/quality-score.png?s=3a911241b61b93285d75b45356860adbd5775add)](https://scrutinizer-ci.com/g/codeconsortium/CCDNUserSecurityBundle/) [![Code Coverage](https://scrutinizer-ci.com/g/codeconsortium/CCDNUserSecurityBundle/badges/coverage.png?s=f9bb5214fc860a3fca0b887780485a92ba3ba124)](https://scrutinizer-ci.com/g/codeconsortium/CCDNUserSecurityBundle/) [![Latest Stable Version](https://poser.pugx.org/codeconsortium/ccdn-user-security-bundle/v/stable.png)](https://packagist.org/packages/codeconsortium/ccdn-user-security-bundle) [![Total Downloads](https://poser.pugx.org/codeconsortium/ccdn-user-security-bundle/downloads.png)](https://packagist.org/packages/codeconsortium/ccdn-user-security-bundle) [![Stories in Ready](https://badge.waffle.io/codeconsortium/ccdnusersecuritybundle.png?label=ready)](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 | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/bc552d3d-50ea-4287-8398-ed165db32f78/big.png)](https://insight.sensiolabs.com/projects/bc552d3d-50ea-4287-8398-ed165db32f78) 25 | [![knpbundles.com](http://knpbundles.com/codeconsortium/CCDNUserSecurityBundle/badge-short)](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 | -------------------------------------------------------------------------------- /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/config/routing.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeconsortium/CCDNUserSecurityBundle/c99576c53611fe91220708474a58538eead0ce1d/Resources/config/routing.yml -------------------------------------------------------------------------------- /Resources/config/services.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | 3 | # Service Parameters defined in app/config 4 | 5 | services: 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Resources/config/services/model-gateway.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | 3 | # Service Parameters defined in app/config 4 | 5 | services: 6 | 7 | # 8 | # Gateways. 9 | # 10 | ccdn_user_security.gateway.session: 11 | class: %ccdn_user_security.gateway.session.class% 12 | arguments: 13 | - @doctrine.orm.entity_manager 14 | - %ccdn_user_security.entity.session.class% 15 | -------------------------------------------------------------------------------- /Resources/config/services/model-manager.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | 3 | # Service Parameters defined in app/config 4 | 5 | services: 6 | 7 | # 8 | # Managers. 9 | # 10 | ccdn_user_security.manager.session: 11 | class: %ccdn_user_security.manager.session.class% 12 | arguments: 13 | - @event_dispatcher 14 | - @ccdn_user_security.gateway.session 15 | -------------------------------------------------------------------------------- /Resources/config/services/model-repository.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | 3 | # Service Parameters defined in app/config 4 | 5 | services: 6 | 7 | # 8 | # Repositories. 9 | # 10 | ccdn_user_security.repository.session: 11 | class: %ccdn_user_security.repository.session.class% 12 | arguments: 13 | - @ccdn_user_security.gateway.session 14 | -------------------------------------------------------------------------------- /Resources/config/services/model.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | 3 | # Service Parameters defined in app/config 4 | 5 | services: 6 | 7 | # 8 | # Models. 9 | # 10 | ccdn_user_security.model.session: 11 | class: %ccdn_user_security.model.session.class% 12 | arguments: 13 | - @event_dispatcher 14 | - @ccdn_user_security.repository.session 15 | - @ccdn_user_security.manager.session 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /Resources/views/home.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hi on this test home page

4 | 5 | 6 | -------------------------------------------------------------------------------- /Resources/views/login.html.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.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 | -------------------------------------------------------------------------------- /Tests/Functional/app/config/routing_dev.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: routing.yml } 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Tests/Functional/src/Entity/User.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 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------