Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f64b805

Browse filesBrowse files
committed
add security.firewalls.not_full_fledged_handler option
if not authenticated at all use callback instead boolean
1 parent 1a16ebc commit f64b805
Copy full SHA for f64b805

File tree

13 files changed

+216
-12
lines changed
Filter options

13 files changed

+216
-12
lines changed

‎src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Allow configuring the secret used to sign login links
8+
* Add `security.firewalls.not_full_fledged_handler` option to configure behavior where user is not full fledged
89

910
7.1
1011
---

‎src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep
176176
'access_denied_url' => $firewallConfig->getAccessDeniedUrl(),
177177
'user_checker' => $firewallConfig->getUserChecker(),
178178
'authenticators' => $firewallConfig->getAuthenticators(),
179+
'not_full_fledged_handler' => $firewallConfig->getNotFullFledgedHandler(),
179180
];
180181

181182
// generate exit impersonation path from current request

‎src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
2020
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
2121
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
22+
use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandle;
2223

2324
/**
2425
* SecurityExtension configuration structure.
@@ -214,6 +215,14 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
214215
->booleanNode('stateless')->defaultFalse()->end()
215216
->booleanNode('lazy')->defaultFalse()->end()
216217
->scalarNode('context')->cannotBeEmpty()->end()
218+
->scalarNode('not_full_fledged_handler')
219+
->beforeNormalization()
220+
->ifTrue(fn ($v): bool => $v == 'original')
221+
->then(fn ($v) => null)
222+
->ifTrue(fn ($v): bool => $v == 'same')
223+
->then(fn ($v) => SameAsNotFullFledgedHandle::class)
224+
->end()
225+
->end()
217226
->arrayNode('logout')
218227
->treatTrueLike([])
219228
->canBeUnset()

‎src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
579579

580580
$config->replaceArgument(10, $listenerKeys);
581581
$config->replaceArgument(11, $firewall['switch_user'] ?? null);
582+
$config->replaceArgument(13, $firewall['not_full_fledged_handler'] ?? null);
582583

583584
return [$matcher, $listeners, $exceptionListener, null !== $logoutListenerId ? new Reference($logoutListenerId) : null, $firewallAuthenticationProviders];
584585
}
@@ -885,6 +886,11 @@ private function createExceptionListener(ContainerBuilder $container, array $con
885886
$listener->replaceArgument(5, $config['access_denied_url']);
886887
}
887888

889+
// not full fledged handler setup
890+
if (isset($config['not_full_fledged_handler'])) {
891+
$listener->replaceArgument(9, new Reference($config['not_full_fledged_handler']));
892+
}
893+
888894
return $exceptionListenerId;
889895
}
890896

‎src/Symfony/Bundle/SecurityBundle/Resources/config/security.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Resources/config/security.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
use Symfony\Component\Security\Core\User\MissingUserProvider;
4343
use Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator;
4444
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
45+
use Symfony\Component\Security\Http\Authorization\SameAsNotFullFledgedHandle;
4546
use Symfony\Component\Security\Http\Controller\SecurityTokenValueResolver;
4647
use Symfony\Component\Security\Http\Controller\UserValueResolver;
4748
use Symfony\Component\Security\Http\EventListener\IsGrantedAttributeListener;
@@ -218,6 +219,7 @@
218219
[], // listeners
219220
null, // switch_user
220221
null, // logout
222+
null, //not_full_fledged_handler
221223
])
222224

223225
->set('security.logout_url_generator', LogoutUrlGenerator::class)
@@ -310,5 +312,7 @@
310312
->set('cache.security_is_csrf_token_valid_attribute_expression_language')
311313
->parent('cache.system')
312314
->tag('cache.pool')
315+
316+
->set('security.same_as_not_full_fledged_handle', SameAsNotFullFledgedHandle::class)
313317
;
314318
};

‎src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
service('security.access.denied_handler')->nullOnInvalid(),
140140
service('logger')->nullOnInvalid(),
141141
false, // Stateless
142+
service('security.not.full.fledged_handler')->nullOnInvalid(),
142143
])
143144
->tag('monolog.logger', ['channel' => 'security'])
144145

‎src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,10 @@
301301
<th>authenticators</th>
302302
<td>{{ collector.firewall.authenticators is empty ? '(none)' : profiler_dump(collector.firewall.authenticators, maxDepth=1) }}</td>
303303
</tr>
304+
<tr>
305+
<th>not_full_fledged_handler</th>
306+
<td>{{ collector.firewall.not_full_fledged_handler ?: '(none)' }}</td>
307+
</tr>
304308
</tbody>
305309
</table>
306310
{% endif %}

‎src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function __construct(
3030
private readonly array $authenticators = [],
3131
private readonly ?array $switchUser = null,
3232
private readonly ?array $logout = null,
33+
private readonly ?string $notFullFledgedHandler = null,
3334
) {
3435
}
3536

@@ -104,4 +105,9 @@ public function getLogout(): ?array
104105
{
105106
return $this->logout;
106107
}
108+
109+
public function getNotFullFledgedHandler(): ?string
110+
{
111+
return $this->notFullFledgedHandler;
112+
}
107113
}

‎src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ public function testFirewalls()
149149
[],
150150
null,
151151
null,
152+
null,
152153
],
153154
[
154155
'secure',
@@ -184,6 +185,7 @@ public function testFirewalls()
184185
'enable_csrf' => null,
185186
'clear_site_data' => [],
186187
],
188+
null,
187189
],
188190
[
189191
'host',
@@ -201,6 +203,7 @@ public function testFirewalls()
201203
],
202204
null,
203205
null,
206+
null,
204207
],
205208
[
206209
'with_user_checker',
@@ -218,6 +221,7 @@ public function testFirewalls()
218221
],
219222
null,
220223
null,
224+
null,
221225
],
222226
], $configs);
223227

+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Http\Authorization;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
17+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
18+
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
19+
20+
/**
21+
* This is used by the ExceptionListener to translate an AccessDeniedException
22+
* to a Response object.
23+
*
24+
* @author Roman JOLY <eltharin18@outlook.fr>
25+
*/
26+
interface NotFullFledgedHandlerInterface
27+
{
28+
/**
29+
* Handles a not full fledged case for acces denied failure.
30+
* @return null|Response
31+
* null: throw original AcessDeniedException
32+
* Response: you can return your own response, AccesDeniedException wil be ignored
33+
*/
34+
public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response;
35+
}
+43Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Http\Authorization;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
17+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
18+
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
19+
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
20+
21+
/**
22+
* This is a basic NotFullFledgedHandle
23+
* If IS_AUTHENTICATED_FULLY is in access denied Exception Attrribute, behavior will be as before,
24+
* Otherwise The original AccessDeniedException is throw
25+
*
26+
* @author Roman JOLY <eltharin18@outlook.fr>
27+
*/
28+
class SameAsNotFullFledgedHandle implements NotFullFledgedHandlerInterface
29+
{
30+
public function handle(Request $request, AccessDeniedException $accessDeniedException, AuthenticationTrustResolverInterface $trustResolver, ?TokenInterface $token, callable $reauthenticateResponse): ?Response
31+
{
32+
if( !$trustResolver->isAuthenticated($token)) {
33+
$reauthenticateResponse();
34+
}
35+
36+
foreach($accessDeniedException->getAttributes() as $attribute) {
37+
if(in_array($attribute, [AuthenticatedVoter::IS_AUTHENTICATED_FULLY])) {
38+
$reauthenticateResponse();
39+
}
40+
}
41+
return null;
42+
}
43+
}

‎src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php
+24-9Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Symfony\Component\Security\Core\Exception\LazyResponseException;
3030
use Symfony\Component\Security\Core\Exception\LogoutException;
3131
use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
32+
use Symfony\Component\Security\Http\Authorization\NotFullFledgedHandlerInterface;
3233
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
3334
use Symfony\Component\Security\Http\EntryPoint\Exception\NotAnEntryPointException;
3435
use Symfony\Component\Security\Http\HttpUtils;
@@ -57,6 +58,7 @@ public function __construct(
5758
private ?AccessDeniedHandlerInterface $accessDeniedHandler = null,
5859
private ?LoggerInterface $logger = null,
5960
private bool $stateless = false,
61+
private ?NotFullFledgedHandlerInterface $notFullFledgedHandler = null,
6062
) {
6163
}
6264

@@ -127,20 +129,33 @@ private function handleAccessDeniedException(ExceptionEvent $event, AccessDenied
127129

128130
$token = $this->tokenStorage->getToken();
129131
if (!$this->authenticationTrustResolver->isFullFledged($token)) {
130-
$this->logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]);
131132

132-
try {
133-
$insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception);
134-
if (null !== $token) {
135-
$insufficientAuthenticationException->setToken($token);
133+
$starAuthenticationResponse = function () use($exception, $event, $token) {
134+
$this->logger?->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]);
135+
136+
try {
137+
$insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception);
138+
if (null !== $token) {
139+
$insufficientAuthenticationException->setToken($token);
140+
}
141+
142+
$event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));
143+
} catch (\Exception $e) {
144+
$event->setThrowable($e);
136145
}
146+
};
137147

138-
$event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));
139-
} catch (\Exception $e) {
140-
$event->setThrowable($e);
148+
if(null === $this->notFullFledgedHandler) {
149+
$starAuthenticationResponse();
150+
return;
141151
}
142152

143-
return;
153+
$response = $this->notFullFledgedHandler->handle($event->getRequest(), $exception,$this->authenticationTrustResolver, $token, $starAuthenticationResponse);
154+
155+
if ($response instanceof Response) {
156+
$event->setResponse($response);
157+
return;
158+
}
144159
}
145160

146161
$this->logger?->debug('Access denied, the user is neither anonymous, nor remember-me.', ['exception' => $exception]);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.