From a66b6432bb8d2b17c6a741498c78e3dff639ccab Mon Sep 17 00:00:00 2001 From: gyufi Date: Wed, 26 Oct 2022 14:18:21 +0200 Subject: [PATCH 1/8] refactor: refactoring for ssp 2.0.0 --- .php_cs.dist | 15 ++ .travis.yml | 2 + composer.json | 19 +- default-enable | 0 lib/Auth/Process/FilterAttributes.php | 179 -------------- phpunit.xml | 12 +- psalm.xml | 29 +++ src/Auth/Process/FilterAttributes.php | 229 ++++++++++++++++++ src/Auth/Process/codecov.yml | 17 ++ tests/_autoload_modules.php | 32 --- tests/bootstrap.php | 5 + .../lib/Auth/Process/FilterAttributesTest.php | 15 +- 12 files changed, 330 insertions(+), 224 deletions(-) create mode 100644 .php_cs.dist delete mode 100644 default-enable delete mode 100644 lib/Auth/Process/FilterAttributes.php create mode 100644 psalm.xml create mode 100644 src/Auth/Process/FilterAttributes.php create mode 100644 src/Auth/Process/codecov.yml delete mode 100644 tests/_autoload_modules.php create mode 100644 tests/bootstrap.php diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000..b46e7f8 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,15 @@ +in([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) +; +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR2' => true, + '@PSR4' => true, + '@PSR5' => true, + ]) + ->setFinder($finder) +; diff --git a/.travis.yml b/.travis.yml index 2fa6332..ef1f0ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ php: - 5.5 - 5.6 - 7.0 +- 7.4 +- 8.1 - hhvm matrix: allow_failures: diff --git a/composer.json b/composer.json index 1596bb1..19fea1f 100644 --- a/composer.json +++ b/composer.json @@ -3,18 +3,25 @@ "description": "Filter to remove attribute values which are not properly scoped.", "keywords": [ "simplesamlphp", "scope", "sp", "module", "filter" ], "type": "simplesamlphp-module", + "autoload": { + "psr-4": { + "SimpleSAML\\Module\\attributescope\\": "src/" + } + }, "require": { - "simplesamlphp/composer-module-installer": "^1.1" + "simplesamlphp/composer-module-installer": "^1.2", + "simplesamlphp/simplesamlphp": "2.0.0-rc2" }, "require-dev": { - "simplesamlphp/simplesamlphp": "1.14", - "phpunit/phpunit": "~4.8.35" - }, - "autoload-dev": { - "files": ["tests/_autoload_modules.php"] + "simplesamlphp/simplesamlphp-test-framework": "^1.2.1" }, "support": { "issues": "https://github.com/NIIF/simplesamlphp-module-attributescope/issues", "source": "https://github.com/NIIF/simplesamlphp-module-attributescope" + }, + "config": { + "allow-plugins": { + "simplesamlphp/composer-module-installer": true + } } } diff --git a/default-enable b/default-enable deleted file mode 100644 index e69de29..0000000 diff --git a/lib/Auth/Process/FilterAttributes.php b/lib/Auth/Process/FilterAttributes.php deleted file mode 100644 index 8e76b0d..0000000 --- a/lib/Auth/Process/FilterAttributes.php +++ /dev/null @@ -1,179 +0,0 @@ -attributesWithScope = $config['attributesWithScope']; - } - if (array_key_exists('scopeAttributes', $config)) { - $this->scopeAttributes = $config['scopeAttributes']; - } - if (array_key_exists('ignoreCheckForEntities', $config)) { - $this->ignoreCheckForEntities = $config['ignoreCheckForEntities']; - } - if (array_key_exists('attributesWithScopeSuffix', $config)) { - $this->attributesWithScopeSuffix = $config['attributesWithScopeSuffix']; - } - if (array_key_exists('ignoreCase', $config)) { - $this->ignoreCase = $config['ignoreCase']; - } - } - - /** - * Apply filter. - * - * @param array &$request the current request - */ - public function process(&$request) - { - $src = $request['Source']; - - if (isset($src['entityid']) && in_array($src['entityid'], $this->ignoreCheckForEntities, true)) { - SimpleSAML_Logger::debug('Ignoring scope checking for assertions from ' . $src['entityid']); - return; - } - - $noscope = false; - if (!isset($src['scope']) || - !is_array($src['scope']) || - !count($src['scope'])) { - SimpleSAML_Logger::warning('No scope extension in IdP metadata, all scoped attributes are filtered out!'); - $noscope = true; - } - $scopes = $noscope ? array() : $src['scope']; - - foreach ($this->attributesWithScope as $attributesWithScope) { - if (!isset($request['Attributes'][$attributesWithScope])) { - continue; - } - if ($noscope) { - SimpleSAML_Logger::info('Attribute '.$attributesWithScope.' is filtered out due to missing scope information in IdP metadata.'); - unset($request['Attributes'][$attributesWithScope]); - continue; - } - $values = $request['Attributes'][$attributesWithScope]; - $newValues = array(); - foreach ($values as $value) { - if ($this->isProperlyScoped($value, $scopes)) { - $newValues[] = $value; - } else { - SimpleSAML_Logger::warning('Attribute value ('.$value.') is removed by attributescope check.'); - } - } - - if (count($newValues)) { - $request['Attributes'][$attributesWithScope] = $newValues; - } else { - unset($request['Attributes'][$attributesWithScope]); - } - } - // Filter out scopeAttributes if the value does not match any scope values - foreach ($this->scopeAttributes as $scopeAttribute) { - if (array_key_exists($scopeAttribute, $request['Attributes'])) { - if (count($request['Attributes'][$scopeAttribute]) != 1) { - SimpleSAML_Logger::warning('$scopeAttribute (' . $scopeAttribute . ') must be single valued. Filtering out.'); - unset($request['Attributes'][$scopeAttribute]); - } elseif (!in_array($request['Attributes'][$scopeAttribute][0], $scopes)) { - SimpleSAML_Logger::warning('Scope attribute (' . $scopeAttribute . ') does not match metadata. Filtering out.'); - unset($request['Attributes'][$scopeAttribute]); - } - } - } - - foreach ($this->attributesWithScopeSuffix as $attributeWithSuffix) { - if (!isset($request['Attributes'][$attributeWithSuffix])) { - continue; - } - if ($noscope) { - SimpleSAML_Logger::info('Attribute '.$attributeWithSuffix.' is filtered out due to missing scope information in IdP metadata.'); - unset($request['Attributes'][$attributeWithSuffix]); - continue; - } - $values = $request['Attributes'][$attributeWithSuffix]; - $newValues = array(); - foreach ($values as $value) { - if ($this->isProperlySuffixed($value, $scopes)) { - $newValues[] = $value; - } else { - SimpleSAML_Logger::warning('Attribute value ('.$value.') is removed by attributeWithScopeSuffix check.'); - } - } - - if (count($newValues)) { - $request['Attributes'][$attributeWithSuffix] = $newValues; - } else { - unset($request['Attributes'][$attributeWithSuffix]); - } - } - } - - /** - * Determines whether an attribute value is properly scoped. - * - * @param string $value The attribute value to check - * @param array $scopes The array of scopes for the Idp - * - * @return bool true if properly scoped - */ - private function isProperlyScoped($value, $scopes) - { - foreach ($scopes as $scope) { - $preg = '/^[^@]+@'.preg_quote($scope).'$/' . ($this->ignoreCase ? 'i' : ''); - if (preg_match($preg, $value) == 1) { - return true; - } - } - } - - /** - * Determines whether an attribute value is properly suffixed with the scope. - * @ and (literal) . are used for suffix boundries - * - * @param string $value The attribute value to check - * @param array $scopes The array of scopes for the IdP - * - * @return bool true if attribute is suffixed with a scope - */ - private function isProperlySuffixed($value, $scopes) - { - foreach ($scopes as $scope) { - $scopeRegex = '/^[^@]+@(.*\.)?'.preg_quote($scope).'$/' . ($this->ignoreCase ? 'i' : ''); - $subdomainRegex = '/^([^@]*\.)?'.preg_quote($scope).'$/' . ($this->ignoreCase ? 'i' : ''); - if (preg_match($subdomainRegex, $value) === 1 || preg_match($scopeRegex, $value) === 1) { - return true; - } - } - } -} diff --git a/phpunit.xml b/phpunit.xml index 758398c..874490c 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,15 @@ - + + + + ./src + + + + + + + ./tests diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..c36957f --- /dev/null +++ b/psalm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Auth/Process/FilterAttributes.php b/src/Auth/Process/FilterAttributes.php new file mode 100644 index 0000000..6e2932f --- /dev/null +++ b/src/Auth/Process/FilterAttributes.php @@ -0,0 +1,229 @@ + + * @author Gyula Szabo + * @author Gyula Szabo + * @author Tamas Frank + * @license http://www.gnu.org/copyleft/lesser.html LGPL License + * @link https://github.com/niif/simplesamlphp-module-attributescope + */ + +namespace SimpleSAML\Module\niif\attributescope\Auth\Process; +use SimpleSAML\Auth; +use SimpleSAML\Logger; + +/** + * Filter to remove + * * all attributes if there is no `shibmd:Scope` value for the IdP + * * attribute values which are not properly scoped + * * configured scopeAttribute if it doesn't match against + * a value from `shibmd:Scope`. + * + * Note: + * * regexp in scope values are not supported. + * * Configured attribute names MUST match with names in attributemaps. + * It is case-sensitive. + * + * @category SimpleSAML + * @package SimpleSAML\Module\niif + * @author Adam Lantos + * @author Gyula Szabo + * @author Gyula Szabo + * @author Tamas Frank + * @license http://www.gnu.org/copyleft/lesser.html LGPL License + * @link https://github.com/niif/simplesamlphp-module-attributescope + */ + + + +class FilterAttributes extends Auth\ProcessingFilter +{ + private array $_attributesWithScope = array( + 'eduPersonPrincipalName', + 'eduPersonScopedAffiliation', + ); + + private array $_scopeAttributes = array( + 'schacHomeOrganization', + ); + + private array $_ignoreCheckForEntities = array(); + + private array $_attributesWithScopeSuffix = array(); + + private bool $_ignoreCase = false; + + /** + * Constructor + * + * @param array $config simplesamlphp configuration + * @param mixed $reserved reserved + */ + public function __construct(array $config, $reserved) + { + parent::__construct($config, $reserved); + if (array_key_exists('attributesWithScope', $config)) { + $this->_attributesWithScope = $config['attributesWithScope']; + } + if (array_key_exists('scopeAttributes', $config)) { + $this->_scopeAttributes = $config['scopeAttributes']; + } + if (array_key_exists('ignoreCheckForEntities', $config)) { + $this->_ignoreCheckForEntities = $config['ignoreCheckForEntities']; + } + if (array_key_exists('attributesWithScopeSuffix', $config)) { + $this->_attributesWithScopeSuffix = $config['attributesWithScopeSuffix']; + } + if (array_key_exists('ignoreCase', $config)) { + $this->_ignoreCase = $config['ignoreCase']; + } + } + + /** + * Process the filter + * + * @param array $state the state array + * + * @return void + */ + public function process(array &$state): void + { + $src = $state['Source']; + + if (isset($src['entityid']) && in_array($src['entityid'], $this->_ignoreCheckForEntities, true)) { + Logger::debug('Ignoring scope checking for assertions from ' . $src['entityid']); + return; + } + + $noscope = false; + if (!isset($src['scope']) + || !is_array($src['scope']) + || !count($src['scope']) + ) { + Logger::warning('No scope extension in IdP metadata, all scoped attributes are filtered out!'); + $noscope = true; + } + $scopes = $noscope ? array() : $src['scope']; + + foreach ($this->_attributesWithScope as $attributesWithScope) { + if (!isset($state['Attributes'][$attributesWithScope])) { + continue; + } + if ($noscope) { + Logger::info('Attribute '.$attributesWithScope.' is filtered out due to missing scope information in IdP metadata.'); + unset($state['Attributes'][$attributesWithScope]); + continue; + } + $values = $state['Attributes'][$attributesWithScope]; + $newValues = array(); + foreach ($values as $value) { + if ($this->_isProperlyScoped($value, $scopes)) { + $newValues[] = $value; + } else { + Logger::warning('Attribute value ('.$value.') is removed by attributescope check.'); + } + } + + if (count($newValues)) { + $state['Attributes'][$attributesWithScope] = $newValues; + } else { + unset($state['Attributes'][$attributesWithScope]); + } + } + // Filter out scopeAttributes if the value does not match any scope values + foreach ($this->_scopeAttributes as $scopeAttribute) { + if (array_key_exists($scopeAttribute, $state['Attributes'])) { + if (count($state['Attributes'][$scopeAttribute]) != 1) { + Logger::warning('$scopeAttribute (' . $scopeAttribute . ') must be single valued. Filtering out.'); + unset($state['Attributes'][$scopeAttribute]); + } elseif (!in_array($state['Attributes'][$scopeAttribute][0], $scopes)) { + Logger::warning('Scope attribute (' . $scopeAttribute . ') does not match metadata. Filtering out.'); + unset($state['Attributes'][$scopeAttribute]); + } + } + } + + foreach ($this->_attributesWithScopeSuffix as $attributeWithSuffix) { + if (!isset($state['Attributes'][$attributeWithSuffix])) { + continue; + } + if ($noscope) { + Logger::info('Attribute '.$attributeWithSuffix.' is filtered out due to missing scope information in IdP metadata.'); + unset($state['Attributes'][$attributeWithSuffix]); + continue; + } + $values = $state['Attributes'][$attributeWithSuffix]; + $newValues = array(); + foreach ($values as $value) { + if ($this->_isProperlySuffixed($value, $scopes)) { + $newValues[] = $value; + } else { + Logger::warning('Attribute value ('.$value.') is removed by attributeWithScopeSuffix check.'); + } + } + + if (count($newValues)) { + $state['Attributes'][$attributeWithSuffix] = $newValues; + } else { + unset($state['Attributes'][$attributeWithSuffix]); + } + } + } + + /** + * Determines whether an attribute value is properly scoped. + * + * @param string $value The attribute value to check + * @param array $scopes The array of scopes for the Idp + * + * @return bool true if properly scoped + */ + private function _isProperlyScoped(string $value, array $scopes): bool + { + foreach ($scopes as $scope) { + $preg = '/^[^@]+@'.preg_quote($scope).'$/' . ($this->_ignoreCase ? 'i' : ''); + if (preg_match($preg, $value) == 1) { + return true; + } + } + + return false; + } + + /** + * Determines whether an attribute value is properly suffixed with the scope. + * @ and (literal) . are used for suffix boundries + * + * @param string $value The attribute value to check + * @param array $scopes The array of scopes for the IdP + * + * @return bool true if attribute is suffixed with a scope + */ + private function _isProperlySuffixed(string $value, array $scopes): bool + { + foreach ($scopes as $scope) { + $scopeRegex = '/^[^@]+@(.*\.)?'.preg_quote($scope).'$/' . ($this->_ignoreCase ? 'i' : ''); + $subdomainRegex = '/^([^@]*\.)?'.preg_quote($scope).'$/' . ($this->_ignoreCase ? 'i' : ''); + if (preg_match($subdomainRegex, $value) === 1 || preg_match($scopeRegex, $value) === 1) { + return true; + } + } + + return false; + } +} diff --git a/src/Auth/Process/codecov.yml b/src/Auth/Process/codecov.yml new file mode 100644 index 0000000..d01dd7d --- /dev/null +++ b/src/Auth/Process/codecov.yml @@ -0,0 +1,17 @@ +coverage: + status: + project: + default: + target: 0% + threshold: 2% + patch: off +comment: + layout: "diff" + behavior: once + require_changes: true + require_base: no + require_head: yes + branches: null + +github_checks: + annotations: false diff --git a/tests/_autoload_modules.php b/tests/_autoload_modules.php deleted file mode 100644 index a6fdea7..0000000 --- a/tests/_autoload_modules.php +++ /dev/null @@ -1,32 +0,0 @@ -process($request); return $request; } @@ -20,7 +23,7 @@ private static function processFilter(array $config, array $request) /** * Test scoped attributes don't match scope * @param array $source The IDP source info - * @dataProvider testWrongScopeDataProvider + * @dataProvider wrongScopeDataProvider */ public function testWrongScope($source) { @@ -47,7 +50,7 @@ public function testWrongScope($source) * Provide data for the tests * @return array test cases with each subtest being array of arguments */ - public function testWrongScopeDataProvider() + public function wrongScopeDataProvider() { return array( // Empty Source @@ -68,7 +71,7 @@ public function testWrongScopeDataProvider() /** * Test correct scope * @param array $source The IDP source info - * @dataProvider testCorrectScopeDataProvider + * @dataProvider correctScopeDataProvider */ public function testCorrectScope($source) { @@ -92,7 +95,7 @@ public function testCorrectScope($source) * Provide data for the tests * @return array test cases with each subtest being array of arguments */ - public function testCorrectScopeDataProvider() + public function correctScopeDataProvider() { return array( // Correct scope From bc7b76bec23d919bc364adae594e811df7f2a1e6 Mon Sep 17 00:00:00 2001 From: Guy Halse Date: Wed, 25 Oct 2023 22:02:21 +0200 Subject: [PATCH 2/8] Fix namespace --- src/Auth/Process/FilterAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Auth/Process/FilterAttributes.php b/src/Auth/Process/FilterAttributes.php index 6e2932f..c4b77ee 100644 --- a/src/Auth/Process/FilterAttributes.php +++ b/src/Auth/Process/FilterAttributes.php @@ -23,7 +23,7 @@ * @link https://github.com/niif/simplesamlphp-module-attributescope */ -namespace SimpleSAML\Module\niif\attributescope\Auth\Process; +namespace SimpleSAML\Module\attributescope\Auth\Process; use SimpleSAML\Auth; use SimpleSAML\Logger; From 89858af1033d597ec0bb4e26a66259217f1020be Mon Sep 17 00:00:00 2001 From: Guy Halse Date: Wed, 25 Oct 2023 22:18:57 +0200 Subject: [PATCH 3/8] Fix unit tests --- tests/bootstrap.php | 14 +++++++++++--- .../Auth/Process/FilterAttributesTest.php | 14 ++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) rename tests/{lib => src}/Auth/Process/FilterAttributesTest.php (96%) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 8f193fb..db8ca73 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,13 @@ Date: Wed, 25 Oct 2023 22:21:07 +0200 Subject: [PATCH 4/8] Tidy stale composer.lock --- .gitignore | 12 +- composer.lock | 1315 ------------------------------------------------- 2 files changed, 10 insertions(+), 1317 deletions(-) delete mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 19c6e64..50e30d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ -*~ -vendor +.phpunit.result.cache +composer.lock +composer.phar +/vendor/ +/build/ .idea +*~ + +# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +# composer.lock diff --git a/composer.lock b/composer.lock deleted file mode 100644 index dd9715a..0000000 --- a/composer.lock +++ /dev/null @@ -1,1315 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "content-hash": "1ee42ece6420f898ca2921c754d26dc9", - "packages": [ - { - "name": "psr/log", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2016-10-10T12:19:37+00:00" - }, - { - "name": "robrichards/xmlseclibs", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/robrichards/xmlseclibs.git", - "reference": "79fb5e03c4ee4dc3ec77e4b2628231374364a017" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/79fb5e03c4ee4dc3ec77e4b2628231374364a017", - "reference": "79fb5e03c4ee4dc3ec77e4b2628231374364a017", - "shasum": "" - }, - "require": { - "php": ">= 5.2" - }, - "suggest": { - "ext/mcrypt": "MCrypt extension", - "ext/openssl": "OpenSSL extension" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "A PHP library for XML Security", - "homepage": "https://github.com/robrichards/xmlseclibs", - "keywords": [ - "security", - "signature", - "xml", - "xmldsig" - ], - "time": "2016-09-08T13:31:44+00:00" - }, - { - "name": "simplesamlphp/composer-module-installer", - "version": "v1.1.6", - "source": { - "type": "git", - "url": "https://github.com/simplesamlphp/composer-module-installer.git", - "reference": "b70414a2112fe49e97a7eddd747657bd8bc38ef0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/composer-module-installer/zipball/b70414a2112fe49e97a7eddd747657bd8bc38ef0", - "reference": "b70414a2112fe49e97a7eddd747657bd8bc38ef0", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0", - "simplesamlphp/simplesamlphp": "*" - }, - "type": "composer-plugin", - "extra": { - "class": "SimpleSamlPhp\\Composer\\ModuleInstallerPlugin" - }, - "autoload": { - "psr-0": { - "SimpleSamlPhp\\Composer": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "description": "A Composer plugin that allows installing SimpleSAMLphp modules through Composer.", - "time": "2017-04-24T07:12:50+00:00" - }, - { - "name": "simplesamlphp/saml2", - "version": "v1.10.6", - "source": { - "type": "git", - "url": "https://github.com/simplesamlphp/saml2.git", - "reference": "93fef13dea9c46dc238eb59e414d3ae76559d8c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/93fef13dea9c46dc238eb59e414d3ae76559d8c4", - "reference": "93fef13dea9c46dc238eb59e414d3ae76559d8c4", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-openssl": "*", - "php": ">=5.3.3", - "psr/log": "~1.0", - "robrichards/xmlseclibs": "^1.3" - }, - "require-dev": { - "mockery/mockery": "~0.9", - "phpmd/phpmd": "~1.5", - "phpunit/phpunit": "~3.7", - "satooshi/php-coveralls": "~0.6.1", - "sebastian/phpcpd": "~1.4", - "sensiolabs/security-checker": "~1.1", - "squizlabs/php_codesniffer": "~1.4" - }, - "type": "library", - "autoload": { - "psr-0": { - "SAML2_": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1-or-later" - ], - "authors": [ - { - "name": "Andreas Åkre Solberg", - "email": "andreas.solberg@uninett.no" - } - ], - "description": "SAML2 PHP library from SimpleSAMLphp", - "time": "2018-03-02T14:46:25+00:00" - }, - { - "name": "simplesamlphp/simplesamlphp", - "version": "v1.14.0", - "source": { - "type": "git", - "url": "https://github.com/simplesamlphp/simplesamlphp.git", - "reference": "03c6303dfee814450836c4ee3d07d51e628e4d4e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp/zipball/03c6303dfee814450836c4ee3d07d51e628e4d4e", - "reference": "03c6303dfee814450836c4ee3d07d51e628e4d4e", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "robrichards/xmlseclibs": "~1.4.1", - "simplesamlphp/saml2": "~1.7", - "whitehat101/apr1-md5": "~1.0" - }, - "require-dev": { - "ext-pdo_sqlite": "*", - "phpunit/phpunit": "~3.7", - "satooshi/php-coveralls": "^1.0" - }, - "type": "project", - "autoload": { - "psr-0": { - "SimpleSAML": "lib/" - }, - "files": [ - "lib/_autoload_modules.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1" - ], - "authors": [ - { - "name": "Olav Morken", - "email": "olav.morken@uninett.no" - }, - { - "name": "Andreas Åkre Solberg", - "email": "andreas.solberg@uninett.no" - } - ], - "description": "A PHP implementation of SAML 2.0 service provider and identity provider functionality. And is also compatible with Shibboleth 1.3 and 2.0.", - "homepage": "http://simplesamlphp.org", - "keywords": [ - "OpenId", - "SAML2", - "aselect", - "idp", - "oauth", - "shibboleth", - "sp", - "ws-federation" - ], - "time": "2016-02-15T12:18:12+00:00" - }, - { - "name": "whitehat101/apr1-md5", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/whitehat101/apr1-md5.git", - "reference": "8b261c9fc0481b4e9fa9d01c6ca70867b5d5e819" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/whitehat101/apr1-md5/zipball/8b261c9fc0481b4e9fa9d01c6ca70867b5d5e819", - "reference": "8b261c9fc0481b4e9fa9d01c6ca70867b5d5e819", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "4.0.*" - }, - "type": "library", - "autoload": { - "psr-4": { - "WhiteHat101\\Crypt\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jeremy Ebler", - "email": "jebler@gmail.com" - } - ], - "description": "Apache's APR1-MD5 algorithm in pure PHP", - "homepage": "https://github.com/whitehat101/apr1-md5", - "keywords": [ - "MD5", - "apr1" - ], - "time": "2015-02-11T11:06:42+00:00" - } - ], - "packages-dev": [ - { - "name": "doctrine/instantiator", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", - "shasum": "" - }, - "require": { - "php": ">=5.3,<8.0-DEV" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2015-06-14T21:17:01+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.5", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b", - "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "suggest": { - "dflydev/markdown": "~1.0", - "erusev/parsedown": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2016-01-25T08:17:30+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "1.7.6", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2018-04-18T13:57:24+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "2.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2015-10-06T15:47:00+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2017-11-27T13:52:08+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.9", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2017-02-26T11:10:40+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.4.12", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", - "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2017-12-04T08:55:13+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "4.8.36", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.2.2", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.8.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2017-06-21T08:07:12+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2015-10-02T06:51:40+00:00" - }, - { - "name": "sebastian/comparator", - "version": "1.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2017-01-29T09:50:25+00:00" - }, - { - "name": "sebastian/diff", - "version": "1.4.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2017-05-22T07:24:03+00:00" - }, - { - "name": "sebastian/environment", - "version": "1.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2016-08-18T05:49:44+00:00" - }, - { - "name": "sebastian/exporter", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2016-06-17T09:04:28+00:00" - }, - { - "name": "sebastian/global-state", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2015-10-12T03:26:01+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", - "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-10-03T07:41:43+00:00" - }, - { - "name": "sebastian/version", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21T13:59:46+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.8.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "time": "2018-04-30T19:57:29+00:00" - }, - { - "name": "symfony/yaml", - "version": "v2.8.42", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff", - "reference": "51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2018-05-01T22:52:40+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": [], - "platform-dev": [], - "platform-overrides": { - "php": "5.3.29" - } -} From 2ba2b1581ca02c6a6e4627d89b3fd13a6b46e556 Mon Sep 17 00:00:00 2001 From: Guy Halse Date: Wed, 25 Oct 2023 22:21:36 +0200 Subject: [PATCH 5/8] Update dependencies --- composer.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 19fea1f..10dbf1a 100644 --- a/composer.json +++ b/composer.json @@ -8,9 +8,15 @@ "SimpleSAML\\Module\\attributescope\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "SimpleSAML\\Test\\Utils\\": "vendor/simplesamlphp/simplesamlphp/tests/Utils" + } + }, "require": { - "simplesamlphp/composer-module-installer": "^1.2", - "simplesamlphp/simplesamlphp": "2.0.0-rc2" + "php": ">=7.4 || ^8.0", + "simplesamlphp/simplesamlphp": "^2.0.0", + "simplesamlphp/composer-module-installer": "^1.3.2" }, "require-dev": { "simplesamlphp/simplesamlphp-test-framework": "^1.2.1" From 0399511ef448ea66f2d5e8e911d181fd626f518c Mon Sep 17 00:00:00 2001 From: Guy Halse Date: Thu, 26 Oct 2023 09:04:27 +0200 Subject: [PATCH 6/8] update test framework --- .gitignore | 1 + phpcs.xml | 16 ++++++++++++++++ phpunit.xml | 18 ++++++++++-------- psalm-dev.xml | 27 +++++++++++++++++++++++++++ psalm.xml | 3 ++- 5 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 phpcs.xml create mode 100644 psalm-dev.xml diff --git a/.gitignore b/.gitignore index 50e30d5..5369c7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .phpunit.result.cache +.phpunit.cache composer.lock composer.phar /vendor/ diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..7e872ae --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,16 @@ + + + + By default it is less stringent about long lines than other coding standards + + + src + tests + + + + + + + + diff --git a/phpunit.xml b/phpunit.xml index 874490c..bc02241 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,6 +1,6 @@ - - - + + + ./src @@ -10,9 +10,11 @@ - - - ./tests - - + + + ./vendor/simplesamlphp/simplesamlphp-test-framework/src + ./tests + + + diff --git a/psalm-dev.xml b/psalm-dev.xml new file mode 100644 index 0000000..6116331 --- /dev/null +++ b/psalm-dev.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/psalm.xml b/psalm.xml index c36957f..dfd9eed 100644 --- a/psalm.xml +++ b/psalm.xml @@ -25,5 +25,6 @@ + - \ No newline at end of file + From 5f593416fe8c4d3cc798b73a65be636fd9cee9a6 Mon Sep 17 00:00:00 2001 From: Guy Halse Date: Thu, 26 Oct 2023 10:00:31 +0200 Subject: [PATCH 7/8] fix code sniffer issues --- src/Auth/Process/FilterAttributes.php | 89 ++++---- .../src/Auth/Process/FilterAttributesTest.php | 209 +++++++++--------- 2 files changed, 157 insertions(+), 141 deletions(-) diff --git a/src/Auth/Process/FilterAttributes.php b/src/Auth/Process/FilterAttributes.php index c4b77ee..07b7d94 100644 --- a/src/Auth/Process/FilterAttributes.php +++ b/src/Auth/Process/FilterAttributes.php @@ -1,5 +1,4 @@ _attributesWithScope = $config['attributesWithScope']; + $this->attributesWithScope = $config['attributesWithScope']; } if (array_key_exists('scopeAttributes', $config)) { - $this->_scopeAttributes = $config['scopeAttributes']; + $this->scopeAttributes = $config['scopeAttributes']; } if (array_key_exists('ignoreCheckForEntities', $config)) { - $this->_ignoreCheckForEntities = $config['ignoreCheckForEntities']; + $this->ignoreCheckForEntities = $config['ignoreCheckForEntities']; } if (array_key_exists('attributesWithScopeSuffix', $config)) { - $this->_attributesWithScopeSuffix = $config['attributesWithScopeSuffix']; + $this->attributesWithScopeSuffix = $config['attributesWithScopeSuffix']; } if (array_key_exists('ignoreCase', $config)) { - $this->_ignoreCase = $config['ignoreCase']; + $this->ignoreCase = $config['ignoreCase']; } } /** * Process the filter - * + * * @param array $state the state array - * + * * @return void */ public function process(array &$state): void { $src = $state['Source']; - if (isset($src['entityid']) && in_array($src['entityid'], $this->_ignoreCheckForEntities, true)) { + if (isset($src['entityid']) && in_array($src['entityid'], $this->ignoreCheckForEntities, true)) { Logger::debug('Ignoring scope checking for assertions from ' . $src['entityid']); return; } $noscope = false; - if (!isset($src['scope']) - || !is_array($src['scope']) + if ( + !isset($src['scope']) + || !is_array($src['scope']) || !count($src['scope']) ) { Logger::warning('No scope extension in IdP metadata, all scoped attributes are filtered out!'); $noscope = true; } - $scopes = $noscope ? array() : $src['scope']; + $scopes = $noscope ? [] : $src['scope']; - foreach ($this->_attributesWithScope as $attributesWithScope) { + foreach ($this->attributesWithScope as $attributesWithScope) { if (!isset($state['Attributes'][$attributesWithScope])) { continue; } if ($noscope) { - Logger::info('Attribute '.$attributesWithScope.' is filtered out due to missing scope information in IdP metadata.'); + Logger::info( + 'Attribute ' . $attributesWithScope . + ' is filtered out due to missing scope information in IdP metadata.' + ); unset($state['Attributes'][$attributesWithScope]); continue; } $values = $state['Attributes'][$attributesWithScope]; - $newValues = array(); + $newValues = []; foreach ($values as $value) { - if ($this->_isProperlyScoped($value, $scopes)) { + if ($this->isProperlyScoped($value, $scopes)) { $newValues[] = $value; } else { - Logger::warning('Attribute value ('.$value.') is removed by attributescope check.'); + Logger::warning('Attribute value (' . $value . ') is removed by attributescope check.'); } } @@ -146,34 +152,41 @@ public function process(array &$state): void } } // Filter out scopeAttributes if the value does not match any scope values - foreach ($this->_scopeAttributes as $scopeAttribute) { + foreach ($this->scopeAttributes as $scopeAttribute) { if (array_key_exists($scopeAttribute, $state['Attributes'])) { if (count($state['Attributes'][$scopeAttribute]) != 1) { - Logger::warning('$scopeAttribute (' . $scopeAttribute . ') must be single valued. Filtering out.'); + Logger::warning( + '$scopeAttribute (' . $scopeAttribute . ') must be single valued. Filtering out.' + ); unset($state['Attributes'][$scopeAttribute]); } elseif (!in_array($state['Attributes'][$scopeAttribute][0], $scopes)) { - Logger::warning('Scope attribute (' . $scopeAttribute . ') does not match metadata. Filtering out.'); + Logger::warning( + 'Scope attribute (' . $scopeAttribute . ') does not match metadata. Filtering out.' + ); unset($state['Attributes'][$scopeAttribute]); } } } - foreach ($this->_attributesWithScopeSuffix as $attributeWithSuffix) { + foreach ($this->attributesWithScopeSuffix as $attributeWithSuffix) { if (!isset($state['Attributes'][$attributeWithSuffix])) { continue; } if ($noscope) { - Logger::info('Attribute '.$attributeWithSuffix.' is filtered out due to missing scope information in IdP metadata.'); + Logger::info( + 'Attribute ' . $attributeWithSuffix . + ' is filtered out due to missing scope information in IdP metadata.' + ); unset($state['Attributes'][$attributeWithSuffix]); continue; } $values = $state['Attributes'][$attributeWithSuffix]; - $newValues = array(); + $newValues = []; foreach ($values as $value) { - if ($this->_isProperlySuffixed($value, $scopes)) { + if ($this->isProperlySuffixed($value, $scopes)) { $newValues[] = $value; } else { - Logger::warning('Attribute value ('.$value.') is removed by attributeWithScopeSuffix check.'); + Logger::warning('Attribute value (' . $value . ') is removed by attributeWithScopeSuffix check.'); } } @@ -193,10 +206,10 @@ public function process(array &$state): void * * @return bool true if properly scoped */ - private function _isProperlyScoped(string $value, array $scopes): bool + private function isProperlyScoped(string $value, array $scopes): bool { foreach ($scopes as $scope) { - $preg = '/^[^@]+@'.preg_quote($scope).'$/' . ($this->_ignoreCase ? 'i' : ''); + $preg = '/^[^@]+@' . preg_quote($scope) . '$/' . ($this->ignoreCase ? 'i' : ''); if (preg_match($preg, $value) == 1) { return true; } @@ -214,11 +227,11 @@ private function _isProperlyScoped(string $value, array $scopes): bool * * @return bool true if attribute is suffixed with a scope */ - private function _isProperlySuffixed(string $value, array $scopes): bool + private function isProperlySuffixed(string $value, array $scopes): bool { foreach ($scopes as $scope) { - $scopeRegex = '/^[^@]+@(.*\.)?'.preg_quote($scope).'$/' . ($this->_ignoreCase ? 'i' : ''); - $subdomainRegex = '/^([^@]*\.)?'.preg_quote($scope).'$/' . ($this->_ignoreCase ? 'i' : ''); + $scopeRegex = '/^[^@]+@(.*\.)?' . preg_quote($scope) . '$/' . ($this->ignoreCase ? 'i' : ''); + $subdomainRegex = '/^([^@]*\.)?' . preg_quote($scope) . '$/' . ($this->ignoreCase ? 'i' : ''); if (preg_match($subdomainRegex, $value) === 1 || preg_match($scopeRegex, $value) === 1) { return true; } diff --git a/tests/src/Auth/Process/FilterAttributesTest.php b/tests/src/Auth/Process/FilterAttributesTest.php index 3792318..2acc535 100644 --- a/tests/src/Auth/Process/FilterAttributesTest.php +++ b/tests/src/Auth/Process/FilterAttributesTest.php @@ -1,12 +1,15 @@ array('sampleSuffixedAttribute') - ); - $request = array( - 'Attributes' => array( - 'eduPersonPrincipalName' => array('joe@example.com'), - 'nonScopedAttribute' => array('not-removed'), - 'eduPersonScopedAffiliation' => array('student@example.com', 'staff@example.com', 'missing-scope'), - 'schacHomeOrganization' => array('example.com'), - 'sampleSuffixedAttribute' => array('joe@example.com'), - ), + $config = [ + 'attributesWithScopeSuffix' => ['sampleSuffixedAttribute'] + ]; + $request = [ + 'Attributes' => [ + 'eduPersonPrincipalName' => ['joe@example.com'], + 'nonScopedAttribute' => ['not-removed'], + 'eduPersonScopedAffiliation' => ['student@example.com', 'staff@example.com', 'missing-scope'], + 'schacHomeOrganization' => ['example.com'], + 'sampleSuffixedAttribute' => ['joe@example.com'], + ], 'Source' => $source, - ); + ]; $result = self::processFilter($config, $request); $attributes = $result['Attributes']; - $expectedData = array('nonScopedAttribute' => array('not-removed')); + $expectedData = ['nonScopedAttribute' => ['not-removed']]; $this->assertEquals($expectedData, $attributes, "Only incorrectly scoped attributes should be removed"); } @@ -58,20 +61,20 @@ public function testWrongScope($source) */ public static function wrongScopeDataProvider() { - return array( + return [ // Empty Source - array(array()), + [[]], // No scope value set - array(array('scope' => null)), + [['scope' => null]], // Empty array - array(array('scope' => array())), + [['scope' => []]], // Scope mismatch on leading . - array(array('scope' => array('.example.com'))), + [['scope' => ['.example.com']]], // Scope mismatch on 's' instead of '. - array(array('scope' => array('examplescom'))), + [['scope' => ['examplescom']]], // No wildcard match - array(array('scope' => array('.com'))), - ); + [['scope' => ['.com']]], + ]; } /** @@ -81,17 +84,17 @@ public static function wrongScopeDataProvider() */ public function testCorrectScope($source) { - $expectedData = array( - 'eduPersonPrincipalName' => array('joe@example.com'), - 'nonScopedAttribute' => array('not-removed'), - 'eduPersonScopedAffiliation' => array('student@example.com', 'staff@example.com'), - 'schacHomeOrganization' => array('example.com') - ); - $config = array(); - $request = array( + $expectedData = [ + 'eduPersonPrincipalName' => ['joe@example.com'], + 'nonScopedAttribute' => ['not-removed'], + 'eduPersonScopedAffiliation' => ['student@example.com', 'staff@example.com'], + 'schacHomeOrganization' => ['example.com'] + ]; + $config = []; + $request = [ 'Attributes' => $expectedData, 'Source' => $source, - ); + ]; $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($expectedData, $attributes, "All attributes should survive"); @@ -103,35 +106,35 @@ public function testCorrectScope($source) */ public static function correctScopeDataProvider() { - return array( + return [ // Correct scope - array(array('scope' => array('example.com'))), + [['scope' => ['example.com']]], // Multiple scopes - array(array('scope' => array('abc.com', 'example.com', 'xyz.com'))), - ); + [['scope' => ['abc.com', 'example.com', 'xyz.com']]], + ]; } public function testIgnoreCaseInScope() { - $config = array( - 'attributesWithScopeSuffix' => array('sampleSuffixedAttribute'), + $config = [ + 'attributesWithScopeSuffix' => ['sampleSuffixedAttribute'], 'ignoreCase' => true, - ); - $request = array( - 'Attributes' => array( - 'eduPersonScopedAffiliation' => array('student@example.com', 'staff@EXAMPLE.COM', 'member@bad.com'), - 'sampleSuffixedAttribute' => array('joe@example.com', 'bob@EXAMPLE.COM', 'wrong@bad.com'), - ), - 'Source' => array( - 'scope' => array('example.com') - ) - ); + ]; + $request = [ + 'Attributes' => [ + 'eduPersonScopedAffiliation' => ['student@example.com', 'staff@EXAMPLE.COM', 'member@bad.com'], + 'sampleSuffixedAttribute' => ['joe@example.com', 'bob@EXAMPLE.COM', 'wrong@bad.com'], + ], + 'Source' => [ + 'scope' => ['example.com'] + ] + ]; $result = self::processFilter($config, $request); $attributes = $result['Attributes']; - $expectedData = array( - 'eduPersonScopedAffiliation' => array('student@example.com', 'staff@EXAMPLE.COM'), - 'sampleSuffixedAttribute' => array('joe@example.com', 'bob@EXAMPLE.COM'), - ); + $expectedData = [ + 'eduPersonScopedAffiliation' => ['student@example.com', 'staff@EXAMPLE.COM'], + 'sampleSuffixedAttribute' => ['joe@example.com', 'bob@EXAMPLE.COM'], + ]; $this->assertEquals($expectedData, $attributes, "Scope case is ignored."); } @@ -140,31 +143,31 @@ public function testIgnoreCaseInScope() */ public function testMixedMultivaluedAttributes() { - $config = array(); - $request = array( - 'Attributes' => array( - 'nonScopedAttribute' => array('not-removed'), - 'eduPersonScopedAffiliation' => array( + $config = []; + $request = [ + 'Attributes' => [ + 'nonScopedAttribute' => ['not-removed'], + 'eduPersonScopedAffiliation' => [ 'faculty@abc.com', 'student@example.com', 'member@EXamPLE.com', // scope is case sensitive 'staff@other.com', 'member@a@example.com', '@example.com' - ), + ], // schacHomeOrganization is required to be single valued and gets filtered out if multi-valued - 'schacHomeOrganization' => array('abc.com', 'example.com', 'other.com') - ), - 'Source' => array( - 'scope' => array('example.com'), + 'schacHomeOrganization' => ['abc.com', 'example.com', 'other.com'] + ], + 'Source' => [ + 'scope' => ['example.com'], 'entityid' => 'https://example.com/idp' - ), - ); + ], + ]; $result = self::processFilter($config, $request); - $expectedData = array( - 'nonScopedAttribute' => array('not-removed'), - 'eduPersonScopedAffiliation' => array('student@example.com'), - ); + $expectedData = [ + 'nonScopedAttribute' => ['not-removed'], + 'eduPersonScopedAffiliation' => ['student@example.com'], + ]; $attributes = $result['Attributes']; $this->assertEquals($expectedData, $attributes, "Incorrectly scoped values should be removed"); } @@ -175,32 +178,32 @@ public function testMixedMultivaluedAttributes() public function testIgnoreSourceScope() { - $expectedData = array( - 'nonScopedAttribute' => array('not-removed'), - 'eduPersonScopedAffiliation' => array('faculty@abc.com', 'student@example.com', 'staff@other.com'), - 'schacHomeOrganization' => array('random.com') - ); - $request = array( + $expectedData = [ + 'nonScopedAttribute' => ['not-removed'], + 'eduPersonScopedAffiliation' => ['faculty@abc.com', 'student@example.com', 'staff@other.com'], + 'schacHomeOrganization' => ['random.com'] + ]; + $request = [ 'Attributes' => $expectedData, - 'Source' => array( - 'scope' => array('example.com'), + 'Source' => [ + 'scope' => ['example.com'], 'entityid' => 'https://example.com/idp' - ) - ); + ] + ]; // Test with entity ID that does NOT match the Source - $config = array( - 'ignoreCheckForEntities' => array('https://NOMATCH.com/idp') - ); + $config = [ + 'ignoreCheckForEntities' => ['https://NOMATCH.com/idp'] + ]; $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertFalse(array_key_exists('schacHomeOrganization', $attributes), 'Scope check shouldn\t be ignored'); // Test with entity ID that does match the Source - $config = array( - 'ignoreCheckForEntities' => array('https://example.com/idp') - ); + $config = [ + 'ignoreCheckForEntities' => ['https://example.com/idp'] + ]; $result = self::processFilter($config, $request); $attributes = $result['Attributes']; @@ -213,9 +216,9 @@ public function testIgnoreSourceScope() public function testAttributeSuffix() { - $request = array( - 'Attributes' => array( - 'department' => array( + $request = [ + 'Attributes' => [ + 'department' => [ // Valid values 'engineering.example.com', // Subdomain 'example.com', // scope @@ -224,8 +227,8 @@ public function testAttributeSuffix() 'invalid-example.com', // not subdomain 'cexample.com', 'examplecom', - ), - 'email' => array( + ], + 'email' => [ // Valid values 'user@example.com', 'user@gsb.example.com', @@ -237,31 +240,31 @@ public function testAttributeSuffix() // scoped values need data before the '@' '@example.com', '@other.example.com', - ), - ), - 'Source' => array( - 'scope' => array('example.com'), + ], + ], + 'Source' => [ + 'scope' => ['example.com'], 'entityid' => 'https://example.com/idp' - ) - ); + ] + ]; - $config = array( - 'attributesWithScopeSuffix' => array('department', 'email') - ); + $config = [ + 'attributesWithScopeSuffix' => ['department', 'email'] + ]; $result = self::processFilter($config, $request); $attributes = $result['Attributes']; - $expectedData = array( - 'department' => array( + $expectedData = [ + 'department' => [ 'engineering.example.com', 'example.com', '.example.com', - ), - 'email' => array( + ], + 'email' => [ 'user@example.com', 'user@gsb.example.com', - ), - ); + ], + ]; $this->assertEquals($expectedData, $attributes, "Incorrectly suffixed variables should be removed"); } } From 944dd10ad15801c249250de4192c09ca50e96018 Mon Sep 17 00:00:00 2001 From: Guy Halse Date: Thu, 26 Oct 2023 10:06:55 +0200 Subject: [PATCH 8/8] Import github CI workflow from simplesamlphp-module-authcrypt --- .github/workflows/php.yml | 243 ++++++++++++++++++++++++++++ tools/composer-require-checker.json | 7 + 2 files changed, 250 insertions(+) create mode 100644 .github/workflows/php.yml create mode 100644 tools/composer-require-checker.json diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..3ea475b --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,243 @@ +--- + +name: CI + +on: # yamllint disable-line rule:truthy + push: + branches: ['**'] + paths-ignore: + - '**.md' + pull_request: + branches: [master, release-*] + paths-ignore: + - '**.md' + workflow_dispatch: + +jobs: + linter: + name: Linter + runs-on: ['ubuntu-latest'] + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Lint Code Base + uses: github/super-linter/slim@v4 + env: + LOG_LEVEL: NOTICE + VALIDATE_ALL_CODEBASE: true + LINTER_RULES_PATH: 'tools/linters' + VALIDATE_CSS: true + VALIDATE_JAVASCRIPT_ES: true + VALIDATE_JSON: true + VALIDATE_PHP_BUILTIN: true + VALIDATE_YAML: true + VALIDATE_XML: true + VALIDATE_GITHUB_ACTIONS: true + + quality: + name: Quality control + runs-on: [ubuntu-latest] + + steps: + - name: Setup PHP, with composer and extensions + id: setup-php + # https://github.com/shivammathur/setup-php + uses: shivammathur/setup-php@v2 + with: + # Should be the higest supported version, so we can use the newest tools + php-version: '8.2' + tools: composer, composer-require-checker, composer-unused, phpcs, psalm + # optional performance gain for psalm: opcache + extensions: ctype, date, dom, fileinfo, filter, hash, intl, mbstring, opcache, openssl, pcre, posix, spl, xml + + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - uses: actions/checkout@v3 + + - name: Get composer cache directory + run: echo COMPOSER_CACHE="$(composer config cache-files-dir)" >> "$GITHUB_ENV" + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: $COMPOSER_CACHE + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Check code for hard dependencies missing in composer.json + run: composer-require-checker check --config-file=tools/composer-require-checker.json composer.json + + - name: Check code for unused dependencies in composer.json + run: composer-unused + + - name: PHP Code Sniffer + run: phpcs + + - name: Psalm + continue-on-error: true + run: | + psalm -c psalm.xml \ + --show-info=true \ + --shepherd \ + --php-version=${{ steps.setup-php.outputs.php-version }} + + - name: Psalm (testsuite) + run: | + psalm -c psalm-dev.xml \ + --show-info=true \ + --shepherd \ + --php-version=${{ steps.setup-php.outputs.php-version }} + + - name: Psalter + run: | + psalm --alter \ + --issues=UnnecessaryVarAnnotation \ + --dry-run \ + --php-version=${{ steps.setup-php.outputs.php-version }} + + security: + name: Security checks + runs-on: [ubuntu-latest] + steps: + - name: Setup PHP, with composer and extensions + # https://github.com/shivammathur/setup-php + uses: shivammathur/setup-php@v2 + with: + # Should be the lowest supported version + php-version: '8.0' + extensions: ctype, date, dom, fileinfo, filter, hash, intl, mbstring, openssl, pcre, posix, spl, xml + tools: composer + coverage: none + + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - uses: actions/checkout@v3 + + - name: Get composer cache directory + run: echo COMPOSER_CACHE="$(composer config cache-files-dir)" >> "$GITHUB_ENV" + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: $COMPOSER_CACHE + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Security check for locked dependencies + run: composer audit + + - name: Update Composer dependencies + run: composer update --no-progress --prefer-dist --optimize-autoloader + + - name: Security check for updated dependencies + run: composer audit + + unit-tests-linux: + name: "Unit tests, PHP ${{ matrix.php-versions }}, ${{ matrix.operating-system }}" + runs-on: ${{ matrix.operating-system }} + needs: [linter, quality, security] + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest] + php-versions: ['8.0', '8.1', '8.2'] + + steps: + - name: Setup PHP, with composer and extensions + # https://github.com/shivammathur/setup-php + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: ctype, date, dom, fileinfo, filter, hash, intl, mbstring, openssl, pcre, posix, spl, xml + tools: composer + ini-values: error_reporting=E_ALL + coverage: pcov + + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf + + - uses: actions/checkout@v3 + + - name: Get composer cache directory + run: echo COMPOSER_CACHE="$(composer config cache-files-dir)" >> "$GITHUB_ENV" + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: $COMPOSER_CACHE + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Run unit tests with coverage + if: ${{ matrix.php-versions == '8.2' }} + run: vendor/bin/phpunit + + - name: Run unit tests (no coverage) + if: ${{ matrix.php-versions != '8.2' }} + run: vendor/bin/phpunit --no-coverage + + - name: Save coverage data + if: ${{ matrix.php-versions == '8.2' }} + uses: actions/upload-artifact@v3 + with: + name: coverage-data + path: ${{ github.workspace }}/build + + coverage: + name: Code coverage + runs-on: [ubuntu-latest] + needs: [unit-tests-linux] + steps: + - uses: actions/checkout@v3 + + - uses: actions/download-artifact@v3 + with: + name: coverage-data + path: ${{ github.workspace }}/build + +# requires codecov.io account +# - name: Codecov +# uses: codecov/codecov-action@v3 +# with: +# token: ${{ secrets.CODECOV_TOKEN }} +# fail_ci_if_error: true +# verbose: true + + cleanup: + name: Cleanup artifacts + needs: [unit-tests-linux, coverage] + runs-on: [ubuntu-latest] + if: | + always() && + needs.coverage.result == 'success' && + (needs.unit-tests-linux == 'success' || needs.coverage == 'skipped') + + steps: + - uses: geekyeggo/delete-artifact@v2 + with: + name: coverage-data diff --git a/tools/composer-require-checker.json b/tools/composer-require-checker.json new file mode 100644 index 0000000..e4b6c1e --- /dev/null +++ b/tools/composer-require-checker.json @@ -0,0 +1,7 @@ +{ + "symbol-whitelist": [ + "SimpleSAML\\Auth\\ProcessingFilter", + "SimpleSAML\\Error\\Exception", + "SimpleSAML\\Logger" + ] +}