From c42edce16dfddced05d29cb0e191f8f3d8c13c2b Mon Sep 17 00:00:00 2001 From: Marko Ivancic Date: Fri, 9 Feb 2024 13:58:40 +0100 Subject: [PATCH] Introduce installation script (#214) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introduce installation script to support automatic deployments * Update readme --------- Co-authored-by: Marko Ivančić --- README.md | 4 +++ bin/install.php | 39 ++++++++++++++++++++++++++ composer.json | 3 +- psalm.xml | 3 ++ src/Forms/ClientForm.php | 14 ++++++--- src/Forms/Controls/CsrfProtection.php | 3 +- src/Utils/ClaimTranslatorExtractor.php | 2 +- 7 files changed, 61 insertions(+), 7 deletions(-) create mode 100755 bin/install.php diff --git a/README.md b/README.md index b122b509..f09c0c59 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,10 @@ The module comes with some default SQL migrations which set up needed tables in open the _Federation_ tab from your _SimpleSAMLphp_ installation and select the option _OpenID Connect Installation_ inside the _Tools_ section. Once there, all you need to do is press the _Install_ button and the schema will be created. +Alternatively, in case of automatic / scripted deployments, you can run the 'install.php' script from the command line: + + php modules/oidc/bin/install.php + ### Relying Party (RP) Administration The module lets you manage (create, read, update and delete) approved RPs from the module user interface itself. diff --git a/bin/install.php b/bin/install.php new file mode 100755 index 00000000..6028c7ec --- /dev/null +++ b/bin/install.php @@ -0,0 +1,39 @@ +#!/usr/bin/env php +isUpdated()) { + echo 'Database is up to date, skipping.' . PHP_EOL; + return 0; + } + + echo 'Running database migrations.' . PHP_EOL; + + $databaseMigration->migrate(); + + echo 'Done running migrations.'; + return 0; +} catch (Throwable $exception) { + echo 'There was an error while trying run database migrations: ' . $exception->getMessage(); + return 1; +} diff --git a/composer.json b/composer.json index 14530243..39f8b63b 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,8 @@ }, "sort-packages": true, "allow-plugins": { - "simplesamlphp/composer-module-installer": true + "simplesamlphp/composer-module-installer": true, + "dealerdirect/phpcodesniffer-composer-installer": true }, "cache-dir": "build/composer" }, diff --git a/psalm.xml b/psalm.xml index ddac7608..0eb366f7 100644 --- a/psalm.xml +++ b/psalm.xml @@ -44,6 +44,9 @@ + + + diff --git a/src/Forms/ClientForm.php b/src/Forms/ClientForm.php index 5387e316..9b43be51 100644 --- a/src/Forms/ClientForm.php +++ b/src/Forms/ClientForm.php @@ -17,12 +17,16 @@ namespace SimpleSAML\Module\oidc\Forms; use Exception; +use Nette\Forms\Container; use Nette\Forms\Form; use SimpleSAML\Auth\Source; use SimpleSAML\Module\oidc\ModuleConfig; use SimpleSAML\Module\oidc\Forms\Controls\CsrfProtection; use Traversable; +/** + * @psalm-suppress PropertyNotSetInConstructor Raised for $httpRequest which is marked as internal, so won't handle. + */ class ClientForm extends Form { protected const TYPE_ARRAY = 'array'; @@ -123,7 +127,7 @@ protected function validateByMatchingRegex( } } - public function getValues($returnType = null, ?array $controls = null): array + public function getValues(string|object|bool|null $returnType = null, ?array $controls = null): array { /** @var array $values */ $values = parent::getValues(self::TYPE_ARRAY); @@ -157,7 +161,7 @@ public function getValues($returnType = null, ?array $controls = null): array /** * @throws Exception */ - public function setDefaults($data, bool $erase = false): ClientForm + public function setDefaults(object|array $data, bool $erase = false): static { if (! is_array($data)) { if ($data instanceof Traversable) { @@ -187,7 +191,9 @@ public function setDefaults($data, bool $erase = false): ClientForm $scopes = is_array($data['scopes']) ? $data['scopes'] : []; $data['scopes'] = array_intersect($scopes, array_keys($this->getScopes())); - return parent::setDefaults($data, $erase); + parent::setDefaults($data, $erase); + + return $this; } /** @@ -203,7 +209,7 @@ protected function buildForm(): void $this->onValidate[] = $this->validateBackChannelLogoutUri(...); $this->setMethod('POST'); - $this->addComponent(new CsrfProtection('{oidc:client:csrf_error}'), Form::PROTECTOR_ID); + $this->addComponent(new CsrfProtection('{oidc:client:csrf_error}'), Form::ProtectorId); $this->addText('name', '{oidc:client:name}') ->setMaxLength(255) diff --git a/src/Forms/Controls/CsrfProtection.php b/src/Forms/Controls/CsrfProtection.php index f7b81dd6..1935b4a9 100644 --- a/src/Forms/Controls/CsrfProtection.php +++ b/src/Forms/Controls/CsrfProtection.php @@ -21,6 +21,7 @@ use Nette\InvalidStateException; use Nette\Utils\Random; use SimpleSAML\Session; +use Stringable; class CsrfProtection extends BaseCsrfProtection { @@ -32,7 +33,7 @@ class CsrfProtection extends BaseCsrfProtection /** * @throws Exception */ - public function __construct(object|string $errorMessage) + public function __construct(string|Stringable|null $errorMessage) { // Instead of calling CsrfProtection parent class constructor, go to it's parent (HiddenField), and call // its constructor. This is to avoid setting a Nette session in CsrfProtection parent, and use the SSP one. diff --git a/src/Utils/ClaimTranslatorExtractor.php b/src/Utils/ClaimTranslatorExtractor.php index fee1ebfb..e52fc404 100644 --- a/src/Utils/ClaimTranslatorExtractor.php +++ b/src/Utils/ClaimTranslatorExtractor.php @@ -197,7 +197,7 @@ public function addClaimSet(ClaimSetEntityInterface $claimSet): self { $scope = $claimSet->getScope(); - if (in_array($scope, $this->protectedClaims) && !empty($this->claimSets[$scope])) { + if (in_array($scope, $this->protectedClaims) && isset($this->claimSets[$scope])) { throw OidcServerException::serverError( sprintf("%s is a protected scope and is pre-defined by the OpenID Connect specification.", $scope) );