diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ab448556cc6009a00c2a58e79383ed0d833100a6..e4eeb4c5f8c14c8c3a0120ce7caeec1f38ba3afa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: test-latest: runs-on: ubuntu-latest container: - image: cicnavi/dap:08 + image: cicnavi/dap:81 steps: - uses: actions/checkout@v3 - name: Validate composer.json and composer.lock diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e50b5fbcf24142aed3b06bad6f59e1e0f93cefe2..36e6cd3690fc6dda60ce5f2f437dafe18764e240 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,10 +20,10 @@ test-74: - composer install --prefer-dist --no-progress --no-suggest - composer run-script pre-commit -# PHP latest -test-08: +# PHP v8.1 +test-81: stage: test - image: cicnavi/dap:08 + image: cicnavi/dap:81 script: - composer install --prefer-dist --no-progress --no-suggest - composer run-script pre-commit diff --git a/composer.json b/composer.json index 4c2e7fc0585800dcd5ef6d4b985dd873ceb8f2c9..f4af26fc1e71c85834a4a8dab99b5b084dd78814 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "php": "^7.4 || ^8.0", "ext-pdo": "*", "ext-pdo_sqlite": "*", + "composer-runtime-api": "^2.0", "doctrine/dbal": "^3", "psr/log": "^1|^2|^3", "simplesamlphp/composer-module-installer": "^1", @@ -37,8 +38,9 @@ "vimeo/psalm": "^5", "phpunit/phpunit": "^9", "squizlabs/php_codesniffer": "^3", - "simplesamlphp/simplesamlphp": "^2@beta", - "simplesamlphp/simplesamlphp-test-framework": "^1" + "simplesamlphp/simplesamlphp": "^2", + "simplesamlphp/simplesamlphp-test-framework": "^1", + "simplesamlphp/simplesamlphp-module-oidc": "^3" }, "suggest": { "ext-pcntl": "Enables job runner to gracefully respond to SIGTERM signal.", diff --git a/composer.lock b/composer.lock index 64d9ba629b02045077fc80ed0583d518673f4f11..76ddc7a1a19e4007287036be7a8c1e191051092a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fe21f8863239731b2f1746d3e887dff7", + "content-hash": "3bee36e7c2158fe267b7704bbd22ad26", "packages": [ { "name": "cicnavi/simple-file-cache-php", @@ -154,16 +154,16 @@ }, { "name": "doctrine/dbal", - "version": "3.6.0", + "version": "3.6.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "85b98cb23c8af471a67abfe14485da696bcabc2e" + "reference": "57815c7bbcda3cd18871d253c1dd8cbe56f8526e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/85b98cb23c8af471a67abfe14485da696bcabc2e", - "reference": "85b98cb23c8af471a67abfe14485da696bcabc2e", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/57815c7bbcda3cd18871d253c1dd8cbe56f8526e", + "reference": "57815c7bbcda3cd18871d253c1dd8cbe56f8526e", "shasum": "" }, "require": { @@ -179,11 +179,11 @@ "doctrine/coding-standard": "11.1.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2022.3", - "phpstan/phpstan": "1.9.14", - "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "9.6.3", + "phpstan/phpstan": "1.10.3", + "phpstan/phpstan-strict-rules": "^1.5", + "phpunit/phpunit": "9.6.4", "psalm/plugin-phpunit": "0.18.4", - "squizlabs/php_codesniffer": "3.7.1", + "squizlabs/php_codesniffer": "3.7.2", "symfony/cache": "^5.4|^6.0", "symfony/console": "^4.4|^5.4|^6.0", "vimeo/psalm": "4.30.0" @@ -246,7 +246,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.6.0" + "source": "https://github.com/doctrine/dbal/tree/3.6.1" }, "funding": [ { @@ -262,7 +262,7 @@ "type": "tidelift" } ], - "time": "2023-02-07T22:52:03+00:00" + "time": "2023-03-02T19:26:24+00:00" }, { "name": "doctrine/deprecations", @@ -605,22 +605,22 @@ }, { "name": "simplesamlphp/composer-module-installer", - "version": "v1.3.3", + "version": "v1.3.4", "source": { "type": "git", "url": "https://github.com/simplesamlphp/composer-module-installer.git", - "reference": "ad700e45b1813cd7bfb067bcf66c78c5b410125f" + "reference": "36508ed9580a30c4d5ab0bb3c25c00d0b5d42946" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/composer-module-installer/zipball/ad700e45b1813cd7bfb067bcf66c78c5b410125f", - "reference": "ad700e45b1813cd7bfb067bcf66c78c5b410125f", + "url": "https://api.github.com/repos/simplesamlphp/composer-module-installer/zipball/36508ed9580a30c4d5ab0bb3c25c00d0b5d42946", + "reference": "36508ed9580a30c4d5ab0bb3c25c00d0b5d42946", "shasum": "" }, "require": { "composer-plugin-api": "^1.1 || ^2.0", "php": "^7.4 || ^8.0", - "simplesamlphp/assert": "^0.8.0" + "simplesamlphp/assert": "^0.8.0 || ^1.0" }, "require-dev": { "composer/composer": "^2.4", @@ -642,9 +642,9 @@ "description": "A Composer plugin that allows installing SimpleSAMLphp modules through Composer.", "support": { "issues": "https://github.com/simplesamlphp/composer-module-installer/issues", - "source": "https://github.com/simplesamlphp/composer-module-installer/tree/v1.3.3" + "source": "https://github.com/simplesamlphp/composer-module-installer/tree/v1.3.4" }, - "time": "2023-01-31T09:51:44+00:00" + "time": "2023-03-08T20:58:22+00:00" }, { "name": "webmozart/assert", @@ -872,6 +872,66 @@ ], "time": "2021-03-30T17:13:30+00:00" }, + { + "name": "brick/math", + "version": "0.9.3", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "vimeo/psalm": "4.9.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "brick", + "math" + ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.9.3" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/brick/math", + "type": "tidelift" + } + ], + "time": "2021-08-15T20:50:18+00:00" + }, { "name": "composer/ca-bundle", "version": "1.3.5", @@ -1023,16 +1083,16 @@ }, { "name": "composer/composer", - "version": "2.5.4", + "version": "2.5.5", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "6b67eeea4d72051c369ccdbfb2423a56e2ab51a9" + "reference": "c7cffaad16a60636a776017eac5bd8cd0095c32f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/6b67eeea4d72051c369ccdbfb2423a56e2ab51a9", - "reference": "6b67eeea4d72051c369ccdbfb2423a56e2ab51a9", + "url": "https://api.github.com/repos/composer/composer/zipball/c7cffaad16a60636a776017eac5bd8cd0095c32f", + "reference": "c7cffaad16a60636a776017eac5bd8cd0095c32f", "shasum": "" }, "require": { @@ -1116,7 +1176,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.5.4" + "source": "https://github.com/composer/composer/tree/2.5.5" }, "funding": [ { @@ -1132,7 +1192,7 @@ "type": "tidelift" } ], - "time": "2023-02-15T12:10:06+00:00" + "time": "2023-03-21T10:50:05+00:00" }, { "name": "composer/metadata-minifier", @@ -1203,79 +1263,6 @@ ], "time": "2021-04-07T13:37:33+00:00" }, - { - "name": "composer/package-versions-deprecated", - "version": "1.11.99.5", - "source": { - "type": "git", - "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", - "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7 || ^8" - }, - "replace": { - "ocramius/package-versions": "1.11.99" - }, - "require-dev": { - "composer/composer": "^1.9.3 || ^2.0@dev", - "ext-zip": "^1.13", - "phpunit/phpunit": "^6.5 || ^7" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "support": { - "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-01-17T14:14:24+00:00" - }, { "name": "composer/pcre", "version": "3.1.0", @@ -1574,6 +1561,72 @@ ], "time": "2022-02-25T21:32:43+00:00" }, + { + "name": "defuse/php-encryption", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/defuse/php-encryption.git", + "reference": "77880488b9954b7884c25555c2a0ea9e7053f9d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/defuse/php-encryption/zipball/77880488b9954b7884c25555c2a0ea9e7053f9d2", + "reference": "77880488b9954b7884c25555c2a0ea9e7053f9d2", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "paragonie/random_compat": ">= 2", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5|^6|^7|^8|^9" + }, + "bin": [ + "bin/generate-defuse-key" + ], + "type": "library", + "autoload": { + "psr-4": { + "Defuse\\Crypto\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Hornby", + "email": "taylor@defuse.ca", + "homepage": "https://defuse.ca/" + }, + { + "name": "Scott Arciszewski", + "email": "info@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "Secure PHP Encryption Library", + "keywords": [ + "aes", + "authenticated encryption", + "cipher", + "crypto", + "cryptography", + "encrypt", + "encryption", + "openssl", + "security", + "symmetric key cryptography" + ], + "support": { + "issues": "https://github.com/defuse/php-encryption/issues", + "source": "https://github.com/defuse/php-encryption/tree/v2.3.1" + }, + "time": "2021-04-09T23:57:26+00:00" + }, { "name": "dnoegel/php-xdg-base-dir", "version": "v0.1.1", @@ -1782,6 +1835,82 @@ }, "time": "2022-03-02T22:36:06+00:00" }, + { + "name": "fgrosse/phpasn1", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/fgrosse/PHPASN1.git", + "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/42060ed45344789fb9f21f9f1864fc47b9e3507b", + "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "~2.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + }, + "suggest": { + "ext-bcmath": "BCmath is the fallback extension for big integer calculations", + "ext-curl": "For loading OID information from the web if they have not bee defined statically", + "ext-gmp": "GMP is the preferred extension for big integer calculations", + "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "FG\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Friedrich Große", + "email": "friedrich.grosse@gmail.com", + "homepage": "https://github.com/FGrosse", + "role": "Author" + }, + { + "name": "All contributors", + "homepage": "https://github.com/FGrosse/PHPASN1/contributors" + } + ], + "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", + "homepage": "https://github.com/FGrosse/PHPASN1", + "keywords": [ + "DER", + "asn.1", + "asn1", + "ber", + "binary", + "decoding", + "encoding", + "x.509", + "x.690", + "x509", + "x690" + ], + "support": { + "issues": "https://github.com/fgrosse/PHPASN1/issues", + "source": "https://github.com/fgrosse/PHPASN1/tree/v2.5.0" + }, + "abandoned": true, + "time": "2022-12-19T11:08:26+00:00" + }, { "name": "fidry/cpu-core-counter", "version": "0.5.1", @@ -2066,39 +2195,58 @@ "time": "2022-02-23T20:29:40+00:00" }, { - "name": "justinrainbow/json-schema", - "version": "5.2.12", + "name": "guzzlehttp/guzzle", + "version": "7.5.0", "source": { "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60" + "url": "https://github.com/guzzle/guzzle.git", + "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba", + "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba", "shasum": "" }, "require": { - "php": ">=5.3.3" + "ext-json": "*", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.9 || ^2.4", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", - "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" + "bamarni/composer-bin-plugin": "^1.8.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" }, - "bin": [ - "bin/validate-json" - ], "type": "library", "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, "branch-alias": { - "dev-master": "5.0.x-dev" + "dev-master": "7.5-dev" } }, "autoload": { + "files": [ + "src/functions_include.php" + ], "psr-4": { - "JsonSchema\\": "src/JsonSchema/" + "GuzzleHttp\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2107,76 +2255,1065 @@ ], "authors": [ { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" }, { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" }, { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", + "description": "Guzzle is a PHP HTTP client library", "keywords": [ - "json", - "schema" + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" ], "support": { - "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12" + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.5.0" }, - "time": "2022-04-13T08:02:27+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-08-28T15:39:27+00:00" }, { - "name": "myclabs/deep-copy", - "version": "1.11.0", + "name": "guzzlehttp/promises", + "version": "1.5.2", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "url": "https://github.com/guzzle/promises.git", + "reference": "b94b2807d85443f9719887892882d0329d1e2598" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "php": ">=5.5" }, "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, "autoload": { "files": [ - "src/DeepCopy/deep_copy.php" + "src/functions_include.php" ], "psr-4": { - "DeepCopy\\": "src/DeepCopy/" + "GuzzleHttp\\Promise\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Create deep copies (clones) of your objects", + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", "keywords": [ - "clone", + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2022-08-28T14:55:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.4.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", + "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.4.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-03-09T13:19:02+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "5.2.12", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", + "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/justinrainbow/json-schema/issues", + "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12" + }, + "time": "2022-04-13T08:02:27+00:00" + }, + { + "name": "laminas/laminas-diactoros", + "version": "2.17.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "5b32597aa46b83c8b85bb1cf9a6ed4fe7dd980c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/5b32597aa46b83c8b85bb1cf9a6ed4fe7dd980c5", + "reference": "5b32597aa46b83c8b85bb1cf9a6ed4fe7dd980c5", + "shasum": "" + }, + "require": { + "php": "^7.4 || ~8.0.0 || ~8.1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "conflict": { + "zendframework/zend-diactoros": "*" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-gd": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^0.9.0", + "laminas/laminas-coding-standard": "^2.4.0", + "php-http/psr7-integration-tests": "^1.1.1", + "phpunit/phpunit": "^9.5.23", + "psalm/plugin-phpunit": "^0.17.0", + "vimeo/psalm": "^4.24.0" + }, + "type": "library", + "extra": { + "laminas": { + "config-provider": "Laminas\\Diactoros\\ConfigProvider", + "module": "Laminas\\Diactoros" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php", + "src/functions/create_uploaded_file.legacy.php", + "src/functions/marshal_headers_from_sapi.legacy.php", + "src/functions/marshal_method_from_sapi.legacy.php", + "src/functions/marshal_protocol_version_from_sapi.legacy.php", + "src/functions/marshal_uri_from_sapi.legacy.php", + "src/functions/normalize_server.legacy.php", + "src/functions/normalize_uploaded_files.legacy.php", + "src/functions/parse_cookie_header.legacy.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-17", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2022-08-30T17:01:46+00:00" + }, + { + "name": "laminas/laminas-httphandlerrunner", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-httphandlerrunner.git", + "reference": "5f94e55d93f756e8ad07b9049aeb3d6d84582d0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/5f94e55d93f756e8ad07b9049aeb3d6d84582d0e", + "reference": "5f94e55d93f756e8ad07b9049aeb3d6d84582d0e", + "shasum": "" + }, + "require": { + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^7.3 || ~8.0.0 || ~8.1.0", + "psr/http-message": "^1.0", + "psr/http-message-implementation": "^1.0", + "psr/http-server-handler": "^1.0" + }, + "replace": { + "zendframework/zend-httphandlerrunner": "^1.1.0" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~1.0.0", + "laminas/laminas-diactoros": "^2.8.0", + "phpunit/phpunit": "^9.5.9", + "psalm/plugin-phpunit": "^0.16.1", + "vimeo/psalm": "^4.10.0" + }, + "type": "library", + "extra": { + "laminas": { + "config-provider": "Laminas\\HttpHandlerRunner\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Laminas\\HttpHandlerRunner\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Execute PSR-15 RequestHandlerInterface instances and emit responses they generate.", + "homepage": "https://laminas.dev", + "keywords": [ + "components", + "laminas", + "mezzio", + "psr-15", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-httphandlerrunner/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-httphandlerrunner/issues", + "rss": "https://github.com/laminas/laminas-httphandlerrunner/releases.atom", + "source": "https://github.com/laminas/laminas-httphandlerrunner" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2021-09-22T09:17:54+00:00" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "e112dd2c099f4f6142c16fc65fda89a638e06885" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/e112dd2c099f4f6142c16fc65fda89a638e06885", + "reference": "e112dd2c099f4f6142c16fc65fda89a638e06885", + "shasum": "" + }, + "require": { + "php": ">=7.4, <8.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5.14", + "psalm/plugin-phpunit": "^0.15.2", + "squizlabs/php_codesniffer": "^3.6.2", + "vimeo/psalm": "^4.21.0" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2022-07-29T13:28:29+00:00" + }, + { + "name": "lcobucci/clock", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/clock.git", + "reference": "353d83fe2e6ae95745b16b3d911813df6a05bfb3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/353d83fe2e6ae95745b16b3d911813df6a05bfb3", + "reference": "353d83fe2e6ae95745b16b3d911813df6a05bfb3", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "infection/infection": "^0.17", + "lcobucci/coding-standard": "^6.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/php-code-coverage": "9.1.4", + "phpunit/phpunit": "9.3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/2.0.x" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2020-08-27T18:56:02+00:00" + }, + { + "name": "lcobucci/jwt", + "version": "4.3.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/4d7de2fe0d51a96418c0d04004986e410e87f6b4", + "reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-sodium": "*", + "lcobucci/clock": "^2.0 || ^3.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "infection/infection": "^0.21", + "lcobucci/coding-standard": "^6.0", + "mikey179/vfsstream": "^1.6.7", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/php-invoker": "^3.1", + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/4.3.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2023-01-02T13:28:00+00:00" + }, + { + "name": "league/event", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/event.git", + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/event/zipball/d2cc124cf9a3fab2bb4ff963307f60361ce4d119", + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "~1.0.1", + "phpspec/phpspec": "^2.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Event\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Event package", + "keywords": [ + "emitter", + "event", + "listener" + ], + "support": { + "issues": "https://github.com/thephpleague/event/issues", + "source": "https://github.com/thephpleague/event/tree/master" + }, + "time": "2018-11-26T11:52:41+00:00" + }, + { + "name": "league/oauth2-server", + "version": "8.4.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth2-server.git", + "reference": "eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24", + "reference": "eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24", + "shasum": "" + }, + "require": { + "defuse/php-encryption": "^2.2.1", + "ext-json": "*", + "ext-openssl": "*", + "lcobucci/jwt": "^3.4.6 || ^4.0.4", + "league/event": "^2.2", + "league/uri": "^6.4", + "php": "^7.2 || ^8.0", + "psr/http-message": "^1.0.1" + }, + "replace": { + "league/oauth2server": "*", + "lncd/oauth2": "*" + }, + "require-dev": { + "laminas/laminas-diactoros": "^2.4.1", + "phpstan/phpstan": "^0.12.57", + "phpstan/phpstan-phpunit": "^0.12.16", + "phpunit/phpunit": "^8.5.13", + "roave/security-advisories": "dev-master" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\OAuth2\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Bilbie", + "email": "hello@alexbilbie.com", + "homepage": "http://www.alexbilbie.com", + "role": "Developer" + }, + { + "name": "Andy Millington", + "email": "andrew@noexceptions.io", + "homepage": "https://www.noexceptions.io", + "role": "Developer" + } + ], + "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", + "homepage": "https://oauth2.thephpleague.com/", + "keywords": [ + "Authentication", + "api", + "auth", + "authorisation", + "authorization", + "oauth", + "oauth 2", + "oauth 2.0", + "oauth2", + "protect", + "resource", + "secure", + "server" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth2-server/issues", + "source": "https://github.com/thephpleague/oauth2-server/tree/8.4.1" + }, + "funding": [ + { + "url": "https://github.com/sephster", + "type": "github" + } + ], + "time": "2023-03-22T11:47:53+00:00" + }, + { + "name": "league/uri", + "version": "6.7.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "d3b50812dd51f3fbf176344cc2981db03d10fe06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/d3b50812dd51f3fbf176344cc2981db03d10fe06", + "reference": "d3b50812dd51f3fbf176344cc2981db03d10fe06", + "shasum": "" + }, + "require": { + "ext-json": "*", + "league/uri-interfaces": "^2.3", + "php": "^7.4 || ^8.0", + "psr/http-message": "^1.0" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v3.3.2", + "nyholm/psr7": "^1.5", + "php-http/psr7-integration-tests": "^1.1", + "phpstan/phpstan": "^1.2.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpstan/phpstan-strict-rules": "^1.1.0", + "phpunit/phpunit": "^9.5.10", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-fileinfo": "Needed to create Data URI from a filepath", + "ext-intl": "Needed to improve host validation", + "league/uri-components": "Needed to easily manipulate URI objects", + "psr/http-factory": "Needed to use the URI factory" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri/issues", + "source": "https://github.com/thephpleague/uri/tree/6.7.2" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2022-09-13T19:50:42+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/00e7e2943f76d8cb50c7dfdc2f6dee356e15e383", + "reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.19", + "phpstan/phpstan": "^0.12.90", + "phpstan/phpstan-phpunit": "^0.12.19", + "phpstan/phpstan-strict-rules": "^0.12.9", + "phpunit/phpunit": "^8.5.15 || ^9.5" + }, + "suggest": { + "ext-intl": "to use the IDNA feature", + "symfony/intl": "to use the IDNA feature via Symfony Polyfill" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interface for URI representation", + "homepage": "http://github.com/thephpleague/uri-interfaces", + "keywords": [ + "rfc3986", + "rfc3987", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/thephpleague/uri-interfaces/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2021-06-28T04:27:21+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", "copy", "duplicate", "object", @@ -2184,7 +3321,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -2192,7 +3329,7 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "netresearch/jsonmapper", @@ -2245,18 +3382,318 @@ }, "time": "2022-12-08T20:46:14+00:00" }, + { + "name": "nette/component-model", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/nette/component-model.git", + "reference": "9d97c0e1916bbf8e306283ab187834501fd4b1f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/component-model/zipball/9d97c0e1916bbf8e306283ab187834501fd4b1f5", + "reference": "9d97c0e1916bbf8e306283ab187834501fd4b1f5", + "shasum": "" + }, + "require": { + "nette/utils": "^2.5 || ^3.0 || ~4.0.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "⚛ Nette Component Model", + "homepage": "https://nette.org", + "keywords": [ + "components", + "nette" + ], + "support": { + "issues": "https://github.com/nette/component-model/issues", + "source": "https://github.com/nette/component-model/tree/v3.0.3" + }, + "time": "2023-01-09T20:16:05+00:00" + }, + { + "name": "nette/forms", + "version": "v3.1.11", + "source": { + "type": "git", + "url": "https://github.com/nette/forms.git", + "reference": "64cdc2d6796a8fe1265bb21a6ee5e9ff93e2b3a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/forms/zipball/64cdc2d6796a8fe1265bb21a6ee5e9ff93e2b3a4", + "reference": "64cdc2d6796a8fe1265bb21a6ee5e9ff93e2b3a4", + "shasum": "" + }, + "require": { + "nette/component-model": "^3.0", + "nette/http": "^3.1", + "nette/utils": "^3.2.5 || ~4.0.0", + "php": ">=7.2 <8.3" + }, + "conflict": { + "latte/latte": ">=3.1" + }, + "require-dev": { + "latte/latte": "^2.10.2 || ^3.0.3", + "nette/application": "^3.0", + "nette/di": "^3.0", + "nette/tester": "^2.4", + "phpstan/phpstan-nette": "^1", + "tracy/tracy": "^2.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📝 Nette Forms: generating, validating and processing secure forms in PHP. Handy API, fully customizable, server & client side validation and mature design.", + "homepage": "https://nette.org", + "keywords": [ + "Forms", + "bootstrap", + "csrf", + "javascript", + "nette", + "validation" + ], + "support": { + "issues": "https://github.com/nette/forms/issues", + "source": "https://github.com/nette/forms/tree/v3.1.11" + }, + "time": "2023-03-08T23:56:24+00:00" + }, + { + "name": "nette/http", + "version": "v3.2.2", + "source": { + "type": "git", + "url": "https://github.com/nette/http.git", + "reference": "9105c26de3dd47da5e7cf6b4132b5d871f835e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/http/zipball/9105c26de3dd47da5e7cf6b4132b5d871f835e25", + "reference": "9105c26de3dd47da5e7cf6b4132b5d871f835e25", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2.1 || ~4.0.0", + "php": ">=7.2 <8.3" + }, + "conflict": { + "nette/di": "<3.0.3", + "nette/schema": "<1.2" + }, + "require-dev": { + "nette/di": "^3.0", + "nette/security": "^3.0", + "nette/tester": "^2.4", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.8" + }, + "suggest": { + "ext-fileinfo": "to detect type of uploaded files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🌐 Nette Http: abstraction for HTTP request, response and session. Provides careful data sanitization and utility for URL and cookies manipulation.", + "homepage": "https://nette.org", + "keywords": [ + "cookies", + "http", + "nette", + "proxy", + "request", + "response", + "security", + "session", + "url" + ], + "support": { + "issues": "https://github.com/nette/http/issues", + "source": "https://github.com/nette/http/tree/v3.2.2" + }, + "time": "2023-03-18T14:55:56+00:00" + }, + { + "name": "nette/utils", + "version": "v3.2.9", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "c91bac3470c34b2ecd5400f6e6fdf0b64a836a5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/c91bac3470c34b2ecd5400f6e6fdf0b64a836a5c", + "reference": "c91bac3470c34b2ecd5400f6e6fdf0b64a836a5c", + "shasum": "" + }, + "require": { + "php": ">=7.2 <8.3" + }, + "conflict": { + "nette/di": "<3.0.6" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "~2.0", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v3.2.9" + }, + "time": "2023-01-18T03:26:20+00:00" + }, { "name": "nikic/php-parser", - "version": "v4.15.3", + "version": "v4.15.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", "shasum": "" }, "require": { @@ -2297,9 +3734,59 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + }, + "time": "2023-03-05T19:49:14+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" }, - "time": "2023-01-16T22:05:37+00:00" + "time": "2020-10-15T08:29:30+00:00" }, { "name": "phar-io/manifest", @@ -2524,24 +4011,27 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.2", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + "reference": "dfc078e8af9c99210337325ff5aa152872c98714" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", + "reference": "dfc078e8af9c99210337325ff5aa152872c98714", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" }, "require-dev": { "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", @@ -2573,22 +4063,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" }, - "time": "2022-10-14T12:47:21+00:00" + "time": "2023-03-27T19:02:04+00:00" }, { "name": "phpmailer/phpmailer", - "version": "v6.7.1", + "version": "v6.8.0", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55" + "reference": "df16b615e371d81fb79e506277faea67a1be18f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/49cd7ea3d2563f028d7811f06864a53b1f15ff55", - "reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1", + "reference": "df16b615e371d81fb79e506277faea67a1be18f1", "shasum": "" }, "require": { @@ -2625,57 +4115,102 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-2.1-only" - ], - "authors": [ - { - "name": "Marcus Bointon", - "email": "phpmailer@synchromedia.co.uk" - }, - { - "name": "Jim Jagielski", - "email": "jimjag@gmail.com" - }, - { - "name": "Andy Prevost", - "email": "codeworxtech@users.sourceforge.net" - }, - { - "name": "Brent R. Matzelle" - } + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "time": "2023-03-06T14:43:22+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.17.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "d3753fcb3abc6f78f5de6f72153d4b9c99c72dee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/d3753fcb3abc6f78f5de6f72153d4b9c99c72dee", + "reference": "d3753fcb3abc6f78f5de6f72153d4b9c99c72dee", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], - "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { - "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.7.1" + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.17.1" }, - "funding": [ - { - "url": "https://github.com/Synchro", - "type": "github" - } - ], - "time": "2022-12-08T13:30:06+00:00" + "time": "2023-04-04T11:11:22+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.24", + "version": "9.2.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", - "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.15", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -2690,8 +4225,8 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { @@ -2724,7 +4259,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" }, "funding": [ { @@ -2732,7 +4267,7 @@ "type": "github" } ], - "time": "2023-01-26T08:26:55+00:00" + "time": "2023-03-06T12:58:08+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2977,16 +4512,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.3", + "version": "9.6.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", - "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115", + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115", "shasum": "" }, "require": { @@ -3019,8 +4554,8 @@ "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -3059,7 +4594,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6" }, "funding": [ { @@ -3075,7 +4611,7 @@ "type": "tidelift" } ], - "time": "2023-02-04T13:37:15+00:00" + "time": "2023-03-27T11:43:46+00:00" }, { "name": "psr/container", @@ -3175,6 +4711,267 @@ }, "time": "2019-01-08T18:20:26+00:00" }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "time": "2023-04-04T09:50:52+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-handler/issues", + "source": "https://github.com/php-fig/http-server-handler/tree/master" + }, + "time": "2018-10-30T16:46:14+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "react/promise", "version": "v2.9.0", @@ -4432,16 +6229,16 @@ }, { "name": "simplesamlphp/saml2", - "version": "v4.6.5", + "version": "v4.6.6", "source": { "type": "git", "url": "https://github.com/simplesamlphp/saml2.git", - "reference": "35e4cac48ef97d454d25a92eb24c85cadf96de9d" + "reference": "717c0adc4877ebd58428637e5626345e59fa0109" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/35e4cac48ef97d454d25a92eb24c85cadf96de9d", - "reference": "35e4cac48ef97d454d25a92eb24c85cadf96de9d", + "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/717c0adc4877ebd58428637e5626345e59fa0109", + "reference": "717c0adc4877ebd58428637e5626345e59fa0109", "shasum": "" }, "require": { @@ -4484,22 +6281,22 @@ "description": "SAML2 PHP library from SimpleSAMLphp", "support": { "issues": "https://github.com/simplesamlphp/saml2/issues", - "source": "https://github.com/simplesamlphp/saml2/tree/v4.6.5" + "source": "https://github.com/simplesamlphp/saml2/tree/v4.6.6" }, - "time": "2022-11-23T12:50:43+00:00" + "time": "2023-03-08T19:32:49+00:00" }, { "name": "simplesamlphp/simplesamlphp", - "version": "v2.0.0-rc3", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/simplesamlphp/simplesamlphp.git", - "reference": "052359245640b596e459599a6d25e9f4be97b198" + "reference": "de912366cb73087889c580dca354582e8ef560e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp/zipball/052359245640b596e459599a6d25e9f4be97b198", - "reference": "052359245640b596e459599a6d25e9f4be97b198", + "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp/zipball/de912366cb73087889c580dca354582e8ef560e0", + "reference": "de912366cb73087889c580dca354582e8ef560e0", "shasum": "" }, "require": { @@ -4521,7 +6318,7 @@ "simplesamlphp/assert": "^0.8.0", "simplesamlphp/composer-module-installer": "^1.3.0", "simplesamlphp/saml2": "^4.6", - "simplesamlphp/simplesamlphp-assets-base": "^2.0.0", + "simplesamlphp/simplesamlphp-assets-base": "^2.0", "symfony/cache": "^5.4", "symfony/config": "^5.4", "symfony/console": "^5.4", @@ -4591,7 +6388,7 @@ } ], "description": "A PHP implementation of a SAML 2.0 service provider and identity provider.", - "homepage": "http://simplesamlphp.org", + "homepage": "https://simplesamlphp.org", "keywords": [ "SAML2", "idp", @@ -4604,20 +6401,20 @@ "issues": "https://github.com/simplesamlphp/simplesamlphp/issues", "source": "https://github.com/simplesamlphp/simplesamlphp" }, - "time": "2023-01-31T12:11:10+00:00" + "time": "2023-03-29T20:24:27+00:00" }, { "name": "simplesamlphp/simplesamlphp-assets-base", - "version": "v2.0.3", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/simplesamlphp/simplesamlphp-assets-base.git", - "reference": "dcc7c7e485a6e6f03e6b2ff7abf64a2149a2fdd0" + "reference": "d2aed5063349880897515b71fca85300e5fad2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-assets-base/zipball/dcc7c7e485a6e6f03e6b2ff7abf64a2149a2fdd0", - "reference": "dcc7c7e485a6e6f03e6b2ff7abf64a2149a2fdd0", + "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-assets-base/zipball/d2aed5063349880897515b71fca85300e5fad2c9", + "reference": "d2aed5063349880897515b71fca85300e5fad2c9", "shasum": "" }, "require": { @@ -4638,41 +6435,117 @@ "description": "Assets for the SimpleSAMLphp main repository", "support": { "issues": "https://github.com/simplesamlphp/simplesamlphp-assets-base/issues", - "source": "https://github.com/simplesamlphp/simplesamlphp-assets-base/tree/v2.0.3" + "source": "https://github.com/simplesamlphp/simplesamlphp-assets-base/tree/v2.0.4" + }, + "time": "2023-02-27T17:17:05+00:00" + }, + { + "name": "simplesamlphp/simplesamlphp-module-oidc", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/simplesamlphp/simplesamlphp-module-oidc.git", + "reference": "28679773dbc795756d7980006b58e2599701ad53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-module-oidc/zipball/28679773dbc795756d7980006b58e2599701ad53", + "reference": "28679773dbc795756d7980006b58e2599701ad53", + "shasum": "" + }, + "require": { + "ext-curl": ">=7.4", + "ext-json": "*", + "ext-openssl": "*", + "ext-pdo": "*", + "guzzlehttp/guzzle": "^7.0", + "laminas/laminas-diactoros": "^2.2.1", + "laminas/laminas-httphandlerrunner": "^1.1.0", + "lcobucci/jwt": "^4.1", + "league/oauth2-server": "^8.1.0", + "nette/forms": "^3", + "php": ">=7.4", + "psr/container": "^1.0", + "psr/log": "^1.1", + "simplesamlphp/composer-module-installer": "^1.2", + "spomky-labs/base64url": "^2.0", + "steverhoades/oauth2-openid-connect-server": "^2.0", + "web-token/jwt-framework": "^2.1" }, - "time": "2023-02-22T12:34:35+00:00" + "require-dev": { + "friends-of-phpspec/phpspec-code-coverage": "^6.1", + "friendsofphp/php-cs-fixer": "^3", + "phpspec/phpspec": "^7.1.0", + "phpunit/php-code-coverage": "^9.0.0", + "phpunit/phpcov": "^8.2.0", + "phpunit/phpunit": "^9.0.0", + "simplesamlphp/simplesamlphp": "^v2.0.0", + "simplesamlphp/simplesamlphp-test-framework": "^1.2.1", + "squizlabs/php_codesniffer": "^3.7", + "vimeo/psalm": "^5.8" + }, + "type": "simplesamlphp-module", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "SimpleSAML\\Module\\oidc\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Spanish Research and Academic Network" + }, + { + "name": "University of Córdoba" + }, + { + "name": "Sergio Gómez", + "email": "sergio@uco.es" + } + ], + "description": "A SimpleSAMLphp module adding support for the OpenID Connect protocol", + "keywords": [ + "OpenID Connect", + "OpenId", + "connect", + "oauth2", + "oidc" + ], + "support": { + "issues": "https://github.com/simplesamlphp/simplesamlphp-module-oidc/issues", + "source": "https://github.com/simplesamlphp/simplesamlphp-module-oidc/tree/v3.0.0" + }, + "time": "2023-03-22T08:49:10+00:00" }, { "name": "simplesamlphp/simplesamlphp-test-framework", - "version": "v1.2.2", + "version": "v1.5.4", "source": { "type": "git", "url": "https://github.com/simplesamlphp/simplesamlphp-test-framework.git", - "reference": "9e39e7ed40da8324c901e997bae7c749621b2859" + "reference": "b627dd12d1d5bb50cef5336b9726f3a2d1b4969e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-test-framework/zipball/9e39e7ed40da8324c901e997bae7c749621b2859", - "reference": "9e39e7ed40da8324c901e997bae7c749621b2859", + "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-test-framework/zipball/b627dd12d1d5bb50cef5336b9726f3a2d1b4969e", + "reference": "b627dd12d1d5bb50cef5336b9726f3a2d1b4969e", "shasum": "" }, "require": { - "php": ">=7.4|^8.0", - "phpunit/phpunit": "^8.5|^9.5", - "squizlabs/php_codesniffer": "^3.6", - "symfony/phpunit-bridge": "^6.0", - "vimeo/psalm": "^4.20|^5.0.0-beta1" + "phpunit/phpunit": "^9.6 || ^10.0" }, "require-dev": { "ext-curl": "*", - "simplesamlphp/simplesamlphp": "dev-master" + "simplesamlphp/simplesamlphp": "^2.0.0" }, - "bin": [ - "bin/check-syntax-json.sh", - "bin/check-syntax-php.sh", - "bin/check-syntax-xml.sh", - "bin/check-syntax-yaml.sh" - ], "type": "project", "autoload": { "psr-4": { @@ -4697,7 +6570,7 @@ "issues": "https://github.com/simplesamlphp/simplesamlphp-test-framework/issues", "source": "https://github.com/simplesamlphp/simplesamlphp-test-framework" }, - "time": "2023-01-12T16:20:27+00:00" + "time": "2023-03-16T20:42:22+00:00" }, { "name": "spatie/array-to-xml", @@ -4763,18 +6636,153 @@ ], "time": "2022-12-26T08:22:07+00:00" }, + { + "name": "spomky-labs/aes-key-wrap", + "version": "v6.0.0", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/aes-key-wrap.git", + "reference": "97388255a37ad6fb1ed332d07e61fa2b7bb62e0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/aes-key-wrap/zipball/97388255a37ad6fb1ed332d07e61fa2b7bb62e0d", + "reference": "97388255a37ad6fb1ed332d07e61fa2b7bb62e0d", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "lib-openssl": "*", + "php": ">=7.2", + "thecodingmachine/safe": "^1.1" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-beberlei-assert": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "thecodingmachine/phpstan-safe-rule": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "AESKW\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/aes-key-wrap/contributors" + } + ], + "description": "AES Key Wrap for PHP.", + "homepage": "https://github.com/Spomky-Labs/aes-key-wrap", + "keywords": [ + "A128KW", + "A192KW", + "A256KW", + "RFC3394", + "RFC5649", + "aes", + "key", + "padding", + "wrap" + ], + "support": { + "issues": "https://github.com/Spomky-Labs/aes-key-wrap/issues", + "source": "https://github.com/Spomky-Labs/aes-key-wrap/tree/v6.0.0" + }, + "time": "2020-08-01T14:07:55+00:00" + }, + { + "name": "spomky-labs/base64url", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/base64url.git", + "reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/7752ce931ec285da4ed1f4c5aa27e45e097be61d", + "reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.11|^0.12", + "phpstan/phpstan-beberlei-assert": "^0.11|^0.12", + "phpstan/phpstan-deprecation-rules": "^0.11|^0.12", + "phpstan/phpstan-phpunit": "^0.11|^0.12", + "phpstan/phpstan-strict-rules": "^0.11|^0.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Base64Url\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/base64url/contributors" + } + ], + "description": "Base 64 URL Safe Encoding/Decoding PHP Library", + "homepage": "https://github.com/Spomky-Labs/base64url", + "keywords": [ + "base64", + "rfc4648", + "safe", + "url" + ], + "support": { + "issues": "https://github.com/Spomky-Labs/base64url/issues", + "source": "https://github.com/Spomky-Labs/base64url/tree/v2.0.4" + }, + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2020-11-03T09:10:25+00:00" + }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.1", + "version": "3.7.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", - "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", "shasum": "" }, "require": { @@ -4810,27 +6818,73 @@ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", - "standards" + "standards", + "static analysis" ], "support": { "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2022-06-18T07:21:10+00:00" + "time": "2023-02-22T23:07:41+00:00" + }, + { + "name": "steverhoades/oauth2-openid-connect-server", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/steverhoades/oauth2-openid-connect-server.git", + "reference": "23381585ebb410ffa11ca9eb0fdba3895fb23119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/steverhoades/oauth2-openid-connect-server/zipball/23381585ebb410ffa11ca9eb0fdba3895fb23119", + "reference": "23381585ebb410ffa11ca9eb0fdba3895fb23119", + "shasum": "" + }, + "require": { + "lcobucci/jwt": "4.1.5|^4.2", + "league/oauth2-server": "^5.1|^6.0|^7.0|^8.0" + }, + "require-dev": { + "laminas/laminas-diactoros": "^1.3.2", + "phpunit/phpunit": "^5.0|^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "OpenIDConnectServer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Steve Rhoades", + "email": "sedonami@gmail.com" + } + ], + "description": "An OpenID Connect Server that sites on The PHP League's OAuth2 Server", + "support": { + "issues": "https://github.com/steverhoades/oauth2-openid-connect-server/issues", + "source": "https://github.com/steverhoades/oauth2-openid-connect-server/tree/v2.5.0" + }, + "time": "2023-01-19T16:49:09+00:00" }, { "name": "symfony/cache", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "e9147c89fdfdc5d5ef798bb7193f23726ad609f5" + "reference": "5ed986c4ef65f0dea5e9753630b5cb1f07f847d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/e9147c89fdfdc5d5ef798bb7193f23726ad609f5", - "reference": "e9147c89fdfdc5d5ef798bb7193f23726ad609f5", + "url": "https://api.github.com/repos/symfony/cache/zipball/5ed986c4ef65f0dea5e9753630b5cb1f07f847d6", + "reference": "5ed986c4ef65f0dea5e9753630b5cb1f07f847d6", "shasum": "" }, "require": { @@ -4898,7 +6952,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v5.4.19" + "source": "https://github.com/symfony/cache/tree/v5.4.22" }, "funding": [ { @@ -4914,7 +6968,7 @@ "type": "tidelift" } ], - "time": "2023-01-19T09:49:58+00:00" + "time": "2023-03-29T20:01:08+00:00" }, { "name": "symfony/cache-contracts", @@ -4997,16 +7051,16 @@ }, { "name": "symfony/config", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "9bd60843443cda9638efdca7c41eb82ed0026179" + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/9bd60843443cda9638efdca7c41eb82ed0026179", - "reference": "9bd60843443cda9638efdca7c41eb82ed0026179", + "url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4", "shasum": "" }, "require": { @@ -5056,7 +7110,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.19" + "source": "https://github.com/symfony/config/tree/v5.4.21" }, "funding": [ { @@ -5072,20 +7126,20 @@ "type": "tidelift" } ], - "time": "2023-01-08T13:23:55+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/console", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740" + "reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740", - "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740", + "url": "https://api.github.com/repos/symfony/console/zipball/3cd51fd2e6c461ca678f84d419461281bd87a0a8", + "reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8", "shasum": "" }, "require": { @@ -5150,12 +7204,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.19" + "source": "https://github.com/symfony/console/tree/v5.4.22" }, "funding": [ { @@ -5171,20 +7225,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-25T09:27:28+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.4.20", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "8185ed0df129005a26715902f1a53bad0fe67102" + "reference": "e1b7c1432efb4ad1dd89d62906187271e2601ed9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8185ed0df129005a26715902f1a53bad0fe67102", - "reference": "8185ed0df129005a26715902f1a53bad0fe67102", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e1b7c1432efb4ad1dd89d62906187271e2601ed9", + "reference": "e1b7c1432efb4ad1dd89d62906187271e2601ed9", "shasum": "" }, "require": { @@ -5244,7 +7298,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.20" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.22" }, "funding": [ { @@ -5260,7 +7314,7 @@ "type": "tidelift" } ], - "time": "2023-01-27T11:08:11+00:00" + "time": "2023-03-10T10:02:45+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5331,16 +7385,16 @@ }, { "name": "symfony/error-handler", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "438ef3e5e6481244785da3ce8cf8f4e74e7f2822" + "reference": "56a94aa8cb5a5fbc411551d8d014a296b5456549" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/438ef3e5e6481244785da3ce8cf8f4e74e7f2822", - "reference": "438ef3e5e6481244785da3ce8cf8f4e74e7f2822", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/56a94aa8cb5a5fbc411551d8d014a296b5456549", + "reference": "56a94aa8cb5a5fbc411551d8d014a296b5456549", "shasum": "" }, "require": { @@ -5382,7 +7436,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.19" + "source": "https://github.com/symfony/error-handler/tree/v5.4.21" }, "funding": [ { @@ -5398,20 +7452,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "abf49cc084c087d94b4cb939c3f3672971784e0c" + "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abf49cc084c087d94b4cb939c3f3672971784e0c", - "reference": "abf49cc084c087d94b4cb939c3f3672971784e0c", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f", + "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f", "shasum": "" }, "require": { @@ -5467,7 +7521,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.19" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22" }, "funding": [ { @@ -5483,7 +7537,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-17T11:31:58+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5566,16 +7620,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8" + "reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/648bfaca6a494f3e22378123bcee2894045dc9d8", - "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e75960b1bbfd2b8c9e483e0d74811d555ca3de9f", + "reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f", "shasum": "" }, "require": { @@ -5610,7 +7664,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.19" + "source": "https://github.com/symfony/filesystem/tree/v5.4.21" }, "funding": [ { @@ -5626,20 +7680,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/finder", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f" + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/6071aebf810ad13fe8200c224f36103abb37cf1f", - "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f", + "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19", + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19", "shasum": "" }, "require": { @@ -5673,7 +7727,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.19" + "source": "https://github.com/symfony/finder/tree/v5.4.21" }, "funding": [ { @@ -5689,20 +7743,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-02-16T09:33:00+00:00" }, { "name": "symfony/framework-bundle", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "a208ee578000f9dedcb50a9784ec7ff8706a7bf1" + "reference": "6cb4f6aed4bd7fbf7b2ee74c231184a07f3d00c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/a208ee578000f9dedcb50a9784ec7ff8706a7bf1", - "reference": "a208ee578000f9dedcb50a9784ec7ff8706a7bf1", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/6cb4f6aed4bd7fbf7b2ee74c231184a07f3d00c1", + "reference": "6cb4f6aed4bd7fbf7b2ee74c231184a07f3d00c1", "shasum": "" }, "require": { @@ -5824,7 +7878,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v5.4.19" + "source": "https://github.com/symfony/framework-bundle/tree/v5.4.22" }, "funding": [ { @@ -5840,20 +7894,20 @@ "type": "tidelift" } ], - "time": "2023-01-10T17:40:25+00:00" + "time": "2023-03-31T08:25:44+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.20", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "d0435363362a47c14e9cf50663cb8ffbf491875a" + "reference": "05cd1acdd0e3ce8473aaba1d86c188321d85f313" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0435363362a47c14e9cf50663cb8ffbf491875a", - "reference": "d0435363362a47c14e9cf50663cb8ffbf491875a", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/05cd1acdd0e3ce8473aaba1d86c188321d85f313", + "reference": "05cd1acdd0e3ce8473aaba1d86c188321d85f313", "shasum": "" }, "require": { @@ -5900,7 +7954,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.20" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.22" }, "funding": [ { @@ -5916,20 +7970,20 @@ "type": "tidelift" } ], - "time": "2023-01-29T11:11:52+00:00" + "time": "2023-03-28T07:28:17+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.20", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "aaeec341582d3c160cc9ecfa8b2419ba6c69954e" + "reference": "2d3a8be2c756353627398827c409af6f126c096d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aaeec341582d3c160cc9ecfa8b2419ba6c69954e", - "reference": "aaeec341582d3c160cc9ecfa8b2419ba6c69954e", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/2d3a8be2c756353627398827c409af6f126c096d", + "reference": "2d3a8be2c756353627398827c409af6f126c096d", "shasum": "" }, "require": { @@ -5938,7 +7992,7 @@ "symfony/deprecation-contracts": "^2.1|^3", "symfony/error-handler": "^4.4|^5.0|^6.0", "symfony/event-dispatcher": "^5.0|^6.0", - "symfony/http-foundation": "^5.3.7|^6.0", + "symfony/http-foundation": "^5.4.21|^6.2.7", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16" @@ -6012,7 +8066,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.20" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.22" }, "funding": [ { @@ -6028,20 +8082,20 @@ "type": "tidelift" } ], - "time": "2023-02-01T08:18:48+00:00" + "time": "2023-03-31T11:54:37+00:00" }, { "name": "symfony/intl", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "f378eb62448dfea67071f9f43529d3a6ad7e0bc8" + "reference": "8afe56b8472888d749ef8955acdc9d38578775d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/f378eb62448dfea67071f9f43529d3a6ad7e0bc8", - "reference": "f378eb62448dfea67071f9f43529d3a6ad7e0bc8", + "url": "https://api.github.com/repos/symfony/intl/zipball/8afe56b8472888d749ef8955acdc9d38578775d7", + "reference": "8afe56b8472888d749ef8955acdc9d38578775d7", "shasum": "" }, "require": { @@ -6100,90 +8154,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v5.4.19" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-11T13:51:47+00:00" - }, - { - "name": "symfony/phpunit-bridge", - "version": "v6.2.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "d759e5372de414bef53a688c7aa7e240e4fd8aa2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/d759e5372de414bef53a688c7aa7e240e4fd8aa2", - "reference": "d759e5372de414bef53a688c7aa7e240e4fd8aa2", - "shasum": "" - }, - "require": { - "php": ">=7.1.3" - }, - "conflict": { - "phpunit/phpunit": "<7.5|9.1.2" - }, - "require-dev": { - "symfony/deprecation-contracts": "^2.1|^3.0", - "symfony/error-handler": "^5.4|^6.0" - }, - "suggest": { - "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" - }, - "bin": [ - "bin/simple-phpunit" - ], - "type": "symfony-bridge", - "extra": { - "thanks": { - "name": "phpunit/phpunit", - "url": "https://github.com/sebastianbergmann/phpunit" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Bridge\\PhpUnit\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides utilities for PHPUnit, especially user deprecation notices management", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.2.5" + "source": "https://github.com/symfony/intl/tree/v5.4.22" }, "funding": [ { @@ -6199,7 +8170,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:38:09+00:00" + "time": "2023-03-10T09:58:14+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6774,16 +8745,16 @@ }, { "name": "symfony/process", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1" + "reference": "4b850da0cc3a2a9181c1ed407adbca4733dc839b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c5ba874c9b636dbccf761e22ce750e88ec3f55e1", - "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1", + "url": "https://api.github.com/repos/symfony/process/zipball/4b850da0cc3a2a9181c1ed407adbca4733dc839b", + "reference": "4b850da0cc3a2a9181c1ed407adbca4733dc839b", "shasum": "" }, "require": { @@ -6816,7 +8787,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.19" + "source": "https://github.com/symfony/process/tree/v5.4.22" }, "funding": [ { @@ -6832,20 +8803,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-06T21:29:33+00:00" }, { "name": "symfony/routing", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "df1b28f37c8e78912213c58ef6ab2f2037bbfdc5" + "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/df1b28f37c8e78912213c58ef6ab2f2037bbfdc5", - "reference": "df1b28f37c8e78912213c58ef6ab2f2037bbfdc5", + "url": "https://api.github.com/repos/symfony/routing/zipball/c2ac11eb34947999b7c38fb4c835a57306907e6d", + "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d", "shasum": "" }, "require": { @@ -6906,7 +8877,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.19" + "source": "https://github.com/symfony/routing/tree/v5.4.22" }, "funding": [ { @@ -6922,7 +8893,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-14T14:59:20+00:00" }, { "name": "symfony/service-contracts", @@ -7009,16 +8980,16 @@ }, { "name": "symfony/string", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb" + "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/0a01071610fd861cc160dfb7e2682ceec66064cb", - "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb", + "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", + "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", "shasum": "" }, "require": { @@ -7075,7 +9046,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.19" + "source": "https://github.com/symfony/string/tree/v5.4.22" }, "funding": [ { @@ -7091,7 +9062,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-14T06:11:53+00:00" }, { "name": "symfony/translation-contracts", @@ -7173,16 +9144,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "0526188cb886be64351454826fecc6d35356eaf1" + "reference": "e5b174464f68be6876046db3ad6e217d9a7dbbac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/0526188cb886be64351454826fecc6d35356eaf1", - "reference": "0526188cb886be64351454826fecc6d35356eaf1", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e5b174464f68be6876046db3ad6e217d9a7dbbac", + "reference": "e5b174464f68be6876046db3ad6e217d9a7dbbac", "shasum": "" }, "require": { @@ -7195,7 +9166,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<5.3", - "symfony/form": "<5.3", + "symfony/form": "<5.4.21|>=6,<6.2.7", "symfony/http-foundation": "<5.3", "symfony/http-kernel": "<4.4", "symfony/translation": "<5.2", @@ -7210,7 +9181,7 @@ "symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/expression-language": "^4.4|^5.0|^6.0", "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/form": "^5.3|^6.0", + "symfony/form": "^5.4.21|^6.2.7", "symfony/http-foundation": "^5.3|^6.0", "symfony/http-kernel": "^4.4|^5.0|^6.0", "symfony/intl": "^4.4|^5.0|^6.0", @@ -7274,7 +9245,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v5.4.19" + "source": "https://github.com/symfony/twig-bridge/tree/v5.4.22" }, "funding": [ { @@ -7290,20 +9261,20 @@ "type": "tidelift" } ], - "time": "2023-01-09T05:43:46+00:00" + "time": "2023-03-31T08:28:44+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b" + "reference": "e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b", - "reference": "2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4", + "reference": "e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4", "shasum": "" }, "require": { @@ -7363,7 +9334,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.19" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.22" }, "funding": [ { @@ -7379,20 +9350,20 @@ "type": "tidelift" } ], - "time": "2023-01-16T10:52:33+00:00" + "time": "2023-03-25T09:27:28+00:00" }, { "name": "symfony/var-exporter", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "2a1d06fcf2b30829d6c01dae8e6e188424d1f8f6" + "reference": "be74908a6942fdd331554b3cec27ff41b45ccad4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/2a1d06fcf2b30829d6c01dae8e6e188424d1f8f6", - "reference": "2a1d06fcf2b30829d6c01dae8e6e188424d1f8f6", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/be74908a6942fdd331554b3cec27ff41b45ccad4", + "reference": "be74908a6942fdd331554b3cec27ff41b45ccad4", "shasum": "" }, "require": { @@ -7436,7 +9407,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.4.19" + "source": "https://github.com/symfony/var-exporter/tree/v5.4.21" }, "funding": [ { @@ -7452,20 +9423,20 @@ "type": "tidelift" } ], - "time": "2023-01-12T16:39:29+00:00" + "time": "2023-02-21T19:46:44+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "71c05db20cb9b54d381a28255f17580e2b7e36a5" + "reference": "3713e20d93e46e681e51605d213027e48dab3469" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/71c05db20cb9b54d381a28255f17580e2b7e36a5", - "reference": "71c05db20cb9b54d381a28255f17580e2b7e36a5", + "url": "https://api.github.com/repos/symfony/yaml/zipball/3713e20d93e46e681e51605d213027e48dab3469", + "reference": "3713e20d93e46e681e51605d213027e48dab3469", "shasum": "" }, "require": { @@ -7511,7 +9482,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.19" + "source": "https://github.com/symfony/yaml/tree/v5.4.21" }, "funding": [ { @@ -7527,7 +9498,146 @@ "type": "tidelift" } ], - "time": "2023-01-10T18:51:14+00:00" + "time": "2023-02-21T19:46:44+00:00" + }, + { + "name": "thecodingmachine/safe", + "version": "v1.3.3", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/a8ab0876305a4cdaef31b2350fcb9811b5608dbc", + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phpstan/phpstan": "^0.12", + "squizlabs/php_codesniffer": "^3.2", + "thecodingmachine/phpstan-strict-rules": "^0.12" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1-dev" + } + }, + "autoload": { + "files": [ + "deprecated/apc.php", + "deprecated/libevent.php", + "deprecated/mssql.php", + "deprecated/stats.php", + "lib/special_cases.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/ingres-ii.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/msql.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/mysqlndMs.php", + "generated/mysqlndQc.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/password.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pdf.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/simplexml.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "psr-4": { + "Safe\\": [ + "lib/", + "deprecated/", + "generated/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v1.3.3" + }, + "time": "2020-10-28T17:51:34+00:00" }, { "name": "theseer/tokenizer", @@ -7726,22 +9836,22 @@ }, { "name": "vimeo/psalm", - "version": "5.7.5", + "version": "5.9.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "5390c212bab06ee230c8720c2e9c54b823db00c8" + "reference": "8b9ad1eb9e8b7d3101f949291da2b9f7767cd163" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/5390c212bab06ee230c8720c2e9c54b823db00c8", - "reference": "5390c212bab06ee230c8720c2e9c54b823db00c8", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/8b9ad1eb9e8b7d3101f949291da2b9f7767cd163", + "reference": "8b9ad1eb9e8b7d3101f949291da2b9f7767cd163", "shasum": "" }, "require": { "amphp/amp": "^2.4.2", "amphp/byte-stream": "^1.5", - "composer/package-versions-deprecated": "^1.10.0", + "composer-runtime-api": "^2", "composer/semver": "^1.4 || ^2.0 || ^3.0", "composer/xdebug-handler": "^2.0 || ^3.0", "dnoegel/php-xdg-base-dir": "^0.1.1", @@ -7756,7 +9866,7 @@ "felixfbecker/language-server-protocol": "^1.5.2", "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.13", + "nikic/php-parser": "^4.14", "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0", "sebastian/diff": "^4.0 || ^5.0", "spatie/array-to-xml": "^2.17.0 || ^3.0", @@ -7767,6 +9877,7 @@ "psalm/psalm": "self.version" }, "require-dev": { + "amphp/phpunit-util": "^2.0", "bamarni/composer-bin-plugin": "^1.4", "brianium/paratest": "^6.9", "ext-curl": "*", @@ -7825,22 +9936,198 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/5.7.5" + "source": "https://github.com/vimeo/psalm/tree/5.9.0" + }, + "time": "2023-03-29T21:38:21+00:00" + }, + { + "name": "web-token/jwt-framework", + "version": "v2.2.11", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-framework.git", + "reference": "643cced197e32471418bd89e7a44b69fd04eb9de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-framework/zipball/643cced197e32471418bd89e7a44b69fd04eb9de", + "reference": "643cced197e32471418bd89e7a44b69fd04eb9de", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.17|^0.9", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-sodium": "*", + "fgrosse/phpasn1": "^2.0", + "php": ">=7.2", + "psr/event-dispatcher": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "spomky-labs/aes-key-wrap": "^5.0|^6.0", + "spomky-labs/base64url": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/console": "^4.2|^5.0", + "symfony/dependency-injection": "^4.2|^5.0", + "symfony/event-dispatcher": "^4.2|^5.0", + "symfony/http-kernel": "^4.2|^5.0", + "symfony/polyfill-mbstring": "^1.12" + }, + "conflict": { + "spomky-labs/jose": "*" + }, + "replace": { + "web-token/encryption-pack": "self.version", + "web-token/jwt-bundle": "self.version", + "web-token/jwt-checker": "self.version", + "web-token/jwt-console": "self.version", + "web-token/jwt-core": "self.version", + "web-token/jwt-easy": "self.version", + "web-token/jwt-encryption": "self.version", + "web-token/jwt-encryption-algorithm-aescbc": "self.version", + "web-token/jwt-encryption-algorithm-aesgcm": "self.version", + "web-token/jwt-encryption-algorithm-aesgcmkw": "self.version", + "web-token/jwt-encryption-algorithm-aeskw": "self.version", + "web-token/jwt-encryption-algorithm-dir": "self.version", + "web-token/jwt-encryption-algorithm-ecdh-es": "self.version", + "web-token/jwt-encryption-algorithm-experimental": "self.version", + "web-token/jwt-encryption-algorithm-pbes2": "self.version", + "web-token/jwt-encryption-algorithm-rsa": "self.version", + "web-token/jwt-key-mgmt": "self.version", + "web-token/jwt-nested-token": "self.version", + "web-token/jwt-signature": "self.version", + "web-token/jwt-signature-algorithm-ecdsa": "self.version", + "web-token/jwt-signature-algorithm-eddsa": "self.version", + "web-token/jwt-signature-algorithm-experimental": "self.version", + "web-token/jwt-signature-algorithm-hmac": "self.version", + "web-token/jwt-signature-algorithm-none": "self.version", + "web-token/jwt-signature-algorithm-rsa": "self.version", + "web-token/jwt-util-ecc": "self.version", + "web-token/signature-pack": "self.version" + }, + "require-dev": { + "bjeavons/zxcvbn-php": "^1.0", + "blackfire/php-sdk": "^1.14", + "ext-curl": "*", + "ext-gmp": "*", + "friendsofphp/php-cs-fixer": "^2.16", + "infection/infection": "^0.15|^0.16|^0.17|^0.18|^0.19|^0.20", + "matthiasnoback/symfony-config-test": "^3.1|^4.0", + "nyholm/psr7": "^1.3", + "php-coveralls/php-coveralls": "^2.0", + "php-http/mock-client": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^8.0|^9.0", + "symfony/browser-kit": "^4.2|^5.0", + "symfony/finder": "^4.2|^5.0", + "symfony/framework-bundle": "^4.2|^5.0", + "symfony/http-client": "^5.2", + "symfony/phpunit-bridge": "^4.2|^5.0", + "symfony/serializer": "^4.2|^5.0", + "symfony/var-dumper": "^4.2|^5.0" + }, + "suggest": { + "bjeavons/zxcvbn-php": "Adds key quality check for oct keys.", + "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "php-http/httplug": "To enable JKU/X5U support.", + "php-http/httplug-bundle": "To enable JKU/X5U support.", + "php-http/message-factory": "To enable JKU/X5U support.", + "symfony/serializer": "Use the Symfony serializer to serialize/unserialize JWS and JWE tokens.", + "symfony/var-dumper": "Used to show data on the debug toolbar." + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Jose\\": "src/", + "Jose\\Component\\Core\\Util\\Ecc\\": [ + "src/Ecc" + ], + "Jose\\Component\\Signature\\Algorithm\\": [ + "src/SignatureAlgorithm/ECDSA", + "src/SignatureAlgorithm/EdDSA", + "src/SignatureAlgorithm/HMAC", + "src/SignatureAlgorithm/None", + "src/SignatureAlgorithm/RSA", + "src/SignatureAlgorithm/Experimental" + ], + "Jose\\Component\\Encryption\\Algorithm\\": [ + "src/EncryptionAlgorithm/Experimental" + ], + "Jose\\Component\\Encryption\\Algorithm\\KeyEncryption\\": [ + "src/EncryptionAlgorithm/KeyEncryption/AESGCMKW", + "src/EncryptionAlgorithm/KeyEncryption/AESKW", + "src/EncryptionAlgorithm/KeyEncryption/Direct", + "src/EncryptionAlgorithm/KeyEncryption/ECDHES", + "src/EncryptionAlgorithm/KeyEncryption/PBES2", + "src/EncryptionAlgorithm/KeyEncryption/RSA" + ], + "Jose\\Component\\Encryption\\Algorithm\\ContentEncryption\\": [ + "src/EncryptionAlgorithm/ContentEncryption/AESGCM", + "src/EncryptionAlgorithm/ContentEncryption/AESCBC" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "JSON Object Signing and Encryption library for PHP and Symfony Bundle.", + "homepage": "https://github.com/web-token/jwt-framework", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "issues": "https://github.com/web-token/jwt-framework/issues", + "source": "https://github.com/web-token/jwt-framework/tree/v2.2.11" }, - "time": "2023-02-21T16:02:51+00:00" + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + } + ], + "time": "2021-06-25T15:59:52+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "simplesamlphp/simplesamlphp": 10 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "^7.4 || ^8.0", "ext-pdo": "*", - "ext-pdo_sqlite": "*" + "ext-pdo_sqlite": "*", + "composer-runtime-api": "^2.0" }, "platform-dev": [], "plugin-api-version": "2.3.0" diff --git a/hooks/hook_adminmenu.php b/hooks/hook_adminmenu.php index 1df9352a58fc8bb241ec3ac4768ff707c8c94f65..8fffd991289b7b44306ceeb6a806618b4c30d220 100644 --- a/hooks/hook_adminmenu.php +++ b/hooks/hook_adminmenu.php @@ -3,7 +3,7 @@ declare(strict_types=1); use SimpleSAML\Locale\Translate; -use SimpleSAML\Module\accounting\Helpers\ModuleRoutes; +use SimpleSAML\Module\accounting\Helpers\Routes; use SimpleSAML\Module\accounting\ModuleConfiguration; use SimpleSAML\XHTML\Template; @@ -12,11 +12,11 @@ function accounting_hook_adminmenu(Template &$template): void { $menuKey = 'menu'; - $moduleRoutesHelper = new ModuleRoutes(); + $moduleRoutesHelper = new Routes(); $profilePageEntry = [ ModuleConfiguration::MODULE_NAME => [ - 'url' => $moduleRoutesHelper->getUrl(ModuleRoutes::PATH_USER_PERSONAL_DATA), + 'url' => $moduleRoutesHelper->getUrl(Routes::PATH_USER_PERSONAL_DATA), 'name' => Translate::noop('Profile Page'), ], ]; diff --git a/hooks/hook_configpage.php b/hooks/hook_configpage.php index 93edf9374e23dbd0252d646c71db1d6e8fcb58be..68aa8efee9bb73427831e0b2a57afc29b49b8cba 100644 --- a/hooks/hook_configpage.php +++ b/hooks/hook_configpage.php @@ -3,14 +3,14 @@ declare(strict_types=1); use SimpleSAML\Locale\Translate; -use SimpleSAML\Module\accounting\Helpers\ModuleRoutes; +use SimpleSAML\Module\accounting\Helpers\Routes; use SimpleSAML\Module\accounting\ModuleConfiguration; use SimpleSAML\XHTML\Template; /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection Reference is used by SimpleSAMLphp */ function accounting_hook_configpage(Template &$template): void { - $moduleRoutesHelper = new ModuleRoutes(); + $moduleRoutesHelper = new Routes(); $dataLinksKey = 'links'; @@ -19,7 +19,7 @@ function accounting_hook_configpage(Template &$template): void } $template->data[$dataLinksKey][] = [ - 'href' => $moduleRoutesHelper->getUrl(ModuleRoutes::PATH_ADMIN_CONFIGURATION_STATUS), + 'href' => $moduleRoutesHelper->getUrl(Routes::PATH_ADMIN_CONFIGURATION_STATUS), 'text' => Translate::noop('Accounting configuration status'), ]; diff --git a/public/assets/css/src/custom.css b/public/assets/css/src/custom.css index cb8acd7af26be658c0754190f87531e2f12e9fce..808e4647b265de25b020a0e416640bab3dc60529 100644 --- a/public/assets/css/src/custom.css +++ b/public/assets/css/src/custom.css @@ -39,4 +39,4 @@ max-height: 0; overflow: hidden; transition: max-height 0.2s ease-out; -} \ No newline at end of file +} diff --git a/public/assets/css/src/default.css b/public/assets/css/src/default.css index 114cfffff67917249119d19540ae8d227a54440a..22f17b95949fc2e243781baa76507faecaca8e30 100644 --- a/public/assets/css/src/default.css +++ b/public/assets/css/src/default.css @@ -458,4 +458,30 @@ display: none; } - } \ No newline at end of file + } + + +/** Alerts */ + +/* The alert message box */ +.alerts .alert { + padding: 20px; + margin-bottom: 15px; +} + +/* The close button */ +.close-btn { + margin-left: 15px; + color: white; + font-weight: bold; + float: right; + font-size: 22px; + line-height: 20px; + cursor: pointer; + transition: 0.3s; +} + +/* When moving the mouse over the close button */ +.close-btn:hover { + color: black; +} diff --git a/routing/routes/routes.yml b/routing/routes/routes.yml index a44a2bd3adf0ddbd1e660269e2b409f56950cdf8..1d2d429e693ff02b3564bab9426e50b047603859 100644 --- a/routing/routes/routes.yml +++ b/routing/routes/routes.yml @@ -1,23 +1,37 @@ accounting-admin-configuration-status: path: /admin/configuration/status - defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\Admin\Configuration::status' } + controller: SimpleSAML\Module\accounting\Http\Controllers\Admin\Configuration::status accounting-user-personal-data: path: /user/personal-data - defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::personalData' } + controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::personalData accounting-user-connected-organizations: path: /user/connected-organizations - defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::connectedOrganizations' } + controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::connectedOrganizations accounting-user-activity: path: /user/activity - defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::activity' } + controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::activity + +accounting-user-oidc-tokens: + path: /user/oidc-tokens + controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::oidcTokens + +accounting-user-oidc-token-revoke: + path: /user/oidc-tokens/revoke + controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::oidcTokenRevoke + methods: POST + +accounting-user-oidc-token-revoke-xhr: + path: /user/oidc-tokens/revoke-xhr + controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::oidcTokenRevokeXhr + methods: POST accounting-user-logout: path: /user/logout + controller: SimpleSAML\Module\accounting\Http\Controllers\User\Profile::logout methods: - GET - POST - defaults: { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::logout' } diff --git a/src/Entities/Bases/AbstractProvider.php b/src/Entities/Bases/AbstractProvider.php index f3833d57ff43681b38b684efa183f6cb80ae1bbb..9e63abde92dc28fc928e623ea3be29f2794de2fb 100644 --- a/src/Entities/Bases/AbstractProvider.php +++ b/src/Entities/Bases/AbstractProvider.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities\Bases; +use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\ProviderInterface; abstract class AbstractProvider implements ProviderInterface @@ -52,4 +53,5 @@ abstract class AbstractProvider implements ProviderInterface abstract public function getName(string $locale = 'en'): ?string; abstract public function getDescription(string $locale = 'en'): ?string; abstract protected function resolveEntityId(): string; + abstract public function getProtocol(): AuthenticationProtocolInterface; } diff --git a/src/Entities/Bases/AbstractState.php b/src/Entities/Bases/AbstractState.php index a2d5cd9115aad7708959318a767564ab99c399f7..02a9e10dab21f928d399087c944d1d445ddfb22f 100644 --- a/src/Entities/Bases/AbstractState.php +++ b/src/Entities/Bases/AbstractState.php @@ -9,10 +9,13 @@ use SimpleSAML\Module\accounting\Entities\Interfaces\StateInterface; use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException; use SimpleSAML\Module\accounting\Services\HelpersManager; use DateTimeImmutable; +use SimpleSAML\Module\accounting\Traits\HasUserAttributesTrait; use Throwable; abstract class AbstractState implements StateInterface { + use HasUserAttributesTrait; + public const KEY_ATTRIBUTES = 'Attributes'; public const KEY_ACCOUNTING = 'accounting'; public const ACCOUNTING_KEY_CLIENT_IP_ADDRESS = 'client_ip_address'; @@ -20,7 +23,6 @@ abstract class AbstractState implements StateInterface protected string $identityProviderEntityId; protected string $serviceProviderEntityId; - protected array $attributes; protected DateTimeImmutable $createdAt; protected ?DateTimeImmutable $authenticationInstant; protected array $identityProviderMetadata; @@ -99,29 +101,6 @@ abstract class AbstractState implements StateInterface return $this->serviceProviderEntityId; } - public function getAttributes(): array - { - return $this->attributes; - } - - public function getFirstAttributeValue(string $attributeName): ?string - { - if (($value = $this->getAttributeValue($attributeName)) !== null) { - return (string)reset($value); - } - - return null; - } - - public function getAttributeValue(string $attributeName): ?array - { - if (!empty($this->attributes[$attributeName]) && is_array($this->attributes[$attributeName])) { - return $this->attributes[$attributeName]; - } - - return null; - } - public function getCreatedAt(): DateTimeImmutable { return $this->createdAt; diff --git a/src/Entities/Interfaces/ProviderInterface.php b/src/Entities/Interfaces/ProviderInterface.php index 30971b67f0141276f5e5fe4c021679efee988cc1..c82a1792698873b1ba3e295addba031708832ca4 100644 --- a/src/Entities/Interfaces/ProviderInterface.php +++ b/src/Entities/Interfaces/ProviderInterface.php @@ -13,4 +13,5 @@ interface ProviderInterface public function getName(string $locale = 'en'): ?string; public function getEntityId(): string; public function getDescription(string $locale = 'en'): ?string; + public function getProtocol(): AuthenticationProtocolInterface; } diff --git a/src/Entities/Providers/Identity/Oidc.php b/src/Entities/Providers/Identity/Oidc.php index 660a850eecc1371ad9d12593cebf5874c7841a2b..d326113ce1918f16819d8eb0b798bd17b8fb3328 100644 --- a/src/Entities/Providers/Identity/Oidc.php +++ b/src/Entities/Providers/Identity/Oidc.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities\Providers\Identity; +use SimpleSAML\Module\accounting\Entities\Authentication; use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider; +use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface; use SimpleSAML\Module\accounting\Exceptions\MetadataException; @@ -36,4 +38,9 @@ class Oidc extends AbstractProvider implements IdentityProviderInterface throw new MetadataException('OpenID Provider metadata does not contain entity ID.'); } + + public function getProtocol(): AuthenticationProtocolInterface + { + return new Authentication\Protocol\Oidc(); + } } diff --git a/src/Entities/Providers/Identity/Saml2.php b/src/Entities/Providers/Identity/Saml2.php index 06bd9390336499ff31696208778598d017cf4475..04768636840af510618c96d26587f396b283afe4 100644 --- a/src/Entities/Providers/Identity/Saml2.php +++ b/src/Entities/Providers/Identity/Saml2.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities\Providers\Identity; +use SimpleSAML\Module\accounting\Entities\Authentication; use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider; +use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface; use SimpleSAML\Module\accounting\Exceptions\MetadataException; @@ -38,4 +40,9 @@ class Saml2 extends AbstractProvider implements IdentityProviderInterface throw new MetadataException('Identity provider metadata does not contain entity ID.'); } + + public function getProtocol(): AuthenticationProtocolInterface + { + return new Authentication\Protocol\Saml2(); + } } diff --git a/src/Entities/Providers/Service/Oidc.php b/src/Entities/Providers/Service/Oidc.php index 37e187b28f11c8aaf0f8830275776267619de7ce..382eabdf1815a3598b8f60bc168c33242febfeb6 100644 --- a/src/Entities/Providers/Service/Oidc.php +++ b/src/Entities/Providers/Service/Oidc.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities\Providers\Service; +use SimpleSAML\Module\accounting\Entities\Authentication; use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider; +use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface; use SimpleSAML\Module\accounting\Exceptions\MetadataException; @@ -38,4 +40,9 @@ class Oidc extends AbstractProvider implements ServiceProviderInterface throw new MetadataException('Relying Provider metadata does not contain entity ID.'); } + + public function getProtocol(): AuthenticationProtocolInterface + { + return new Authentication\Protocol\Oidc(); + } } diff --git a/src/Entities/Providers/Service/Saml2.php b/src/Entities/Providers/Service/Saml2.php index d88bfaee365311bf62f1aaf2c1dc62cec4c602fd..d0dfd4ac065c2b22a7f3dcdcf82c14096981f40d 100644 --- a/src/Entities/Providers/Service/Saml2.php +++ b/src/Entities/Providers/Service/Saml2.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities\Providers\Service; +use SimpleSAML\Module\accounting\Entities\Authentication; use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider; +use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface; use SimpleSAML\Module\accounting\Exceptions\MetadataException; @@ -38,4 +40,9 @@ class Saml2 extends AbstractProvider implements ServiceProviderInterface throw new MetadataException('Service provider metadata does not contain entity ID.'); } + + public function getProtocol(): AuthenticationProtocolInterface + { + return new Authentication\Protocol\Saml2(); + } } diff --git a/src/Entities/User.php b/src/Entities/User.php index 138bc4cb5f99501a15aea7b7fe23ffb4f601d9db..99bbf8642192ab84c508c414986a0e8284d30f77 100644 --- a/src/Entities/User.php +++ b/src/Entities/User.php @@ -4,20 +4,14 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities; +use SimpleSAML\Module\accounting\Traits\HasUserAttributesTrait; + class User { - protected array $attributes; + use HasUserAttributesTrait; public function __construct(array $attributes) { $this->attributes = $attributes; } - - /** - * @return array - */ - public function getAttributes(): array - { - return $this->attributes; - } } diff --git a/src/Helpers/Arr.php b/src/Helpers/Arr.php index be464ee22144e7635cabd05dc5d32394134ec6b1..465e122ad3de3e8d9f57aed34b8c8e3494d3678c 100644 --- a/src/Helpers/Arr.php +++ b/src/Helpers/Arr.php @@ -17,4 +17,24 @@ class Arr ksort($array); } + + /** + * @param array $array + * @param int|string $key + * @return array + */ + public function groupByValue(array $array, $key): array + { + return array_reduce($array, function (array $carry, array $item) use ($key) { + /** @psalm-suppress MixedArrayOffset, MixedArrayAssignment */ + $carry[$item[$key]][] = $item; + return $carry; + }, []); + } + + public function isAssociative(array $array): bool + { + $keys = array_keys($array); + return $keys !== array_keys($keys); + } } diff --git a/src/Helpers/DateTime.php b/src/Helpers/DateTime.php index 1e328171ae42cda9987592db0cf403f6ef059220..e87b927d552a4f06e662f5bc632a37365a94dd28 100644 --- a/src/Helpers/DateTime.php +++ b/src/Helpers/DateTime.php @@ -9,6 +9,7 @@ use DateTimeImmutable; class DateTime { + public const FORMAT_MYSQL = 'Y-m-d H:i:s'; /** * Convert date interval to seconds, interval being minimum 1 second. * @param DateInterval $dateInterval Minimum is 1 second. @@ -27,4 +28,13 @@ class DateTime return $duration; } + + public function toFormattedString( + \DateTimeInterface $dateTime = null, + string $format = self::FORMAT_MYSQL + ): string { + $dateTime = $dateTime ?? new DateTimeImmutable(); + + return $dateTime->format($format); + } } diff --git a/src/Helpers/Random.php b/src/Helpers/Random.php index e56fde76d5b31056d9929c392ed2e782460d5f9f..c839663891b8ae06f47f0dfdde224dacc0bdd6ec 100644 --- a/src/Helpers/Random.php +++ b/src/Helpers/Random.php @@ -8,7 +8,7 @@ use Throwable; class Random { - public function getRandomInt(int $minimum = PHP_INT_MIN, int $maximum = PHP_INT_MAX): int + public function getInt(int $minimum = PHP_INT_MIN, int $maximum = PHP_INT_MAX): int { try { return random_int($minimum, $maximum); @@ -18,4 +18,15 @@ class Random // @codeCoverageIgnoreEnd } } + + public function getString(int $length = 16): string + { + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[$this->getInt(0, $charactersLength - 1)]; + } + return $randomString; + } } diff --git a/src/Helpers/ModuleRoutes.php b/src/Helpers/Routes.php similarity index 52% rename from src/Helpers/ModuleRoutes.php rename to src/Helpers/Routes.php index f03617f990d087f6ade1e9d6e3187c9d8d8c184b..70bec363a3194f6b492368b26ca072173fb9b124 100644 --- a/src/Helpers/ModuleRoutes.php +++ b/src/Helpers/Routes.php @@ -9,20 +9,24 @@ use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException; use SimpleSAML\Module\accounting\ModuleConfiguration; use SimpleSAML\Utils\HTTP; -class ModuleRoutes +class Routes { public const PATH_ADMIN_CONFIGURATION_STATUS = 'admin/configuration/status'; public const PATH_USER_PERSONAL_DATA = 'user/personal-data'; + public const PATH_USER_OIDC_TOKENS = 'user/oidc-tokens'; + public const QUERY_REDIRECT_TO_PATH = 'redirectTo'; protected HTTP $sspHttpUtils; + protected Arr $arr; - public function __construct(HTTP $sspHttpUtils = null) + public function __construct(HTTP $sspHttpUtils = null, Arr $arr = null) { $this->sspHttpUtils = $sspHttpUtils ?? new HTTP(); + $this->arr = $arr ?? new Arr(); } - public function getUrl(string $path, array $parameters = []): string + public function getUrl(string $path, array $queryParameters = [], array $fragmentParameters = []): string { try { $url = $this->sspHttpUtils->getBaseURL() . 'module.php/' . ModuleConfiguration::MODULE_NAME . '/' . $path; @@ -34,8 +38,24 @@ class ModuleRoutes // @codeCoverageIgnoreEnd } - if (!empty($parameters)) { - $url = $this->sspHttpUtils->addURLParameters($url, $parameters); + if (!empty($queryParameters)) { + $url = $this->sspHttpUtils->addURLParameters($url, $queryParameters); + } + + // Let's assume there are no current fragments in the URL. If the fragment array is not associative, + // simply append value(s). Otherwise, create key-value fragment pairs. + if (!empty($fragmentParameters)) { + /** @psalm-suppress MixedArgumentTypeCoercion */ + $url .= '#' . implode( + '&', + ( + ! $this->arr->isAssociative($fragmentParameters) ? + $fragmentParameters : + array_map(function ($key, string $value): string { + return $key . '=' . $value; + }, array_keys($fragmentParameters), $fragmentParameters) + ) + ); } return $url; diff --git a/src/Helpers/SspModule.php b/src/Helpers/SspModule.php new file mode 100644 index 0000000000000000000000000000000000000000..df5798a0f7c18fc57b3c7e2c0b5409da8615c06b --- /dev/null +++ b/src/Helpers/SspModule.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\Helpers; + +use SimpleSAML\Module; + +class SspModule +{ + /** + * @throws \Exception + */ + public function isEnabled(string $moduleName): bool + { + try { + return Module::isModuleEnabled($moduleName); + } catch (\Throwable $exception) { + $message = sprintf('Could not check if module %s is enabled', $moduleName); + throw new Module\accounting\Exceptions\InvalidConfigurationException( + $message, + (int) $exception->getCode(), + $exception + ); + } + } +} diff --git a/src/Http/Controllers/Admin/Configuration.php b/src/Http/Controllers/Admin/Configuration.php index 3ce99220ea42cdedb7513560662f53d6f50968a4..cd5d9534f49bc0d2bdfb63c3562c812c3848aa4e 100644 --- a/src/Http/Controllers/Admin/Configuration.php +++ b/src/Http/Controllers/Admin/Configuration.php @@ -7,7 +7,7 @@ namespace SimpleSAML\Module\accounting\Http\Controllers\Admin; use Exception; use Psr\Log\LoggerInterface; use SimpleSAML\Configuration as SspConfiguration; -use SimpleSAML\Module\accounting\Helpers\ModuleRoutes; +use SimpleSAML\Module\accounting\Helpers\Routes; use SimpleSAML\Module\accounting\ModuleConfiguration; use SimpleSAML\Module\accounting\Services\HelpersManager; use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder; @@ -119,8 +119,8 @@ class Configuration 'defaultDataTrackerAndProvider' => $defaultDataTrackerAndProvider, 'additionalTrackers' => $additionalTrackers, 'setupNeeded' => $setupNeeded, - 'profilePageUri' => $this->helpersManager->getModuleRoutes() - ->getUrl(ModuleRoutes::PATH_USER_PERSONAL_DATA), + 'profilePageUri' => $this->helpersManager->getRoutes() + ->getUrl(Routes::PATH_USER_PERSONAL_DATA), ]; $template = new Template($this->sspConfiguration, 'accounting:admin/configuration/status.twig'); diff --git a/src/Http/Controllers/User/Profile.php b/src/Http/Controllers/User/Profile.php index 5ef9218bdd38b37d39a159e2af610a619b0ba8e1..c144a97b3bc35368582813b296cf54f9a654352d 100644 --- a/src/Http/Controllers/User/Profile.php +++ b/src/Http/Controllers/User/Profile.php @@ -10,16 +10,28 @@ use SimpleSAML\Configuration as SspConfiguration; use SimpleSAML\Error\ConfigurationError; use SimpleSAML\Error\CriticalConfigurationError; use SimpleSAML\HTTP\RunnableResponse; +use SimpleSAML\Locale\Translate; +use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc; +use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider; +use SimpleSAML\Module\accounting\Entities\User; use SimpleSAML\Module\accounting\Exceptions\Exception; use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException; use SimpleSAML\Module\accounting\Helpers\Attributes; +use SimpleSAML\Module\accounting\Helpers\Routes; use SimpleSAML\Module\accounting\ModuleConfiguration; use SimpleSAML\Module\accounting\ModuleConfiguration\ConnectionType; use SimpleSAML\Module\accounting\Providers\Builders\AuthenticationDataProviderBuilder; use SimpleSAML\Module\accounting\Providers\Interfaces\AuthenticationDataProviderInterface; +use SimpleSAML\Module\accounting\Services\AlertsBag; +use SimpleSAML\Module\accounting\Services\CsrfToken; use SimpleSAML\Module\accounting\Services\HelpersManager; +use SimpleSAML\Module\accounting\Services\MenuManager; +use SimpleSAML\Module\accounting\Services\SspModuleManager; use SimpleSAML\Session; use SimpleSAML\XHTML\Template; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -36,6 +48,11 @@ class Profile protected Simple $authSimple; protected AuthenticationDataProviderBuilder $authenticationDataProviderBuilder; protected HelpersManager $helpersManager; + protected SspModuleManager $sspModuleManager; + protected User $user; + protected MenuManager $menuManager; + protected CsrfToken $csrfToken; + protected AlertsBag $alertsBag; /** * @param ModuleConfiguration $moduleConfiguration @@ -45,6 +62,9 @@ class Profile * @param Simple|null $authSimple * @param AuthenticationDataProviderBuilder|null $authenticationDataProviderBuilder * @param HelpersManager|null $helpersManager + * @param SspModuleManager|null $sspModuleManager + * @param CsrfToken|null $csrfToken + * @param AlertsBag|null $alertsBag */ public function __construct( ModuleConfiguration $moduleConfiguration, @@ -53,7 +73,10 @@ class Profile LoggerInterface $logger, Simple $authSimple = null, AuthenticationDataProviderBuilder $authenticationDataProviderBuilder = null, - HelpersManager $helpersManager = null + HelpersManager $helpersManager = null, + SspModuleManager $sspModuleManager = null, + CsrfToken $csrfToken = null, + AlertsBag $alertsBag = null ) { $this->moduleConfiguration = $moduleConfiguration; $this->sspConfiguration = $sspConfiguration; @@ -68,8 +91,14 @@ class Profile $this->authenticationDataProviderBuilder = $authenticationDataProviderBuilder ?? new AuthenticationDataProviderBuilder($this->moduleConfiguration, $this->logger, $this->helpersManager); + $this->sspModuleManager = $sspModuleManager ?? new SspModuleManager($this->logger, $this->helpersManager); + // Make sure the end user is authenticated. $this->authSimple->requireAuth(); + $this->user = new User($this->authSimple->getAttributes()); + $this->menuManager = $this->prepareMenuManager(); + $this->csrfToken = $csrfToken ?? new CsrfToken($this->session, $this->helpersManager); + $this->alertsBag = $alertsBag ?? new AlertsBag($this->session); } /** @@ -85,7 +114,7 @@ class Profile * @var string $name * @var string[] $value */ - foreach ($this->authSimple->getAttributes() as $name => $value) { + foreach ($this->user->getAttributes() as $name => $value) { // Convert attribute names to user-friendly names. if (array_key_exists($name, $toNameAttributeMap)) { $name = (string)$toNameAttributeMap[$name]; @@ -94,7 +123,7 @@ class Profile } $template = $this->resolveTemplate('accounting:user/personal-data.twig'); - $template->data = compact('normalizedAttributes'); + $template->data += compact('normalizedAttributes'); return $template; } @@ -111,8 +140,48 @@ class Profile $connectedServiceProviderBag = $authenticationDataProvider->getConnectedServiceProviders($userIdentifier); + $oidc = $this->sspModuleManager->getOidc(); + $accessTokensByClient = []; + $refreshTokensByClient = []; + $oidcProtocolDesignation = Oidc::DESIGNATION; + + // If oidc module is enabled, gather users access and refresh tokens for particular OIDC service providers. + if ($oidc->isEnabled()) { + // Filter out OIDC service providers and get their entity (client) IDs. + $oidcClientIds = array_map( + function (ConnectedServiceProvider $connectedServiceProvider) { + return $connectedServiceProvider->getServiceProvider()->getEntityId(); + }, + array_filter( + $connectedServiceProviderBag->getAll(), + function (ConnectedServiceProvider $connectedServiceProvider) { + return $connectedServiceProvider->getServiceProvider()->getProtocol()->getDesignation() === + Oidc::DESIGNATION; + } + ) + ); + + if (! empty($oidcClientIds)) { + $accessTokensByClient = $this->helpersManager->getArr()->groupByValue( + $oidc->getUsersAccessTokens($userIdentifier, $oidcClientIds), + 'client_id' + ); + + $refreshTokensByClient = $this->helpersManager->getArr()->groupByValue( + $oidc->getUsersRefreshTokens($userIdentifier, $oidcClientIds), + 'client_id' + ); + } + //die(var_dump($oidcClientIds, $accessTokensByClient, $refreshTokensByClient)); + } + $template = $this->resolveTemplate('accounting:user/connected-organizations.twig'); - $template->data = compact('connectedServiceProviderBag'); + $template->data += compact( + 'connectedServiceProviderBag', + 'accessTokensByClient', + 'refreshTokensByClient', + 'oidcProtocolDesignation' + ); return $template; } @@ -135,25 +204,159 @@ class Profile $activityBag = $authenticationDataProvider->getActivity($userIdentifier, $maxResults, $firstResult); $template = $this->resolveTemplate('accounting:user/activity.twig'); - $template->data = compact('activityBag', 'page', 'maxResults'); + $template->data += compact('activityBag', 'page', 'maxResults'); return $template; } + /** + * @throws Exception|ConfigurationError + */ + public function oidcTokens(): Response + { + $oidc = $this->sspModuleManager->getOidc(); + + // If oidc module is not enabled, this route should not be called. + if (!$oidc->isEnabled()) { + return new RedirectResponse($this->helpersManager->getRoutes()->getUrl(Routes::PATH_USER_PERSONAL_DATA)); + } + + $userIdentifier = $this->resolveUserIdentifier(); + + $accessTokensByClient = $this->helpersManager->getArr()->groupByValue( + $oidc->getUsersAccessTokens($userIdentifier), + 'client_id' + ); + + $refreshTokensByClient = $this->helpersManager->getArr()->groupByValue( + $oidc->getUsersRefreshTokens($userIdentifier), + 'client_id' + ); + + $clientIds = array_unique(array_merge(array_keys($accessTokensByClient), array_keys($refreshTokensByClient))); + $clients = $this->helpersManager->getArr()->groupByValue( + $oidc->getClients($clientIds), + 'id' + ); + + //die(var_dump($accessTokensByClient, $refreshTokensByClient, $clientIds, $clients)); + + $template = $this->resolveTemplate('accounting:user/oidc-tokens.twig'); + $template->data += compact('accessTokensByClient', 'refreshTokensByClient', 'clients'); + + return $template; + } + + public function oidcTokenRevoke(Request $request): Response + { + $oidc = $this->sspModuleManager->getOidc(); + + // If oidc module is not enabled, this route should not be called. + if (! $oidc->isEnabled()) { + return new RedirectResponse($this->helpersManager->getRoutes()->getUrl(Routes::PATH_USER_PERSONAL_DATA)); + } + + $redirectTo = (string) $request->query->get(Routes::QUERY_REDIRECT_TO_PATH, Routes::PATH_USER_OIDC_TOKENS); + + $response = new RedirectResponse( + $this->helpersManager->getRoutes()->getUrl($redirectTo) + ); + + if (! $this->csrfToken->validate($request->request->getAlnum('csrf-token'))) { + $this->alertsBag->put( + new AlertsBag\Alert('Could not verify CSRF token.', 'warning') + ); + + return $response; + } + + $validTokenTypes = ['access', 'refresh']; + + $tokenType = $request->request->getAlnum('token-type'); + + if (! in_array($tokenType, $validTokenTypes)) { + $this->alertsBag->put( + new AlertsBag\Alert('Token type not valid.', 'warning') + ); + return $response; + } + + $tokenId = $request->request->getAlnum('token-id'); + + $userIdentifier = $this->resolveUserIdentifier(); + + if ($tokenType === 'access') { + $oidc->revokeUsersAccessToken($userIdentifier, $tokenId); + } elseif ($tokenType === 'refresh') { + $oidc->revokeUsersRefreshToken($userIdentifier, $tokenId); + } + + $this->alertsBag->put( + new AlertsBag\Alert('Token revoked successfully.', 'success') + ); + + return $response; + } + + public function oidcTokenRevokeXhr(Request $request): Response + { + + $oidc = $this->sspModuleManager->getOidc(); + $response = new JsonResponse(); + + + // If oidc module is not enabled, this route should not be called. + if (! $oidc->isEnabled()) { + return new JsonResponse(['status' => 'error', 'message' => 'Not available.'], 404); + } + + if (! $this->csrfToken->validate((string) $request->cookies->get(CsrfToken::KEY))) { + $this->appendCsrfCookie($response); + return $response + ->setData(['status' => 'error', 'message' => 'CSRF validation failed.']) + ->setStatusCode(400); + } + + $this->appendCsrfCookie($response); + + $validTokenTypes = ['access', 'refresh']; + + $tokenType = $request->request->getAlnum('token-type'); + + if (! in_array($tokenType, $validTokenTypes)) { + return $response + ->setData(['status' => 'error', 'message' => 'Token type not valid.']) + ->setStatusCode(422); + } + + $tokenId = $request->request->getAlnum('token-id'); + + $userIdentifier = $this->resolveUserIdentifier(); + + if ($tokenType === 'access') { + $oidc->revokeUsersAccessToken($userIdentifier, $tokenId); + } elseif ($tokenType === 'refresh') { + $oidc->revokeUsersRefreshToken($userIdentifier, $tokenId); + } + + return $response + ->setData(['status' => 'success', 'message' => 'Token revoked successfully.']); + } + /** * @throws Exception */ protected function resolveUserIdentifier(): string { - $attributes = $this->authSimple->getAttributes(); - $idAttributeName = $this->moduleConfiguration->getUserIdAttributeName(); + $userIdAttributeName = $this->moduleConfiguration->getUserIdAttributeName(); + $userIdentifier = $this->user->getFirstAttributeValue($userIdAttributeName); - if (empty($attributes[$idAttributeName]) || !is_array($attributes[$idAttributeName])) { - $message = sprintf('No identifier %s present in user attributes.', $idAttributeName); + if (is_null($userIdentifier)) { + $message = sprintf('No identifier %s present in user attributes.', $userIdAttributeName); throw new Exception($message); } - return (string)reset($attributes[$idAttributeName]); + return $userIdentifier; } /** @@ -204,6 +407,64 @@ class Profile $templateInstance->getLocalization()->addModuleDomain(ModuleConfiguration::MODULE_NAME); $templateInstance->getLocalization()->addAttributeDomains(); + $templateInstance->data = [ + 'menuManager' => $this->menuManager, + 'csrfToken' => $this->csrfToken, + 'alertsBag' => $this->alertsBag, + ]; + + // Make CSRF token also available as a cookie, so it can be used for XHR POST requests validation. + $this->appendCsrfCookie($templateInstance); + return $templateInstance; } + + protected function prepareMenuManager(): MenuManager + { + $menuManager = new MenuManager(); + + $menuManager->addItems( + new MenuManager\MenuItem( + 'personal-data', + Translate::noop('Personal Data'), + 'css/src/icons/prof-page.svg' + ), + new MenuManager\MenuItem( + 'connected-organizations', + Translate::noop('Connected Organizations'), + 'css/src/icons/conn-orgs.svg' + ), + new MenuManager\MenuItem( + 'activity', + Translate::noop('Activity'), + 'css/src/icons/activity.svg' + ) + ); + + // Depending on other functionalities, add additional menu items. + if ($this->sspModuleManager->getOidc()->isEnabled()) { + $menuManager->addItems( + new MenuManager\MenuItem( + 'oidc-tokens', + Translate::noop('Tokens'), + 'css/src/icons/activity.svg' + ) + ); + } + + $menuManager->addItems( + new MenuManager\MenuItem( + 'logout', + Translate::noop('Log out'), + 'css/src/icons/logout.svg' + ) + ); + + return $menuManager; + } + + protected function appendCsrfCookie(Response $response): void + { + $response->headers->setCookie(new Cookie(CsrfToken::KEY, $this->csrfToken->get())); + } } diff --git a/src/Services/AlertsBag.php b/src/Services/AlertsBag.php new file mode 100644 index 0000000000000000000000000000000000000000..3e392e26d757f2fffc5682e264f5cc693da3639e --- /dev/null +++ b/src/Services/AlertsBag.php @@ -0,0 +1,54 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\Services; + +use SimpleSAML\Module\accounting\Exceptions\Exception; +use SimpleSAML\Module\accounting\ModuleConfiguration; +use SimpleSAML\Module\accounting\Services\AlertsBag\Alert; +use SimpleSAML\Session; + +class AlertsBag +{ + protected Session $sspSession; + + public const SESSION_KEY = 'alerts'; + + public function __construct(Session $session) + { + $this->sspSession = $session; + } + + public function isNotEmpty(): bool + { + return ! empty($this->getAll(false)); + } + + /** + * @throws Exception + */ + public function getAll(bool $reinitialize = true): array + { + $alerts = $this->sspSession->getData(ModuleConfiguration::MODULE_NAME, self::SESSION_KEY) ?? []; + + if (! is_array($alerts)) { + throw new Exception('Unexpected value type.'); + } + + if ($reinitialize) { + $this->sspSession->setData(ModuleConfiguration::MODULE_NAME, self::SESSION_KEY, null); + } + + return $alerts; + } + + public function put(Alert $alert): void + { + $this->sspSession->setData( + ModuleConfiguration::MODULE_NAME, + self::SESSION_KEY, + array_merge($this->getAll(false), [$alert]) + ); + } +} diff --git a/src/Services/AlertsBag/Alert.php b/src/Services/AlertsBag/Alert.php new file mode 100644 index 0000000000000000000000000000000000000000..5e4db04f34f31a97455f66f897ecfed6283f72cd --- /dev/null +++ b/src/Services/AlertsBag/Alert.php @@ -0,0 +1,27 @@ +<?php + +namespace SimpleSAML\Module\accounting\Services\AlertsBag; + +class Alert +{ + protected string $message; + protected string $level; + + public function __construct( + string $message, + string $level + ) { + $this->message = $message; + $this->level = $level; + } + + public function getMessage(): string + { + return $this->message; + } + + public function getLevel(): string + { + return $this->level; + } +} diff --git a/src/Services/CsrfToken.php b/src/Services/CsrfToken.php new file mode 100644 index 0000000000000000000000000000000000000000..ff2d2c577cd44aa2881b5b434b9ad5dc661b69cf --- /dev/null +++ b/src/Services/CsrfToken.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\Services; + +use SimpleSAML\Module\accounting\ModuleConfiguration; +use SimpleSAML\Session; + +class CsrfToken +{ + protected Session $session; + + public const KEY = 'ssp-' . ModuleConfiguration::MODULE_NAME . '-csrf-token'; + protected HelpersManager $helpersManager; + + public function __construct( + Session $session = null, + HelpersManager $helpersManager = null + ) { + $this->session = $session ?? Session::getSessionFromRequest(); + $this->helpersManager = $helpersManager ?? new HelpersManager(); + + if ($this->get() === null) { + $this->set(); + } + } + + protected function set(?string $token = null): void + { + $this->session->setData( + ModuleConfiguration::MODULE_NAME, + self::KEY, + $token ?? $this->helpersManager->getRandom()->getString() + ); + } + + public function get(): ?string + { + $token = $this->session->getData(ModuleConfiguration::MODULE_NAME, self::KEY); + + if ($token !== null) { + return (string) $token; + } + + return null; + } + + public function validate(string $token): bool + { + $isValid = $token === $this->get(); + + $this->set(); + + return $isValid; + } +} diff --git a/src/Services/HelpersManager.php b/src/Services/HelpersManager.php index e61c64d2f012c0084ad8a76f08fc2f07e70799e9..5fe3a362f58a6e81347757fa92678d073ac7096d 100644 --- a/src/Services/HelpersManager.php +++ b/src/Services/HelpersManager.php @@ -15,14 +15,15 @@ use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration use SimpleSAML\Module\accounting\Helpers\Network; use SimpleSAML\Module\accounting\Helpers\ProviderResolver; use SimpleSAML\Module\accounting\Helpers\Random; -use SimpleSAML\Module\accounting\Helpers\ModuleRoutes; +use SimpleSAML\Module\accounting\Helpers\Routes; +use SimpleSAML\Module\accounting\Helpers\SspModule; class HelpersManager { protected static ?DateTime $dateTime; protected static ?Environment $environment; protected static ?Random $random; - protected static ?ModuleRoutes $routes; + protected static ?Routes $routes; protected static ?Arr $arr; protected static ?Hash $hash; protected static ?Attributes $attributes; @@ -31,6 +32,7 @@ class HelpersManager protected static ?Network $network; protected static ?AuthenticationEventStateResolver $authenticationEventStateResolver; protected static ?ProviderResolver $providerResolver; + protected static ?SspModule $sspModule; public function getDateTime(): DateTime @@ -48,9 +50,9 @@ class HelpersManager return self::$random ??= new Random(); } - public function getModuleRoutes(): ModuleRoutes + public function getRoutes(): Routes { - return self::$routes ??= new ModuleRoutes(); + return self::$routes ??= new Routes(); } public function getArr(): Arr @@ -92,4 +94,9 @@ class HelpersManager { return self::$providerResolver ??= new ProviderResolver(); } + + public function getSspModule(): SspModule + { + return self::$sspModule ??= new SspModule(); + } } diff --git a/src/Services/JobRunner.php b/src/Services/JobRunner.php index 0e9fc05d6491fe331ac699562f2cfb7737c9ff96..12b47e2fbbefeb4be1b848764e0a8941ecd38de8 100644 --- a/src/Services/JobRunner.php +++ b/src/Services/JobRunner.php @@ -79,7 +79,7 @@ class JobRunner $this->cache = $cache ?? $this->resolveCache(); - $this->jobRunnerId = $this->helpersManager->getRandom()->getRandomInt(); + $this->jobRunnerId = $this->helpersManager->getRandom()->getInt(); $this->state = $state ?? new State($this->jobRunnerId); diff --git a/src/Services/MenuManager.php b/src/Services/MenuManager.php new file mode 100644 index 0000000000000000000000000000000000000000..45ae8287998dbaccffd9aec5fcb6e443e0aa5c84 --- /dev/null +++ b/src/Services/MenuManager.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\Services; + +use SimpleSAML\Module\accounting\Services\MenuManager\MenuItem; + +class MenuManager +{ + /** @var array<MenuItem> */ + protected array $items = []; + + /** + * Add MenuItems to the end of the list. + * @param MenuItem ...$menuItems + * @return void + */ + public function addItems(MenuItem ...$menuItems): void + { + array_push($this->items, ...$menuItems); + } + + /** + * Add MenuItem to specific offset (position). If offset not set, MenuItem will be appended to the end. + * @param MenuItem $menuItem + * @param int|null $offset + * @return void + */ + public function addItem(MenuItem $menuItem, int $offset = null): void + { + $offset = $offset ?? count($this->items); + + array_splice($this->items, $offset, 0, [$menuItem]); + } + + public function getItems(): array + { + return $this->items; + } +} diff --git a/src/Services/MenuManager/MenuItem.php b/src/Services/MenuManager/MenuItem.php new file mode 100644 index 0000000000000000000000000000000000000000..aef046f490c0404bc172c765e8f702149da055c8 --- /dev/null +++ b/src/Services/MenuManager/MenuItem.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\Services\MenuManager; + +class MenuItem +{ + protected string $hrefPath; + protected string $label; + protected ?string $iconAssetPath; + + public function __construct( + string $hrefPath, + string $label, + string $iconAssetPath = null + ) { + $this->hrefPath = $hrefPath; + $this->label = $label; + $this->iconAssetPath = $iconAssetPath; + } + + /** + * @return string + */ + public function getHrefPath(): string + { + return $this->hrefPath; + } + + /** + * @return string + */ + public function getLabel(): string + { + return $this->label; + } + + /** + * @return string + */ + public function getIconAssetPath(): ?string + { + return $this->iconAssetPath; + } +} diff --git a/src/Services/SspModuleManager.php b/src/Services/SspModuleManager.php new file mode 100644 index 0000000000000000000000000000000000000000..0c55cf6b691e2437fb932eb8a7e05912b8f80fe7 --- /dev/null +++ b/src/Services/SspModuleManager.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\Services; + +use Psr\Log\LoggerInterface; +use SimpleSAML\Module\accounting\SspModule\Oidc; + +class SspModuleManager +{ + protected LoggerInterface $logger; + protected HelpersManager $helpersManager; + + protected static ?Oidc $oidc; + + public function __construct( + LoggerInterface $logger = null, + HelpersManager $helpersManager = null + ) { + $this->logger = $logger ?? new Logger(); + $this->helpersManager = $helpersManager ?? new HelpersManager(); + } + + public function getOidc(): Oidc + { + return self::$oidc ??= new Oidc( + $this->logger, + $this->helpersManager + ); + } +} diff --git a/src/SspModule/Oidc.php b/src/SspModule/Oidc.php new file mode 100644 index 0000000000000000000000000000000000000000..f9850412b27a4ec3222c88d16b40d174b5c13760 --- /dev/null +++ b/src/SspModule/Oidc.php @@ -0,0 +1,241 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\SspModule; + +use Psr\Log\LoggerInterface; +use SimpleSAML\Database; +use SimpleSAML\Module\accounting\Services\HelpersManager; +use SimpleSAML\Module\accounting\Services\Logger; +use SimpleSAML\Module\oidc\Repositories\AccessTokenRepository; +use SimpleSAML\Module\oidc\Repositories\ClientRepository; +use SimpleSAML\Module\oidc\Repositories\RefreshTokenRepository; +use SimpleSAML\Module\oidc\Services\Container; + +class Oidc +{ + public const MODULE_NAME = 'oidc'; + public const DEFAULT_LIMIT = 50; + + protected LoggerInterface $logger; + protected HelpersManager $helpersManager; + protected bool $isEnabled = false; + protected Container $container; + protected Database $database; + + public function __construct( + LoggerInterface $logger = null, + HelpersManager $helpersManager = null, + Container $container = null, + Database $database = null + ) { + $this->logger = $logger ?? new Logger(); + $this->helpersManager = $helpersManager ?? new HelpersManager(); + $this->container = $container ?? new Container(); + $this->database = $database ?? Database::getInstance(); + + $this->isEnabled = $this->helpersManager->getSspModule()->isEnabled(self::MODULE_NAME); + } + + /** + * @return bool + */ + public function isEnabled(): bool + { + return $this->isEnabled; + } + + /** + * @return Container + */ + public function getContainer(): Container + { + return $this->container; + } + + public function getUsersAccessTokens( + string $userId, + ?array $clientIds = null, + ?int $limit = self::DEFAULT_LIMIT + ): array { + $sql = sprintf( + <<<EOF + SELECT id, client_id, expires_at, is_revoked + FROM %s + WHERE user_id = :user_id AND is_revoked = 0 AND expires_at > '%s' + EOF, + $this->getPrefixedTableName(AccessTokenRepository::TABLE_NAME), + $this->helpersManager->getDateTime()->toFormattedString() + ); + + $params = ['user_id' => $userId,]; + + if ($clientIds !== null) { + $index = 0; + $clientIdPlaceholders = []; + $clientIdParams = []; + + /** @var string $clientId */ + foreach ($clientIds as $clientId) { + $currentPlaceholder = 'client_id' . $index++; + $clientIdPlaceholders[] = ':' . $currentPlaceholder; + $clientIdParams[$currentPlaceholder] = $clientId; + } + + $sql .= ' AND client_id IN (' . implode(', ', $clientIdPlaceholders) . ')'; + $params += $clientIdParams; + } + + $sql .= ' ORDER BY client_id, expires_at'; + + if ($limit > 0) { + $sql .= ' LIMIT ' . $limit; + } + + $statement = $this->database->read($sql, $params); + + if (!$data = $statement->fetchAll(\PDO::FETCH_ASSOC)) { + $this->logger->debug('No OIDC access tokens available for user ID ' . $userId); + return []; + } + + return $data; + } + + /** + * @param string $userId + * @param string $accessTokenId + * @return false|int + */ + public function revokeUsersAccessToken(string $userId, string $accessTokenId) + { + $sql = sprintf( + <<<EOF + UPDATE %s + SET is_revoked = 1 + WHERE user_id = :user_id AND id = :access_token_id + EOF, + $this->getPrefixedTableName(AccessTokenRepository::TABLE_NAME), + ); + + $params = ['user_id' => $userId, 'access_token_id' => $accessTokenId]; + + return $this->database->write($sql, $params); + } + + public function getUsersRefreshTokens( + string $userId, + ?array $clientIds = null, + ?int $limit = self::DEFAULT_LIMIT + ): array { + $sql = sprintf( + <<<EOF + SELECT ort.id, oat.client_id, ort.expires_at, ort.is_revoked + FROM %s AS ort + INNER JOIN %s as oat ON ort.access_token_id = oat.id + WHERE oat.user_id = :user_id AND ort.is_revoked = 0 AND ort.expires_at > '%s' + EOF, + $this->getPrefixedTableName(RefreshTokenRepository::TABLE_NAME), + $this->getPrefixedTableName(AccessTokenRepository::TABLE_NAME), + $this->helpersManager->getDateTime()->toFormattedString() + ); + + $params = ['user_id' => $userId,]; + + if ($clientIds !== null) { + $index = 0; + $clientIdPlaceholders = []; + $clientIdParams = []; + + /** @var string $clientId */ + foreach ($clientIds as $clientId) { + $currentPlaceholder = 'client_id' . $index++; + $clientIdPlaceholders[] = ':' . $currentPlaceholder; + $clientIdParams[$currentPlaceholder] = $clientId; + } + + $sql .= ' AND oat.client_id IN (' . implode(', ', $clientIdPlaceholders) . ')'; + $params += $clientIdParams; + } + + $sql .= ' ORDER BY oat.client_id, ort.expires_at'; + + if ($limit > 0) { + $sql .= ' LIMIT ' . $limit; + } + + $statement = $this->database->read($sql, $params); + + if (!$data = $statement->fetchAll(\PDO::FETCH_ASSOC)) { + $this->logger->debug('No OIDC refresh tokens available for user ID ' . $userId); + return []; + } + + return $data; + } + + /** + * @param string $userId + * @param string $refreshTokenId + * @return false|int + */ + public function revokeUsersRefreshToken(string $userId, string $refreshTokenId) + { + $sql = sprintf( + <<<EOF + UPDATE %s AS ort + INNER JOIN %s as oat ON ort.access_token_id = oat.id + SET ort.is_revoked = 1 + WHERE oat.user_id = :user_id AND ort.id = :refresh_token_id + EOF, + $this->getPrefixedTableName(RefreshTokenRepository::TABLE_NAME), + $this->getPrefixedTableName(AccessTokenRepository::TABLE_NAME), + ); + + $params = ['user_id' => $userId, 'refresh_token_id' => $refreshTokenId]; + + return $this->database->write($sql, $params); + } + + public function getClients(array $clientIds): array + { + $index = 0; + $clientIdPlaceholders = []; + $clientIdParams = []; + + /** @var string $clientId */ + foreach ($clientIds as $clientId) { + $currentPlaceholder = 'client_id' . $index++; + $clientIdPlaceholders[] = ':' . $currentPlaceholder; + $clientIdParams[$currentPlaceholder] = $clientId; + } + + $sql = sprintf( + <<<EOF + SELECT id, name, description + FROM %s + EOF, + $this->getPrefixedTableName(ClientRepository::TABLE_NAME), + ); + + $sql .= ' WHERE id IN (' . implode(', ', $clientIdPlaceholders) . ')'; + $sql .= ' ORDER BY name'; + + $params = $clientIdParams; + + $statement = $this->database->read($sql, $params); + + if (!$data = $statement->fetchAll(\PDO::FETCH_ASSOC)) { + $this->logger->debug('No OIDC clients available for ' . var_export($clientIds, true)); + return []; + } + + return $data; + } + + protected function getPrefixedTableName(string $tableName): string + { + return $this->database->applyPrefix($tableName); + } +} diff --git a/src/Traits/HasUserAttributesTrait.php b/src/Traits/HasUserAttributesTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..13e30450bdd94a38e92c8252188e92a0e06b2dec --- /dev/null +++ b/src/Traits/HasUserAttributesTrait.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\Traits; + +trait HasUserAttributesTrait +{ + protected array $attributes = []; + + public function getAttributes(): array + { + return $this->attributes; + } + + public function getFirstAttributeValue(string $attributeName): ?string + { + if (($value = $this->getAttributeValue($attributeName)) !== null) { + return (string)reset($value); + } + + return null; + } + + public function getAttributeValue(string $attributeName): ?array + { + if (!empty($this->attributes[$attributeName]) && is_array($this->attributes[$attributeName])) { + return $this->attributes[$attributeName]; + } + + return null; + } +} diff --git a/templates/base.twig b/templates/base.twig index 6ee008bde89bdcc8aaad74aef745c0397fe86de7..d07567be3d9081aab97108a4a3241ae3b3de837e 100644 --- a/templates/base.twig +++ b/templates/base.twig @@ -24,6 +24,8 @@ {% block banner %}{% endblock %} <section id="main"> + {% include '@accounting/includes/_alerts.twig' %} + {% block content %}{% endblock %} </section> @@ -35,5 +37,24 @@ {% endtrans %} </div> </footer> + +<script> + const accounting = { + alert: function (message) { + // TODO implement nice alerts. + alert(message); + }, + removeElement: function (element, speed = 500) { + const seconds = speed / 1000; + element.style.transition = "opacity " + seconds + "s ease"; + element.style.opacity = 0; + setTimeout(function() { + element.parentNode.removeChild(element); + }, speed); + } + }; +</script> + +{% block tail %}{% endblock %} </body> </html> \ No newline at end of file diff --git a/templates/includes/_alerts.twig b/templates/includes/_alerts.twig new file mode 100644 index 0000000000000000000000000000000000000000..5e3d80ade0cbe32e8e9bbbd9df6492434551faa9 --- /dev/null +++ b/templates/includes/_alerts.twig @@ -0,0 +1,14 @@ + +{# @var alertsBag \SimpleSAML\Module\accounting\Services\AlertsBag #} +{# @var alert \SimpleSAML\Module\accounting\Services\AlertsBag\Alert #} + +{% if alertsBag is defined and alertsBag.isNotEmpty %} + <div class="alerts"> + {% for alert in alertsBag.getAll %} + <div class="alert"> + <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> + {{ alert.message }} + </div> + {% endfor %} + </div> +{% endif %} \ No newline at end of file diff --git a/templates/includes/_navigation.twig b/templates/includes/_navigation.twig index a77537ae85dde946bf4dd24235e427f19976041e..90a76e4fa1ce6be0e37ef04cb16589f400b93435 100644 --- a/templates/includes/_navigation.twig +++ b/templates/includes/_navigation.twig @@ -1,40 +1,24 @@ +{# @var menuManager \SimpleSAML\Module\accounting\Services\MenuManager #} +{# @var menuItem \SimpleSAML\Module\accounting\Services\MenuManager\MenuItem #} +{# @var csrfToken \SimpleSAML\Module\accounting\Services\CsrfToken #} + <div id="nav"> <input type="checkbox" id="nav-toggle" class="nav-toggle"> <nav role="navigation" aria-label="XXX-pagedesc-XXX"> <ul> - <li> - <a href="personal-data"> - <span class="navicon"> - <img src="{{ asset('css/src/icons/prof-page.svg', 'accounting') }}" alt="Profile Page Icon"/> - </span> - <span class="navlabel">{{ 'Personal Data'|trans }}</span> - </a> - </li> - <li> - <a href="connected-organizations"> - <span class="navicon"> - <img src="{{ asset('css/src/icons/conn-orgs.svg', 'accounting') }}" - alt="Connected Organizations Icon"/> - </span> - <span class="navlabel">{{ 'Connected Organizations'|trans }}</span> - </a> - </li> - <li> - <a href="activity"> - <span class="navicon"> - <img src="{{ asset('css/src/icons/activity.svg', 'accounting') }}" alt="Activity Icon"/> - </span> - <span class="navlabel">{{ 'Activity'|trans }}</span> - </a> - </li> - <li> - <a href="logout"> - <span class="navicon"> - <img src="{{ asset('css/src/icons/logout.svg', 'accounting') }}" alt="Logout Icon"/> - </span> - <span class="navlabel">{{ 'Log out'|trans }}</span> - </a> - </li> + {% for menuItem in menuManager.items %} + <li> + <a href="{{ menuItem.hrefPath }}"> + {% if menuItem.iconAssetPath %} + <span class="navicon"> + <img src="{{ asset(menuItem.iconAssetPath, 'accounting') }}" + alt="{{ menuItem.label|trans }} Icon"/> + </span> + {% endif %} + <span class="navlabel">{{ menuItem.label|trans }}</span> + </a> + </li> + {% endfor %} </ul> </nav> </div> \ No newline at end of file diff --git a/templates/user/connected-organizations.twig b/templates/user/connected-organizations.twig index 69851706db384fbe79130699237635b7393a9b93..00d545462f8c11162b205dbe851fbacc26288342 100644 --- a/templates/user/connected-organizations.twig +++ b/templates/user/connected-organizations.twig @@ -1,5 +1,7 @@ {# @var connectedServiceProviderBag \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider\Bag #} {# @var connectedServiceProvider \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider #} +{# @var accessTokensByClient array #} +{# @var refreshTokensByClient array #} {% extends "@accounting/base.twig" %} @@ -17,7 +19,7 @@ </tr> {% for connectedServiceProvider in connectedServiceProviderBag.getAll %} - <tr> + <tr id="connected-service-provider-{{ loop.index }}"> <td>{{ connectedServiceProvider.getServiceProvider.getName|e }}</td> <td>{{ connectedServiceProvider.getNumberOfAuthentications|e }}</td> <td>{{ connectedServiceProvider.getLastAuthenticationAt|date() }}</td> @@ -28,7 +30,7 @@ <label class="dropdown-label" for="dropdown-toggle-{{ loop.index }}"> <img src="{{ asset('css/src/icons/dropdown.svg', 'accounting') }}" alt="Dropdown icon"> </label> - <div class="dropdown-box"> + <div class="dropdown-box" > <strong>{{ 'Service details'|trans }}</strong> <ul> <li>{{ 'Entity ID'|trans }}: {{ connectedServiceProvider.getServiceProvider.getEntityId|e }}</li> @@ -44,6 +46,50 @@ {{ 'Last access'|trans }}: {{ connectedServiceProvider.getLastAuthenticationAt|date() }} </li> </ul> + + {% if connectedServiceProvider.serviceProvider.protocol.designation is same as oidcProtocolDesignation %} + {% if accessTokensByClient is not empty and attribute(accessTokensByClient, connectedServiceProvider.serviceProvider.entityId) %} + <strong>{{ 'Access Tokens'|trans }}</strong> + <table> + {% for accessToken in attribute(accessTokensByClient, connectedServiceProvider.serviceProvider.entityId) %} + <tr> + <td> + {{ accessToken.id }}<br> + {{ 'Expires at'|trans }} {{ accessToken.expires_at|date }} + </td> + <td> + <form class="token-revoke-form" action="oidc-tokens/revoke-xhr"> + <input type="hidden" name="token-type" value="access"> + <input type="hidden" name="token-id" value="{{ accessToken.id }}"> + <input type="submit" value="Revoke"> + </form> + </td> + </tr> + {% endfor %} + </table> + {% endif %} + + {% if refreshTokensByClient is not empty and attribute(refreshTokensByClient, connectedServiceProvider.serviceProvider.entityId) %} + <strong>{{ 'Refresh Tokens'|trans }}</strong> + <table> + {% for refreshToken in attribute(refreshTokensByClient, connectedServiceProvider.serviceProvider.entityId) %} + <tr> + <td> + {{ refreshToken.id }}<br> + {{ 'Expires at'|trans }} {{ refreshToken.expires_at|date }} + </td> + <td> + <form class="token-revoke-form" action="oidc-tokens/revoke-xhr"> + <input type="hidden" name="token-type" value="refresh"> + <input type="hidden" name="token-id" value="{{ refreshToken.id }}"> + <input type="submit" value="Revoke"> + </form> + </td> + </tr> + {% endfor %} + </table> + {% endif %} + {% endif %} </div> </td> </tr> @@ -55,3 +101,45 @@ <!-- end of repeating item --> </table> {% endblock %} + +{% block tail %} + + <script> + (function () { + document.querySelectorAll('.token-revoke-form').forEach( + element => element.addEventListener('submit', revokeToken) + ); + + function revokeToken(event) { + event.preventDefault(); + + const form = event.target; + const submitButton = event.submitter; + const formData = new FormData(form); + + if (! confirm('{{ 'Are you sure?'|trans }}')) { + return; + } + + submitButton.disabled = true; + + const request = new XMLHttpRequest(); + + request.open('POST', form.action); + + request.onload = function () { + if (this.status === 200) { + accounting.removeElement(form.closest('tr')); + } else { + const response = JSON.parse(this.responseText); + console.log(response); + accounting.alert('{{ 'Oups, there was an error while trying to revoke token.'|trans }}'); + } + }; + + request.send(formData); + } + })(); + </script> + +{% endblock %} \ No newline at end of file diff --git a/templates/user/oidc-tokens.twig b/templates/user/oidc-tokens.twig new file mode 100644 index 0000000000000000000000000000000000000000..0f9c6e95125f3ae97478a4e971929bf977e54495 --- /dev/null +++ b/templates/user/oidc-tokens.twig @@ -0,0 +1,78 @@ +{# @var accessTokensByClient array #} +{# @var refreshTokensByClient array #} +{# @var clients array #} + +{% extends "@accounting/base.twig" %} + +{% set pagetitle = 'OIDC Tokens'|trans %} + +{% set pageMenuItem = 'oidc-tokens' %} + +{% block content %} + <section id="banner"> + <div> + {% trans %}Overview of active OIDC Access / Refresh Tokens by OIDC client.{% endtrans %} + </div> + </section> + + <table> + {% for clientId, clientInfo in clients %} + <tr> + <td colspan="2"> + <strong>{{ clientInfo.0.name }}</strong> + <br> + {{ clientInfo.0.description }} + </td> + </tr> + + {% if accessTokensByClient is not empty and attribute(accessTokensByClient, clientId) %} + <tr> + <td colspan="2">{{ 'Access Tokens'|trans }}</td> + </tr> + {% for accessToken in attribute(accessTokensByClient, clientId) %} + <tr> + <td> + {{ accessToken.id }}<br> + {{ 'Expires at'|trans }} {{ accessToken.expires_at|date }} + </td> + <td> + <form method="post" action="oidc-tokens/revoke"> + <input type="hidden" name="csrf-token" value="{{ csrfToken.get }}"> + <input type="hidden" name="token-type" value="access"> + <input type="hidden" name="token-id" value="{{ accessToken.id }}"> + <input type="submit" value="Revoke"> + </form> + </td> + </tr> + {% endfor %} + {% endif %} + + {% if refreshTokensByClient is not empty and attribute(refreshTokensByClient, clientId) %} + <tr> + <td colspan="2">{{ 'Refresh Tokens'|trans }}</td> + </tr> + {% for refreshToken in attribute(refreshTokensByClient, clientId) %} + <tr> + <td> + {{ refreshToken.id }}<br> + {{ 'Expires at'|trans }} {{ refreshToken.expires_at|date }} + </td> + <td> + <form method="post" action="oidc-tokens/revoke"> + <input type="hidden" name="csrf-token" value="{{ csrfToken.get }}"> + <input type="hidden" name="token-type" value="refresh"> + <input type="hidden" name="token-id" value="{{ refreshToken.id }}"> + <input type="submit" value="Revoke"> + </form> + </td> + </tr> + {% endfor %} + {% endif %} + {% else %} + <tr> + <td colspan="3">{{ 'No data available'|trans }}</td> + </tr> + {% endfor %} + <!-- end of repeating item --> + </table> +{% endblock %} diff --git a/tests/src/Entities/Bases/AbstractProviderTest.php b/tests/src/Entities/Bases/AbstractProviderTest.php index 5eac3d84f2b596d24eed02675c18d46016f745ea..e8d8a2743b4492f6242c9ae8aa5b162bc8cead90 100644 --- a/tests/src/Entities/Bases/AbstractProviderTest.php +++ b/tests/src/Entities/Bases/AbstractProviderTest.php @@ -6,6 +6,7 @@ namespace SimpleSAML\Test\Module\accounting\Entities\Bases; use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider; use PHPUnit\Framework\TestCase; +use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface; use SimpleSAML\Module\accounting\Entities\Providers\Identity\Saml2; /** @@ -96,6 +97,21 @@ class AbstractProviderTest extends TestCase { return (string)($this->metadata['entityid'] ?? 'N/A'); } + + public function getProtocol(): AuthenticationProtocolInterface + { + return new class implements AuthenticationProtocolInterface { + public function getDesignation(): string + { + return 'designation'; + } + + public function getId(): int + { + return 999; + } + }; + } }; } } diff --git a/tests/src/Helpers/RandomTest.php b/tests/src/Helpers/RandomTest.php index 3031c219b855e9dd098cc1d664deac2384705bb2..29fa51e895c02c3a17435abc33c2ef3060d5951c 100644 --- a/tests/src/Helpers/RandomTest.php +++ b/tests/src/Helpers/RandomTest.php @@ -14,6 +14,6 @@ class RandomTest extends TestCase { public function testCanGetRandomInt(): void { - $this->assertIsInt((new Random())->getRandomInt()); + $this->assertIsInt((new Random())->getInt()); } } diff --git a/tests/src/Helpers/ModuleRoutesTest.php b/tests/src/Helpers/RoutesTest.php similarity index 82% rename from tests/src/Helpers/ModuleRoutesTest.php rename to tests/src/Helpers/RoutesTest.php index 15fd5609393e8af7d8f33e28bcd6bdb3d5339540..b649a1458867d538d1e2af76888772ed6031569e 100644 --- a/tests/src/Helpers/ModuleRoutesTest.php +++ b/tests/src/Helpers/RoutesTest.php @@ -7,15 +7,15 @@ namespace SimpleSAML\Test\Module\accounting\Helpers; use PHPUnit\Framework\MockObject\Stub; use SimpleSAML\Error\CriticalConfigurationError; use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException; -use SimpleSAML\Module\accounting\Helpers\ModuleRoutes; +use SimpleSAML\Module\accounting\Helpers\Routes; use PHPUnit\Framework\TestCase; use SimpleSAML\Module\accounting\ModuleConfiguration; use SimpleSAML\Utils\HTTP; /** - * @covers \SimpleSAML\Module\accounting\Helpers\ModuleRoutes + * @covers \SimpleSAML\Module\accounting\Helpers\Routes */ -class ModuleRoutesTest extends TestCase +class RoutesTest extends TestCase { protected const BASE_URL = 'https://example.org/ssp/'; /** @@ -37,7 +37,7 @@ class ModuleRoutesTest extends TestCase $path = 'sample-path'; $moduleUrlWithPath = $this->moduleUrl . '/' . $path; - $moduleRoutesHelper = new ModuleRoutes($this->sspHttpUtilsStub); + $moduleRoutesHelper = new Routes($this->sspHttpUtilsStub); $this->assertSame($moduleUrlWithPath, $moduleRoutesHelper->getUrl($path)); } @@ -49,7 +49,7 @@ class ModuleRoutesTest extends TestCase $fullUrl = 'full-url-with-sample-param'; $this->sspHttpUtilsStub->method('addURLParameters')->willReturn($fullUrl); - $moduleRoutesHelper = new ModuleRoutes($this->sspHttpUtilsStub); + $moduleRoutesHelper = new Routes($this->sspHttpUtilsStub); $this->assertSame($fullUrl, $moduleRoutesHelper->getUrl($path, $params)); } diff --git a/tests/src/Services/HelpersManagerTest.php b/tests/src/Services/HelpersManagerTest.php index 0d82af94c48085979a4dd8d1a4cb313df81406d1..aad618084fdde23b22033c93d8930b73a1f8a8e8 100644 --- a/tests/src/Services/HelpersManagerTest.php +++ b/tests/src/Services/HelpersManagerTest.php @@ -12,7 +12,7 @@ use SimpleSAML\Module\accounting\Helpers\Environment; use SimpleSAML\Module\accounting\Helpers\Filesystem; use SimpleSAML\Module\accounting\Helpers\Hash; use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration; -use SimpleSAML\Module\accounting\Helpers\ModuleRoutes; +use SimpleSAML\Module\accounting\Helpers\Routes; use SimpleSAML\Module\accounting\Helpers\Network; use SimpleSAML\Module\accounting\Helpers\ProviderResolver; use SimpleSAML\Module\accounting\Helpers\Random; @@ -21,7 +21,7 @@ use PHPUnit\Framework\TestCase; /** * @covers \SimpleSAML\Module\accounting\Services\HelpersManager - * @uses \SimpleSAML\Module\accounting\Helpers\ModuleRoutes + * @uses \SimpleSAML\Module\accounting\Helpers\Routes * @uses \SimpleSAML\Module\accounting\Helpers\Hash */ class HelpersManagerTest extends TestCase @@ -42,7 +42,7 @@ class HelpersManagerTest extends TestCase ); $this->assertInstanceOf(Network::class, $helpersManager->getNetwork()); $this->assertInstanceOf(Random::class, $helpersManager->getRandom()); - $this->assertInstanceOf(ModuleRoutes::class, $helpersManager->getModuleRoutes()); + $this->assertInstanceOf(Routes::class, $helpersManager->getRoutes()); $this->assertInstanceOf( AuthenticationEventStateResolver::class, $helpersManager->getAuthenticationEventStateResolver() diff --git a/tests/src/Services/JobRunnerTest.php b/tests/src/Services/JobRunnerTest.php index 15b57fe144b1a42d0cba4541fe49231cae035773..5c748b25b80ce2b3ce06d6c279e8e94c99219624 100644 --- a/tests/src/Services/JobRunnerTest.php +++ b/tests/src/Services/JobRunnerTest.php @@ -123,7 +123,7 @@ class JobRunnerTest extends TestCase */ public function testCanCreateInstance(): void { - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->assertInstanceOf( @@ -148,7 +148,7 @@ class JobRunnerTest extends TestCase */ public function testPreRunValidationFailsForSameJobRunnerId(): void { - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(123); @@ -185,7 +185,7 @@ class JobRunnerTest extends TestCase */ public function testPreRunValidationFailsForStaleState(): void { - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(321); @@ -222,7 +222,7 @@ class JobRunnerTest extends TestCase */ public function testPreRunValidationPassesWhenStateIsNull(): void { - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->cacheMock->method('get')->willReturn(null); @@ -258,7 +258,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(321); @@ -296,7 +296,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(321); @@ -336,7 +336,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(321); @@ -372,7 +372,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(321); @@ -417,7 +417,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getJobRunnerMaximumExecutionTime') ->willReturn(new DateInterval('PT1S')); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->cacheMock->method('get')->willReturn(null); @@ -459,7 +459,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getJobRunnerMaximumExecutionTime') ->willReturn(new DateInterval('PT20S')); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->environmentHelperStub->method('isCli')->willReturn(false); $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub); @@ -505,7 +505,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->cacheMock->method('get')->willReturn(null); @@ -544,7 +544,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->cacheMock->method('get')->willReturnOnConsecutiveCalls( @@ -585,7 +585,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->cacheMock->method('get')->willReturnOnConsecutiveCalls( @@ -626,7 +626,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(321); @@ -669,7 +669,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(123); @@ -713,7 +713,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->stateStub->method('getJobRunnerId')->willReturn(123); @@ -758,7 +758,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->environmentHelperStub->method('isCli')->willReturn(true); $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub); @@ -813,7 +813,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getAccountingProcessingType') ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->environmentHelperStub->method('isCli')->willReturn(false); $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub); @@ -867,7 +867,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass') ->willReturn('mock'); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->environmentHelperStub->method('isCli')->willReturn(false); $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub); @@ -934,7 +934,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass') ->willReturn('mock'); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->environmentHelperStub->method('isCli')->willReturn(false); $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub); @@ -998,7 +998,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getJobRunnerShouldPauseAfterNumberOfJobsProcessed') ->willReturn(0); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->environmentHelperStub->method('isCli')->willReturn(false); $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub); @@ -1069,7 +1069,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass') ->willReturn('mock'); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->environmentHelperStub->method('isCli')->willReturn(false); $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub); @@ -1135,7 +1135,7 @@ class JobRunnerTest extends TestCase $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass') ->willReturn('mock'); - $this->randomHelperStub->method('getRandomInt')->willReturn(123); + $this->randomHelperStub->method('getInt')->willReturn(123); $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub); $this->environmentHelperStub->method('isCli')->willReturn(false); $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);