Skip to content

Commit

Permalink
Rewrite rememberme services to use ORM
Browse files Browse the repository at this point in the history
  • Loading branch information
aschempp committed Jun 11, 2019
1 parent 642cfe7 commit e98ce36
Show file tree
Hide file tree
Showing 6 changed files with 437 additions and 107 deletions.
59 changes: 55 additions & 4 deletions core-bundle/src/Entity/RememberMe.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
namespace Contao\CoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;

/**
* @ORM\Entity
* @ORM\Table(
* name="tl_remember_me",
* indexes={
* @ORM\Index(name="series", columns={"series"})
* }
* )
* @ORM\Entity(repositoryClass="Contao\CoreBundle\Repository\RememberMeRepository")
*/
class RememberMe
{
Expand All @@ -33,14 +34,14 @@ class RememberMe
protected $value;

/**
* @var string
* @var \DateTime
*
* @ORM\Column(type="datetime", nullable=true)
* @ORM\Column(type="datetime", nullable=false)
*/
protected $lastUsed;

/**
* @var string
* @var \DateTime|null
*
* @ORM\Column(type="datetime", nullable=true)
*/
Expand All @@ -59,4 +60,54 @@ class RememberMe
* @ORM\Column(type="string", length=200, nullable=false)
*/
protected $username;

public function __construct(UserInterface $user, string $encodedSeries)
{
$this->class = \get_class($user);
$this->series = $encodedSeries;
$this->value = base64_encode(random_bytes(64));
$this->username = $user->getUsername();
$this->lastUsed = new \DateTime();
}

public function __clone()
{
$this->value = base64_encode(random_bytes(64));
$this->lastUsed = new \DateTime();
$this->expires = null;
}

public function getValue(): string
{
return $this->value;
}

public function getLastUsed(): \DateTime
{
return $this->lastUsed;
}

public function getExpires(): ?\DateTime
{
return $this->expires;
}

public function setExpiresInSeconds(int $seconds): self
{
if (null === $this->expires) {
$this->expires = (new \DateTime())->add(new \DateInterval('PT'.$seconds.'S'));
}

return $this;
}

public function getClass(): string
{
return $this->class;
}

public function getUsername(): string
{
return $this->username;
}
}
101 changes: 101 additions & 0 deletions core-bundle/src/Repository/RememberMeRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

declare(strict_types=1);

/*
* This file is part of Contao.
*
* (c) Leo Feyer
*
* @license LGPL-3.0-or-later
*/

namespace Contao\CoreBundle\Repository;

use Contao\CoreBundle\Entity\RememberMe;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types\Type as DoctrineType;

class RememberMeRepository extends ServiceEntityRepository
{
/**
* @var Connection
*/
private $connection;

public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, RememberMe::class);

$this->connection = $registry->getConnection();
}

public function lockTable()
{
$table = $this->getClassMetadata()->getTableName();

$this->connection->exec("LOCK TABLES $table WRITE");
}

public function unlockTable()
{
$this->connection->exec('UNLOCK TABLES');
}

/**
* @return RememberMe[]
*/
public function findBySeries(string $encodedSeries): array
{
$qb = $this->createQueryBuilder('rm');

$qb
->where('rm.series = :series')
->andWhere(
$qb->expr()->orX(
$qb->expr()->isNull('rm.expires'),
$qb->expr()->lte('rm.expires', 'NOW()')
)
)
->setParameter('series', $encodedSeries)
->orderBy($qb->expr()->isNull('rm.expires'), 'DESC')
;

return $qb->getQuery()->getResult();
}

public function deleteBySeries(string $encodedSeries): int
{
$table = $this->getClassMetadata()->getTableName();

return $this->connection->delete($table, ['series' => $encodedSeries]);
}

public function deleteExpired(int $lastUsedLifetime, int $expiresLifetime): int
{
$table = $this->getClassMetadata()->getTableName();

return $this->connection->executeUpdate(
"DELETE FROM $table WHERE lastUsed<:lastUsed OR expires<:expires",
[
'lastUsed' => (new \DateTime())->sub(new \DateInterval('PT'.$lastUsedLifetime.'S')),
'expires' => (new \DateTime())->sub(new \DateInterval('PT'.$expiresLifetime.'S')),
],
[
'lastUsed' => DoctrineType::DATETIME,
'expires' => DoctrineType::DATETIME,
]
);
}

public function persist(RememberMe ...$entities)
{
foreach ($entities as $entity) {
$this->_em->persist($entity);
}

$this->_em->flush();
}
}
8 changes: 7 additions & 1 deletion core-bundle/src/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,12 @@ services:
- '%contao.prepend_locale%'
public: true

contao.repository.remember_me:
class: Contao\CoreBundle\Repository\RememberMeRepository
arguments:
- '@doctrine'
- 'Contao\CoreBundle\Entity\RememberMe'

contao.security.authentication_failure_handler:
class: Contao\CoreBundle\Security\Authentication\AuthenticationFailureHandler
arguments:
Expand Down Expand Up @@ -461,7 +467,7 @@ services:
contao.security.expiring_token_based_rememberme_services:
class: Contao\CoreBundle\Security\Authentication\RememberMe\ExpiringTokenBasedRememberMeServices
arguments:
- '@database_connection'
- '@contao.repository.remember_me'
- ~ # User Providers
- ~ # Shared Token Key
- ~ # Shared Provider Key
Expand Down
Loading

0 comments on commit e98ce36

Please sign in to comment.