Open
Description
Version(s) affected
5.2
Description
User check is not considered when login
How to reproduce
UserChecker check if user have "login" in role array
<?php
namespace App\Security;
use App\Entity\User as AppUser;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
class UserChecker implements UserCheckerInterface {
public function __construct(private readonly TranslatorInterface $translator) {
}
public function checkPreAuth(UserInterface $user): void {
if (!$user instanceof AppUser) {
return;
}
if (!in_array('login', $user->getRoles())) {
throw new CustomUserMessageAuthenticationException(
$this->translator->trans('Not privileged to request the resource.', [], 'security')
);
}
}
public function checkPostAuth(UserInterface $user): void {
if (!$user instanceof AppUser) {
return;
}
}
}
Security configuration
security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
user_checker: App\Security\UserChecker
logout:
path: security.logout
target: security.login
custom_authenticators:
- App\Security\LoginFormAuthenticator
- App\Security\CustomWebAuthnAuthenticator
entry_point: App\Security\LoginFormAuthenticator
access_control:
- { path: ^/(login|logout|fr|en|reset-password), requires_channel: 'https', roles: PUBLIC_ACCESS }
- { path: ^/, requires_channel: 'https', roles: IS_AUTHENTICATED_FULLY }
App\Security\CustomWebAuthnAuthenticator
<?php
namespace App\Security;
use App\Repository\UserRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Contracts\Translation\TranslatorInterface;
use Webauthn\Bundle\Security\Authentication\WebauthnBadge;
use Webauthn\Bundle\Security\Authentication\WebauthnPassport;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
/**
* @see https://symfony.com/doc/current/security/custom_authenticator.html
*/
class CustomWebAuthnAuthenticator extends AbstractAuthenticator {
public function __construct(
private readonly UrlGeneratorInterface $urlGenerator,
private readonly RouterInterface $router,
private readonly UserRepository $userRepository,
private readonly TranslatorInterface $translator
) {
}
public function supports(Request $request): ?bool {
return $request->isMethod('POST') && $request->getPathInfo() === $this->router->generate('webauthn.controller.request.response.login');
}
public function authenticate(Request $request): Passport {
return new WebauthnPassport( #Dedicated Passport
new WebauthnBadge( # Dedicated badge
$request->getHost(),
$request->getContent() // From the login form. See below
)
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response {
return new JsonResponse([
'status' => 'ok',
'message' => 'Authentication successful',
'user' => $token->getUserIdentifier(),
], Response::HTTP_OK);
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response {
$data = ['message' => strtr($exception->getMessageKey(), $exception->getMessageData())];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
}
Possible Solution
No response
Additional Context
No response
Metadata
Metadata
Assignees
Labels
No labels