From 73c2f34263ed5c3de33ba7b687f72bde117013bd Mon Sep 17 00:00:00 2001 From: Sebastian Krupinski Date: Mon, 20 Jul 2026 23:53:40 -0400 Subject: [PATCH] feat: command to set user password Signed-off-by: Sebastian Krupinski --- lib/Console/UserPasswordCommand.php | 102 ++++++++++++++++++++++++++++ lib/Module.php | 11 ++- 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 lib/Console/UserPasswordCommand.php diff --git a/lib/Console/UserPasswordCommand.php b/lib/Console/UserPasswordCommand.php new file mode 100644 index 0000000..fc5b41b --- /dev/null +++ b/lib/Console/UserPasswordCommand.php @@ -0,0 +1,102 @@ +addArgument('tenant', InputArgument::REQUIRED, 'Tenant identifier') + ->addArgument('identity', InputArgument::REQUIRED, 'User identity (email/username)') + ->addArgument('password', InputArgument::OPTIONAL, 'Password (prompted for interactively when omitted)') + ->setHelp('This command sets or updates the password credential for a user account. Omit the password argument to be prompted securely.') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $tenant = $input->getArgument('tenant'); + $identity = $input->getArgument('identity'); + $password = $input->getArgument('password'); + + $io->title('Set User Password'); + + try { + if (!$this->tenantService->fetchById($tenant)) { + $io->error("Tenant '{$tenant}' not found."); + return Command::FAILURE; + } + + if (!$this->userStore->fetchByIdentity($tenant, $identity)) { + $io->error("User '{$identity}' not found in tenant '{$tenant}'."); + return Command::FAILURE; + } + + if ($password === null) { + $password = $io->askHidden('Password'); + } + + if (empty($password)) { + $io->error('Password cannot be empty.'); + return Command::FAILURE; + } + + if (!$this->provider->setCredential($tenant, $identity, $password)) { + $io->error("Failed to store password credential for '{$identity}'."); + return Command::FAILURE; + } + + $this->logger->info('User password credential set via console', [ + 'tenant' => $tenant, + 'identity' => $identity, + 'command' => $this->getName(), + ]); + + $io->success("Password credential for '{$identity}' stored successfully!"); + + return Command::SUCCESS; + + } catch (\Throwable $e) { + $io->error('Failed to set password: ' . $e->getMessage()); + $this->logger->error('User password set failed', [ + 'tenant' => $tenant, + 'identity' => $identity, + 'error' => $e->getMessage(), + ]); + return Command::FAILURE; + } + } +} diff --git a/lib/Module.php b/lib/Module.php index d629825..e285534 100644 --- a/lib/Module.php +++ b/lib/Module.php @@ -5,13 +5,15 @@ declare(strict_types=1); namespace KTXM\AuthenticationProviderPassword; use KTXC\Resource\ProviderManager; +use KTXF\Module\ModuleConsoleInterface; use KTXF\Module\ModuleInstanceAbstract; +use KTXM\AuthenticationProviderPassword\Console\UserPasswordCommand; /** * Default Identity Provider Module * Provides local database authentication */ -class Module extends ModuleInstanceAbstract +class Module extends ModuleInstanceAbstract implements ModuleConsoleInterface { public function __construct( private readonly ProviderManager $providerManager, @@ -58,6 +60,13 @@ class Module extends ModuleInstanceAbstract $this->providerManager->register('authentication', 'password', Provider::class); } + public function registerCI(): array + { + return [ + UserPasswordCommand::class, + ]; + } + public function registerBI(): array { return [