Implemented mechanism to add/remove roles from API keys

This commit is contained in:
Alejandro Celaya 2021-01-06 10:59:02 +01:00
parent 01b3c504f8
commit 041f231ff2
4 changed files with 82 additions and 5 deletions

View file

@ -38,5 +38,8 @@ return static function (ClassMetadata $metadata, array $emConfig): void {
$builder->createOneToMany('roles', ApiKeyRole::class) $builder->createOneToMany('roles', ApiKeyRole::class)
->mappedBy('apiKey') ->mappedBy('apiKey')
->setIndexBy('roleName')
->cascadePersist()
->orphanRemoval()
->build(); ->build();
}; };

View file

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\ApiKey\Model;
use Shlinkio\Shlink\Rest\ApiKey\Role;
final class RoleDefinition
{
private string $roleName;
private array $meta;
private function __construct(string $roleName, array $meta)
{
$this->roleName = $roleName;
$this->meta = $meta;
}
public static function forAuthoredShortUrls(): self
{
return new self(Role::AUTHORED_SHORT_URLS, []);
}
public static function forDomain(string $domainId): self
{
return new self(Role::DOMAIN_SPECIFIC, ['domain_id' => $domainId]);
}
public function roleName(): string
{
return $this->roleName;
}
public function meta(): array
{
return $this->meta;
}
}

View file

@ -7,10 +7,12 @@ namespace Shlinkio\Shlink\Rest\Entity;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Exception;
use Happyr\DoctrineSpecification\Spec; use Happyr\DoctrineSpecification\Spec;
use Happyr\DoctrineSpecification\Specification\Specification; use Happyr\DoctrineSpecification\Specification\Specification;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use Shlinkio\Shlink\Common\Entity\AbstractEntity; use Shlinkio\Shlink\Common\Entity\AbstractEntity;
use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
use Shlinkio\Shlink\Rest\ApiKey\Role; use Shlinkio\Shlink\Rest\ApiKey\Role;
class ApiKey extends AbstractEntity class ApiKey extends AbstractEntity
@ -21,12 +23,20 @@ class ApiKey extends AbstractEntity
/** @var Collection|ApiKeyRole[] */ /** @var Collection|ApiKeyRole[] */
private Collection $roles; private Collection $roles;
public function __construct(?Chronos $expirationDate = null) /**
* @param RoleDefinition[] $roleDefinitions
* @throws Exception
*/
public function __construct(?Chronos $expirationDate = null, array $roleDefinitions = [])
{ {
$this->key = Uuid::uuid4()->toString(); $this->key = Uuid::uuid4()->toString();
$this->expirationDate = $expirationDate; $this->expirationDate = $expirationDate;
$this->enabled = true; $this->enabled = true;
$this->roles = new ArrayCollection(); $this->roles = new ArrayCollection();
foreach ($roleDefinitions as $roleDefinition) {
$this->registerRole($roleDefinition);
}
} }
public function getExpirationDate(): ?Chronos public function getExpirationDate(): ?Chronos
@ -81,13 +91,33 @@ class ApiKey extends AbstractEntity
public function hasRole(string $roleName): bool public function hasRole(string $roleName): bool
{ {
return $this->roles->exists(fn ($key, ApiKeyRole $role) => $role->name() === $roleName); return $this->roles->containsKey($roleName);
} }
public function getRoleMeta(string $roleName): array public function getRoleMeta(string $roleName): array
{ {
/** @var ApiKeyRole|false $role */ /** @var ApiKeyRole|null $role */
$role = $this->roles->filter(fn (ApiKeyRole $role) => $role->name() === $roleName)->first(); $role = $this->roles->get($roleName);
return ! $role ? [] : $role->meta(); return $role === null ? [] : $role->meta();
}
public function registerRole(RoleDefinition $roleDefinition): void
{
$roleName = $roleDefinition->roleName();
$meta = $roleDefinition->meta();
if ($this->hasRole($roleName)) {
/** @var ApiKeyRole $role */
$role = $this->roles->get($roleName);
$role->updateMeta($meta);
} else {
$role = new ApiKeyRole($roleDefinition->roleName(), $roleDefinition->meta(), $this);
$this->roles[$roleName] = $role;
}
}
public function removeRole(string $roleName): void
{
$this->roles->remove($roleName);
} }
} }

View file

@ -29,6 +29,11 @@ class ApiKeyRole extends AbstractEntity
return $this->meta; return $this->meta;
} }
public function updateMeta(array $newMeta): void
{
$this->meta = $newMeta;
}
public function apiKey(): ApiKey public function apiKey(): ApiKey
{ {
return $this->apiKey; return $this->apiKey;