Files
Phraseanet/lib/Alchemy/Phrasea/Authentication/Phrasea/FailureManager.php
Benoît Burnichon 3944580f8c fix return type from Failure Manager.
Also require injection of an AuthFailureRepository instance.
Add flush of entities.
2016-03-15 12:21:56 +01:00

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);
}
}