Commit ca3971b3 authored by Baudouin Feildel's avatar Baudouin Feildel
Browse files

Enable login from LizmapUser and User transparently

parent 773b2cd5
......@@ -8,11 +8,20 @@ security:
algorithm: bcrypt
providers:
ddecinfo_db:
ddecinfo_users:
entity:
class: App\Entity\User
manager_name: ddec
lizmap_users:
entity:
class: App\Entity\Lizmap\LizmapUser
manager_name: lizmap
users:
chain:
providers: ['ddecinfo_users', 'lizmap_users']
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
......@@ -22,6 +31,7 @@ security:
pattern: ^/admin
#host: ^ddec-info-admin\.example\.com$
user_checker: App\Security\UserChecker
provider: users
anonymous: ~
form_login:
login_path: admin_login
......@@ -33,6 +43,7 @@ security:
main:
anonymous: ~
user_checker: App\Security\UserChecker
provider: users
guard:
authenticators:
......
......@@ -37,6 +37,9 @@ services:
tags:
- {name: kernel.event_listener, event: security.interactive_login, method: 'onLogin'}
App\EventListener\LizmapUserLoadListener:
tags:
- {name: doctrine.event_listener, event: postLoad}
App\Controller\ExceptionController:
public: true
......
......@@ -101,6 +101,11 @@ class LizmapUser implements UserInterface
*/
private $changed = false;
/**
* @var string[] User roles
*/
private $roles = ['ROLE_USER'];
public function __construct($login) {
$this->usr_login = $login;
}
......@@ -140,6 +145,10 @@ class LizmapUser implements UserInterface
return $this->lastname;
}
public function getName(): string {
return $this->firstname . ' ' . $this->lastname;
}
/**
* @return string
*/
......@@ -337,7 +346,15 @@ class LizmapUser implements UserInterface
* @return (Role|string)[] The user roles
*/
public function getRoles() {
return [];
return $this->roles;
}
/**
* Set user roles
* @param string[] $roles
*/
public function setRoles(array $roles) {
$this->roles = $roles;
}
/**
......
......@@ -4,6 +4,7 @@ namespace App\EventListener;
use App\Entity\User;
use App\Service\UsersTools;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\ORMException;
use Psr\Log\LoggerInterface;
......@@ -13,16 +14,18 @@ class AuthenticationListener
{
private $em;
private $logger;
private $usersTools;
public function __construct(ManagerRegistry $doctrine, LoggerInterface $logger) {
public function __construct(UsersTools $usersTools, ManagerRegistry $doctrine, LoggerInterface $logger) {
$this->usersTools = $usersTools;
$this->em = $doctrine->getManager('ddec');
$this->logger = $logger;
}
public function onLogin(InteractiveLoginEvent $event)
{
$user = $event->getAuthenticationToken()->getUser();
if($user instanceof User)
$user = $this->usersTools->getUserFromToken($event->getAuthenticationToken());
if($user !== null && $user instanceof User)
{
$user->setLastLogin(date_create());
try {
......@@ -34,7 +37,7 @@ class AuthenticationListener
}
else
{
$this->logger->warning("user is not a User instance in authentication event");
$this->logger->warning("Cannot load user from authentication event");
}
}
}
\ No newline at end of file
<?php
namespace App\EventListener;
use App\Entity\Lizmap\LizmapUser;
use App\Repository\UserRepository;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
class LizmapUserLoadListener
{
private $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function postLoad(LifecycleEventArgs $args) {
$entity = $args->getObject();
if (!$entity instanceof LizmapUser)
return;
$ddecInfoUser = $this->userRepository->fromLizmapUser($entity);
if ($ddecInfoUser !== null) {
$entity->setRoles($ddecInfoUser->getRoles());
}
}
}
\ No newline at end of file
......@@ -6,9 +6,12 @@ namespace App\Repository\Lizmap;
use App\Entity\Lizmap\LizmapUser;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NonUniqueResultException;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class LizmapUserRepository extends EntityRepository implements ServiceEntityRepositoryInterface
class LizmapUserRepository extends EntityRepository implements ServiceEntityRepositoryInterface, UserLoaderInterface
{
public function __construct(RegistryInterface $registry)
{
......@@ -29,4 +32,25 @@ class LizmapUserRepository extends EntityRepository implements ServiceEntityRepo
;
}
*/
/**
* Loads the user for the given username.
*
* This method must return null if the user is not found.
*
* @param string $username The username
*
* @return UserInterface|null
*/
public function loadUserByUsername($username) {
try {
return $this->createQueryBuilder('u')
->where('u.usr_login = :username')
->setParameter('username', $username)
->getQuery()
->getOneOrNullResult();
} catch (NonUniqueResultException $e) {
return null;
}
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@
namespace App\Repository;
use App\Entity\Lizmap\LizmapUser;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\NonUniqueResultException;
......@@ -66,6 +67,23 @@ class UserRepository extends ServiceEntityRepository implements UserLoaderInterf
->execute();
}
/**
* Get user from LizmapUser
* @param LizmapUser $user
* @return User|null
*/
public function fromLizmapUser(LizmapUser $user) {
try {
return $this->createQueryBuilder('u')
->where('u.lizmap_login = :usr_login')
->setParameter('usr_login', $user->getLogin())
->getQuery()
->getOneOrNullResult();
} catch (NonUniqueResultException $e) {
return null;
}
}
/*
public function findBySomething($value)
{
......
......@@ -7,6 +7,7 @@ use App\Entity\Content\AbstractPage;
use App\Entity\EntityWithPermInterface;
use App\Entity\User;
use App\Service\Settings;
use App\Service\UsersTools;
use App\Utils\StringUtils;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
......@@ -22,9 +23,12 @@ class PageVoter extends Voter
private $settings;
public function __construct(LoggerInterface $logger, Settings $settings) {
private $usersTools;
public function __construct(UsersTools $usersTools, LoggerInterface $logger, Settings $settings) {
$this->logger = $logger;
$this->settings = $settings;
$this->usersTools = $usersTools;
}
/**
......@@ -54,9 +58,9 @@ class PageVoter extends Voter
return true;
if($attribute == self::ATTRIBUTE_READ)
return $this->userCanRead($token->getUser(), $page);
return $this->userCanRead($this->usersTools->getUserFromToken($token), $page);
return $this->userCanWrite($token->getUser(), $page);
return $this->userCanWrite($this->usersTools->getUserFromToken($token), $page);
}
/**
......
......@@ -11,9 +11,11 @@ use App\Repository\GroupRepository;
use App\Repository\Lizmap\LizmapUserRepository;
use App\Repository\UserRepository;
use App\Service\ApiKeyGenerator;
use App\Service\UsersTools;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Id\UuidGenerator;
use Exception;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
......@@ -81,6 +83,11 @@ class UserImporter extends AbstractImporter
*/
private $importLogger;
/**
* @var UsersTools
*/
private $usersTools;
/**
* @var Group[]
*/
......@@ -92,7 +99,8 @@ class UserImporter extends AbstractImporter
LoggerInterface $logger,
ApiKeyGenerator $apiKeyGenerator,
UserPasswordEncoderInterface $encoder,
ImportLogger $importLogger)
ImportLogger $importLogger,
UsersTools $usersTools)
{
parent::__construct($this, $logger);
......@@ -108,6 +116,7 @@ class UserImporter extends AbstractImporter
$this->apiKeyGenerator = $apiKeyGenerator;
$this->passwordEncoder = $encoder;
$this->importLogger = $importLogger;
$this->usersTools = $usersTools;
}
protected function flushRepository(): void {
......@@ -194,7 +203,7 @@ class UserImporter extends AbstractImporter
private function getRandomBytes(int $length = 10): string {
try {
return bin2hex(random_bytes($length));
} catch (\Exception $e) {
} catch (Exception $e) {
return uniqid(time(), true);
}
}
......@@ -299,8 +308,7 @@ class UserImporter extends AbstractImporter
}
protected function clearRepository(): void {
/** @var User $user */
$user = $this->token->getToken()->getUser();
$user = $this->usersTools->getUserFromToken($this->token->getToken());
$this->logger->info("Clear user table, except for current logged in user", ['currentUser' => $user]);
$this->userRepository->truncateExcept([$user->getId()]);
}
......
......@@ -8,6 +8,7 @@ use App\Entity\User;
use App\Repository\GroupRepository;
use App\Repository\Lizmap\LizmapUserRepository;
use App\Repository\UserRepository;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class UsersTools
{
......@@ -50,4 +51,19 @@ class UsersTools
/** @noinspection PhpIncompatibleReturnTypeInspection */
return $this->userRepo->findOneBy(['lizmap_login' => $lizmapUser->getLogin()]);
}
public function getUserFromToken(?TokenInterface $token) : ?User {
if ($token === null)
return null;
$tokenUser = $token->getUser();
if ($tokenUser instanceof LizmapUser)
return $this->userRepo->fromLizmapUser($tokenUser);
if ($tokenUser instanceof User)
return $tokenUser;
return null;
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment