mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-17 06:53:15 +00:00
138 lines
3.1 KiB
PHP
138 lines
3.1 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of Phraseanet
|
|
*
|
|
* (c) 2005-2016 Alchemy
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Alchemy\Phrasea\Authentication\Phrasea;
|
|
|
|
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
|
use Alchemy\Phrasea\Authentication\Exception\RequireCaptchaException;
|
|
use Alchemy\Phrasea\Model\Repositories\AuthFailureRepository;
|
|
use Doctrine\ORM\EntityManager;
|
|
use Alchemy\Phrasea\Model\Entities\AuthFailure;
|
|
use Neutron\ReCaptcha\ReCaptcha;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
|
|
class FailureManager
|
|
{
|
|
/**
|
|
* @var ReCaptcha
|
|
*/
|
|
private $captcha;
|
|
|
|
/**
|
|
* @var EntityManager
|
|
*/
|
|
private $em;
|
|
|
|
/**
|
|
* @var AuthFailureRepository
|
|
*/
|
|
private $repository;
|
|
|
|
/**
|
|
* @var int
|
|
*/
|
|
private $trials;
|
|
|
|
public function __construct(AuthFailureRepository $repo, EntityManager $em, ReCaptcha $captcha, $trials)
|
|
{
|
|
$this->captcha = $captcha;
|
|
$this->em = $em;
|
|
$this->repository = $repo;
|
|
|
|
if ($trials < 0) {
|
|
throw new InvalidArgumentException('Trials number must be a positive integer');
|
|
}
|
|
|
|
$this->trials = (int)$trials;
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function getTrials()
|
|
{
|
|
return $this->trials;
|
|
}
|
|
|
|
/**
|
|
* Saves an authentication failure
|
|
*
|
|
* @param string $username
|
|
* @param Request $request
|
|
*
|
|
* @return FailureManager
|
|
*/
|
|
public function saveFailure($username, Request $request)
|
|
{
|
|
$this->removeOldFailures();
|
|
|
|
$failure = new AuthFailure();
|
|
$failure->setIp($request->getClientIp());
|
|
$failure->setUsername($username);
|
|
$failure->setLocked(true);
|
|
|
|
$this->em->persist($failure);
|
|
$this->em->flush();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Checks a request for previous failures
|
|
*
|
|
* @param string $username
|
|
* @param Request $request
|
|
*
|
|
* @return FailureManager
|
|
*
|
|
* @throws RequireCaptchaException In case a captcha unlock is required
|
|
*/
|
|
public function checkFailures($username, Request $request)
|
|
{
|
|
$failures = $this->repository->findLockedFailuresMatching($username, $request->getClientIp());
|
|
|
|
if (0 === count($failures)) {
|
|
return $this;
|
|
}
|
|
|
|
if ($this->trials < count($failures) && $this->captcha->isSetup()) {
|
|
$response = $this->captcha->bind($request);
|
|
|
|
if (!$response->isValid()) {
|
|
throw new RequireCaptchaException('Too many failures, require captcha');
|
|
}
|
|
|
|
foreach ($failures as $failure) {
|
|
$failure->setLocked(false);
|
|
}
|
|
|
|
$this->em->flush($failures);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
private function removeOldFailures()
|
|
{
|
|
$failures = $this->repository->findOldFailures('-2 months');
|
|
|
|
if (empty($failures)) {
|
|
return;
|
|
}
|
|
|
|
foreach ($failures as $failure) {
|
|
$this->em->remove($failure);
|
|
}
|
|
|
|
$this->em->flush($failures);
|
|
}
|
|
}
|