first commit
This commit is contained in:
87
src/Security/CasUserProvider.php
Normal file
87
src/Security/CasUserProvider.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Repository\UserRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
|
||||
class CasUserProvider implements UserProviderInterface
|
||||
{
|
||||
private UserRepository $userRepository;
|
||||
private EntityManagerInterface $em;
|
||||
private ParameterBagInterface $parameterBag;
|
||||
|
||||
public function __construct(UserRepository $userRepository, EntityManagerInterface $em, ParameterBagInterface $parameterBag)
|
||||
{
|
||||
$this->userRepository = $userRepository;
|
||||
$this->em = $em;
|
||||
$this->parameterBag = $parameterBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge un utilisateur par son identifiant CAS.
|
||||
*/
|
||||
public function loadUserByIdentifier(string $identifier): UserInterface
|
||||
{
|
||||
// Récupérer l'utilisateur depuis la base de données
|
||||
$user = $this->userRepository->findOneBy(['username' => $identifier]);
|
||||
|
||||
if (!$user) {
|
||||
throw new UserNotFoundException(sprintf('User with username "%s" not found.', $identifier));
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge un utilisateur par son identifiant CAS et autosubmit autoupdate en fonction des attributs CAS
|
||||
*/
|
||||
public function loadUserByIdentifierAndAttributes(string $identifier, array $attributes): UserInterface
|
||||
{
|
||||
// Charger l'utilisateur existant depuis la base de données
|
||||
$user = $this->userRepository->findOneBy(['username' => $identifier]);
|
||||
|
||||
if (!$user) {
|
||||
// Créer un nouvel utilisateur avec les attributs CAS
|
||||
$user = new User();
|
||||
$user->setUsername($identifier);
|
||||
$user->setPassword(Uuid::uuid4()->toString());
|
||||
$user->setRoles(['ROLE_USER']);
|
||||
|
||||
// Persister l'utilisateur en base si nécessaire
|
||||
$this->em->persist($user);
|
||||
}
|
||||
|
||||
$user->setEmail($attributes[$this->parameterBag->get('casMail')] ?? null);
|
||||
$this->em->flush();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de recharger un utilisateur déjà authentifié (si nécessaire).
|
||||
*/
|
||||
public function refreshUser(UserInterface $user): UserInterface
|
||||
{
|
||||
if (!$user instanceof User) {
|
||||
throw new \InvalidArgumentException(sprintf('Instances of "%s" are not supported.', get_class($user)));
|
||||
}
|
||||
|
||||
// Recharge l'utilisateur en base si nécessaire (ex. : rôles mis à jour)
|
||||
return $this->userRepository->find($user->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indique si ce provider supporte un type d'utilisateur donné.
|
||||
*/
|
||||
public function supportsClass(string $class): bool
|
||||
{
|
||||
return User::class === $class;
|
||||
}
|
||||
}
|
123
src/Security/DynamicAuthenticator.php
Normal file
123
src/Security/DynamicAuthenticator.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use App\Repository\UserRepository;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
|
||||
|
||||
class DynamicAuthenticator extends AbstractAuthenticator
|
||||
{
|
||||
private string $modeAuth;
|
||||
private UserRepository $userRepository;
|
||||
private CasUserProvider $casUserProvider;
|
||||
private ParameterBagInterface $parameterBag;
|
||||
|
||||
public function __construct(string $modeAuth, UserRepository $userRepository, CasUserProvider $casUserProvider, ParameterBagInterface $parameterBag)
|
||||
{
|
||||
$this->modeAuth = $modeAuth;
|
||||
$this->userRepository = $userRepository;
|
||||
$this->casUserProvider = $casUserProvider;
|
||||
$this->parameterBag = $parameterBag;
|
||||
}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
// Vérifie si l'utilisateur est déjà connecté
|
||||
if ($request->getSession()->get('_security_main')) {
|
||||
return false; // L'utilisateur est déjà authentifié
|
||||
}
|
||||
|
||||
// Exclure les routes de login et logout pour éviter les boucles
|
||||
$currentPath = $request->getPathInfo();
|
||||
if (in_array($currentPath, ['/login', '/logout'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): Passport
|
||||
{
|
||||
switch ($this->modeAuth) {
|
||||
case 'SQL':
|
||||
return $this->authenticateWithSql($request);
|
||||
|
||||
case 'CAS':
|
||||
return $this->authenticateWithCas($request);
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException('Invalid authentication method');
|
||||
}
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
||||
{
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
private function authenticateWithSql(Request $request): Passport
|
||||
{
|
||||
$username = $request->request->get('_username', '');
|
||||
$password = $request->request->get('_password', '');
|
||||
|
||||
if (!$username || !$password) {
|
||||
throw new AuthenticationException('Username and password are required.');
|
||||
}
|
||||
|
||||
// Charger l'utilisateur via Doctrine
|
||||
$user = $this->userRepository->findOneBy(['username' => $username]);
|
||||
|
||||
if (!$user) {
|
||||
throw new AuthenticationException('User not found.');
|
||||
}
|
||||
|
||||
return new Passport(
|
||||
new UserBadge($username, function ($userIdentifier) {
|
||||
return $this->userRepository->findOneBy(['username' => $userIdentifier]);
|
||||
}),
|
||||
new PasswordCredentials($password)
|
||||
);
|
||||
}
|
||||
|
||||
private function authenticateWithCas(Request $request): Passport
|
||||
{
|
||||
// Récupérer l'hôte d'origine derrière le reverse proxy
|
||||
$host = $request->headers->get('X-Forwarded-Host') ?? $request->getHost().($request->getPort() ? ':'.$request->getPort() : '');
|
||||
$scheme = $request->headers->get('X-Forwarded-Proto') ?? $request->getScheme();
|
||||
|
||||
// Construire l'URL
|
||||
$url = $scheme.'://'.$host;
|
||||
|
||||
// \phpCAS::setDebug('/tmp/logcas.log');
|
||||
\phpCAS::client(CAS_VERSION_2_0, $this->parameterBag->get('casHost'), (int) $this->parameterBag->get('casPort'), $this->parameterBag->get('casPath'), $url, false);
|
||||
\phpCAS::setNoCasServerValidation();
|
||||
\phpCAS::forceAuthentication();
|
||||
|
||||
$username = \phpCAS::getUser();
|
||||
$attributes = \phpCAS::getAttributes();
|
||||
|
||||
if (!$username) {
|
||||
throw new AuthenticationException('CAS authentication failed.');
|
||||
}
|
||||
|
||||
$userBadge = new UserBadge($username, function ($userIdentifier) use ($attributes) {
|
||||
return $this->casUserProvider->loadUserByIdentifierAndAttributes($userIdentifier, $attributes);
|
||||
});
|
||||
|
||||
return new SelfValidatingPassport($userBadge);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user