Skip to content

Commit

Permalink
use callback instead boolean
Browse files Browse the repository at this point in the history
  • Loading branch information
eltharin committed Jul 9, 2024
1 parent a7ace88 commit bdb9552
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

/**
Expand All @@ -25,10 +27,9 @@ interface NotFullFledgedHandlerInterface
{
/**
* Handles a not full fledged case for acces denied failure.
* @return bool|Response : bool|Response
* true : user have to be fully authenticated, continu to startAuthentication
* false : user have'nt to be fully authenticated, throw original AcessDeniedException
* @return null|Response
* null: throw original AcessDeniedException
* Response: you can return your own response, AccesDeniedException wil be ignored
*/
public function handle(Request $request, AccessDeniedException $accessDeniedException): bool|Response;
public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

Expand All @@ -25,13 +27,17 @@
*/
class SameAsNotFullFledgedHandle implements NotFullFledgedHandlerInterface
{
public function handle(Request $request, AccessDeniedException $accessDeniedException): bool|Response
public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response
{
if( !$trustResolver->isAuthenticated($token)) {
$reauthenticateResponse();
}

foreach($accessDeniedException->getAttributes() as $attribute) {
if(in_array($attribute, [AuthenticatedVoter::IS_AUTHENTICATED_FULLY])) {
return true;
$reauthenticateResponse();
}
}
return false;
return null;
}
}
15 changes: 11 additions & 4 deletions src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,8 @@ private function handleAccessDeniedException(ExceptionEvent $event, AccessDenied

$token = $this->tokenStorage->getToken();
if (!$this->authenticationTrustResolver->isFullFledged($token)) {
$response = ((!$this->authenticationTrustResolver->isAuthenticated($token)) || (null === $this->notFullFledgedHandler) ? true : $this->notFullFledgedHandler->handle($event->getRequest(), $exception));

if ($response instanceof Response) {
$event->setResponse($response);
} elseif ($response === true) {
$starAuthenticationResponse = function () use($exception, $event, $token) {
$this->logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]);

try {
Expand All @@ -146,7 +143,17 @@ private function handleAccessDeniedException(ExceptionEvent $event, AccessDenied
} catch (\Exception $e) {
$event->setThrowable($e);
}
};

if(null === $this->notFullFledgedHandler) {
$starAuthenticationResponse();
return;
}

$response = $this->notFullFledgedHandler->handle($event->getRequest(), $exception,$this->authenticationTrustResolver, $token, $starAuthenticationResponse);

if ($response instanceof Response) {
$event->setResponse($response);
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,40 +149,6 @@ public function testAccessDeniedExceptionNotFullFledged(\Exception $exception, ?
$this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious());
}

/**
* @dataProvider getAccessDeniedExceptionProvider
*/
public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseTrueNotAuthenticated(\Exception $exception, ?\Exception $eventException = null)
{
$event = $this->createEvent($exception);

$tokenStorage = $this->createMock(TokenStorageInterface::class);
$tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class));

$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,false), null, $this->createEntryPoint(), null, null, $this->createNotFullFledgedHandler(false));
$listener->onKernelException($event);

$this->assertEquals('OK', $event->getResponse()->getContent());
$this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious());
}

/**
* @dataProvider getAccessDeniedExceptionProvider
*/
public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseFalseNotAuthenticated(\Exception $exception, ?\Exception $eventException = null)
{
$event = $this->createEvent($exception);

$tokenStorage = $this->createMock(TokenStorageInterface::class);
$tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class));

$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,false), null, $this->createEntryPoint(), null, null, $this->createNotFullFledgedHandler(true));
$listener->onKernelException($event);

$this->assertEquals('OK', $event->getResponse()->getContent());
$this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious());
}

/**
* @dataProvider getAccessDeniedExceptionProvider
*/
Expand All @@ -193,47 +159,30 @@ public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseCustom
$tokenStorage = $this->createMock(TokenStorageInterface::class);
$tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class));

$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,false), null, $this->createEntryPoint(), null, null, $this->createNotFullFledgedHandler(new Response('Full Fledged Response', 401)));
$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,false), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(new Response('Full Fledged Response', 401)));
$listener->onKernelException($event);

$this->assertEquals('OK', $event->getResponse()->getContent());
$this->assertEquals('Full Fledged Response', $event->getResponse()->getContent());
$this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious());
}

/**
* @dataProvider getAccessDeniedExceptionProvider
*/
public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseTrueAuthenticated(\Exception $exception, ?\Exception $eventException = null)
public function testAccessDeniedExceptionNotFullFledgedWithoutHandlerResponseAuthenticated(\Exception $exception, ?\Exception $eventException = null)
{
$event = $this->createEvent($exception);

$tokenStorage = $this->createMock(TokenStorageInterface::class);
$tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class));

$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(false));
$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPointWithoutStartCalled(), null, null, $this->createNotFullFledgedHandler(null));
$listener->onKernelException($event);

$this->assertNull($event->getResponse());
$this->assertEquals($eventException?->getMessage() ?? $exception->getMessage(),$event->getThrowable()->getMessage());
}

/**
* @dataProvider getAccessDeniedExceptionProvider
*/
public function testAccessDeniedExceptionNotFullFledgedWithHandlerResponseFalseAuthenticated(\Exception $exception, ?\Exception $eventException = null)
{
$event = $this->createEvent($exception);

$tokenStorage = $this->createMock(TokenStorageInterface::class);
$tokenStorage->expects($this->once())->method('getToken')->willReturn($this->createMock(TokenInterface::class));

$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false,true), null, $this->createEntryPoint(), null, null, $this->createNotFullFledgedHandler(true));
$listener->onKernelException($event);

$this->assertEquals('OK', $event->getResponse()->getContent());
$this->assertSame($eventException ?? $exception, $event->getThrowable()->getPrevious());
}

/**
* @dataProvider getAccessDeniedExceptionProvider
*/
Expand Down Expand Up @@ -334,7 +283,7 @@ private function createExceptionListener(?TokenStorageInterface $tokenStorage =
);
}

private function createNotFullFledgedHandler(bool|Response $response = false)
private function createNotFullFledgedHandler(?Response $response = null)
{
$entryPoint = $this->createMock(NotFullFledgedHandlerInterface::class);
$entryPoint->method('handle')->willReturn($response);
Expand Down

0 comments on commit bdb9552

Please sign in to comment.