Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Security] Deprecate remaining anonymous checks #42510

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
Aug 14, 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
24 changes: 24 additions & 0 deletions UPGRADE-5.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,30 @@ Security
* Deprecate `AnonymousToken`, as the related authenticator was deprecated in 5.3
* Deprecate `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
* Deprecate not returning an `UserInterface` from `Token::getUser()`
* Deprecate `AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY` and `AuthenticatedVoter::IS_ANONYMOUS`,
use `AuthenticatedVoter::PUBLIC_ACCESS` instead.

Before:
```yaml
# config/packages/security.yaml
security:
# ...
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
```

After:
```yaml
# config/packages/security.yaml
security:
# ...
access_control:
- { path: ^/login, roles: PUBLIC_ACCESS }
```

* Deprecate `AuthenticationTrustResolverInterface::isAnonymous()` and the `is_anonymous()` expression function
as anonymous no longer exists in version 6, use the `isFullFledged()` or the new `isAuthenticated()` instead
if you want to check if the request is (fully) authenticated.
* Deprecate the `$authManager` argument of `AccessListener`, the argument will be removed
* Deprecate the `$authenticationManager` argument of the `AuthorizationChecker` constructor, the argument will be removed
* Deprecate setting the `$alwaysAuthenticate` argument to `true` and not setting the
Expand Down
24 changes: 24 additions & 0 deletions UPGRADE-6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,30 @@ Security
* Remove `AnonymousToken`
* Remove `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
* Restrict the return type of `Token::getUser()` to `UserInterface` (removing `string|\Stringable`)
* Remove `AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY` and `AuthenticatedVoter::IS_ANONYMOUS`,
use `AuthenticatedVoter::PUBLIC_ACCESS` instead.

Before:
```yaml
# config/packages/security.yaml
security:
# ...
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
```

After:
```yaml
# config/packages/security.yaml
security:
# ...
access_control:
- { path: ^/login, roles: PUBLIC_ACCESS }
```

* Remove `AuthenticationTrustResolverInterface::isAnonymous()` and the `is_anonymous()` expression function
as anonymous no longer exists in version 6, use the `isFullFledged()` or the new `isAuthenticated()` instead
if you want to check if the request is (fully) authenticated.
* Remove the 4th and 5th argument of `AuthorizationChecker`
* Remove the 5th argument of `AccessListener`
* Remove class `User`, use `InMemoryUser` or your own implementation instead.
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bundle/SecurityBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CHANGELOG
5.4
---

* Deprecate `FirewallConfig::allowsAnonymous()` and the `allows_anonymous` from the data collector data, there will be no anonymous concept as of version 6.
* Deprecate not setting `$authenticatorManagerEnabled` to `true` in `SecurityDataCollector` and `DebugFirewallCommand`
* Deprecate `SecurityFactoryInterface` and `SecurityExtension::addSecurityListenerFactory()` in favor of
`AuthenticatorFactoryInterface` and `SecurityExtension::addAuthenticatorFactory()`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public function collect(Request $request, Response $response, \Throwable $except
if (null !== $firewallConfig) {
$this->data['firewall'] = [
'name' => $firewallConfig->getName(),
'allows_anonymous' => $firewallConfig->allowsAnonymous(),
'allows_anonymous' => $this->authenticatorManagerEnabled ? false : $firewallConfig->allowsAnonymous(),
'request_matcher' => $firewallConfig->getRequestMatcher(),
'security_enabled' => $firewallConfig->isSecurityEnabled(),
'stateless' => $firewallConfig->isStateless(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,13 @@ public function isSecurityEnabled(): bool
return $this->securityEnabled;
}

/**
* @deprecated since Symfony 5.4
*/
public function allowsAnonymous(): bool
{
trigger_deprecation('symfony/security-bundle', '5.4', 'The "%s()" method is deprecated.', __METHOD__);

return \in_array('anonymous', $this->listeners, true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ public function testGetFirewall()
$collected = $collector->getFirewall();

$this->assertSame($firewallConfig->getName(), $collected['name']);
$this->assertSame($firewallConfig->allowsAnonymous(), $collected['allows_anonymous']);
$this->assertSame($firewallConfig->getRequestMatcher(), $collected['request_matcher']);
$this->assertSame($firewallConfig->isSecurityEnabled(), $collected['security_enabled']);
$this->assertSame($firewallConfig->isStateless(), $collected['stateless']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ security:
- { path: ^/secured-by-one-env-placeholder-and-one-real-ip$, ips: ['%env(APP_IP)%', 198.51.100.0], roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured-by-one-env-placeholder-multiple-ips-and-one-real-ip$, ips: ['%env(APP_IPS)%', 198.51.100.0], roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/highly_protected_resource$, roles: IS_ADMIN }
- { path: ^/protected-via-expression$, allow_if: "(is_anonymous() and request.headers.get('user-agent') matches '/Firefox/i') or is_granted('ROLE_USER')" }
- { path: ^/protected-via-expression$, allow_if: "(!is_authenticated() and request.headers.get('user-agent') matches '/Firefox/i') or is_granted('ROLE_USER')" }
- { path: .*, roles: IS_AUTHENTICATED_FULLY }
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class FirewallConfigTest extends TestCase
{
public function testGetters()
{
$listeners = ['logout', 'remember_me', 'anonymous'];
$listeners = ['logout', 'remember_me'];
$options = [
'request_matcher' => 'foo_request_matcher',
'security' => false,
Expand Down Expand Up @@ -57,7 +57,6 @@ public function testGetters()
$this->assertSame($options['access_denied_handler'], $config->getAccessDeniedHandler());
$this->assertSame($options['access_denied_url'], $config->getAccessDeniedUrl());
$this->assertSame($options['user_checker'], $config->getUserChecker());
$this->assertTrue($config->allowsAnonymous());
$this->assertSame($listeners, $config->getListeners());
$this->assertSame($options['switch_user'], $config->getSwitchUser());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,22 @@
*/
class AuthenticationTrustResolver implements AuthenticationTrustResolverInterface
{
public function isAuthenticated(TokenInterface $token = null): bool
{
return null !== $token && !$token instanceof NullToken
// @deprecated since Symfony 5.4, TokenInterface::isAuthenticated() and AnonymousToken no longer exists in 6.0
&& !$token instanceof AnonymousToken && $token->isAuthenticated(false);
}

/**
* {@inheritdoc}
*/
public function isAnonymous(TokenInterface $token = null)
public function isAnonymous(TokenInterface $token = null/*, $deprecation = true*/)
{
if (1 === \func_num_args() || false !== func_get_arg(1)) {
trigger_deprecation('symfony/security-core', '5.4', 'The "%s()" method is deprecated, use "isAuthenticated()" or "isFullFledged()" if you want to check if the request is (fully) authenticated.', __METHOD__);
}

if (null === $token) {
return false;
}
Expand Down Expand Up @@ -56,6 +67,6 @@ public function isFullFledged(TokenInterface $token = null)
return false;
}

return !$this->isAnonymous($token) && !$this->isRememberMe($token);
return !$this->isAnonymous($token, false) && !$this->isRememberMe($token);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* Interface for resolving the authentication status of a given token.
*
* @author Johannes M. Schmitt <[email protected]>
*
* @method bool isAuthenticated(TokenInterface $token = null)
*/
interface AuthenticationTrustResolverInterface
{
Expand All @@ -27,6 +29,8 @@ interface AuthenticationTrustResolverInterface
* If null is passed, the method must return false.
*
* @return bool
*
* @deprecated since Symfony 5.4, use !isAuthenticated() instead
*/
public function isAnonymous(TokenInterface $token = null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;

/**
* Define some ExpressionLanguage functions.
Expand All @@ -25,15 +26,18 @@ public function getFunctions()
{
return [
new ExpressionFunction('is_anonymous', function () {
return '$token && $auth_checker->isGranted("IS_ANONYMOUS")';
return 'trigger_deprecation("symfony/security-core", "5.4", "The \"is_anonymous()\" expression function is deprecated.") || ($token && $auth_checker->isGranted("IS_ANONYMOUS"))';
}, function (array $variables) {
trigger_deprecation('symfony/security-core', '5.4', 'The "is_anonymous()" expression function is deprecated.');

return $variables['token'] && $variables['auth_checker']->isGranted('IS_ANONYMOUS');
}),

// @deprecated remove the ternary and always use IS_AUTHENTICATED in 6.0
new ExpressionFunction('is_authenticated', function () {
return '$token && !$auth_checker->isGranted("IS_ANONYMOUS")';
return 'defined("'.AuthenticatedVoter::class.'::IS_AUTHENTICATED") ? $auth_checker->isGranted("IS_AUTHENTICATED") : ($token && !$auth_checker->isGranted("IS_ANONYMOUS"))';
}, function (array $variables) {
return $variables['token'] && !$variables['auth_checker']->isGranted('IS_ANONYMOUS');
return \defined(AuthenticatedVoter::class.'::IS_AUTHENTICATED') ? $variables['auth_checker']->isGranted('IS_AUTHENTICATED') : ($variables['token'] && !$variables['auth_checker']->isGranted('IS_ANONYMOUS'));
}),

new ExpressionFunction('is_fully_authenticated', function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
namespace Symfony\Component\Security\Core\Authorization\Voter;

use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;

/**
* AuthenticatedVoter votes if an attribute like IS_AUTHENTICATED_FULLY,
* IS_AUTHENTICATED_REMEMBERED, or IS_AUTHENTICATED_ANONYMOUSLY is present.
* IS_AUTHENTICATED_REMEMBERED, IS_AUTHENTICATED is present.
*
* This list is most restrictive to least restrictive checking.
*
Expand All @@ -28,8 +29,15 @@ class AuthenticatedVoter implements VoterInterface
{
public const IS_AUTHENTICATED_FULLY = 'IS_AUTHENTICATED_FULLY';
public const IS_AUTHENTICATED_REMEMBERED = 'IS_AUTHENTICATED_REMEMBERED';
/**
* @deprecated since Symfony 5.4
*/
public const IS_AUTHENTICATED_ANONYMOUSLY = 'IS_AUTHENTICATED_ANONYMOUSLY';
/**
* @deprecated since Symfony 5.4
*/
public const IS_ANONYMOUS = 'IS_ANONYMOUS';
public const IS_AUTHENTICATED = 'IS_AUTHENTICATED';
public const IS_IMPERSONATOR = 'IS_IMPERSONATOR';
public const IS_REMEMBERED = 'IS_REMEMBERED';
public const PUBLIC_ACCESS = 'PUBLIC_ACCESS';
Expand All @@ -55,6 +63,7 @@ public function vote(TokenInterface $token, $subject, array $attributes)
if (null === $attribute || (self::IS_AUTHENTICATED_FULLY !== $attribute
&& self::IS_AUTHENTICATED_REMEMBERED !== $attribute
&& self::IS_AUTHENTICATED_ANONYMOUSLY !== $attribute
&& self::IS_AUTHENTICATED !== $attribute
&& self::IS_ANONYMOUS !== $attribute
&& self::IS_IMPERSONATOR !== $attribute
&& self::IS_REMEMBERED !== $attribute)) {
Expand All @@ -78,6 +87,16 @@ public function vote(TokenInterface $token, $subject, array $attributes)
&& ($this->authenticationTrustResolver->isAnonymous($token)
|| $this->authenticationTrustResolver->isRememberMe($token)
|| $this->authenticationTrustResolver->isFullFledged($token))) {
trigger_deprecation('symfony/security-core', '5.4', 'The "IS_AUTHENTICATED_ANONYMOUSLY" security attribute is deprecated, use "IS_AUTHENTICATED" or "IS_AUTHENTICATED_FULLY" instead if you want to check if the request is (fully) authenticated.');

return VoterInterface::ACCESS_GRANTED;
}

// @deprecated $this->authenticationTrustResolver must implement isAuthenticated() in 6.0
if (self::IS_AUTHENTICATED === $attribute
&& (method_exists($this->authenticationTrustResolver, 'isAuthenticated')
? $this->authenticationTrustResolver->isAuthenticated($token)
: (null !== $token && !$token instanceof NullToken))) {
return VoterInterface::ACCESS_GRANTED;
}

Expand All @@ -86,6 +105,8 @@ public function vote(TokenInterface $token, $subject, array $attributes)
}

if (self::IS_ANONYMOUS === $attribute && $this->authenticationTrustResolver->isAnonymous($token)) {
trigger_deprecation('symfony/security-core', '5.4', 'The "IS_ANONYMOUSLY" security attribute is deprecated, anonymous no longer exists in version 6.');

return VoterInterface::ACCESS_GRANTED;
}

Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Security/Core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ CHANGELOG
* Deprecate `AnonymousToken`, as the related authenticator was deprecated in 5.3
* Deprecate `Token::getCredentials()`, tokens should no longer contain credentials (as they represent authenticated sessions)
* Deprecate returning `string|\Stringable` from `Token::getUser()` (it must return a `UserInterface`)
* Deprecate `AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY` and `AuthenticatedVoter::IS_ANONYMOUS`,
use `AuthenticatedVoter::IS_AUTHENTICATED_FULLY` or `AuthenticatedVoter::IS_AUTHENTICATED` instead.
* Deprecate `AuthenticationTrustResolverInterface::isAnonymous()` and the `is_anonymous()` expression
function as anonymous no longer exists in version 6, use the `isFullFledged()` or the new
`isAuthenticated()` instead if you want to check if the request is (fully) authenticated.
* Deprecate the `$authenticationManager` argument of the `AuthorizationChecker` constructor
* Deprecate setting the `$alwaysAuthenticate` argument to `true` and not setting the
`$exceptionOnNoToken` argument to `false` of `AuthorizationChecker`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\InMemoryUser;
use Symfony\Component\Security\Core\User\User;

class AuthenticationTrustResolverTest extends TestCase
{
/**
* @group legacy
*/
public function testIsAnonymous()
{
$resolver = new AuthenticationTrustResolver();
Expand Down Expand Up @@ -50,6 +55,17 @@ public function testisFullFledged()
$this->assertTrue($resolver->isFullFledged(new FakeCustomToken()));
}

public function testIsAuthenticated()
{
$resolver = new AuthenticationTrustResolver();
$this->assertFalse($resolver->isAuthenticated(null));
$this->assertTrue($resolver->isAuthenticated($this->getRememberMeToken()));
$this->assertTrue($resolver->isAuthenticated(new FakeCustomToken()));
}

/**
* @group legacy
*/
public function testIsAnonymousWithClassAsConstructorButStillExtending()
{
$resolver = $this->getResolver();
Expand Down Expand Up @@ -102,7 +118,7 @@ protected function getToken()

protected function getAnonymousToken()
{
return $this->getMockBuilder(AnonymousToken::class)->setConstructorArgs(['', ''])->getMock();
return new AnonymousToken('secret', 'anon.');
}

private function getRealCustomAnonymousToken()
Expand All @@ -116,7 +132,9 @@ public function __construct()

protected function getRememberMeToken()
{
return $this->getMockBuilder(RememberMeToken::class)->setMethods(['setPersistent'])->disableOriginalConstructor()->getMock();
$user = class_exists(InMemoryUser::class) ? new InMemoryUser('wouter', '', ['ROLE_USER']) : new User('wouter', '', ['ROLE_USER']);

return new RememberMeToken($user, 'main', 'secret');
}

protected function getResolver()
Expand Down Expand Up @@ -176,6 +194,7 @@ public function getUserIdentifier(): string

public function isAuthenticated(): bool
{
return true;
}

public function setAuthenticated(bool $isAuthenticated)
Expand Down
Loading