Skip to content
Commits on Source (4)
......@@ -10,7 +10,7 @@ use Symfony\Component\HttpFoundation\Response;
abstract class AbstractAuthorizationService
{
/** @var UserAuthorizationChecker */
/** @var AuthorizationExpressionChecker */
private $userAuthorizationChecker;
/** @var AuthorizationUser|null */
......@@ -18,8 +18,9 @@ abstract class AbstractAuthorizationService
public function __construct(UserSessionInterface $userSession, AuthorizationDataProviderProvider $authorizationDataProviderProvider)
{
$this->userAuthorizationChecker = new UserAuthorizationChecker($userSession->getUserIdentifier(), $authorizationDataProviderProvider);
$this->currentAuthorizationUser = new AuthorizationUser($this->userAuthorizationChecker);
$muxer = new AuthorizationDataMuxer($authorizationDataProviderProvider->getAuthorizationDataProviders());
$this->userAuthorizationChecker = new AuthorizationExpressionChecker($muxer);
$this->currentAuthorizationUser = new AuthorizationUser($userSession->getUserIdentifier(), $this->userAuthorizationChecker);
}
public function setConfig(array $config)
......
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Authorization;
class AuthorizationDataMuxer
{
/** @var iterable */
private $authorizationDataProviders;
/** @var array */
private $customAttributes;
/**
* @param iterable<AuthorizationDataProviderInterface> $authorizationDataProviders
*/
public function __construct(iterable $authorizationDataProviders)
{
$this->authorizationDataProviders = $authorizationDataProviders;
$this->customAttributes = [];
}
private function loadUserAttributesFromAuthorizationProvider(?string $userIdentifier, AuthorizationDataProviderInterface $authorizationDataProvider): void
{
$userAttributes = $authorizationDataProvider->getUserAttributes($userIdentifier);
foreach ($authorizationDataProvider->getAvailableAttributes() as $availableAttribute) {
if (array_key_exists($availableAttribute, $userAttributes)) {
$this->customAttributes[$availableAttribute] = $userAttributes[$availableAttribute];
}
}
}
/**
* Returns an array of available attributes.
*
* @return string[]
*/
public function getAvailableAttributes(): array
{
$res = [];
foreach ($this->authorizationDataProviders as $authorizationDataProvider) {
$availableAttributes = $authorizationDataProvider->getAvailableAttributes();
$res = array_merge($res, $availableAttributes);
}
return $res;
}
/**
* @param mixed|null $defaultValue
*
* @return mixed|null
*
* @throws AuthorizationException
*/
public function getCustomAttribute(?string $userIdentifier, string $attributeName, $defaultValue = null)
{
if (array_key_exists($attributeName, $this->customAttributes) === false) {
$this->loadCustomAttribute($userIdentifier, $attributeName);
}
return $this->customAttributes[$attributeName] ?? $defaultValue;
}
/**
* @throws AuthorizationException
*/
private function loadCustomAttribute(?string $userIdentifier, string $attributeName): void
{
$wasFound = false;
foreach ($this->authorizationDataProviders as $authorizationDataProvider) {
$availableAttributes = $authorizationDataProvider->getAvailableAttributes();
if (in_array($attributeName, $availableAttributes, true)) {
$this->loadUserAttributesFromAuthorizationProvider($userIdentifier, $authorizationDataProvider);
$wasFound = true;
break;
}
}
if ($wasFound === false) {
throw new AuthorizationException(sprintf('custom attribute \'%s\' undefined', $attributeName), AuthorizationException::ATTRIBUTE_UNDEFINED);
}
}
}
......@@ -7,9 +7,20 @@ namespace Dbp\Relay\CoreBundle\Authorization;
interface AuthorizationDataProviderInterface
{
/**
* Returns a list of available attributes.
*
* @return string[]
*/
public function getAvailableAttributes(): array;
public function getUserAttributes(string $userIdentifier): array;
/**
* Returns an array of attribute names and values.
* In case an attribute has no value then it isn't contained.
*
* In case $userIdentifier is null then there is no active user and
* only globally available attributes shold be returned.
*
* @return array<string, mixed>
*/
public function getUserAttributes(?string $userIdentifier): array;
}
......@@ -6,7 +6,6 @@ namespace Dbp\Relay\CoreBundle\Authorization;
class AuthorizationException extends \RuntimeException
{
public const ROLE_UNDEFINED = 1;
public const PRIVILEGE_UNDEFINED = 2;
public const ATTRIBUTE_UNDEFINED = 3;
public const INFINITE_LOOP_DETECTED = 4;
......
......@@ -5,27 +5,17 @@ declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Authorization;
use Dbp\Relay\CoreBundle\Authorization\ExpressionLanguage\ExpressionLanguage;
use Dbp\Relay\CoreBundle\Helpers\Tools;
class UserAuthorizationChecker
class AuthorizationExpressionChecker
{
public const RIGHTS_CONFIG_ATTRIBUTE = 'rights';
public const ATTRIBUTES_CONFIG_ATTRIBUTE = 'attributes';
private const MAX_NUM_CALLS = 16;
/** @var ?string */
private $currentUserIdentifier;
/** @var iterable */
private $authorizationDataProviders;
/** @var ExpressionLanguage */
private $expressionLanguage;
/** @var array */
private $customAttributes;
/** @var array */
private $rightExpressions;
......@@ -35,16 +25,16 @@ class UserAuthorizationChecker
/** @var int */
private $callCounter;
public function __construct(?string $userIdentifier, AuthorizationDataProviderProvider $authorizationDataProviderProvider)
/** @var AuthorizationDataMuxer */
private $dataMux;
public function __construct(AuthorizationDataMuxer $dataMux)
{
$this->currentUserIdentifier = $userIdentifier;
$this->authorizationDataProviders = $authorizationDataProviderProvider->getAuthorizationDataProviders();
$this->expressionLanguage = new ExpressionLanguage();
$this->customAttributes = [];
$this->rightExpressions = [];
$this->attributeExpressions = [];
$this->dataMux = $dataMux;
}
public function setConfig(array $config)
......@@ -58,11 +48,6 @@ class UserAuthorizationChecker
$this->callCounter = 0;
}
public function getCurrentUserIdentifier(): ?string
{
return $this->currentUserIdentifier;
}
/**
* @param mixed|null $defaultValue
*
......@@ -92,11 +77,7 @@ class UserAuthorizationChecker
*/
public function getCustomAttribute(AuthorizationUser $currentAuthorizationUser, string $attributeName, $defaultValue = null)
{
if (array_key_exists($attributeName, $this->customAttributes) === false) {
$this->loadCustomAttribute($attributeName);
}
return $this->customAttributes[$attributeName] ?? $defaultValue;
return $this->dataMux->getCustomAttribute($currentAuthorizationUser->getIdentifier(), $attributeName, $defaultValue);
}
/**
......@@ -127,39 +108,6 @@ class UserAuthorizationChecker
}
}
/**
* @throws AuthorizationException
*/
private function loadCustomAttribute(string $attributeName): void
{
$wasFound = false;
foreach ($this->authorizationDataProviders as $authorizationDataProvider) {
$availableAttributes = $authorizationDataProvider->getAvailableAttributes();
if (in_array($attributeName, $availableAttributes, true)) {
$this->loadUserAttributesFromAuthorizationProvider($authorizationDataProvider);
$wasFound = true;
break;
}
}
if ($wasFound === false) {
throw new AuthorizationException(sprintf('custom attribute \'%s\' undefined', $attributeName), AuthorizationException::ATTRIBUTE_UNDEFINED);
}
}
private function loadUserAttributesFromAuthorizationProvider(AuthorizationDataProviderInterface $authorizationDataProvider): void
{
$userAttributes = [];
if (Tools::isNullOrEmpty($this->currentUserIdentifier) === false) {
$userAttributes = $authorizationDataProvider->getUserAttributes($this->currentUserIdentifier);
}
foreach ($authorizationDataProvider->getAvailableAttributes() as $availableAttribute) {
$this->customAttributes[$availableAttribute] = $userAttributes[$availableAttribute] ?? null;
}
}
/**
* @throws AuthorizationException
*/
......
......@@ -9,17 +9,23 @@ namespace Dbp\Relay\CoreBundle\Authorization;
*/
class AuthorizationUser
{
/** @var UserAuthorizationChecker */
/** @var AuthorizationExpressionChecker */
private $authorizationChecker;
public function __construct(UserAuthorizationChecker $authorizationChecker)
/**
* @var string|null
*/
private $identifier;
public function __construct(?string $identifier, AuthorizationExpressionChecker $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
$this->identifier = $identifier;
}
public function getIdentifier(): ?string
{
return $this->authorizationChecker->getCurrentUserIdentifier();
return $this->identifier;
}
/**
......
......@@ -37,32 +37,26 @@ class DebugCommand extends Command implements LoggerAwareInterface
protected function execute(InputInterface $input, OutputInterface $output): int
{
$username = $input->getArgument('username');
if ($username === null) {
// No username, list all providers
$output->writeln("<fg=blue;options=bold>Attributes available for all provider</>\n");
$providers = $this->provider->getAuthorizationDataProviders();
foreach ($providers as $provider) {
$output->writeln('<fg=green;options=bold>['.get_class($provider).']</>');
foreach ($provider->getAvailableAttributes() as $attr) {
$output->writeln($attr);
}
$output->writeln('');
}
// TODO: list all attributes
} else {
// get all available attributes for a user per provider
$output->writeln('<fg=blue;options=bold>Attributes for user "'.$username."\":</>\n");
$providers = $this->provider->getAuthorizationDataProviders();
foreach ($providers as $provider) {
$output->writeln('<fg=green;options=bold>['.get_class($provider).']</>');
foreach ($provider->getUserAttributes($username) as $attr => $value) {
$output->writeln($attr.'='.json_encode($value));
}
$output->writeln('');
}
// Fetch all attributes first (to get potential log spam first)
$providers = $this->provider->getAuthorizationDataProviders();
$mux = new AuthorizationDataMuxer($providers);
$attrs = $mux->getAvailableAttributes();
$all = [];
$default = new \stdClass();
sort($attrs, SORT_STRING | SORT_FLAG_CASE);
foreach ($attrs as $attr) {
$all[$attr] = $mux->getCustomAttribute($username, $attr, $default);
}
// TODO: list all attributes
// Now print them out
$output->writeln('<fg=blue;options=bold>[Authorization attributes]</>');
foreach ($all as $attr => $value) {
if ($value === $default) {
$output->writeln('<fg=green;options=bold>'.$attr.'</> = <fg=magenta;options=bold>\<N/A\></>');
} else {
$output->writeln('<fg=green;options=bold>'.$attr.'</> = '.json_encode($value));
}
}
return 0;
......