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

Add missing console commands for client management #41

Merged
merged 37 commits into from
May 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
77b7190
Added client Delete command
Allypost Apr 16, 2019
a6cafbe
Lint oopsie doopsie
Allypost Apr 16, 2019
7122d20
Added client Delete command test
Allypost Apr 16, 2019
d471074
Added client List command
Allypost Apr 16, 2019
5c005a3
Registered new list and delete commands
Allypost Apr 16, 2019
dc5b3df
Now actually checking if client is deleted
Allypost Apr 16, 2019
6ca5710
Removed superfluous assert
Allypost Apr 16, 2019
a18bf03
Added client list command tests
Allypost Apr 16, 2019
dcd8a0f
Updated docs
Allypost Apr 16, 2019
182f26b
Added required methods to `ClientManagerInterface` instead of using `…
Allypost Apr 17, 2019
935956f
Moved fixtures to tests that actually need them
Allypost Apr 17, 2019
4a2ea0a
Changed list tests to assert that the table has a constant form
Allypost Apr 17, 2019
e3a343d
Added ClientFilter to unify filtering lists
Allypost Apr 17, 2019
462cd6b
Implemented filtering for memory client
Allypost Apr 17, 2019
b1cad99
Added default value (list all) to ListClients columns parameter
Allypost Apr 17, 2019
f6bef37
Oopsie doopsie lint results
Allypost Apr 17, 2019
abe0020
Allowed columns is now static
Allypost Apr 17, 2019
dbd091f
Tightened up checks
Allypost Apr 17, 2019
01f8bfa
Now using builtin function to map to string
Allypost Apr 17, 2019
35defac
$repository->findAll() === $repository->findBy([])
Allypost Apr 17, 2019
16b5d5d
Naming :)
Allypost Apr 17, 2019
bbc5437
Renamed ClientFilter::createFilter -> ClientFilter::create
Allypost Apr 17, 2019
7268ab4
Added nulls to phpdoc
Allypost Apr 17, 2019
40ec5fd
Added empty client list test
Allypost Apr 17, 2019
4468133
Moved duplicate logic to own method
Allypost Apr 17, 2019
8e7d9e2
Some more explicit null checks
Allypost Apr 17, 2019
e3d4e9e
Renamed client filter argument to make a bit more sense
Allypost Apr 17, 2019
0ed7310
Made list command arguments arrays
Allypost May 6, 2019
1353ca8
Values no longer optional
Allypost May 6, 2019
6e12755
Fix invalid hasFilters check
Allypost May 6, 2019
86cbd10
Add missing typehints
Allypost May 6, 2019
965ef14
Fix invalid PHPDoc comment style
Allypost May 6, 2019
2a370c5
Updated command option description
Allypost May 6, 2019
9e21ee0
ClientFilter add*Criteria now takes list or arguments
Allypost May 6, 2019
2f5df30
All arguments are now required if they have a value
Allypost May 6, 2019
d0351d7
Relinquish last surviving VALUE_OPTIONAL
Allypost May 7, 2019
f58c052
ClientFilter values now always arrays
Allypost May 7, 2019
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
20 changes: 10 additions & 10 deletions Command/CreateClientCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,23 @@ protected function configure()
->addOption(
'redirect-uri',
null,
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets redirect uri for client. Use this option multiple times to set multiple redirect URIs.',
null
[]
)
->addOption(
'grant-type',
null,
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets allowed grant type for client. Use this option multiple times to set multiple grant types.',
null
[]
)
->addOption(
'scope',
null,
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets allowed scope for client. Use this option multiple times to set multiple scopes.',
null
[]
)
->addArgument(
'identifier',
Expand Down Expand Up @@ -81,7 +81,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
return 0;
}

private function buildClientFromInput(InputInterface $input)
private function buildClientFromInput(InputInterface $input): Client
{
$identifier = $input->getArgument('identifier') ?? hash('md5', random_bytes(16));
$secret = $input->getArgument('secret') ?? hash('sha512', random_bytes(32));
Expand All @@ -90,19 +90,19 @@ private function buildClientFromInput(InputInterface $input)
$client->setActive(true);

$redirectUris = array_map(
function (string $redirectUri) { return new RedirectUri($redirectUri); },
function (string $redirectUri): RedirectUri { return new RedirectUri($redirectUri); },
$input->getOption('redirect-uri')
);
$client->setRedirectUris(...$redirectUris);

$grants = array_map(
function (string $grant) { return new Grant($grant); },
function (string $grant): Grant { return new Grant($grant); },
$input->getOption('grant-type')
);
$client->setGrants(...$grants);

$scopes = array_map(
function (string $scope) { return new Scope($scope); },
function (string $scope): Scope { return new Scope($scope); },
$input->getOption('scope')
);
$client->setScopes(...$scopes);
Expand Down
50 changes: 50 additions & 0 deletions Command/DeleteClientCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Trikoder\Bundle\OAuth2Bundle\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Trikoder\Bundle\OAuth2Bundle\Manager\ClientManagerInterface;

final class DeleteClientCommand extends Command
{
protected static $defaultName = 'trikoder:oauth2:delete-client';
private $clientManager;

public function __construct(ClientManagerInterface $clientManager)
{
parent::__construct();
$this->clientManager = $clientManager;
}

protected function configure(): void
{
$this
->setDescription('Deletes an oAuth2 client')
->addArgument(
'identifier',
InputArgument::REQUIRED,
'The client ID'
)
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$identifier = $input->getArgument('identifier');
$client = $this->clientManager->find($identifier);
if (null === $client) {
$io->error(sprintf('oAuth2 client identified as "%s" does not exist', $identifier));

return 1;
}
$this->clientManager->remove($client);
$io->success('Given oAuth2 client deleted successfully.');

return 0;
}
}
127 changes: 127 additions & 0 deletions Command/ListClientsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?php

namespace Trikoder\Bundle\OAuth2Bundle\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Trikoder\Bundle\OAuth2Bundle\Manager\ClientFilter;
use Trikoder\Bundle\OAuth2Bundle\Manager\ClientManagerInterface;
use Trikoder\Bundle\OAuth2Bundle\Model\Client;
use Trikoder\Bundle\OAuth2Bundle\Model\Grant;
use Trikoder\Bundle\OAuth2Bundle\Model\RedirectUri;
use Trikoder\Bundle\OAuth2Bundle\Model\Scope;

final class ListClientsCommand extends Command
{
public const ALLOWED_COLUMNS = ['identifier', 'secret', 'scope', 'redirect uri', 'grant type'];

protected static $defaultName = 'trikoder:oauth2:list-clients';
private $clientManager;

public function __construct(ClientManagerInterface $clientManager)
{
parent::__construct();
$this->clientManager = $clientManager;
}

protected function configure(): void
{
$this
->setDescription('Lists existing oAuth2 clients')
->addOption(
'columns',
null,
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Determine which columns are shown. Can be used multiple times to specify multiple columns.',
self::ALLOWED_COLUMNS
)
->addOption(
'redirect-uri',
null,
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Finds by redirect uri for client. Use this option multiple times to filter by multiple redirect URIs.',
[]
)
->addOption(
'grant-type',
null,
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Finds by allowed grant type for client. Use this option multiple times to filter by multiple grant types.',
[]
)
->addOption(
'scope',
null,
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Finds by allowed scope for client. Use this option multiple times to find by multiple scopes.',
[]
)
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$criteria = $this->getFindByCriteria($input);
$clients = $this->clientManager->list($criteria);
$this->drawTable($input, $output, $clients);

return 0;
}

private function getFindByCriteria(InputInterface $input): ClientFilter
{
return
ClientFilter
::create()
->addGrantCriteria(...array_map(function (string $grant): Grant {
return new Grant($grant);
}, $input->getOption('grant-type')))
->addRedirectUriCriteria(...array_map(function (string $redirectUri): RedirectUri {
return new RedirectUri($redirectUri);
}, $input->getOption('redirect-uri')))
->addScopeCriteria(...array_map(function (string $scope): Scope {
return new Scope($scope);
}, $input->getOption('scope')))
;
}

private function drawTable(InputInterface $input, OutputInterface $output, array $clients): void
{
$io = new SymfonyStyle($input, $output);
$columns = $this->getColumns($input);
$rows = $this->getRows($clients, $columns);
$io->table($columns, $rows);
}

private function getRows(array $clients, array $columns): array
{
return array_map(function (Client $client) use ($columns): array {
$values = [
'identifier' => $client->getIdentifier(),
'secret' => $client->getSecret(),
'scope' => implode(', ', $client->getScopes()),
'redirect uri' => implode(', ', $client->getRedirectUris()),
'grant type' => implode(', ', $client->getGrants()),
];

return array_map(function (string $column) use ($values): string {
return $values[$column];
}, $columns);
}, $clients);
}

private function getColumns(InputInterface $input): array
{
$allowedColumns = self::ALLOWED_COLUMNS;

$requestedColumns = $input->getOption('columns');
$requestedColumns = array_map(function (string $column): string {
return strtolower(trim($column));
}, $requestedColumns);

return array_intersect($requestedColumns, $allowedColumns);
}
}
22 changes: 11 additions & 11 deletions Command/UpdateClientCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,30 @@ public function __construct(ClientManagerInterface $clientManager)
$this->clientManager = $clientManager;
}

protected function configure()
protected function configure(): void
{
$this
->setDescription('Updates an oAuth2 client')
->addOption(
'redirect-uri',
null,
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets redirect uri for client. Use this option multiple times to set multiple redirect URIs.',
null
[]
)
->addOption(
'grant-type',
null,
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets allowed grant type for client. Use this option multiple times to set multiple grant types.',
null
[]
)
->addOption(
'scope',
null,
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets allowed scope for client. Use this option multiple times to set multiple scopes.',
null
[]
)
->addOption(
'deactivated',
Expand All @@ -66,7 +66,7 @@ protected function configure()
;
}

protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

Expand All @@ -88,19 +88,19 @@ private function updateClientFromInput(Client $client, InputInterface $input): C
$client->setActive(!$input->getOption('deactivated'));

$redirectUris = array_map(
function (string $redirectUri) { return new RedirectUri($redirectUri); },
function (string $redirectUri): RedirectUri { return new RedirectUri($redirectUri); },
$input->getOption('redirect-uri')
);
$client->setRedirectUris(...$redirectUris);

$grants = array_map(
function (string $grant) { return new Grant($grant); },
function (string $grant): Grant { return new Grant($grant); },
$input->getOption('grant-type')
);
$client->setGrants(...$grants);

$scopes = array_map(
function (string $scope) { return new Scope($scope); },
function (string $scope): Scope { return new Scope($scope); },
$input->getOption('scope')
);
$client->setScopes(...$scopes);
Expand Down
86 changes: 86 additions & 0 deletions Manager/ClientFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Trikoder\Bundle\OAuth2Bundle\Manager;

use Trikoder\Bundle\OAuth2Bundle\Model\Grant;
use Trikoder\Bundle\OAuth2Bundle\Model\RedirectUri;
use Trikoder\Bundle\OAuth2Bundle\Model\Scope;

final class ClientFilter
{
/**
* @var array
*/
private $grants = [];
/**
* @var array
*/
private $redirectUris = [];
/**
* @var array
*/
private $scopes = [];

public static function create(): self
{
return new static();
}

public function addGrantCriteria(Grant ...$grants): self
{
return $this->addCriteria($this->grants, ...$grants);
}

public function addRedirectUriCriteria(RedirectUri ...$redirectUris): self
{
return $this->addCriteria($this->redirectUris, ...$redirectUris);
}

public function addScopeCriteria(Scope ...$scopes): self
{
return $this->addCriteria($this->scopes, ...$scopes);
}

private function addCriteria(&$field, ...$values): self
{
if (0 === \count($values)) {
return $this;
}

$field = array_merge($field, $values);

return $this;
}

/**
* @return Grant[]
*/
public function getGrants(): array
{
return $this->grants;
}

/**
* @return RedirectUri[]
*/
public function getRedirectUris(): array
{
return $this->redirectUris;
}

/**
* @return Scope[]
*/
public function getScopes(): array
{
return $this->scopes;
}

public function hasFilters(): bool
{
return
!empty($this->grants)
|| !empty($this->redirectUris)
|| !empty($this->scopes);
}
HypeMC marked this conversation as resolved.
Show resolved Hide resolved
}
Loading