-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1198 from cultuurnet/PPF-511/migration-auth0
PPF-508 Add migration auth0 -> keycloak clients
- Loading branch information
Showing
2 changed files
with
184 additions
and
0 deletions.
There are no files selected for viewing
79 changes: 79 additions & 0 deletions
79
app/Console/Commands/Migrations/MigrateAuth0ToKeycloakClients.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Console\Commands\Migrations; | ||
|
||
use App\Domain\Integrations\Environment; | ||
use App\Keycloak\Client; | ||
use App\Keycloak\Repositories\KeycloakClientRepository; | ||
use Illuminate\Console\Command; | ||
use Illuminate\Support\Collection; | ||
use Illuminate\Support\Facades\DB; | ||
use Ramsey\Uuid\Uuid; | ||
|
||
final class MigrateAuth0ToKeycloakClients extends Command | ||
{ | ||
protected $signature = 'migrate:keycloak'; | ||
protected $description = 'Copy all auth0 clients to keycloak clients - does NOT remove the auth0 clients.'; | ||
|
||
public function __construct(private readonly KeycloakClientRepository $keycloakClientRepository) | ||
{ | ||
parent::__construct(); | ||
} | ||
|
||
public function handle(): int | ||
{ | ||
$auth0Clients = $this->findAuth0Clients(); | ||
|
||
$total = count($auth0Clients); | ||
if ($total <= 0) { | ||
$this->warn('No clients found to migrate'); | ||
return self::SUCCESS; | ||
} | ||
|
||
if (!$this->confirm( | ||
sprintf( | ||
'Are you sure you want to copy %s auth0 clients to Keycloak?', | ||
$total | ||
) | ||
)) { | ||
return self::FAILURE; | ||
} | ||
|
||
$bar = $this->output->createProgressBar($total); | ||
$bar->start(); | ||
|
||
foreach ($auth0Clients as $auth0Client) { | ||
$client = new Client( | ||
Uuid::fromString($auth0Client->id), | ||
Uuid::fromString($auth0Client->integration_id), | ||
$auth0Client->auth0_client_id, | ||
$auth0Client->auth0_client_secret, | ||
Environment::from($auth0Client->auth0_tenant), | ||
); | ||
$this->keycloakClientRepository->create($client); | ||
|
||
$this->info(sprintf('Converted client %s', $auth0Client->id)); | ||
|
||
$bar->advance(); | ||
} | ||
|
||
$bar->finish(); | ||
|
||
return self::SUCCESS; | ||
} | ||
|
||
private function findAuth0Clients(): Collection | ||
{ | ||
$query = DB::table('auth0_clients') | ||
->orderBy('updated_at', 'asc') | ||
->whereNotIn('auth0_clients.id', function ($query) { | ||
$query->select('id') | ||
->from('keycloak_clients'); | ||
}) | ||
->whereNull('deleted_at'); | ||
|
||
return $query->get(); | ||
} | ||
} |
105 changes: 105 additions & 0 deletions
105
tests/Console/Commands/Migrations/MigrateAuth0ToKeycloakClientsTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Tests\Console\Commands\Migrations; | ||
|
||
use Illuminate\Foundation\Testing\RefreshDatabase; | ||
use Illuminate\Support\Facades\DB; | ||
use Illuminate\Testing\PendingCommand; | ||
use Ramsey\Uuid\Uuid; | ||
use Symfony\Component\Console\Command\Command; | ||
use Tests\TestCase; | ||
|
||
final class MigrateAuth0ToKeycloakClientsTest extends TestCase | ||
{ | ||
use RefreshDatabase; | ||
|
||
private const CLIENT_ID_1 = '27c500be-4cc4-4cb2-97d6-c966a27716c4'; | ||
|
||
public function test_no_clients_to_migrate(): void | ||
{ | ||
$this->getPendingCommand('migrate:keycloak') | ||
->expectsOutput('No clients found to migrate') | ||
->assertExitCode(Command::SUCCESS); | ||
} | ||
|
||
|
||
public function test_complex_query_clients_already_exist_in_keycloak_table(): void | ||
{ | ||
$integrationId = Uuid::uuid4()->toString(); | ||
$id1 = Uuid::uuid4()->toString(); | ||
$id2 = Uuid::uuid4()->toString(); | ||
|
||
DB::table('auth0_clients')->insert([ | ||
'id' => $id1, | ||
'integration_id' => $integrationId, | ||
'auth0_client_id' => 'deleted_client', | ||
'auth0_client_secret' => 'secret1', | ||
'auth0_tenant' => 'acc', | ||
'created_at' => now(), | ||
'updated_at' => now(), | ||
'deleted_at' => now(), | ||
]); | ||
|
||
DB::table('auth0_clients')->insert([ | ||
'id' => $id2, | ||
'integration_id' => $integrationId, | ||
'auth0_client_id' => 'client_already_exist', | ||
'auth0_client_secret' => 'secret1', | ||
'auth0_tenant' => 'test', | ||
'created_at' => now(), | ||
'updated_at' => now(), | ||
]); | ||
|
||
DB::table('keycloak_clients')->insert([ | ||
'id' => $id2, | ||
'integration_id' => $integrationId, | ||
'client_id' => 'client_already_exist', | ||
'client_secret' => 'secret1', | ||
'realm' => 'test', | ||
'created_at' => now(), | ||
'updated_at' => now(), | ||
]); | ||
|
||
$this->getPendingCommand('migrate:keycloak') | ||
->expectsOutput('No clients found to migrate') | ||
->assertExitCode(Command::SUCCESS); | ||
|
||
$this->assertDatabaseCount('auth0_clients', 2); | ||
$this->assertDatabaseCount('keycloak_clients', 1); | ||
} | ||
|
||
public function test_migration_with_clients(): void | ||
{ | ||
DB::table('auth0_clients')->insert([ | ||
'id' => self::CLIENT_ID_1, | ||
'integration_id' => '3c570fb7-ff26-4284-a848-ae8c9c8e205d', | ||
'auth0_client_id' => 'auth0_client1', | ||
'auth0_client_secret' => 'secret1', | ||
'auth0_tenant' => 'acc', | ||
'created_at' => now(), | ||
'updated_at' => now(), | ||
]); | ||
|
||
$this->getPendingCommand('migrate:keycloak') | ||
->expectsConfirmation('Are you sure you want to copy 1 auth0 clients to Keycloak?', 'yes') | ||
->expectsOutput('Converted client 27c500be-4cc4-4cb2-97d6-c966a27716c4') | ||
->assertExitCode(Command::SUCCESS); | ||
|
||
$this->assertDatabaseHas('keycloak_clients', [ | ||
'id' => self::CLIENT_ID_1, | ||
'integration_id' => '3c570fb7-ff26-4284-a848-ae8c9c8e205d', | ||
'client_id' => 'auth0_client1', | ||
'client_secret' => 'secret1', | ||
'realm' => 'acc', | ||
]); | ||
} | ||
|
||
private function getPendingCommand(string $command, array $params = []): PendingCommand | ||
{ | ||
$command = $this->artisan($command, $params); | ||
$this->assertInstanceOf(PendingCommand::class, $command); | ||
return $command; | ||
} | ||
} |