feat: gate oauth2 authorization on per-client roles
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Adds the per-client role requirement that App\EventListener\AuthorizationCodeListener
|
||||
* gates the authorization code grant on.
|
||||
*
|
||||
* The column defaults to an empty list and an empty list denies, so every client is
|
||||
* refused until its roles are set. The two clients in actual use are therefore set here
|
||||
* rather than by hand after the deploy: it closes the window in which both staff tools
|
||||
* would be live but unable to authorize anyone, and it keeps the role strings somewhere
|
||||
* review can see them.
|
||||
*
|
||||
* Matched on name, not identifier: client identifiers are generated per environment and
|
||||
* differ between local, staging and production, while the names do not.
|
||||
*
|
||||
* Deliberately left empty, and so denied: myepapp (the mobile app) and myep (the Keycloak
|
||||
* broker), both R&D only and not in use. The client_credentials clients never reach the
|
||||
* authorization endpoint and are unaffected either way.
|
||||
*/
|
||||
final class Version20260923120000 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Adds oauth2_client.required_roles and sets it for the two staff clients.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// Added nullable and backfilled before being tightened: a NOT NULL column with no
|
||||
// default leaves existing rows holding an empty string, which is not valid JSON and
|
||||
// fails to hydrate -- the row cannot even reach the listener that would deny it.
|
||||
$this->addSql("ALTER TABLE oauth2_client ADD required_roles JSON DEFAULT NULL COMMENT '(DC2Type:json)'");
|
||||
$this->addSql("UPDATE oauth2_client SET required_roles = '[]'");
|
||||
$this->addSql("ALTER TABLE oauth2_client MODIFY required_roles JSON NOT NULL COMMENT '(DC2Type:json)'");
|
||||
|
||||
// mirrors ephub's App\Security\Role::ELIGIBLE
|
||||
$this->addSql('UPDATE oauth2_client SET required_roles = :roles WHERE name = :name', [
|
||||
'roles' => json_encode(['ROLE_EMPLOYEE', 'ROLE_ADMIN'], JSON_THROW_ON_ERROR),
|
||||
'name' => 'EPHub',
|
||||
]);
|
||||
|
||||
// mirrors myep-team's App\Security\MyEpAuthenticator::ELIGIBLE_ROLES
|
||||
$this->addSql('UPDATE oauth2_client SET required_roles = :roles WHERE name = :name', [
|
||||
'roles' => json_encode(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER', 'ROLE_MANAGER', 'ROLE_HOUSE_MANAGER'], JSON_THROW_ON_ERROR),
|
||||
'name' => 'MyEPTeam',
|
||||
]);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE oauth2_client DROP required_roles');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user