diff --git a/app/Console/Commands/Migrations/MigrateAuth0ToKeycloakClients.php b/app/Console/Commands/Migrations/MigrateAuth0ToKeycloakClients.php new file mode 100644 index 000000000..203940f31 --- /dev/null +++ b/app/Console/Commands/Migrations/MigrateAuth0ToKeycloakClients.php @@ -0,0 +1,79 @@ +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(); + } +} diff --git a/tests/Console/Commands/Migrations/MigrateAuth0ToKeycloakClientsTest.php b/tests/Console/Commands/Migrations/MigrateAuth0ToKeycloakClientsTest.php new file mode 100644 index 000000000..7c78706a9 --- /dev/null +++ b/tests/Console/Commands/Migrations/MigrateAuth0ToKeycloakClientsTest.php @@ -0,0 +1,105 @@ +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; + } +}