Skip to content
Snippets Groups Projects
Commit 7430fbcf authored by Reiter, Christoph's avatar Reiter, Christoph :snake:
Browse files

Move the user session into the core

and remove roles and oidc specifics. Instead we provide the session
in the core and forward requests to a oidc specific backend.

This also means the session can provide useful values even in case
it is used from the CLI and unauthenticated.
parent 27e4adc9
No related branches found
No related tags found
No related merge requests found
Pipeline #202509 passed
......@@ -6,58 +6,37 @@ namespace Dbp\Relay\CoreBundle\API;
interface UserSessionInterface
{
/**
* This gets called with the active JWT before any of the other methods are called.
*/
public function setSessionToken(?array $jwt): void;
/**
* The unique identifier of the authenticated user. Or null in case it is called
* before the user is known or if the user is a system.
*
* Can be derived from the session token for example.
*/
public function getUserIdentifier(): ?string;
/**
* Returns a list of Symfony user roles, like ['ROLE_FOOBAR'].
*
* Can be derived from the session token for example.
*/
public function getUserRoles(): array;
/**
* Returns an ID represents a "session" of a user which can be used for logging. It should not be possible to
* figure out which user is behind the ID based on the ID itself and the ID should change regularly.
* This is useful for connecting various requests together for logging while not exposing details about the user.
*
* Can be derived from long running session IDs embedded in the token for example.
*
* Return null in case no logging ID exists
*/
public function getSessionLoggingId(): ?string;
public function getSessionLoggingId(): string;
/**
* @deprecated
*/
public function getUserRoles(): array;
/**
* Returns a unique caching key that can be used to cache metadata related to the current user session like
* any user metadata, authorization related information etc.
* It should not be possible to figure out which user is behind the ID based on the ID itself and the ID should
* change regularly (after a logout/login or a key refresh for example).
*
* For example a hashed version of the token.
*
* Return null in case no appropriate cache key exists to disable any caching.
*/
public function getSessionCacheKey(): ?string;
public function getSessionCacheKey(): string;
/**
* Should return the duration the session is valid (as a whole, not from now) in seconds.
* Returns the duration the session is valid (as a whole, not from now) in seconds.
* After the specified amount of time has passed the logging ID and the caching key should have changed.
*
* This is mostly useful for limiting the cache.
*
* For example the lifespan of the token.
*
* Return <0 in case that information isn't available.
*/
public function getSessionTTL(): int;
}
......@@ -19,9 +19,15 @@ class ProxyAuthenticator extends AbstractAuthenticator
*/
private $authenticators;
public function __construct()
/**
* @var UserSession
*/
private $userSession;
public function __construct(UserSession $userSession)
{
$this->authenticators = [];
$this->userSession = $userSession;
}
public function addAuthenticator(AuthenticatorInterface $sub)
......@@ -54,7 +60,11 @@ class ProxyAuthenticator extends AbstractAuthenticator
$auth = $this->getAuthenticator($request);
assert($auth !== null);
return $auth->authenticate($request);
$passport = $auth->authenticate($request);
$provider = $passport->getAttribute('relay_user_session_provider');
$this->userSession->setProvider($provider);
return $passport;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
......@@ -67,6 +77,8 @@ class ProxyAuthenticator extends AbstractAuthenticator
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$this->userSession->setProvider(null);
$auth = $this->getAuthenticator($request);
assert($auth !== null);
......
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Auth;
use Dbp\Relay\CoreBundle\API\UserSessionInterface;
use Dbp\Relay\CoreBundle\API\UserSessionProviderInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Uid\Uuid;
/**
* This service provides user session information, either sourcing information from the active auth provider
* or in case it is used from the CLI or unauthenticated then it returns some reasonable defaults.
*/
class UserSession implements UserSessionInterface
{
/**
* @var ?UserSessionProviderInterface
*/
private $provider;
/**
* @var Security
*/
private $security;
public function __construct(?Security $security = null)
{
$this->security = $security;
}
public function setProvider(?UserSessionProviderInterface $provider)
{
$this->provider = $provider;
}
public function getUserIdentifier(): ?string
{
if ($this->provider === null) {
return null;
}
return $this->provider->getUserIdentifier();
}
public function getSessionLoggingId(): string
{
$id = null;
if ($this->provider !== null) {
$id = $this->provider->getSessionLoggingId();
}
if ($id === null) {
$id = 'unknown';
}
return $id;
}
public function getSessionCacheKey(): string
{
$key = null;
if ($this->provider !== null) {
$key = $this->provider->getSessionCacheKey();
}
if ($key === null) {
$key = (Uuid::v4())->toRfc4122();
}
return $key;
}
public function getSessionTTL(): int
{
$ttl = -1;
if ($this->provider !== null) {
$ttl = $this->provider->getSessionTTL();
}
if ($ttl === -1) {
$ttl = 60;
}
return $ttl;
}
public function getUserRoles(): array
{
if ($this->provider === null) {
return [];
}
$user = $this->security->getUser();
if ($user === null) {
return [];
}
return $user->getRoles();
}
}
......@@ -43,10 +43,7 @@ final class LoggingProcessor
$this->maskUserId($record);
// Add a session ID (the same during multiple requests for the same user session)
$loggingId = $this->userDataProvider->getSessionLoggingId();
if ($loggingId !== null) {
$record['context']['relay-session-id'] = $loggingId;
}
$record['context']['relay-session-id'] = $this->userDataProvider->getSessionLoggingId();
// Add a request ID (the same during the same client request)
$request = $this->requestStack->getMainRequest();
......
......@@ -58,6 +58,13 @@ services:
autowire: true
autoconfigure: true
Dbp\Relay\CoreBundle\Auth\UserSession:
autowire: true
autoconfigure: true
Dbp\Relay\CoreBundle\API\UserSessionInterface:
'@Dbp\Relay\CoreBundle\Auth\UserSession'
Dbp\Relay\CoreBundle\LocalData\LocalDataAwareEventDispatcher:
autowire: true
autoconfigure: true
......
......@@ -41,12 +41,12 @@ class TestUserSession implements UserSessionInterface
return $this->roles;
}
public function getSessionLoggingId(): ?string
public function getSessionLoggingId(): string
{
return 'logging-id';
}
public function getSessionCacheKey(): ?string
public function getSessionCacheKey(): string
{
return 'cache';
}
......
......@@ -6,6 +6,7 @@ namespace Dbp\Relay\CoreBundle\Tests\Auth;
use Dbp\Relay\CoreBundle\Auth\AuthenticatorCompilerPass;
use Dbp\Relay\CoreBundle\Auth\ProxyAuthenticator;
use Dbp\Relay\CoreBundle\Auth\UserSession;
use Dbp\Relay\CoreBundle\TestUtils\TestAuthenticator;
use Dbp\Relay\CoreBundle\TestUtils\TestUser;
use PHPUnit\Framework\TestCase;
......@@ -17,13 +18,13 @@ class AuthenticatorTest extends TestCase
{
public function testSupports()
{
$auth = new ProxyAuthenticator();
$auth = new ProxyAuthenticator(new UserSession());
$this->assertFalse($auth->supports(new Request()));
}
public function testSingle()
{
$auth = new ProxyAuthenticator();
$auth = new ProxyAuthenticator(new UserSession());
$user = new TestUser();
$sub = new TestAuthenticator($user, 'bla');
$auth->addAuthenticator($sub);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment