Skip to content

[Security] Deprecate "always authenticate" and "exception on no token" #41965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions UPGRADE-5.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,17 @@ HttpKernel
----------

* Deprecate `AbstractTestSessionListener::getSession` inject a session in the request instead

SecurityBundle
--------------

* Deprecate the `always_authenticate_before_granting` option

Security
--------

* Deprecate setting the 4th argument (`$alwaysAuthenticate`) to `true` and not setting the
5th argument (`$exceptionOnNoToken`) to `false` of `AuthorizationChecker` (this is the default
behavior when using `enable_authenticator_manager: true`)
* Deprecate not setting the 5th argument (`$exceptionOnNoToken`) of `AccessListener` to `false`
(this is the default behavior when using `enable_authenticator_manager: true`)
3 changes: 3 additions & 0 deletions UPGRADE-6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ Routing
Security
--------

* Remove the 4th and 5th argument of `AuthorizationChecker`
* Remove the 5th argument of `AccessListener`
* Remove class `User`, use `InMemoryUser` or your own implementation instead.
If you are using the `isAccountNonLocked()`, `isAccountNonExpired()` or `isCredentialsNonExpired()` method, consider re-implementing them
in your own user class as they are not part of the `InMemoryUser` API
Expand Down Expand Up @@ -313,6 +315,7 @@ Security
SecurityBundle
--------------

* Remove the `always_authenticate_before_granting` option
* Remove the `UserPasswordEncoderCommand` class and the corresponding `user:encode-password` command,
use `UserPasswordHashCommand` and `user:hash-password` instead
* Remove the `security.encoder_factory.generic` service, the `security.encoder_factory` and `Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface` aliases,
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Bundle/SecurityBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

5.4
---

* Deprecate the `always_authenticate_before_granting` option

5.3
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ public function getConfigTreeBuilder()
->defaultValue(SessionAuthenticationStrategy::MIGRATE)
->end()
->booleanNode('hide_user_not_found')->defaultTrue()->end()
->booleanNode('always_authenticate_before_granting')->defaultFalse()->end()
->booleanNode('always_authenticate_before_granting')
->defaultFalse()
->setDeprecated('symfony/security-bundle', '5.4')
->end()
->booleanNode('erase_credentials')->defaultTrue()->end()
->booleanNode('enable_authenticator_manager')->defaultFalse()->info('Enables the new Symfony Security system based on Authenticators, all used authenticators must support this before enabling this.')->end()
->arrayNode('access_decision_manager')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,9 @@ public function provideEntryPointRequiredData()
];
}

/**
* @group legacy
*/
public function testAlwaysAuthenticateBeforeGrantingCannotBeTrueWithAuthenticatorManager()
{
$this->expectException(InvalidConfigurationException::class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ class AuthorizationChecker implements AuthorizationCheckerInterface

public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager, bool $alwaysAuthenticate = false, bool $exceptionOnNoToken = true)
{
if (false !== $alwaysAuthenticate) {
trigger_deprecation('symfony/security-core', '5.4', 'Not setting the 4th argument of "%s" to "false" is deprecated.', __METHOD__);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor) we might prefer talking about arguments names over positions in deprecation messages, see e.g. 8e3058d

}
if (false !== $exceptionOnNoToken) {
trigger_deprecation('symfony/security-core', '5.4', 'Not setting the 5th argument of "%s" to "false" is deprecated.', __METHOD__);
}

$this->tokenStorage = $tokenStorage;
$this->authenticationManager = $authenticationManager;
$this->accessDecisionManager = $accessDecisionManager;
Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/Security/Core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
CHANGELOG
=========

5.4
---

* Deprecate setting the 4th argument (`$alwaysAuthenticate`) to `true` and not setting the
5th argument (`$exceptionOnNoToken`) to `false` of `AuthorizationChecker`

5.3
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ protected function setUp(): void
$this->authorizationChecker = new AuthorizationChecker(
$this->tokenStorage,
$this->authenticationManager,
$this->accessDecisionManager
$this->accessDecisionManager,
false,
false
);
}

Expand Down Expand Up @@ -71,13 +73,23 @@ public function testVoteAuthenticatesTokenIfNecessary()
$this->assertSame($newToken, $this->tokenStorage->getToken());
}

public function testVoteWithoutAuthenticationToken()
/**
* @group legacy
*/
public function testLegacyVoteWithoutAuthenticationToken()
{
$authorizationChecker = new AuthorizationChecker(
$this->tokenStorage,
$this->authenticationManager,
$this->accessDecisionManager
);

$this->expectException(AuthenticationCredentialsNotFoundException::class);
$this->authorizationChecker->isGranted('ROLE_FOO');

$authorizationChecker->isGranted('ROLE_FOO');
}

public function testVoteWithoutAuthenticationTokenAndExceptionOnNoTokenIsFalse()
public function testVoteWithoutAuthenticationToken()
{
$authorizationChecker = new AuthorizationChecker($this->tokenStorage, $this->authenticationManager, $this->accessDecisionManager, false, false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function testIsAuthenticated($token, $expression, $result)
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$accessDecisionManager = new AccessDecisionManager([new RoleVoter(), new AuthenticatedVoter($trustResolver)]);
$authChecker = new AuthorizationChecker($tokenStorage, $this->createMock(AuthenticationManagerInterface::class), $accessDecisionManager);
$authChecker = new AuthorizationChecker($tokenStorage, $this->createMock(AuthenticationManagerInterface::class), $accessDecisionManager, false, false);

$context = [];
$context['auth_checker'] = $authChecker;
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Security/Http/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

5.4
---

* Deprecate not setting the 5th argument (`$exceptionOnNoToken`) of `AccessListener` to `false`

5.3
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class AccessListener extends AbstractListener

public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, AuthenticationManagerInterface $authManager, bool $exceptionOnNoToken = true)
{
if (false !== $exceptionOnNoToken) {
trigger_deprecation('symfony/security-core', '5.4', 'Not setting the 5th argument of "%s" to "false" is deprecated.', __METHOD__);
}

$this->tokenStorage = $tokenStorage;
$this->accessDecisionManager = $accessDecisionManager;
$this->map = $map;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ public function testHandleWhenTheAccessDecisionManagerDecidesToRefuseAccess()
$tokenStorage,
$accessDecisionManager,
$accessMap,
$this->createMock(AuthenticationManagerInterface::class)
$this->createMock(AuthenticationManagerInterface::class),
false,
false
);

$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST));
Expand Down Expand Up @@ -135,7 +137,9 @@ public function testHandleWhenTheTokenIsNotAuthenticated()
$tokenStorage,
$accessDecisionManager,
$accessMap,
$authManager
$authManager,
false,
false
);

$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST));
Expand Down Expand Up @@ -170,7 +174,9 @@ public function testHandleWhenThereIsNoAccessMapEntryMatchingTheRequest()
$tokenStorage,
$this->createMock(AccessDecisionManagerInterface::class),
$accessMap,
$this->createMock(AuthenticationManagerInterface::class)
$this->createMock(AuthenticationManagerInterface::class),
false,
false
);

$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST));
Expand Down Expand Up @@ -198,15 +204,20 @@ public function testHandleWhenAccessMapReturnsEmptyAttributes()
$tokenStorage,
$this->createMock(AccessDecisionManagerInterface::class),
$accessMap,
$this->createMock(AuthenticationManagerInterface::class)
$this->createMock(AuthenticationManagerInterface::class),
false,
false
);

$event = new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);

$listener(new LazyResponseEvent($event));
}

public function testHandleWhenTheSecurityTokenStorageHasNoToken()
/**
* @group legacy
*/
public function testLegacyHandleWhenTheSecurityTokenStorageHasNoToken()
{
$this->expectException(AuthenticationCredentialsNotFoundException::class);
$tokenStorage = $this->createMock(TokenStorageInterface::class);
Expand Down Expand Up @@ -236,7 +247,7 @@ public function testHandleWhenTheSecurityTokenStorageHasNoToken()
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST));
}

public function testHandleWhenTheSecurityTokenStorageHasNoTokenAndExceptionOnTokenIsFalse()
public function testHandleWhenTheSecurityTokenStorageHasNoToken()
{
$this->expectException(AccessDeniedException::class);
$tokenStorage = new TokenStorage();
Expand All @@ -260,13 +271,14 @@ public function testHandleWhenTheSecurityTokenStorageHasNoTokenAndExceptionOnTok
$accessDecisionManager,
$accessMap,
$this->createMock(AuthenticationManagerInterface::class),
false,
false
);

$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST));
}

public function testHandleWhenPublicAccessIsAllowedAndExceptionOnTokenIsFalse()
public function testHandleWhenPublicAccessIsAllowed()
{
$tokenStorage = new TokenStorage();
$request = new Request();
Expand All @@ -289,6 +301,7 @@ public function testHandleWhenPublicAccessIsAllowedAndExceptionOnTokenIsFalse()
$accessDecisionManager,
$accessMap,
$this->createMock(AuthenticationManagerInterface::class),
false,
false
);

Expand Down Expand Up @@ -320,6 +333,7 @@ public function testHandleWhenPublicAccessWhileAuthenticated()
$accessDecisionManager,
$accessMap,
$this->createMock(AuthenticationManagerInterface::class),
false,
false
);

Expand Down Expand Up @@ -355,7 +369,9 @@ public function testHandleMWithultipleAttributesShouldBeHandledAsAnd()
$tokenStorage,
$accessDecisionManager,
$accessMap,
$this->createMock(AuthenticationManagerInterface::class)
$this->createMock(AuthenticationManagerInterface::class),
false,
false
);

$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST));
Expand Down