Skip to content
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

[Security] Track session usage whenever a new token is set #36335

Merged
merged 1 commit into from Apr 4, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -23,7 +23,7 @@ class AppCustomAuthenticator extends AbstractGuardAuthenticator
{
public function supports(Request $request)
{
return true;
return '/manual_login' !== $request->getPathInfo() && '/profile' !== $request->getPathInfo();
}

public function getCredentials(Request $request)
Expand Down
@@ -0,0 +1,38 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\User\User;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;

class AuthenticationController
{
public function manualLoginAction(GuardAuthenticatorHandler $guardAuthenticatorHandler, Request $request)
{
$guardAuthenticatorHandler->authenticateWithToken(new PostAuthenticationGuardToken(new User('Jane', 'test', ['ROLE_USER']), 'secure', ['ROLE_USER']), $request, 'secure');

return new Response('Logged in.');
}

public function profileAction(UserInterface $user = null)
{
if (null === $user) {
return new Response('Not logged in.');
}

return new Response('Username: '.$user->getUsername());
}
}
Expand Up @@ -21,4 +21,14 @@ public function testGuarded()

$this->assertSame(418, $client->getResponse()->getStatusCode());
}

public function testManualLogin()
{
$client = $this->createClient(['debug' => true, 'test_case' => 'Guarded', 'root_config' => 'config.yml']);

$client->request('GET', '/manual_login');
$client->request('GET', '/profile');

$this->assertSame('Username: Jane', $client->getResponse()->getContent());
}
}
Expand Up @@ -10,8 +10,19 @@ framework:
services:
logger: { class: Psr\Log\NullLogger }
Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle\AppCustomAuthenticator: ~
Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle\AuthenticationController:
tags: [controller.service_arguments]

security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext

providers:
in_memory:
memory:
users:
Jane: { password: test, roles: [ROLE_USER] }

firewalls:
secure:
pattern: ^/
Expand Down
Expand Up @@ -3,3 +3,12 @@ main:
defaults:
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction
path: /app
profile:
path: /profile
defaults:
_controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle\AuthenticationController::profileAction

manual_login:
path: /manual_login
defaults:
_controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\GuardedBundle\AuthenticationController::manualLoginAction
Expand Up @@ -49,6 +49,11 @@ public function setToken(TokenInterface $token = null)
@trigger_error(sprintf('Not implementing the "%s::getRoleNames()" method in "%s" is deprecated since Symfony 4.3.', TokenInterface::class, \get_class($token)), E_USER_DEPRECATED);
}

if ($token) {
// ensure any initializer is called
$this->getToken();
}

$this->initializer = null;
$this->token = $token;
}
Expand Down
Expand Up @@ -52,6 +52,11 @@ public function getToken(): ?TokenInterface
public function setToken(TokenInterface $token = null): void
{
$this->storage->setToken($token);

if ($token && $this->enableUsageTracking) {
// increments the internal session usage index
$this->sessionLocator->get('session')->getMetadataBag();
}
}

public function enableUsageTracking(): void
Expand Down
Expand Up @@ -411,9 +411,9 @@ protected function runSessionOnKernelResponse($newToken, $original = null)

private function handleEventWithPreviousSession($userProviders, UserInterface $user = null, RememberMeServicesInterface $rememberMeServices = null)
{
$user = $user ?: new User('foo', 'bar');
$tokenUser = $user ?: new User('foo', 'bar');
$session = new Session(new MockArraySessionStorage());
$session->set('_security_context_key', serialize(new UsernamePasswordToken($user, '', 'context_key', ['ROLE_USER'])));
$session->set('_security_context_key', serialize(new UsernamePasswordToken($tokenUser, '', 'context_key', ['ROLE_USER'])));

$request = new Request();
$request->setSession($session);
Expand Down Expand Up @@ -442,6 +442,10 @@ private function handleEventWithPreviousSession($userProviders, UserInterface $u
$listener(new RequestEvent($this->getMockBuilder(HttpKernelInterface::class)->getMock(), $request, HttpKernelInterface::MASTER_REQUEST));

if (null !== $usageIndex) {
if (null !== $user) {
++$usageIndex;
}

$this->assertSame($usageIndex, $session->getUsageIndex());
$tokenStorage->getToken();
$this->assertSame(1 + $usageIndex, $session->getUsageIndex());
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/Security/Http/composer.json
Expand Up @@ -17,7 +17,7 @@
],
"require": {
"php": "^7.1.3",
"symfony/security-core": "^4.4.7",
"symfony/security-core": "^4.4.8",
"symfony/http-foundation": "^3.4.40|^4.4.7|^5.0.7",
"symfony/http-kernel": "^4.4",
"symfony/property-access": "^3.4|^4.0|^5.0"
Expand Down