diff options
| author | Marcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de> | 2022-07-15 11:47:35 +0000 |
|---|---|---|
| committer | Marcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de> | 2022-07-15 11:47:35 +0000 |
| commit | 55852ef4819e5eafce9ae53dc4de2d84cdad1778 (patch) | |
| tree | 9aedcdf89f416a7936f7df80da339a537082b5d5 /cli/Commands | |
| parent | a9585dad3547a4ebbadd00f44065f95017d18684 (diff) | |
StEP-366: Add OAuth2 support to Stud.IP
Closes #1035 and #1198
Merge request studip/studip!635
Diffstat (limited to 'cli/Commands')
| -rw-r--r-- | cli/Commands/OAuth2/Keys.php | 68 | ||||
| -rw-r--r-- | cli/Commands/OAuth2/Purge.php | 58 |
2 files changed, 126 insertions, 0 deletions
diff --git a/cli/Commands/OAuth2/Keys.php b/cli/Commands/OAuth2/Keys.php new file mode 100644 index 0000000..c9c0738 --- /dev/null +++ b/cli/Commands/OAuth2/Keys.php @@ -0,0 +1,68 @@ +<?php + +namespace Studip\Cli\Commands\OAuth2; + +use phpseclib\Crypt\RSA; +use Studip\OAuth2\Container; +use Studip\OAuth2\KeyInformation; +use Studip\OAuth2\SetupInformation; +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; + +class Keys extends Command +{ + protected static $defaultName = 'oauth2:keys'; + + protected function configure(): void + { + $this->setDescription( + 'Erstelle alle kryptografischen Schlüssel, um Stud.IP als OAuth2-Authorization-Server zu verwenden.' + ); + $this->addOption('force', null, InputOption::VALUE_NONE, 'Überschreibe ggf. vorhandene Schlüssel'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $container = new Container(); + $setup = $container->get(SetupInformation::class); + + $encryptionKey = $setup->encryptionKey(); + $publicKey = $setup->publicKey(); + $privateKey = $setup->privateKey(); + + $force = $input->getOption('force'); + + if (($encryptionKey->exists() || $publicKey->exists() || $privateKey->exists()) && !$force) { + $io->error( + 'Schlüsseldateien liegen bereits vor. Verwenden Sie die Option --force, um diese zu überschreiben.' + ); + return Command::FAILURE; + } + + $this->storeKeyContentsToFile($encryptionKey, $this->generateEncryptionKey()); + + $keys = (new RSA())->createKey(4096); + $this->storeKeyContentsToFile($publicKey, $keys['publickey']); + $this->storeKeyContentsToFile($privateKey, $keys['privatekey']); + + $io->info('Schlüsseldateien erfolgreich angelegt.'); + + return Command::SUCCESS; + } + + private function storeKeyContentsToFile(KeyInformation $key, string $contents) + { + file_put_contents($key->filename(), $contents); + chmod($key->filename(), 0660); + } + + private function generateEncryptionKey(): string + { + return "<?php return '" . randomString(48) . "';"; + } +} diff --git a/cli/Commands/OAuth2/Purge.php b/cli/Commands/OAuth2/Purge.php new file mode 100644 index 0000000..3f7561f --- /dev/null +++ b/cli/Commands/OAuth2/Purge.php @@ -0,0 +1,58 @@ +<?php + +namespace Studip\Cli\Commands\OAuth2; + +use Studip\OAuth2\Models\AccessToken; +use Studip\OAuth2\Models\AuthCode; +use Studip\OAuth2\Models\RefreshToken; +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; + +class Purge extends Command +{ + protected static $defaultName = 'oauth2:purge'; + + protected function configure(): void + { + $this->setDescription('Bereinige die OAuth2-Datenbanktabellen von widerrufenen und/oder abgelaufenen Token'); + $this->addOption('revoked', null, InputOption::VALUE_NONE, 'Entferne widerrufene Token'); + $this->addOption('expired', null, InputOption::VALUE_NONE, 'Entferne abgelaufene Token'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $expiryDate = strtotime('-7days midnight'); + + $revoked = $input->getOption('revoked'); + $expired = $input->getOption('expired'); + + if (($revoked && $expired) || (!$revoked && !$expired)) { + AccessToken::deleteBySQL('revoked = ? AND expires_at < ?', [1, $expiryDate]); + AuthCode::deleteBySQL('revoked = ? AND expires_at < ?', [1, $expiryDate]); + RefreshToken::deleteBySQL('revoked = ? AND expires_at < ?', [1, $expiryDate]); + + $io->info( + 'Alle Token, die widerrufen wurden oder vor mindestens 7 Tagen abgelaufen sind, wurden entfernt.' + ); + } elseif ($revoked) { + AccessToken::deleteBySQL('revoked = ?', [1]); + AuthCode::deleteBySQL('revoked = ?', [1]); + RefreshToken::deleteBySQL('revoked = ?', [1]); + + $io->info('Alle widerrufenen Token wurden entfernt.'); + } elseif ($expired) { + AccessToken::deleteBySQL('expires_at < ?', [$expiryDate]); + AuthCode::deleteBySQL('expires_at < ?', [$expiryDate]); + RefreshToken::deleteBySQL('expires_at < ?', [$expiryDate]); + + $io->info('Alle Token, die vor mindestens 7 Tagen abgelaufen sind, wurden entfernt.'); + } + + return Command::SUCCESS; + } +} |
