diff --git a/.appveyor.yml b/.appveyor.yml index 6bae47a324f13ecb5fa1dffc763fef214121741c..78b8a60ee1236559cb948a7f6eaa248999b12dfd 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,12 +1,11 @@ build: false shallow_clone: false -version: '1.17.1.{build}' +version: '1.19.0.{build}' platform: 'x64' clone_folder: C:\projects\simplesamlphp environment: matrix: - - PHP_VERSION: "5.6" - PHP_VERSION: "7.0" - PHP_VERSION: "7.1" - PHP_VERSION: "7.2" diff --git a/.travis.yml b/.travis.yml index 937598cb6c7fb61c9321573ee6700674900f4d46..3f51b83ca41435f6f00e2dc813044901c11c2879 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,6 @@ stages: ################ php: - - 5.6 - 7.0 - 7.1 - 7.2 @@ -34,13 +33,13 @@ script: jobs: fast_finish: true allow_failures: - - php: 5.6 + - php: 7.0 env: Psalm - - php: 5.6 + - php: 7.0 env: Security check (composer install) - - php: 5.6 + - php: 7.0 env: Security check (composer update) - - php: 5.6 + - php: 7.0 env: PHP Codesniffer include: @@ -49,14 +48,6 @@ jobs: # Pre-conditions stage # ########################## - - stage: pre-conditions - php: 5.6 - env: Syntax check PHP - before_script: - - composer install - script: - - vendor/bin/check-syntax-php.sh - - stage: pre-conditions php: 7.0 env: Syntax check PHP @@ -104,6 +95,7 @@ jobs: ################### - stage: quality + php: 7.3 env: Security check (composer install) before_script: - composer install @@ -111,6 +103,7 @@ jobs: - vendor/bin/security-checker security:check - stage: quality + php: 7.3 env: Security check (composer update) before_script: - composer update @@ -118,7 +111,7 @@ jobs: - vendor/bin/security-checker security:check - stage: quality - php: 7.2 + php: 7.3 env: Codecov before_script: - composer update @@ -127,6 +120,7 @@ jobs: - bash <(curl -s https://codecov.io/bash) - stage: quality + php: 7.3 env: Psalm before_script: - composer update @@ -134,6 +128,7 @@ jobs: - vendor/bin/psalm - stage: quality + php: 7.3 env: PHP Codesniffer before_script: - composer update diff --git a/bin/memcacheSync.php b/bin/memcacheSync.php index 910841e1c8e698c646b7f620d0184951054a035d..cc60d614d91e4306db83269c60e1170999e096ad 100755 --- a/bin/memcacheSync.php +++ b/bin/memcacheSync.php @@ -91,7 +91,7 @@ if ($warnBigSlab > 0) { * * @return array An array with all the keys available on the server. */ -function getServerKeys($server) +function getServerKeys(string $server): array { $server = explode(':', $server); $host = $server[0]; diff --git a/composer.json b/composer.json index 50f0b8a338f4afae284928d15c6bf920fcae1682..5c5ef94f04b33c069d3a30082658916c48b7a510 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "files": ["tests/_autoload_modules.php"] }, "require": { - "php": ">=5.6", + "php": ">=7.0", "ext-SPL": "*", "ext-zlib": "*", "ext-pcre": "*", @@ -88,11 +88,11 @@ "require-dev": { "ext-curl": "*", "mikey179/vfsstream": "~1.6", - "phpunit/phpunit": "~5.7", + "phpunit/phpunit": "~6.3", "sensiolabs/security-checker": "^5.0.3", - "simplesamlphp/simplesamlphp-test-framework": "^0.0.12", + "simplesamlphp/simplesamlphp-test-framework": "^0.1.0", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "~1.1.9" + "vimeo/psalm": "~3.2" }, "suggest": { "predis/predis": "Needed if a Redis server is used to store session information", diff --git a/docs/simplesamlphp-upgrade-notes-1.19.md b/docs/simplesamlphp-upgrade-notes-1.19.md new file mode 100644 index 0000000000000000000000000000000000000000..5e039e97425c0b960fc1c7880fef4d83299303d5 --- /dev/null +++ b/docs/simplesamlphp-upgrade-notes-1.19.md @@ -0,0 +1,4 @@ +Upgrade notes for SimpleSAMLphp 1.19 +==================================== + +The minimum PHP version required is now PHP 7.0. diff --git a/lib/SimpleSAML/Auth/ProcessingChain.php b/lib/SimpleSAML/Auth/ProcessingChain.php index d160928a8fbbdb440c49b15316d277c12f8444d8..b5bb4888d79282aa357cf14b7d08f5866433c23f 100644 --- a/lib/SimpleSAML/Auth/ProcessingChain.php +++ b/lib/SimpleSAML/Auth/ProcessingChain.php @@ -93,11 +93,8 @@ class ProcessingChain * @param array $src Source filters. May be unsorted. * @return void */ - private static function addFilters(&$target, $src) + private static function addFilters(array &$target, array $src) { - assert(is_array($target)); - assert(is_array($src)); - foreach ($src as $filter) { $fp = $filter->priority; @@ -120,10 +117,8 @@ class ProcessingChain * @param array $filterSrc Array with filter configuration. * @return array Array of ProcessingFilter objects. */ - private static function parseFilterList($filterSrc) + private static function parseFilterList(array $filterSrc): array { - assert(is_array($filterSrc)); - $parsedFilters = []; foreach ($filterSrc as $priority => $filter) { @@ -151,10 +146,8 @@ class ProcessingChain * definition.) * @return \SimpleSAML\Auth\ProcessingFilter The parsed filter. */ - private static function parseFilter($config, $priority) + private static function parseFilter(array $config, int $priority): ProcessingFilter { - assert(is_array($config)); - if (!array_key_exists('class', $config)) { throw new \Exception('Authentication processing filter without name given.'); } @@ -346,9 +339,8 @@ class ProcessingChain * @param array &$state * @return void */ - private static function addUserID(&$state) + private static function addUserID(array &$state) { - assert(is_array($state)); assert(array_key_exists('Attributes', $state)); if (isset($state['Destination']['userid.attribute'])) { diff --git a/lib/SimpleSAML/Auth/Source.php b/lib/SimpleSAML/Auth/Source.php index 36b7e28c6dae3c7efba60b531e9c3efabaa4bed1..b3dfffc285f70e5d07481aa76bdc068a89585e35 100644 --- a/lib/SimpleSAML/Auth/Source.php +++ b/lib/SimpleSAML/Auth/Source.php @@ -307,11 +307,8 @@ abstract class Source * @return \SimpleSAML\Auth\Source The parsed authentication source. * @throws \Exception If the authentication source is invalid. */ - private static function parseAuthSource($authId, $config) + private static function parseAuthSource(string $authId, array $config): Source { - assert(is_string($authId)); - assert(is_array($config)); - self::validateSource($config, $authId); $id = $config[0]; diff --git a/lib/SimpleSAML/Auth/State.php b/lib/SimpleSAML/Auth/State.php index ac915cbd3161194b72a70e8067e7c843703a2897..f938f9d572a7a0612629d34ced583f2d88ac6371 100644 --- a/lib/SimpleSAML/Auth/State.php +++ b/lib/SimpleSAML/Auth/State.php @@ -177,7 +177,7 @@ class State * * @return integer State timeout. */ - private static function getStateTimeout() + private static function getStateTimeout(): int { if (self::$stateTimeout === null) { $globalConfig = Configuration::getInstance(); diff --git a/lib/SimpleSAML/Auth/TimeLimitedToken.php b/lib/SimpleSAML/Auth/TimeLimitedToken.php index ac5846dec9eb9c308086cd8d5406db8dc4312c6a..e668d73ab25a4d6ea8763037b71d52579456152a 100644 --- a/lib/SimpleSAML/Auth/TimeLimitedToken.php +++ b/lib/SimpleSAML/Auth/TimeLimitedToken.php @@ -84,7 +84,7 @@ class TimeLimitedToken * * @return string The token for the given time and offset. */ - private function calculateTokenValue($offset, $time = null) + private function calculateTokenValue(int $offset, int $time = null): string { if ($time === null) { $time = time(); diff --git a/lib/SimpleSAML/Bindings/Shib13/Artifact.php b/lib/SimpleSAML/Bindings/Shib13/Artifact.php index 09703ec99d15dc3dd0dddfc1645d1de38858f555..dfead878b6cab900a03204f89c786c3d53faa896 100644 --- a/lib/SimpleSAML/Bindings/Shib13/Artifact.php +++ b/lib/SimpleSAML/Bindings/Shib13/Artifact.php @@ -24,7 +24,7 @@ class Artifact * * @return array The artifacts. */ - private static function getArtifacts() + private static function getArtifacts(): array { assert(array_key_exists('QUERY_STRING', $_SERVER)); @@ -53,7 +53,7 @@ class Artifact * @param array $artifacts The artifacts we will request. * @return string The request, as an XML string. */ - private static function buildRequest(array $artifacts) + private static function buildRequest(array $artifacts): string { $msg = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">'. '<SOAP-ENV:Body>'. @@ -82,10 +82,8 @@ class Artifact * @return string The <saml1p:Response> element, as a string. * @throws Error\Exception */ - private static function extractResponse($soapResponse) + private static function extractResponse(string $soapResponse): string { - assert(is_string($soapResponse)); - try { $doc = DOMDocumentFactory::fromString($soapResponse); } catch (\Exception $e) { diff --git a/lib/SimpleSAML/Configuration.php b/lib/SimpleSAML/Configuration.php index afa394e2ce96933c70d7bd67a66226c1be605bdf..8949a10c4f088ed4babdfd906e54ab9ccc2ba59e 100644 --- a/lib/SimpleSAML/Configuration.php +++ b/lib/SimpleSAML/Configuration.php @@ -109,11 +109,8 @@ class Configuration implements Utils\ClearableState * * @throws \Exception If the configuration file is invalid or missing. */ - private static function loadFromFile($filename, $required) + private static function loadFromFile(string $filename, bool $required): Configuration { - assert(is_string($filename)); - assert(is_bool($required)); - if (array_key_exists($filename, self::$loadedConfigs)) { return self::$loadedConfigs[$filename]; } diff --git a/lib/SimpleSAML/Database.php b/lib/SimpleSAML/Database.php index 59b108f2e05a4fab75cc43a7e0e6e8c407ccd304..5fb3779a7a5c9008f8c2e874e62e60dd7192bb64 100644 --- a/lib/SimpleSAML/Database.php +++ b/lib/SimpleSAML/Database.php @@ -4,6 +4,7 @@ namespace SimpleSAML; use PDO; use PDOException; +use PDOStatement; /** * This file implements functions to read and write to a group of database servers. @@ -76,7 +77,7 @@ class Database * * @param \SimpleSAML\Configuration $config Instance of the \SimpleSAML\Configuration class */ - private function __construct($config) + private function __construct(Configuration $config) { $driverOptions = $config->getArray('database.driver_options', []); if ($config->getBoolean('database.persistent', true)) { @@ -116,7 +117,7 @@ class Database * * @return string $instanceId */ - private static function generateInstanceId($config) + private static function generateInstanceId(Configuration $config): string { $assembledConfig = [ 'master' => [ @@ -137,14 +138,14 @@ class Database * This function connects to a database. * * @param string $dsn Database connection string - * @param string $username SQL user - * @param string $password SQL password + * @param string|null $username SQL user + * @param string|null $password SQL password * @param array $options PDO options * * @throws \Exception If an error happens while trying to connect to the database. * @return \PDO object */ - private function connect($dsn, $username, $password, $options) + private function connect(string $dsn, string $username = null, string $password = null, array $options): PDO { try { $db = new PDO($dsn, $username, $password, $options); @@ -163,7 +164,7 @@ class Database * * @return \PDO object */ - private function getSlave() + private function getSlave(): PDO { if (count($this->dbSlaves) > 0) { $slaveId = rand(0, count($this->dbSlaves) - 1); @@ -197,12 +198,8 @@ class Database * @throws \Exception If an error happens while trying to execute the query. * @return \PDOStatement object */ - private function query($db, $stmt, $params) + private function query(PDO $db, string $stmt, array $params): PDOStatement { - assert(is_object($db)); - assert(is_string($stmt)); - assert(is_array($params)); - try { $query = $db->prepare($stmt); @@ -233,11 +230,8 @@ class Database * @throws \Exception If an error happens while trying to execute the query. * @return int The number of rows affected. */ - private function exec($db, $stmt) + private function exec(PDO $db, string $stmt): int { - assert(is_object($db)); - assert(is_string($stmt)); - try { return $db->exec($stmt); } catch (PDOException $e) { @@ -260,8 +254,7 @@ class Database $db = $this->dbMaster; if (is_array($params)) { - $obj = $this->query($db, $stmt, $params); - return ($obj === false) ? $obj : $obj->rowCount(); + return $this->query($db, $stmt, $params)->rowCount(); } else { return $this->exec($db, $stmt); } diff --git a/lib/SimpleSAML/Error/Exception.php b/lib/SimpleSAML/Error/Exception.php index abfc6633ba8d33c37daff814ec6bd0acd15d1af7..3e6690942185ac63945f4e6f5b79a188a5e44f3f 100644 --- a/lib/SimpleSAML/Error/Exception.php +++ b/lib/SimpleSAML/Error/Exception.php @@ -22,7 +22,7 @@ class Exception extends \Exception * We need to save the backtrace, since we cannot rely on * serializing the Exception::trace-variable. * - * @var array + * @var array<int, string> */ private $backtrace = []; diff --git a/lib/SimpleSAML/Error/UnserializableException.php b/lib/SimpleSAML/Error/UnserializableException.php index 6ac5b39fff3fd5ab76cfe2babe80c25bd81a158e..5634c287443a8fcb76f654d2e5cf6317eba0c253 100644 --- a/lib/SimpleSAML/Error/UnserializableException.php +++ b/lib/SimpleSAML/Error/UnserializableException.php @@ -37,7 +37,7 @@ class UnserializableException extends Exception $msg = $original->getMessage(); $code = $original->getCode(); - if ($original instanceof \PDOException) { + if (is_string($code)) { // PDOException uses a string as the code. Filter it out here. $code = -1; } diff --git a/lib/SimpleSAML/IdP.php b/lib/SimpleSAML/IdP.php index e11926a78f02a77f1991617f55ba781eb27e2c0e..b1de1602ac953dc4007db2e2afaf1c46d95fafe1 100644 --- a/lib/SimpleSAML/IdP.php +++ b/lib/SimpleSAML/IdP.php @@ -64,10 +64,8 @@ class IdP * * @throws \SimpleSAML\Error\Exception If the IdP is disabled or no such auth source was found. */ - private function __construct($id) + private function __construct(string $id) { - assert(is_string($id)); - $this->id = $id; $this->associationGroup = $id; diff --git a/lib/SimpleSAML/IdP/TraditionalLogoutHandler.php b/lib/SimpleSAML/IdP/TraditionalLogoutHandler.php index 9c18499364c707af8c95ad31a0e99e84e3327495..5e1921ad0c0f2d993a88cfa9dfbbca906652c895 100644 --- a/lib/SimpleSAML/IdP/TraditionalLogoutHandler.php +++ b/lib/SimpleSAML/IdP/TraditionalLogoutHandler.php @@ -109,6 +109,7 @@ class TraditionalLogoutHandler implements LogoutHandlerInterface throw new Error\Exception('RelayState lost during logout.'); } + /** @psalm-var array $state */ $state = Auth\State::loadState($relayState, 'core:LogoutTraditional'); if ($error === null) { diff --git a/lib/SimpleSAML/Locale/Language.php b/lib/SimpleSAML/Locale/Language.php index 0c5b761ade03c86124d956145b214e639cfff362..cf32a274b39c1059baecf4e3c79cac022b755ca8 100644 --- a/lib/SimpleSAML/Locale/Language.php +++ b/lib/SimpleSAML/Locale/Language.php @@ -163,7 +163,7 @@ class Language * * @return array The set of languages both in 'language.available' and self::$language_names. */ - private function getInstalledLanguages() + private function getInstalledLanguages(): array { $configuredAvailableLanguages = $this->configuration->getArray('language.available', ['en']); $availableLanguages = []; diff --git a/lib/SimpleSAML/Locale/Localization.php b/lib/SimpleSAML/Locale/Localization.php index 7e73ca7805dc0aeb2fd1d1aad05c0c5af964fd64..5121772173eab904d43ad9264f2aca590f05c8ed 100644 --- a/lib/SimpleSAML/Locale/Localization.php +++ b/lib/SimpleSAML/Locale/Localization.php @@ -238,7 +238,7 @@ class Localization * * @throws \Exception If something is wrong with the locale file for the domain and activated language */ - private function loadGettextGettextFromPO($domain = self::DEFAULT_DOMAIN, $catchException = true) + private function loadGettextGettextFromPO(string $domain = self::DEFAULT_DOMAIN, bool $catchException = true) { try { $langPath = $this->getLangPath($domain); diff --git a/lib/SimpleSAML/Locale/Translate.php b/lib/SimpleSAML/Locale/Translate.php index 0d0475edfe74bdb1ed9fb61eefffc86b64bd0698..6d7f5446ada3b3fc7824eb0205d3cbb271809ca2 100644 --- a/lib/SimpleSAML/Locale/Translate.php +++ b/lib/SimpleSAML/Locale/Translate.php @@ -97,10 +97,8 @@ class Translate * * @return array An associative array with the dictionary. */ - private function getDictionary($name) + private function getDictionary(string $name): array { - assert(is_string($name)); - if (!array_key_exists($name, $this->dictionaries)) { $sepPos = strpos($name, ':'); if ($sepPos !== false) { @@ -261,7 +259,7 @@ class Translate * @param bool $striptags * @deprecated Not used in twig, gettext * - * @return string|null The translated tag, or a placeholder value if the tag wasn't found. + * @return string The translated tag, or a placeholder value if the tag wasn't found. */ public function t( $tag, @@ -282,26 +280,6 @@ class Translate ' identical to the $tag in 2.0.' ); } - if (!is_array($replacements)) { - // TODO: remove this entire if for 2.0 - - // old style call to t(...). Print warning to log - Logger::warning( - 'Deprecated use of SimpleSAML\Locale\Translate::t(...) at ' . $where . - '. Please update the code to use the new style of parameters.' - ); - - // for backwards compatibility - /** @psalm-suppress PossiblyInvalidArgument */ - if (!$replacements && ($this->getTag($tag) === null)) { - Logger::warning( - 'Code which uses $fallbackdefault === FALSE should be updated to use the getTag() method instead.' - ); - return null; - } - - $replacements = $oldreplacements; - } if (is_array($tag)) { $tagData = $tag; @@ -339,7 +317,7 @@ class Translate * * @return string The string that should be used, or the tag name if $fallbacktag is set to false. */ - private function getStringNotTranslated($tag, $fallbacktag) + private function getStringNotTranslated(string $tag, bool $fallbacktag) { if ($fallbacktag) { return 'not translated (' . $tag . ')'; @@ -404,7 +382,7 @@ class Translate * * @return array An array holding all the translations in the file. */ - private function readDictionaryJSON($filename) + private function readDictionaryJSON(string $filename): array { $definitionFile = $filename . '.definition.json'; assert(file_exists($definitionFile)); @@ -436,7 +414,7 @@ class Translate * * @return array An array holding all the translations in the file. */ - private function readDictionaryPHP($filename) + private function readDictionaryPHP(string $filename): array { $phpFile = $filename . '.php'; assert(file_exists($phpFile)); @@ -457,10 +435,8 @@ class Translate * * @return array An array holding all the translations in the file. */ - private function readDictionaryFile($filename) + private function readDictionaryFile(string $filename): array { - assert(is_string($filename)); - Logger::debug('Translate: Reading dictionary [' . $filename . ']'); $jsonFile = $filename . '.definition.json'; diff --git a/lib/SimpleSAML/Logger.php b/lib/SimpleSAML/Logger.php index 69d38ca699cf22a10964c26a980c604102a005e9..9cbe9ee693137e2c27f4422bc0a899dd0bcd3d4a 100644 --- a/lib/SimpleSAML/Logger.php +++ b/lib/SimpleSAML/Logger.php @@ -389,7 +389,7 @@ class Logger * @param boolean $stats Whether this is a stats message or a regular one. * @return void */ - private static function defer($level, $message, $stats) + private static function defer(int $level, string $message, bool $stats) { // save the message for later self::$earlyLog[] = ['level' => $level, 'string' => $message, 'statsLog' => $stats]; @@ -407,7 +407,7 @@ class Logger * @return void * @throws \Exception */ - private static function createLoggingHandler($handler = null) + private static function createLoggingHandler(string $handler = null) { self::$initializing = true; @@ -466,7 +466,7 @@ class Logger * @param bool $statsLog * @return void */ - private static function log($level, $string, $statsLog = false) + private static function log(int $level, string $string, bool $statsLog = false) { if (self::$initializing) { // some error occurred while initializing logging @@ -487,17 +487,17 @@ class Logger } if (self::$captureLog) { - $ts = microtime(true); - $msecs = (int) (($ts - (int) $ts) * 1000); - $ts = gmdate('H:i:s', $ts) . sprintf('.%03d', $msecs) . 'Z'; + $sample = microtime(false); + list($msecs, $mtime) = explode(' ', $sample); + + $time = intval($mtime); + $usec = substr($msecs, 2, 3); + + $ts = gmdate('H:i:s', $time) . '.' . $usec . 'Z'; self::$capturedLog[] = $ts . ' ' . $string; } if (self::$logLevel >= $level || $statsLog) { - if (is_array($string)) { - $string = implode(",", $string); - } - $formats = ['%trackid', '%msg', '%srcip', '%stat']; $replacements = [self::$trackid, $string, $_SERVER['REMOTE_ADDR']]; diff --git a/lib/SimpleSAML/Memcache.php b/lib/SimpleSAML/Memcache.php index bca1d8a1dff3d1b1c7bae783bd097487c963814e..d95b6c6c139881c0637f33ef53f6288bd9352cb4 100644 --- a/lib/SimpleSAML/Memcache.php +++ b/lib/SimpleSAML/Memcache.php @@ -218,7 +218,7 @@ class Memcache * * @throws \Exception If any configuration option for the server is invalid. */ - private static function addMemcacheServer($memcache, $server) + private static function addMemcacheServer($memcache, array $server) { // the hostname option is required if (!array_key_exists('hostname', $server)) { @@ -364,7 +364,7 @@ class Memcache * * @throws \Exception If the servers configuration is invalid. */ - private static function getMemcacheServers() + private static function getMemcacheServers(): array { // check if we have loaded the servers already if (self::$serverGroups != null) { @@ -423,7 +423,7 @@ class Memcache * * @throws \Exception If the option 'memcache_store.expires' has a negative value. */ - private static function getExpireTime() + private static function getExpireTime(): int { // get the configuration instance $config = Configuration::getInstance(); diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php index 5e77a43bbbfcf2e1a63244314040b91b5d90f1b5..db0dc2a2418bab7c365f837302ba76a7cae41bb2 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php @@ -287,6 +287,7 @@ class MetaDataStorageHandler implements \SimpleSAML\Utils\ClearableState } } // We found the entity id so remove it from the list that needs resolving + /** @psalm-suppress PossiblyInvalidArrayOffset */ unset($entityIds[array_search($key, $entityIds)]); } $result = array_merge($srcList, $result); diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php index 9f15a11f3ac27eab5a61242fc5a377096337ee36..33c3d8ba8a12c2f3575897097b414f5ecc200528 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php @@ -75,7 +75,7 @@ class MetaDataStorageHandlerFlatFile extends MetaDataStorageSource * or null if we are unable to load metadata from the given file. * @throws \Exception If the metadata set cannot be loaded. */ - private function load($set) + private function load(string $set) { $metadatasetfile = $this->directory . $set . '.php'; @@ -83,6 +83,7 @@ class MetaDataStorageHandlerFlatFile extends MetaDataStorageSource return null; } + /** @psalm-var mixed $metadata We cannot be sure what the include below will do with this var */ $metadata = []; include($metadatasetfile); diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerPdo.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerPdo.php index c6f6c3aed44185f3d7d75ea1906af669f7883abf..ea1d5ee8b2bff7f142954ec178bc7298fbde0787 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerPdo.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerPdo.php @@ -79,10 +79,8 @@ class MetaDataStorageHandlerPdo extends MetaDataStorageSource * @throws \Exception If a database error occurs. * @throws \SimpleSAML\Error\Exception If the metadata can be retrieved from the database, but cannot be decoded. */ - private function load($set) + private function load(string $set) { - assert(is_string($set)); - $tableName = $this->getTableName($set); if (!in_array($set, $this->supportedSets, true)) { @@ -275,10 +273,8 @@ class MetaDataStorageHandlerPdo extends MetaDataStorageSource * * @return string Replaced table name */ - private function getTableName($table) + private function getTableName(string $table): string { - assert(is_string($table)); - return $this->db->applyPrefix(str_replace("-", "_", $this->tablePrefix . $table)); } diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php index 85c2440d152e4014c1b892c2e8f14c33783f841f..f168c04aa5f664febdd48479fc1712727c3e3146 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php @@ -62,11 +62,8 @@ class MetaDataStorageHandlerSerialize extends MetaDataStorageSource * * @return string The path to the metadata file. */ - private function getMetadataPath($entityId, $set) + private function getMetadataPath(string $entityId, string $set): string { - assert(is_string($entityId)); - assert(is_string($set)); - return $this->directory . '/' . rawurlencode($set) . '/' . rawurlencode($entityId) . self::EXTENSION; } diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php index 5ba3fd19ffba28a9a71c49f8c5d9c2ffba7254c6..04f188435ed83a9a2103894fe1df483f9c8b7b92 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php @@ -298,7 +298,6 @@ abstract class MetaDataStorageSource protected function lookupIndexFromEntityId($entityId, array $metadataSet) { assert(is_string($entityId)); - assert(is_array($metadataSet)); // check for hostname $currentHost = Utils\HTTP::getSelfHost(); // sp.example.org @@ -324,10 +323,8 @@ abstract class MetaDataStorageSource * @throws \Exception * @return string */ - private function getDynamicHostedUrl($set) + private function getDynamicHostedUrl(string $set): string { - assert(is_string($set)); - // get the configuration $baseUrl = Utils\HTTP::getBaseURL(); @@ -362,7 +359,6 @@ abstract class MetaDataStorageSource { assert(is_string($metadataSet)); assert(is_string($entityId)); - assert(is_array($metadataEntry)); $modifiedMetadataEntry = $metadataEntry; diff --git a/lib/SimpleSAML/Metadata/SAMLBuilder.php b/lib/SimpleSAML/Metadata/SAMLBuilder.php index 0752591bebfa117a5f34a071082e58966696e0e7..84ccdb6fb5b16ee96101aa14b0df90cabc5aa1f7 100644 --- a/lib/SimpleSAML/Metadata/SAMLBuilder.php +++ b/lib/SimpleSAML/Metadata/SAMLBuilder.php @@ -86,7 +86,7 @@ class SAMLBuilder * @param array $metadata * @return void */ - private function setExpiration($metadata) + private function setExpiration(array $metadata) { if (array_key_exists('expire', $metadata)) { if ($metadata['expire'] - time() < $this->maxDuration) { @@ -363,10 +363,8 @@ class SAMLBuilder * @return array An array of endpoint objects, * either \SAML2\XML\md\EndpointType or \SAML2\XML\md\IndexedEndpointType. */ - private static function createEndpoints(array $endpoints, $indexed) + private static function createEndpoints(array $endpoints, bool $indexed): array { - assert(is_bool($indexed)); - $ret = []; foreach ($endpoints as &$ep) { @@ -695,7 +693,6 @@ class SAMLBuilder */ public function addAttributeAuthority(array $metadata) { - assert(is_array($metadata)); assert(isset($metadata['entityid'])); assert(isset($metadata['metadata-set'])); @@ -791,10 +788,9 @@ class SAMLBuilder * @param string $x509data The certificate data. * @return void */ - private function addX509KeyDescriptor(RoleDescriptor $rd, $use, $x509data) + private function addX509KeyDescriptor(RoleDescriptor $rd, string $use, string $x509data) { assert(in_array($use, ['encryption', 'signing'], true)); - assert(is_string($x509data)); $keyDescriptor = \SAML2\Utils::createKeyDescriptor($x509data); $keyDescriptor->setUse($use); diff --git a/lib/SimpleSAML/Metadata/SAMLParser.php b/lib/SimpleSAML/Metadata/SAMLParser.php index 2c8fb8fb9debf002256cd3e58930faf26f4cbdc7..9e154c438f609d2aa3c4fdc691e4adbfb1b3ae7c 100644 --- a/lib/SimpleSAML/Metadata/SAMLParser.php +++ b/lib/SimpleSAML/Metadata/SAMLParser.php @@ -3,10 +3,12 @@ namespace SimpleSAML\Metadata; use DOMDocument; +use DOMElement; use RobRichards\XMLSecLibs\XMLSecurityDSig; use RobRichards\XMLSecLibs\XMLSecurityKey; use SAML2\Constants; use SAML2\DOMDocumentFactory; +use SAML2\SignedElementHelper; use SAML2\XML\Chunk; use SAML2\XML\ds\X509Certificate; use SAML2\XML\ds\X509Data; @@ -183,12 +185,10 @@ class SAMLParser */ private function __construct( EntityDescriptor $entityElement, - $maxExpireTime, + int $maxExpireTime = null, array $validators = [], array $parentExtensions = [] ) { - assert($maxExpireTime === null || is_int($maxExpireTime)); - $this->spDescriptors = []; $this->idpDescriptors = []; @@ -372,7 +372,7 @@ class SAMLParser * be the entity id. * @throws \Exception if the document is empty or the root is an unexpected node. */ - public static function parseDescriptorsElement(\DOMElement $element = null) + public static function parseDescriptorsElement(DOMElement $element = null) { if ($element === null) { throw new \Exception('Document was empty.'); @@ -398,13 +398,11 @@ class SAMLParser * @return SAMLParser[] Array of SAMLParser instances. */ private static function processDescriptorsElement( - $element, - $maxExpireTime = null, + SignedElementHelper $element, + int $maxExpireTime = null, array $validators = [], array $parentExtensions = [] ) { - assert($maxExpireTime === null || is_int($maxExpireTime)); - if ($element instanceof EntityDescriptor) { $ret = new SAMLParser($element, $maxExpireTime, $validators, $parentExtensions); $ret = [$ret->getEntityId() => $ret]; @@ -440,7 +438,7 @@ class SAMLParser * @return int|null The unix timestamp for when the element should expire. Will be NULL if no * limit is set for the element. */ - private static function getExpireTime($element, $maxExpireTime) + private static function getExpireTime($element, int $maxExpireTime = null) { // validUntil may be null $expire = $element->getValidUntil(); @@ -467,7 +465,7 @@ class SAMLParser /** * @return array */ - private function getMetadataCommon() + private function getMetadataCommon(): array { $ret = []; $ret['entityid'] = $this->entityId; @@ -865,10 +863,8 @@ class SAMLParser * * @return array An associative array with metadata we have extracted from this element. */ - private static function parseRoleDescriptorType(RoleDescriptor $element, $expireTime) + private static function parseRoleDescriptorType(RoleDescriptor $element, int $expireTime = null) { - assert($expireTime === null || is_int($expireTime)); - $ret = []; $expireTime = self::getExpireTime($element, $expireTime); @@ -916,10 +912,8 @@ class SAMLParser * * @return array An associative array with metadata we have extracted from this element. */ - private static function parseSSODescriptor(SSODescriptorType $element, $expireTime) + private static function parseSSODescriptor(SSODescriptorType $element, int $expireTime = null): array { - assert($expireTime === null || is_int($expireTime)); - $sd = self::parseRoleDescriptorType($element, $expireTime); // find all SingleLogoutService elements @@ -944,10 +938,8 @@ class SAMLParser * NULL if unknown. * @return void */ - private function processSPSSODescriptor(SPSSODescriptor $element, $expireTime) + private function processSPSSODescriptor(SPSSODescriptor $element, int $expireTime = null) { - assert($expireTime === null || is_int($expireTime)); - $sp = self::parseSSODescriptor($element, $expireTime); // find all AssertionConsumerService elements @@ -981,10 +973,8 @@ class SAMLParser * NULL if unknown. * @return void */ - private function processIDPSSODescriptor(IDPSSODescriptor $element, $expireTime) + private function processIDPSSODescriptor(IDPSSODescriptor $element, int $expireTime = null) { - assert($expireTime === null || is_int($expireTime)); - $idp = self::parseSSODescriptor($element, $expireTime); // find all SingleSignOnService elements @@ -1035,7 +1025,7 @@ class SAMLParser * * @return array An associative array with the extensions parsed. */ - private static function processExtensions($element, $parentExtensions = []) + private static function processExtensions($element, array $parentExtensions = []): array { $ret = [ 'scope' => [], @@ -1086,6 +1076,7 @@ class SAMLParser // only saml:Attribute are currently supported here. The specifications also allows // saml:Assertions, which more complex processing if ($attr instanceof Attribute) { + /** @psalm-var string|null $attrName Remove for SSP 2.0 */ $attrName = $attr->getName(); $attrNameFormat = $attr->getNameFormat(); $attrValue = $attr->getAttributeValue(); @@ -1097,7 +1088,7 @@ class SAMLParser // attribute names that is not URI is prefixed as this: '{nameformat}name' $name = $attrName; if ($attrNameFormat === null) { - $name = '{' . Constants::NAMEFORMAT_UNSPECIFIED . '}' . $attr->getName(); + $name = '{' . Constants::NAMEFORMAT_UNSPECIFIED . '}' . $attrName; } elseif ($attrNameFormat !== Constants::NAMEFORMAT_URI) { $name = '{' . $attrNameFormat . '}' . $attrName; } @@ -1123,6 +1114,7 @@ class SAMLParser foreach ($e->getKeywords() as $uiItem) { $keywords = $uiItem->getKeywords(); + /** @psalm-var string|null $language */ $language = $uiItem->getLanguage(); if (($keywords === []) || ($language === null)) { continue; @@ -1130,6 +1122,7 @@ class SAMLParser $ret['UIInfo']['Keywords'][$language] = $keywords; } foreach ($e->getLogo() as $uiItem) { + /** @psalm-suppress TypeDoesNotContainNull Remove in SSP 2.0 */ if ( !($uiItem instanceof Logo) || ($uiItem->getUrl() === null) @@ -1169,7 +1162,7 @@ class SAMLParser $name = $attribute->getAttribute('Name'); $values = array_map( - ['\SimpleSAML\Utils\XML', 'getDOMText'], + '\SimpleSAML\Utils\XML::getDOMText', Utils\XML::getDOMChildren($attribute, 'AttributeValue', '@saml2') ); @@ -1240,10 +1233,8 @@ class SAMLParser * @param array $sp The array with the SP's metadata. * @return void */ - private static function parseAttributeConsumerService(AttributeConsumingService $element, &$sp) + private static function parseAttributeConsumerService(AttributeConsumingService $element, array &$sp) { - assert(is_array($sp)); - $sp['name'] = $element->getServiceName(); $sp['description'] = $element->getServiceDescription(); @@ -1299,7 +1290,7 @@ class SAMLParser * * @return array An associative array with the data we have extracted from the element. */ - private static function parseGenericEndpoint(EndpointType $element) + private static function parseGenericEndpoint(EndpointType $element): array { $ep = []; @@ -1329,9 +1320,9 @@ class SAMLParser * * @return array Array of parsed endpoints. */ - private static function extractEndpoints(array $endpoints) + private static function extractEndpoints(array $endpoints): array { - return array_map(['self', 'parseGenericEndpoint'], $endpoints); + return array_map('self::parseGenericEndpoint', $endpoints); } @@ -1366,6 +1357,7 @@ class SAMLParser $keyInfo = $kd->getKeyInfo(); + /** @psalm-suppress PossiblyNullReference This will be fixed in saml2 5.0 */ foreach ($keyInfo->getInfo() as $i) { if ($i instanceof X509Data) { foreach ($i->getData() as $d) { @@ -1389,10 +1381,8 @@ class SAMLParser * * @return array with SP descriptors which supports one of the given protocols. */ - private function getSPDescriptors($protocols) + private function getSPDescriptors(array $protocols): array { - assert(is_array($protocols)); - $ret = []; foreach ($this->spDescriptors as $spd) { @@ -1413,10 +1403,8 @@ class SAMLParser * * @return array with IdP descriptors which supports one of the given protocols. */ - private function getIdPDescriptors($protocols) + private function getIdPDescriptors(array $protocols): array { - assert(is_array($protocols)); - $ret = []; foreach ($this->idpDescriptors as $idpd) { @@ -1441,10 +1429,8 @@ class SAMLParser * @return \SAML2\XML\md\EntityDescriptor The \DOMEntity which represents the EntityDescriptor. * @throws \Exception If the document is empty or the first element is not an EntityDescriptor element. */ - private static function findEntityDescriptor($doc) + private static function findEntityDescriptor(DOMDocument $doc): EntityDescriptor { - assert($doc instanceof DOMDocument); - // find the EntityDescriptor DOMElement. This should be the first (and only) child of the DOMDocument $ed = $doc->documentElement; @@ -1500,7 +1486,7 @@ class SAMLParser * @throws \UnexpectedValueException * @return string */ - private function computeFingerprint($algorithm, $data) + private function computeFingerprint(string $algorithm, string $data): string { switch ($algorithm) { case XMLSecurityDSig::SHA1: diff --git a/lib/SimpleSAML/Metadata/Signer.php b/lib/SimpleSAML/Metadata/Signer.php index 7a80bdd139df7abec27e8417c8b377394821a7de..37b0cc699b1ec56ec37ee14f450ffce003eec32e 100644 --- a/lib/SimpleSAML/Metadata/Signer.php +++ b/lib/SimpleSAML/Metadata/Signer.php @@ -30,7 +30,7 @@ class Signer * @return array An associative array with the keys 'privatekey', 'certificate', and optionally 'privatekey_pass'. * @throws \Exception If the key and certificate used to sign is unknown. */ - private static function findKeyCert($config, $entityMetadata, $type) + private static function findKeyCert(Configuration $config, array $entityMetadata, string $type): array { // first we look for metadata.privatekey and metadata.certificate in the metadata if ( @@ -130,7 +130,7 @@ class Signer * @return boolean True if metadata signing is enabled, false otherwise. * @throws \Exception If the value of the 'metadata.sign.enable' option is not a boolean. */ - private static function isMetadataSigningEnabled($config, $entityMetadata, $type) + private static function isMetadataSigningEnabled(Configuration $config, array $entityMetadata, string $type): bool { // first check the metadata for the entity if (array_key_exists('metadata.sign.enable', $entityMetadata)) { @@ -166,7 +166,7 @@ class Signer * * @throws \SimpleSAML\Error\CriticalConfigurationError */ - private static function getMetadataSigningAlgorithm($config, $entityMetadata, $type) + private static function getMetadataSigningAlgorithm(Configuration $config, array $entityMetadata, string $type): array { // configure the algorithm to use if (array_key_exists('metadata.sign.algorithm', $entityMetadata)) { diff --git a/lib/SimpleSAML/Metadata/Sources/MDQ.php b/lib/SimpleSAML/Metadata/Sources/MDQ.php index 3b8431a14d82712f36d987048da20bc909e97aa1..9694d102bf0270e05b9154d1233c661824d36e48 100644 --- a/lib/SimpleSAML/Metadata/Sources/MDQ.php +++ b/lib/SimpleSAML/Metadata/Sources/MDQ.php @@ -154,11 +154,8 @@ class MDQ extends \SimpleSAML\Metadata\MetaDataStorageSource * if the entity could not be found. * @throws \Exception If an error occurs while loading metadata from cache. */ - private function getFromCache($set, $entityId) + private function getFromCache(string $set, string $entityId) { - assert(is_string($set)); - assert(is_string($entityId)); - if (empty($this->cacheDir)) { return null; } @@ -214,12 +211,8 @@ class MDQ extends \SimpleSAML\Metadata\MetaDataStorageSource * @throws \Exception If metadata cannot be written to cache. * @return void */ - private function writeToCache($set, $entityId, $data) + private function writeToCache(string $set, string $entityId, array $data) { - assert(is_string($set)); - assert(is_string($entityId)); - assert(is_array($data)); - if (empty($this->cacheDir)) { return; } @@ -242,10 +235,8 @@ class MDQ extends \SimpleSAML\Metadata\MetaDataStorageSource * @return array|NULL The associative array with the metadata, or NULL if no metadata for * the given set was found. */ - private static function getParsedSet(SAMLParser $entity, $set) + private static function getParsedSet(SAMLParser $entity, string $set) { - assert(is_string($set)); - switch ($set) { case 'saml20-idp-remote': return $entity->getMetadata20IdP(); diff --git a/lib/SimpleSAML/Module.php b/lib/SimpleSAML/Module.php index 33470a77d27b822dd543f3c8d77ea8d9f4e4e832..10ad2a437facf074a99ef2b63600d4eb71639a0e 100644 --- a/lib/SimpleSAML/Module.php +++ b/lib/SimpleSAML/Module.php @@ -305,7 +305,7 @@ class Module * @param array $mod_config * @return bool */ - private static function isModuleEnabledWithConf($module, $mod_config) + private static function isModuleEnabledWithConf(string $module, array $mod_config): bool { if (isset(self::$module_info[$module]['enabled'])) { return self::$module_info[$module]['enabled']; @@ -539,7 +539,7 @@ class Module self::$module_info[$module]['hooks'] = self::getModuleHooks($module); } - if (!isset(self::$module_info[$module]['hooks'][$hook])) { + if (!isset(self::$module_info[$module]['hooks'][$hook]) || !empty(self::$module_info[$module]['hooks'][$hook])) { continue; } diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php index 8b54ae5f298d69b1f184762728de4e4ba3bddffe..7cef0c647ccd74bf693e695dad724b77eb081aa7 100644 --- a/lib/SimpleSAML/Session.php +++ b/lib/SimpleSAML/Session.php @@ -145,7 +145,7 @@ class Session implements \Serializable, Utils\ClearableState * * @param boolean $transient Whether to create a transient session or not. */ - private function __construct($transient = false) + private function __construct(bool $transient = false) { $this->setConfiguration(Configuration::getInstance()); @@ -393,7 +393,7 @@ class Session implements \Serializable, Utils\ClearableState * @param Session $session The session to load. * @return Session The session we just loaded, just for convenience. */ - private static function load(Session $session) + private static function load(Session $session): Session { Logger::setTrackId($session->getTrackID()); self::$instance = $session; @@ -636,8 +636,11 @@ class Session implements \Serializable, Utils\ClearableState continue; } + /** @psalm-var \DOMNode $node We made sure value has at least 1 item in the check above */ + $node = $value->item(0); + // create an AttributeValue object and save it to 'RawAttributes', using same attribute name and index - $attrval = new AttributeValue($value->item(0)->parentNode); + $attrval = new AttributeValue($node->parentNode); $data['RawAttributes'][$attribute][$idx] = $attrval; } } @@ -711,9 +714,8 @@ class Session implements \Serializable, Utils\ClearableState * * @throws \Exception If the handler is not a valid function or method. */ - private function callLogoutHandlers($authority) + private function callLogoutHandlers(string $authority) { - assert(is_string($authority)); assert(isset($this->authData[$authority])); if (empty($this->authData[$authority]['LogoutHandlers'])) { diff --git a/lib/SimpleSAML/SessionHandlerCookie.php b/lib/SimpleSAML/SessionHandlerCookie.php index 556105f2e830f2d6986cf8514e934cc113b60bf8..4b90a69f97a6768e020d8e6ac542f8214639d305 100644 --- a/lib/SimpleSAML/SessionHandlerCookie.php +++ b/lib/SimpleSAML/SessionHandlerCookie.php @@ -101,7 +101,7 @@ abstract class SessionHandlerCookie extends SessionHandler * * @return string A random session id. */ - private static function createSessionID() + private static function createSessionID(): string { return bin2hex(openssl_random_pseudo_bytes(16)); } @@ -115,11 +115,8 @@ abstract class SessionHandlerCookie extends SessionHandler * * @return boolean True if this session ID is valid, false otherwise. */ - private static function isValidSessionID($session_id) + private static function isValidSessionID(string $session_id): bool { - if (!is_string($session_id)) { - return false; - } if (strlen($session_id) != 32) { return false; diff --git a/lib/SimpleSAML/Stats.php b/lib/SimpleSAML/Stats.php index 25ff214ac09394780488485936aa0deb1da83e41..7a65c9b1a95bcbcd6e9a94322e5b0bb0f6036011 100644 --- a/lib/SimpleSAML/Stats.php +++ b/lib/SimpleSAML/Stats.php @@ -35,7 +35,7 @@ class Stats * * @return mixed A new instance of the configured class. */ - private static function createOutput(\SimpleSAML\Configuration $config) + private static function createOutput(Configuration $config) { $cls = $config->getString('class'); $cls = Module::resolveClass($cls, 'Stats\Output', '\SimpleSAML\Stats\Output'); @@ -52,7 +52,6 @@ class Stats */ private static function initOutputs() { - $config = Configuration::getInstance(); $outputCfgs = $config->getConfigList('statistics.out'); diff --git a/lib/SimpleSAML/Utils/Crypto.php b/lib/SimpleSAML/Utils/Crypto.php index a3f5b23727607d44c735d375adc23dcdc9186701..ba5af37a234e339dce0dfc7ab8c088b5e05a6ec6 100644 --- a/lib/SimpleSAML/Utils/Crypto.php +++ b/lib/SimpleSAML/Utils/Crypto.php @@ -25,13 +25,8 @@ class Crypto * * @see \SimpleSAML\Utils\Crypto::aesDecrypt() */ - private static function aesDecryptInternal($ciphertext, $secret) + private static function aesDecryptInternal(string $ciphertext, string $secret): string { - if (!is_string($ciphertext)) { - throw new \InvalidArgumentException( - 'Input parameter "$ciphertext" must be a string with more than 48 characters.' - ); - } /** @var int $len */ $len = mb_strlen($ciphertext, '8bit'); if ($len < 48) { @@ -99,12 +94,8 @@ class Crypto * * @see \SimpleSAML\Utils\Crypto::aesEncrypt() */ - private static function aesEncryptInternal($data, $secret) + private static function aesEncryptInternal(string $data, string $secret): string { - if (!is_string($data)) { - throw new \InvalidArgumentException('Input parameter "$data" must be a string.'); - } - if (!function_exists("openssl_encrypt")) { throw new Error\Exception('The openssl PHP module is not loaded.'); } diff --git a/lib/SimpleSAML/Utils/EMail.php b/lib/SimpleSAML/Utils/EMail.php index 9ed3692794af6358f5683c11508f2bbe258931a8..f1595c972b9c8eca7e7fdb46973f01999210270c 100644 --- a/lib/SimpleSAML/Utils/EMail.php +++ b/lib/SimpleSAML/Utils/EMail.php @@ -157,8 +157,6 @@ class EMail public function setTransportMethod($transportMethod, array $transportOptions = []) { assert(is_string($transportMethod)); - assert(is_array($transportOptions)); - switch (strtolower($transportMethod)) { // smtp transport method diff --git a/lib/SimpleSAML/Utils/HTTP.php b/lib/SimpleSAML/Utils/HTTP.php index 016f09e0e0c8eaaf7f411343496af1a76a1d601d..b5ed7d1990a27b36f6d048d174cac0480fadf669 100644 --- a/lib/SimpleSAML/Utils/HTTP.php +++ b/lib/SimpleSAML/Utils/HTTP.php @@ -27,7 +27,7 @@ class HTTP * * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no> */ - private static function getSecurePOSTRedirectURL($destination, $data) + private static function getSecurePOSTRedirectURL(string $destination, array $data): string { $session = Session::getSessionFromRequest(); $id = self::savePOSTData($session, $destination, $data); @@ -56,7 +56,7 @@ class HTTP * * @author Olav Morken, UNINETT AS <olav.morken@uninett.no> */ - private static function getServerHost() + private static function getServerHost(): string { if (array_key_exists('HTTP_HOST', $_SERVER)) { $current = $_SERVER['HTTP_HOST']; @@ -171,9 +171,9 @@ class HTTP * @author Mads Freek Petersen * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no> */ - private static function redirect($url, $parameters = []) + private static function redirect(string $url, array $parameters = []) { - if (!is_string($url) || empty($url) || !is_array($parameters)) { + if (empty($url)) { throw new \InvalidArgumentException('Invalid input parameters.'); } if (!self::isValidURL($url)) { @@ -246,7 +246,7 @@ class HTTP * @author Andjelko Horvat * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no> */ - private static function savePOSTData(Session $session, $destination, $data) + private static function savePOSTData(Session $session, string $destination, array $data): string { // generate a random ID to avoid replay attacks $id = Random::generateID(); @@ -1165,7 +1165,7 @@ class HTTP 'lifetime' => 0, 'expire' => null, 'path' => '/', - 'domain' => null, + 'domain' => '', 'secure' => false, 'httponly' => true, 'raw' => false, diff --git a/lib/SimpleSAML/Utils/Net.php b/lib/SimpleSAML/Utils/Net.php index 351a7cf6e03f5b8bd5b6daa9736addd5046b19c7..efff0756718b7a9a6576f7a8c64a21a98934ade6 100644 --- a/lib/SimpleSAML/Utils/Net.php +++ b/lib/SimpleSAML/Utils/Net.php @@ -73,8 +73,8 @@ class Net $ip_mask = ~((1 << (32 - $iteration_mask)) - 1); - $ip_net_mask = $ip_net[$i] & $ip_mask; - $ip_ip_mask = $ip_ip[$i] & $ip_mask; + $ip_net_mask = intval($ip_net[$i]) & $ip_mask; + $ip_ip_mask = intval($ip_ip[$i]) & $ip_mask; if ($ip_ip_mask != $ip_net_mask) { return false; diff --git a/lib/SimpleSAML/Utils/System.php b/lib/SimpleSAML/Utils/System.php index 26b0e992f0afc6fcd9d03559571bfc04e850d21b..3864cf1bd3605856addea2559122971e53d3f98f 100644 --- a/lib/SimpleSAML/Utils/System.php +++ b/lib/SimpleSAML/Utils/System.php @@ -240,7 +240,7 @@ class System * * @return bool */ - private static function pathContainsDriveLetter($path) + private static function pathContainsDriveLetter(string $path): bool { $letterAsciiValue = ord(strtoupper(substr($path, 0, 1))); return substr($path, 1, 1) === ':' @@ -252,7 +252,7 @@ class System * @param string $path * @return bool */ - private static function pathContainsStreamWrapper($path) + private static function pathContainsStreamWrapper(string $path): bool { return preg_match('/^[\w\d]*:\/{2}/', $path) === 1; } diff --git a/lib/SimpleSAML/XHTML/IdPDisco.php b/lib/SimpleSAML/XHTML/IdPDisco.php index 1b8f56cc6f3e54d6711aee9a4d102e1aa5cb1196..70f2d7adfdad1fe0ae2714eab3fd41613d810eef 100644 --- a/lib/SimpleSAML/XHTML/IdPDisco.php +++ b/lib/SimpleSAML/XHTML/IdPDisco.php @@ -651,7 +651,7 @@ class IdPDisco * @param string $language * @return string|null */ - private function getEntityDisplayName(array $idpData, $language) + private function getEntityDisplayName(array $idpData, string $language) { if (isset($idpData['UIInfo']['DisplayName'][$language])) { return $idpData['UIInfo']['DisplayName'][$language]; diff --git a/lib/SimpleSAML/XHTML/Template.php b/lib/SimpleSAML/XHTML/Template.php index 24f46bbc912332e2036fd474a4a52fa750f0f01e..4b14817b1d1187e180c905e19e2a4203465f6795 100644 --- a/lib/SimpleSAML/XHTML/Template.php +++ b/lib/SimpleSAML/XHTML/Template.php @@ -213,7 +213,7 @@ class Template extends Response * @param string $templateName The template name to normalize. * @return string The filename we need to look for. */ - private function normalizeTemplateName($templateName) + private function normalizeTemplateName(string $templateName): string { if (strripos($templateName, '.twig')) { return $templateName; @@ -240,7 +240,7 @@ class Template extends Response * @return TemplateLoader The twig template loader or false if the template does not exist. * @throws \Twig\Error\LoaderError In case a failure occurs. */ - private function setupTwigTemplatepaths() + private function setupTwigTemplatepaths(): TemplateLoader { $filename = $this->normalizeTemplateName($this->template); @@ -281,7 +281,7 @@ class Template extends Response * @return \Twig\Environment * @throws \Exception if the template does not exist */ - private function setupTwig() + private function setupTwig(): \Twig\Environment { $auto_reload = $this->configuration->getBoolean('template.auto_reload', true); $cache = $this->configuration->getString('template.cache', false); @@ -358,7 +358,7 @@ class Template extends Response * * @return array An array of module => templatedir lookups. */ - private function findThemeTemplateDirs() + private function findThemeTemplateDirs(): array { if (!isset($this->theme['module'])) { // no module involved @@ -398,7 +398,7 @@ class Template extends Response * * @throws \InvalidArgumentException If the module is not enabled or it has no templates directory. */ - private function getModuleTemplateDir($module) + private function getModuleTemplateDir(string $module): string { if (!Module::isModuleEnabled($module)) { throw new \InvalidArgumentException('The module \'' . $module . '\' is not enabled.'); @@ -555,7 +555,7 @@ class Template extends Response * * @return array An array with the name of the module and template */ - private function findModuleAndTemplateName($template) + private function findModuleAndTemplateName(string $template): array { $tmp = explode(':', $template, 2); return (count($tmp) === 2) ? [$tmp[0], $tmp[1]] : [null, $tmp[0]]; @@ -578,9 +578,8 @@ class Template extends Response * * @throws \Exception If the template file couldn't be found. */ - private function findTemplatePath($template, $throw_exception = true) + private function findTemplatePath(string $template, bool $throw_exception = true) { - assert(is_string($template)); $extensions = ['.tpl.php', '.php']; list($templateModule, $templateName) = $this->findModuleAndTemplateName($template); @@ -791,7 +790,7 @@ class Template extends Response * @param string $file * @return void */ - private function includeAtTemplateBase($file) + private function includeAtTemplateBase(string $file) { $data = $this->data; @@ -837,7 +836,7 @@ class Template extends Response * * @return bool */ - private function isLanguageRTL() + private function isLanguageRTL(): bool { return $this->translator->getLanguage()->isLanguageRTL(); } diff --git a/lib/SimpleSAML/XML/Shib13/AuthnResponse.php b/lib/SimpleSAML/XML/Shib13/AuthnResponse.php index f50045d8f6f5a0f678ba63f8f035c49a15f504d3..9492626142a9bd96c1954bbecfc759921e4c1814 100644 --- a/lib/SimpleSAML/XML/Shib13/AuthnResponse.php +++ b/lib/SimpleSAML/XML/Shib13/AuthnResponse.php @@ -12,6 +12,7 @@ namespace SimpleSAML\XML\Shib13; use DOMDocument; use DOMNode; +use DOMNodeList; use DOMXpath; use SAML2\DOMDocumentFactory; use SimpleSAML\Configuration; @@ -160,7 +161,7 @@ class AuthnResponse * @param \DOMElement|\SimpleXMLElement $node Node to be validated. * @return bool TRUE if the node is validated or FALSE if not. */ - private function isNodeValidated($node) + private function isNodeValidated($node): bool { if ($this->messageValidated) { // This message was validated externally @@ -190,9 +191,8 @@ class AuthnResponse * then the query will be relative to the root of the response. * @return \DOMNodeList */ - private function doXPathQuery($query, $node = null) + private function doXPathQuery(string $query, DOMNode $node = null): DOMNodeList { - assert(is_string($query)); assert($this->dom instanceof DOMDocument); if ($node === null) { @@ -252,7 +252,7 @@ class AuthnResponse } $conditions = $this->doXPathQuery('shib:Conditions', $assertion); - if ($conditions && $conditions->length > 0) { + if ($conditions->length > 0) { $condition = $conditions->item(0); $start = $condition->getAttribute('NotBefore'); @@ -453,13 +453,8 @@ class AuthnResponse * @param array $scopedAttributes Array of attributes names which are scoped. * @return string The attribute encoded as an XML-string. */ - private function encAttribute($name, $values, $base64, $scopedAttributes) + private function encAttribute(string $name, array $values, bool $base64, array $scopedAttributes): string { - assert(is_string($name)); - assert(is_array($values)); - assert(is_bool($base64)); - assert(is_array($scopedAttributes)); - if (in_array($name, $scopedAttributes, true)) { $scoped = true; } else { diff --git a/lib/SimpleSAML/XML/Validator.php b/lib/SimpleSAML/XML/Validator.php index 0e201c88984a74b077aab0a2c0ddc6a42e1e7518..55ddd456aaa02690e1761369a23bb2a0c0f32245 100644 --- a/lib/SimpleSAML/XML/Validator.php +++ b/lib/SimpleSAML/XML/Validator.php @@ -159,10 +159,8 @@ class Validator * @return string|null The fingerprint as a 40-character lowercase hexadecimal number. NULL is returned if the * argument isn't an X509 certificate. */ - private static function calculateX509Fingerprint($x509cert) + private static function calculateX509Fingerprint(string $x509cert) { - assert(is_string($x509cert)); - $lines = explode("\n", $x509cert); $data = ''; @@ -203,11 +201,8 @@ class Validator * @throws \Exception * @return void */ - private static function validateCertificateFingerprint($certificate, $fingerprints) + private static function validateCertificateFingerprint(string $certificate, array $fingerprints) { - assert(is_string($certificate)); - assert(is_array($fingerprints)); - $certFingerprint = self::calculateX509Fingerprint($certificate); if ($certFingerprint === null) { // Couldn't calculate fingerprint from X509 certificate. Should not happen. @@ -323,11 +318,8 @@ class Validator * @return boolean|string TRUE on success, or a string with error messages if it failed. * @deprecated */ - private static function validateCABuiltIn($certificate, $caFile) + private static function validateCABuiltIn(string $certificate, string $caFile) { - assert(is_string($certificate)); - assert(is_string($caFile)); - // Clear openssl errors while (openssl_error_string() !== false) { } @@ -361,11 +353,8 @@ class Validator * @throws \Exception * @deprecated */ - private static function validateCAExec($certificate, $caFile) + private static function validateCAExec(string $certificate, string $caFile) { - assert(is_string($certificate)); - assert(is_string($caFile)); - $command = [ 'openssl', 'verify', '-CAfile', $caFile, diff --git a/lib/_autoload_modules.php b/lib/_autoload_modules.php index 5bc55bfdafb64cd929d3c284ee82cb1cd1a96e88..6d43e555b46c2f4df59f277e056953f690a51c54 100644 --- a/lib/_autoload_modules.php +++ b/lib/_autoload_modules.php @@ -17,7 +17,7 @@ * with 'SimpleSAML_'. * @deprecated This function will be removed in SSP 2.0. */ -function temporaryLoader($class) +function temporaryLoader(string $class) { // handle the upgrade to the latest version of XMLSecLibs using namespaces if (strstr($class, 'XMLSec') && !strstr($class, '\\RobRichards\\XMLSecLibs\\')) { @@ -83,7 +83,7 @@ function temporaryLoader($class) * * TODO: this autoloader should be removed once everything has been migrated to namespaces. */ -function sspmodAutoloadPSR0($className) +function sspmodAutoloadPSR0(string $className) { $modulePrefixLength = strlen('sspmod_'); $classPrefix = substr($className, 0, $modulePrefixLength); @@ -141,7 +141,7 @@ function sspmodAutoloadPSR0($className) * * @param string $className Name of the class. */ -function sspmodAutoloadPSR4($className) +function sspmodAutoloadPSR4(string $className) { $elements = explode('\\', $className); if ($elements[0] === '') { diff --git a/modules/admin/lib/ConfigController.php b/modules/admin/lib/ConfigController.php index d4764b58502c09e98d764bf9546288a7eba0c5e1..4f9ea216a6e6ef40c68b2f99db8824c60e95bfea 100644 --- a/modules/admin/lib/ConfigController.php +++ b/modules/admin/lib/ConfigController.php @@ -155,11 +155,11 @@ class ConfigController 'descr' => [ Translate::noop('PHP %minimum% or newer is needed. You are running: %current%'), [ - '%minimum%' => '5.6', + '%minimum%' => '7.0', '%current%' => explode('-', phpversion())[0] ] ], - 'enabled' => version_compare(phpversion(), '5.6', '>=') + 'enabled' => version_compare(phpversion(), '7.0', '>=') ] ]; $store = $this->config->getString('store.type', ''); @@ -389,7 +389,7 @@ class ConfigController $response = curl_exec($ch); if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) === 200) { - /** @psalm-suppress InvalidScalarArgument */ + /** @psalm-var string $response */ $latest = json_decode($response, true); $this->session->setData(self::LATEST_VERSION_STATE_KEY, 'version', $latest); } diff --git a/modules/admin/lib/FederationController.php b/modules/admin/lib/FederationController.php index f167514972a4a4b3161d4fe2533c4a1162040db0..d9ceda7291d25baae3b533c36917a4404630804c 100644 --- a/modules/admin/lib/FederationController.php +++ b/modules/admin/lib/FederationController.php @@ -162,7 +162,7 @@ class FederationController * @return array * @throws \Exception */ - private function getHostedIdP() + private function getHostedIdP(): array { $entities = []; @@ -326,7 +326,7 @@ class FederationController * @return array * @throws \SimpleSAML\Error\Exception If OrganizationName is set for an SP instance but OrganizationURL is not. */ - private function getHostedSP() + private function getHostedSP(): array { $entities = []; diff --git a/modules/admin/lib/TestController.php b/modules/admin/lib/TestController.php index b77da54f8f5bc7fc7ac2676b1300422de20738a2..62ecf008c0553f116bfb609910e6a0891fa3299a 100644 --- a/modules/admin/lib/TestController.php +++ b/modules/admin/lib/TestController.php @@ -25,7 +25,6 @@ use Webmozart\Assert\Assert; */ class TestController { - /** @var \SimpleSAML\Configuration */ protected $config; @@ -116,10 +115,12 @@ class TestController * @param \SAML2\XML\saml\NameID $nameId * @return string */ - private function getNameIDHTML(Template $t, NameID $nameId) + private function getNameIDHTML(Template $t, NameID $nameId): string { $translator = $t->getTranslator(); $result = ''; + + /** @psalm-suppress TypeDoesNotContainNull Remove if-case in 2.0 */ if ($nameId->getValue() === null) { $list = ["NameID" => [$translator->t('{status:subject_notset}')]]; /** @var string $notset */ @@ -154,7 +155,7 @@ class TestController * @param string $nameParent * @return string */ - private function getAttributesHTML(Template $t, $attributes, $nameParent) + private function getAttributesHTML(Template $t, array $attributes, string $nameParent): string { $alternate = ['pure-table-odd', 'pure-table-even']; $i = 0; @@ -232,7 +233,7 @@ class TestController * @param array|string $attr * @return string */ - private function presentList($attr) + private function presentList($attr): string { if (is_array($attr) && count($attr) > 1) { $str = '<ul>'; @@ -251,7 +252,7 @@ class TestController * @param array|string $attr * @return string */ - private function presentAssoc($attr) + private function presentAssoc($attr): string { if (is_array($attr)) { $str = '<dl>'; @@ -271,7 +272,7 @@ class TestController * @param \SAML2\XML\saml\NameID $nameID * @return string */ - private function presentEptid(Translate $t, NameID $nameID) + private function presentEptid(Translate $t, NameID $nameID): string { $eptid = [ 'NameID' => [$nameID->getValue()], diff --git a/modules/core/hooks/hook_sanitycheck.php b/modules/core/hooks/hook_sanitycheck.php index 7e401a0dc5e7abdfb0f8157419b51018d1c00fe1..730e91c6727a6d9316ac2ca14c78c5c856777534 100644 --- a/modules/core/hooks/hook_sanitycheck.php +++ b/modules/core/hooks/hook_sanitycheck.php @@ -26,7 +26,7 @@ function core_hook_sanitycheck(&$hookinfo) $hookinfo['info'][] = '[core] In config.php technicalcontact_email is set properly'; } - if (version_compare(phpversion(), '5.6', '>=')) { + if (version_compare(phpversion(), '7.0', '>=')) { $hookinfo['info'][] = '[core] You are running a PHP version suitable for SimpleSAMLphp.'; } else { $hookinfo['errors'][] = '[core] You are running an old PHP installation. ' . diff --git a/modules/core/lib/ACL.php b/modules/core/lib/ACL.php index dac755fe601e98912624f0379b0e5c86590daafd..e69b5ffc99cb102eb1c6262bfc741d6fc705d014 100644 --- a/modules/core/lib/ACL.php +++ b/modules/core/lib/ACL.php @@ -57,10 +57,8 @@ class ACL * @param string $id The id of the access control list. * @return array The access control list array. */ - private static function getById($id) + private static function getById(string $id): array { - assert(is_string($id)); - $config = Configuration::getOptionalConfig('acl.php'); if (!$config->hasValue($id)) { throw new Error\Exception('No ACL with id ' . var_export($id, true) . ' in config/acl.php.'); @@ -100,7 +98,7 @@ class ACL * @param array $rule The rule we should check. * @return boolean TRUE if the rule matches, FALSE if not. */ - private static function match(array $attributes, array $rule) + private static function match(array $attributes, array $rule): bool { $op = array_shift($rule); if ($op === null) { @@ -135,7 +133,7 @@ class ACL * @param array $rule The rule we should check. * @return boolean TRUE if the rule matches, FALSE if not. */ - private static function opAnd($attributes, $rule) + private static function opAnd(array $attributes, array $rule): bool { foreach ($rule as $subRule) { if (!self::match($attributes, $subRule)) { @@ -154,7 +152,7 @@ class ACL * @param array $rule The rule we should check. * @return boolean TRUE if the rule matches, FALSE if not. */ - private static function opEquals($attributes, $rule) + private static function opEquals(array $attributes, array $rule): bool { $attributeName = array_shift($rule); @@ -194,7 +192,7 @@ class ACL * @param array $rule The rule we should check. * @return boolean TRUE if the rule matches, FALSE if not. */ - private static function opEqualsPreg($attributes, $rule) + private static function opEqualsPreg(array $attributes, array $rule): bool { $attributeName = array_shift($rule); @@ -235,7 +233,7 @@ class ACL * @param array $rule The rule we should check. * @return boolean TRUE if the rule matches, FALSE if not. */ - private static function opHas($attributes, $rule) + private static function opHas(array $attributes, array $rule): bool { $attributeName = array_shift($rule); @@ -262,7 +260,7 @@ class ACL * @param array $rule The rule we should check. * @return boolean TRUE if the rule matches, FALSE if not. */ - private static function opHasPreg($attributes, $rule) + private static function opHasPreg(array $attributes, array $rule): bool { $attributeName = array_shift($rule); @@ -290,7 +288,7 @@ class ACL * @param array $rule The rule we should check. * @return boolean TRUE if the rule matches, FALSE if not. */ - private static function opOr($attributes, $rule) + private static function opOr(array $attributes, array $rule): bool { foreach ($rule as $subRule) { if (self::match($attributes, $subRule)) { diff --git a/modules/core/lib/Auth/Process/AttributeLimit.php b/modules/core/lib/Auth/Process/AttributeLimit.php index 2767a9555d0ee7ff571ee4f23b44113d49821cd8..87db3155c348111f3babf21b9c8d87a4b5308e8a 100644 --- a/modules/core/lib/Auth/Process/AttributeLimit.php +++ b/modules/core/lib/Auth/Process/AttributeLimit.php @@ -139,7 +139,7 @@ class AttributeLimit extends \SimpleSAML\Auth\ProcessingFilter * @param array $allowedConfigValues The allowed values, and possibly configuration options. * @return array The filtered values */ - private function filterAttributeValues(array $values, array $allowedConfigValues) + private function filterAttributeValues(array $values, array $allowedConfigValues): array { if (array_key_exists('regex', $allowedConfigValues) && $allowedConfigValues['regex'] === true) { $matchedValues = []; diff --git a/modules/core/lib/Auth/Process/AttributeMap.php b/modules/core/lib/Auth/Process/AttributeMap.php index 7efdd2f73e77c99e831b0d48c6eaed64d84737d0..317a6d4cc2e685fc5082daac10706ec555bc50c2 100644 --- a/modules/core/lib/Auth/Process/AttributeMap.php +++ b/modules/core/lib/Auth/Process/AttributeMap.php @@ -79,7 +79,7 @@ class AttributeMap extends \SimpleSAML\Auth\ProcessingFilter * @throws \Exception If the filter could not load the requested attribute map file. * @return void */ - private function loadMapFile($fileName) + private function loadMapFile(string $fileName) { $config = Configuration::getInstance(); diff --git a/modules/core/lib/Auth/Process/GenerateGroups.php b/modules/core/lib/Auth/Process/GenerateGroups.php index a6e2257e774b5afa20a09805d8127c1cab756569..f2f82bbe38b107e99c846fc6e4c74bed29bee24c 100644 --- a/modules/core/lib/Auth/Process/GenerateGroups.php +++ b/modules/core/lib/Auth/Process/GenerateGroups.php @@ -102,10 +102,8 @@ class GenerateGroups extends \SimpleSAML\Auth\ProcessingFilter * @param array $attributes The attributes of the user. * @return string|null The realm of the user, or NULL if we are unable to determine the realm. */ - private static function getRealm($attributes) + private static function getRealm(array $attributes) { - assert(is_array($attributes)); - if (!array_key_exists('eduPersonPrincipalName', $attributes)) { return null; } @@ -136,10 +134,8 @@ class GenerateGroups extends \SimpleSAML\Auth\ProcessingFilter * @param string $string The string which should be escaped. * @return string The escaped string. */ - private static function escapeIllegalChars($string) + private static function escapeIllegalChars(string $string): string { - assert(is_string($string)); - return preg_replace_callback( '/([^a-zA-Z0-9_@=.])/', /** diff --git a/modules/core/lib/Auth/Process/StatisticsWithAttribute.php b/modules/core/lib/Auth/Process/StatisticsWithAttribute.php index 63d0a62d89f4a3af52fdd8a0111c884e11869fed..1e357a1296fb0557e528f4977c87538c2fe57f1d 100644 --- a/modules/core/lib/Auth/Process/StatisticsWithAttribute.php +++ b/modules/core/lib/Auth/Process/StatisticsWithAttribute.php @@ -104,7 +104,7 @@ class StatisticsWithAttribute extends \SimpleSAML\Auth\ProcessingFilter * * @return string */ - private function setIdentifier($direction, $state) + private function setIdentifier(string $direction, array $state): string { if (array_key_exists($direction, $state)) { if (isset($state[$direction]['core:statistics-id'])) { diff --git a/modules/core/lib/Auth/Process/TargetedID.php b/modules/core/lib/Auth/Process/TargetedID.php index 950f02f9ba3a5c8a3420fb6f215546b98f4fba53..0f8d07890687626abf872dd74a0d76dabaff479f 100644 --- a/modules/core/lib/Auth/Process/TargetedID.php +++ b/modules/core/lib/Auth/Process/TargetedID.php @@ -160,10 +160,8 @@ class TargetedID extends \SimpleSAML\Auth\ProcessingFilter * @param array $metadata The metadata of the entity. * @return string The unique identifier for the entity. */ - private static function getEntityId($metadata) + private static function getEntityId(array $metadata): string { - assert(is_array($metadata)); - $id = ''; if (array_key_exists('metadata-set', $metadata)) { diff --git a/modules/core/lib/Auth/UserPassBase.php b/modules/core/lib/Auth/UserPassBase.php index 90104e5f14d2999a5b0b04f2fccfc3672c62f2fa..a2d4d1c069f9defcebd4ac9597196ab6ae8ec49b 100644 --- a/modules/core/lib/Auth/UserPassBase.php +++ b/modules/core/lib/Auth/UserPassBase.php @@ -47,7 +47,7 @@ abstract class UserPassBase extends \SimpleSAML\Auth\Source * * @var array */ - protected $loginLinks; + protected $loginLinks = []; /** * Storage for authsource config option remember.username.enabled diff --git a/modules/core/lib/Controller/Exception.php b/modules/core/lib/Controller/Exception.php index 072282e8e3f399cc41a981e31b147a8b12542838..9a8e4f009e1d95fba651a888d37f868300036c0c 100644 --- a/modules/core/lib/Controller/Exception.php +++ b/modules/core/lib/Controller/Exception.php @@ -11,6 +11,7 @@ use SimpleSAML\Session; use SimpleSAML\Utils; use SimpleSAML\XHTML\Template; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; /** * Controller class for the core module. @@ -55,7 +56,7 @@ class Exception * @return \SimpleSAML\XHTML\Template|\Symfony\Component\HttpFoundation\RedirectResponse * An HTML template or a redirection if we are not authenticated. */ - public function cardinality(Request $request) + public function cardinality(Request $request): Response { $stateId = $request->get('StateId', false); if ($stateId === false) { @@ -91,7 +92,7 @@ class Exception * @return \SimpleSAML\XHTML\Template|\Symfony\Component\HttpFoundation\RedirectResponse * An HTML template or a redirection if we are not authenticated. */ - public function nocookie(Request $request) + public function nocookie(Request $request): Response { $retryURL = $request->get('retryURL', null); if ($retryURL !== null) { @@ -115,7 +116,7 @@ class Exception * * @throws \SimpleSAML\Error\BadRequest */ - public function shortSsoInterval(Request $request) + public function shortSsoInterval(Request $request): Response { $stateId = $request->get('StateId', false); if ($stateId === false) { diff --git a/modules/core/lib/Controller/Login.php b/modules/core/lib/Controller/Login.php index 8a5859ff577e067289e1e45c8086be074bb09a89..8e5285088e7e7ecdd55e4361f0334839e11ac612 100644 --- a/modules/core/lib/Controller/Login.php +++ b/modules/core/lib/Controller/Login.php @@ -13,6 +13,7 @@ use SimpleSAML\Utils; use SimpleSAML\XHTML\Template; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Webmozart\Assert\Assert; /** @@ -70,7 +71,7 @@ class Login * * @throws \SimpleSAML\Error\Exception An exception in case the auth source specified is invalid. */ - public function account($as) + public function account(string $as): Response { if (!array_key_exists($as, $this->sources)) { throw new Error\Exception('Invalid authentication source'); @@ -118,7 +119,7 @@ class Login * * @throws \SimpleSAML\Error\Exception */ - public function login(Request $request, $as = null) + public function login(Request $request, string $as = null): Response { // delete admin if (isset($this->sources['admin'])) { @@ -180,7 +181,7 @@ class Login * * @throws \SimpleSAML\Error\CriticalConfigurationError */ - public function logout($as) + public function logout(string $as): Response { $auth = new Auth\Simple($as); return new RunnableResponse([$auth, 'logout'], [$this->config->getBasePath() . 'core/logout/' . urlencode($as)]); diff --git a/modules/core/lib/Controller/Redirection.php b/modules/core/lib/Controller/Redirection.php index 718fd3d941be465741331f188c623be3c74e2a9d..14b7454e64672e6c50048ed2061409726627b363 100644 --- a/modules/core/lib/Controller/Redirection.php +++ b/modules/core/lib/Controller/Redirection.php @@ -11,6 +11,7 @@ use SimpleSAML\Session; use SimpleSAML\Utils; use SimpleSAML\XHTML\Template; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Webmozart\Assert\Assert; /** @@ -56,7 +57,7 @@ class Redirection * @return \SimpleSAML\XHTML\Template|\Symfony\Component\HttpFoundation\RedirectResponse * An HTML template or a redirection if we are not authenticated. */ - public function postredirect(Request $request) + public function postredirect(Request $request): Response { $redirId = $request->get('RedirId', false); $redirInfo = $request->get('RedirInfo', false); diff --git a/modules/core/lib/Stats/Output/File.php b/modules/core/lib/Stats/Output/File.php index 30a97e1722cfe45f7d204f8053b00efc7f894f9c..37fb79f21e12c333113b36e2603d92b692dda40a 100644 --- a/modules/core/lib/Stats/Output/File.php +++ b/modules/core/lib/Stats/Output/File.php @@ -55,10 +55,8 @@ class File extends \SimpleSAML\Stats\Output * @param string $date The date for the log file. * @return void */ - private function openLog($date) + private function openLog(string $date) { - assert(is_string($date)); - if ($this->file !== null && $this->file !== false) { fclose($this->file); $this->file = null; diff --git a/modules/core/lib/Storage/SQLPermanentStorage.php b/modules/core/lib/Storage/SQLPermanentStorage.php index 1ff18f8ab344a8ad58879a4b8ebb2e6aa09845d4..ed920dd2558cf0bce649d0a01188c70a0d5e9643 100644 --- a/modules/core/lib/Storage/SQLPermanentStorage.php +++ b/modules/core/lib/Storage/SQLPermanentStorage.php @@ -70,9 +70,9 @@ class SQLPermanentStorage /** * @param string $type - * @param mixed $key1 - * @param mixed $key2 - * @param mixed $value + * @param string $key1 + * @param string $key2 + * @param string $value * @param int|null $duration * @return void */ @@ -88,13 +88,13 @@ class SQLPermanentStorage /** * @param string $type - * @param mixed $key1 - * @param mixed $key2 - * @param mixed $value + * @param string $key1 + * @param string $key2 + * @param string $value * @param int|null $duration * @return array */ - private function insert($type, $key1, $key2, $value, $duration = null) + private function insert(string $type, string $key1, string $key2, string $value, int $duration = null): array { $expire = is_null($duration) ? null : (time() + $duration); @@ -114,13 +114,13 @@ class SQLPermanentStorage /** * @param string $type - * @param mixed $key1 - * @param mixed $key2 - * @param mixed $value + * @param string $key1 + * @param string $key2 + * @param string $value * @param int|null $duration * @return array */ - private function update($type, $key1, $key2, $value, $duration = null) + private function update(string $type, string $key1, string $key2, string $value, int $duration = null): array { $expire = is_null($duration) ? null : (time() + $duration); @@ -139,8 +139,8 @@ class SQLPermanentStorage /** * @param string $type - * @param mixed $key1 - * @param mixed $key2 + * @param string $key1 + * @param string $key2 * @return array|null */ public function get($type = null, $key1 = null, $key2 = null) @@ -164,8 +164,8 @@ class SQLPermanentStorage * Return the value directly (not in a container) * * @param string $type - * @param mixed $key1 - * @param mixed $key2 + * @param string $key1 + * @param string $key2 * @return array|null */ public function getValue($type = null, $key1 = null, $key2 = null) @@ -180,8 +180,8 @@ class SQLPermanentStorage /** * @param string $type - * @param mixed $key1 - * @param mixed $key2 + * @param string $key1 + * @param string $key2 * @return bool */ public function exists($type, $key1, $key2) @@ -197,8 +197,8 @@ class SQLPermanentStorage /** * @param string $type - * @param mixed $key1 - * @param mixed $key2 + * @param string $key1 + * @param string $key2 * @return array|false */ public function getList($type = null, $key1 = null, $key2 = null) @@ -222,8 +222,8 @@ class SQLPermanentStorage /** * @param string $type - * @param mixed $key1 - * @param mixed $key2 + * @param string $key1 + * @param string $key2 * @param string $whichKey * @throws \Exception * @return array|null @@ -254,8 +254,8 @@ class SQLPermanentStorage /** * @param string $type - * @param mixed $key1 - * @param mixed $key2 + * @param string $key1 + * @param string $key2 * @return bool */ public function remove($type, $key1, $key2) @@ -285,11 +285,11 @@ class SQLPermanentStorage * Create a SQL condition statement based on parameters * * @param string $type - * @param mixed $key1 - * @param mixed $key2 + * @param string $key1 + * @param string $key2 * @return string */ - private function getCondition($type = null, $key1 = null, $key2 = null) + private function getCondition(string $type = null, string $key1 = null, string $key2 = null): string { $conditions = []; if (!is_null($type)) { diff --git a/modules/core/www/frontpage_config.php b/modules/core/www/frontpage_config.php index 2ede138cdccdaa4015e786c938c008857b9d489b..6669498cbcec3051e6a6c1bfbc237f7dfd214a3a 100644 --- a/modules/core/www/frontpage_config.php +++ b/modules/core/www/frontpage_config.php @@ -123,8 +123,8 @@ if (\SimpleSAML\Module::isModuleEnabled('radius')) { $funcmatrix = []; $funcmatrix[] = [ 'required' => 'required', - 'descr' => 'PHP Version >= 5.6. You run: ' . phpversion(), - 'enabled' => version_compare(phpversion(), '5.6', '>=') + 'descr' => 'PHP Version >= 7.0. You run: ' . phpversion(), + 'enabled' => version_compare(phpversion(), '7.0', '>=') ]; foreach ($functionchecks as $func => $descr) { $funcmatrix[] = ['descr' => $descr[1], 'required' => $descr[0], 'enabled' => function_exists($func)]; diff --git a/modules/core/www/idp/logout-iframe-done.php b/modules/core/www/idp/logout-iframe-done.php index 92733d00ad5d692c7b512c674cd57b55506a36fc..ca1618dfcd4e5cef624f9b6e613a7e5424f6cea0 100644 --- a/modules/core/www/idp/logout-iframe-done.php +++ b/modules/core/www/idp/logout-iframe-done.php @@ -3,6 +3,8 @@ if (!isset($_REQUEST['id'])) { throw new \SimpleSAML\Error\BadRequest('Missing required parameter: id'); } + +/** @psalm-var array $state */ $state = \SimpleSAML\Auth\State::loadState($_REQUEST['id'], 'core:Logout-IFrame'); $idp = \SimpleSAML\IdP::getByState($state); diff --git a/modules/core/www/idp/logout-iframe.php b/modules/core/www/idp/logout-iframe.php index 8f38c891f3984e3f09fc1879a70467d2cb425358..80f94cca9e12aa2e5e6c5b02e0eb791f36a0e3d3 100644 --- a/modules/core/www/idp/logout-iframe.php +++ b/modules/core/www/idp/logout-iframe.php @@ -18,6 +18,7 @@ if ($type !== 'embed') { \SimpleSAML\Stats::log('core:idp:logout-iframe:page', ['type' => $type]); } +/** @psalm-var array $state */ $state = \SimpleSAML\Auth\State::loadState($_REQUEST['id'], 'core:Logout-IFrame'); $idp = \SimpleSAML\IdP::getByState($state); $mdh = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler(); diff --git a/modules/core/www/idp/resumelogout.php b/modules/core/www/idp/resumelogout.php index 3e84b3a4e2a8b78c001ef8db9b810dc221e556c5..5f90c0bca8b2f7cff6b2f265b9cb7e40a7ebc2a9 100644 --- a/modules/core/www/idp/resumelogout.php +++ b/modules/core/www/idp/resumelogout.php @@ -3,6 +3,8 @@ if (!isset($_REQUEST['id'])) { throw new \SimpleSAML\Error\BadRequest('Missing id-parameter.'); } + +/** @psalm-var array $state */ $state = \SimpleSAML\Auth\State::loadState($_REQUEST['id'], 'core:Logout:afterbridge'); $idp = \SimpleSAML\IdP::getByState($state); diff --git a/modules/cron/bin/cron.php b/modules/cron/bin/cron.php index 436397fd296f60cc0265ad5c36fe6f460d83cedf..cb85cbe764639138582ceceda7e96947941680c2 100755 --- a/modules/cron/bin/cron.php +++ b/modules/cron/bin/cron.php @@ -32,6 +32,7 @@ if (!array_key_exists('t', $options)) { exit(2); } +/** @psalm-var string $tag */ $tag = $options['t']; $cron = new SimpleSAML\Module\cron\Cron(); if (!$cron->isValidTag($tag)) { diff --git a/modules/multiauth/lib/Auth/Source/MultiAuth.php b/modules/multiauth/lib/Auth/Source/MultiAuth.php index 85d723588a1aa4743c15af3386ff81d7379324f4..3e0e453c552dc82d137e87c5d110be40d97192c5 100644 --- a/modules/multiauth/lib/Auth/Source/MultiAuth.php +++ b/modules/multiauth/lib/Auth/Source/MultiAuth.php @@ -80,7 +80,10 @@ class MultiAuth extends \SimpleSAML\Auth\Source $defaultLanguage = $globalConfiguration->getString('language.default', 'en'); $authsources = Configuration::getConfig('authsources.php'); $this->sources = []; - foreach ($config['sources'] as $source => $info) { + + /** @psalm-var array $sources */ + $sources = $config['sources']; + foreach ($sources as $source => $info) { if (is_int($source)) { // Backwards compatibility $source = $info; diff --git a/modules/saml/lib/Auth/Process/NameIDAttribute.php b/modules/saml/lib/Auth/Process/NameIDAttribute.php index 5ed3e9800705202864e65504cb7c11a024b241a5..01c09c22b57af53df0150ee01f8db1cd5f12b569 100644 --- a/modules/saml/lib/Auth/Process/NameIDAttribute.php +++ b/modules/saml/lib/Auth/Process/NameIDAttribute.php @@ -64,10 +64,8 @@ class NameIDAttribute extends \SimpleSAML\Auth\ProcessingFilter * * @throws \SimpleSAML\Error\Exception if the replacement is invalid. */ - private static function parseFormat($format) + private static function parseFormat(string $format): array { - assert(is_string($format)); - $ret = []; $pos = 0; while (($next = strpos($format, '%', $pos)) !== false) { diff --git a/modules/saml/lib/Auth/Source/SP.php b/modules/saml/lib/Auth/Source/SP.php index 4dd06c044dd70d429a350fce090ac9a29ae77e40..83090e3ce87fd62789c242d355b9640483ad2507 100644 --- a/modules/saml/lib/Auth/Source/SP.php +++ b/modules/saml/lib/Auth/Source/SP.php @@ -345,7 +345,7 @@ class SP extends \SimpleSAML\Auth\Source * @return array * @throws \Exception */ - private function getACSEndpoints() + private function getACSEndpoints(): array { $endpoints = []; $default = [ @@ -427,7 +427,7 @@ class SP extends \SimpleSAML\Auth\Source * @return array * @throws \SimpleSAML\Error\CriticalConfigurationError */ - private function getSLOEndpoints() + private function getSLOEndpoints(): array { $store = Store::getInstance(); $bindings = $this->metadata->getArray( diff --git a/modules/saml/lib/Error.php b/modules/saml/lib/Error.php index 50604b39ffbe82300be17666ba8c41792ddf2111..042bc6eb65e08e91538cbe9d18554c6991f1a3ad 100644 --- a/modules/saml/lib/Error.php +++ b/modules/saml/lib/Error.php @@ -187,10 +187,8 @@ class Error extends \SimpleSAML\Error\Exception * @param string $status The status code. * @return string A shorter version of the status code. */ - private static function shortStatus($status) + private static function shortStatus(string $status): string { - assert(is_string($status)); - $t = 'urn:oasis:names:tc:SAML:2.0:status:'; if (substr($status, 0, strlen($t)) === $t) { return substr($status, strlen($t)); diff --git a/modules/saml/lib/IdP/SAML2.php b/modules/saml/lib/IdP/SAML2.php index eca7ad6e8949d38dcb516956829eec04eab87714..14cd0e6e09ab2fc38b53d9a4cc3b8218061909a8 100644 --- a/modules/saml/lib/IdP/SAML2.php +++ b/modules/saml/lib/IdP/SAML2.php @@ -13,6 +13,7 @@ use SAML2\EncryptedAssertion; use SAML2\HTTPRedirect; use SAML2\LogoutRequest; use SAML2\LogoutResponse; +use SAML2\Response; use SAML2\SOAP; use SAML2\XML\ds\X509Certificate; use SAML2\XML\ds\X509Data; @@ -192,14 +193,10 @@ class SAML2 private static function getAssertionConsumerService( array $supportedBindings, Configuration $spMetadata, - $AssertionConsumerServiceURL, - $ProtocolBinding, - $AssertionConsumerServiceIndex + string $AssertionConsumerServiceURL = null, + string $ProtocolBinding = null, + int $AssertionConsumerServiceIndex = null ) { - assert(is_string($AssertionConsumerServiceURL) || $AssertionConsumerServiceURL === null); - assert(is_string($ProtocolBinding) || $ProtocolBinding === null); - assert(is_int($AssertionConsumerServiceIndex) || $AssertionConsumerServiceIndex === null); - /* We want to pick the best matching endpoint in the case where for example * only the ProtocolBinding is given. We therefore pick endpoints with the * following priority: @@ -363,12 +360,14 @@ class SAML2 ); } + /** @psalm-var null|string|\SAML2\XML\saml\Issuer $issuer Remove in SSP 2.0 */ $issuer = $request->getIssuer(); if ($issuer === null) { throw new Error\BadRequest( 'Received message on authentication request endpoint without issuer.' ); } elseif ($issuer instanceof Issuer) { + /** @psalm-var string|null $spEntityId */ $spEntityId = $issuer->getValue(); if ($spEntityId === null) { /* Without an issuer we have no way to respond to the message. */ @@ -604,11 +603,13 @@ class SAML2 $binding = Binding::getCurrentBinding(); $message = $binding->receive(); + /** @psalm-var null|string|\SAML2\XML\saml\Issuer Remove in SSP 2.0 */ $issuer = $message->getIssuer(); if ($issuer === null) { /* Without an issuer we have no way to respond to the message. */ throw new Error\BadRequest('Received message on logout endpoint without issuer.'); } elseif ($issuer instanceof Issuer) { + /** @psalm-var string|null $spEntityId */ $spEntityId = $issuer->getValue(); if ($spEntityId === null) { /* Without an issuer we have no way to respond to the message. */ @@ -948,7 +949,6 @@ class SAML2 Configuration $spMetadata, array &$state ) { - $attribute = $spMetadata->getString('simplesaml.nameidattribute', null); if ($attribute === null) { $attribute = $idpMetadata->getString('simplesaml.nameidattribute', null); @@ -999,7 +999,7 @@ class SAML2 Configuration $idpMetadata, Configuration $spMetadata, array $attributes - ) { + ): array { $base64Attributes = $spMetadata->getBoolean('base64attributes', null); if ($base64Attributes === null) { $base64Attributes = $idpMetadata->getBoolean('base64attributes', false); @@ -1038,6 +1038,7 @@ class SAML2 $attrval = $value; if ($value instanceof DOMNodeList) { + /** @psalm-suppress PossiblyNullPropertyFetch */ $attrval = new AttributeValue($value->item(0)->parentNode); } @@ -1078,7 +1079,7 @@ class SAML2 private static function getAttributeNameFormat( Configuration $idpMetadata, Configuration $spMetadata - ) { + ): string { // try SP metadata first $attributeNameFormat = $spMetadata->getString('attributes.NameFormat', null); if ($attributeNameFormat !== null) { @@ -1119,7 +1120,7 @@ class SAML2 Configuration $idpMetadata, Configuration $spMetadata, array &$state - ) { + ): Assertion { assert(isset($state['Attributes'])); assert(isset($state['saml:ConsumerURL'])); @@ -1376,8 +1377,8 @@ class SAML2 Configuration $idpMetadata, Configuration $spMetadata, array $association, - $relayState - ) { + string $relayState = null + ): LogoutRequest { $lr = \SimpleSAML\Module\saml\Message::buildLogoutRequest($idpMetadata, $spMetadata); $lr->setRelayState($relayState); $lr->setSessionIndex($association['saml:SessionIndex']); @@ -1413,14 +1414,14 @@ class SAML2 private static function buildResponse( Configuration $idpMetadata, Configuration $spMetadata, - $consumerURL - ) { + string $consumerURL + ): Response { $signResponse = $spMetadata->getBoolean('saml20.sign.response', null); if ($signResponse === null) { $signResponse = $idpMetadata->getBoolean('saml20.sign.response', true); } - $r = new \SAML2\Response(); + $r = new Response(); $issuer = new Issuer(); $issuer->setValue($idpMetadata->getString('entityid')); $issuer->setFormat(Constants::NAMEID_ENTITY); diff --git a/modules/saml/lib/IdP/SQLNameID.php b/modules/saml/lib/IdP/SQLNameID.php index d4f91d9d3f3d0528bdbda5b3cdfd4d6162cc3fc2..8777dd02b3c73a53a3a5d9567f1bc64cb5625fe4 100644 --- a/modules/saml/lib/IdP/SQLNameID.php +++ b/modules/saml/lib/IdP/SQLNameID.php @@ -3,6 +3,7 @@ namespace SimpleSAML\Module\saml\IdP; use PDO; +use PDOStatement; use SimpleSAML\Error; use SimpleSAML\Store; use SimpleSAML\Database; @@ -26,7 +27,7 @@ class SQLNameID * @param array $config * @return \PDOStatement object */ - private static function read($query, array $params = [], array $config = []) + private static function read(string $query, array $params = [], array $config = []): PDOStatement { if (!empty($config)) { $database = Database::getInstance(Configuration::loadFromArray($config)); @@ -46,7 +47,7 @@ class SQLNameID * @param array $config * @return int|false The number of rows affected by the query or false on error. */ - private static function write($query, array $params = [], array $config = []) + private static function write(string $query, array $params = [], array $config = []) { if (!empty($config)) { $database = Database::getInstance(Configuration::loadFromArray($config)); @@ -67,7 +68,7 @@ class SQLNameID * @param array $config * @return string */ - private static function tableName(array $config = []) + private static function tableName(array $config = []): string { $store = empty($config) ? self::getStore() : null; $prefix = $store === null ? self::DEFAULT_TABLE_PREFIX : $store->prefix; @@ -102,7 +103,7 @@ class SQLNameID * @param array $config * @return \PDOStatement */ - private static function createAndRead($query, array $params = [], array $config = []) + private static function createAndRead(string $query, array $params = [], array $config = []): PDOStatement { self::create($config); return self::read($query, $params, $config); @@ -115,7 +116,7 @@ class SQLNameID * @param array $config * @return int|false The number of rows affected by the query or false on error. */ - private static function createAndWrite($query, array $params = [], array $config = []) + private static function createAndWrite(string $query, array $params = [], array $config = []) { self::create($config); return self::write($query, $params, $config); @@ -129,7 +130,7 @@ class SQLNameID * @param array $config * @return void */ - private static function createTable($table, array $config = []) + private static function createTable(string $table, array $config = []) { $query = 'CREATE TABLE ' . $table . ' ( _idp VARCHAR(256) NOT NULL, @@ -151,7 +152,7 @@ class SQLNameID * * @return \SimpleSAML\Store\SQL SQL datastore. */ - private static function getStore() + private static function getStore(): Store\SQL { $store = Store::getInstance(); if (!($store instanceof Store\SQL)) { diff --git a/modules/saml/lib/Message.php b/modules/saml/lib/Message.php index ca15e50130b8089b1e65c4a5e35cf3e5c0f4bb23..379d24065cfaa09cb59782c2b686353f6deb835b 100644 --- a/modules/saml/lib/Message.php +++ b/modules/saml/lib/Message.php @@ -133,7 +133,7 @@ class Message * * @throws \SimpleSAML\Error\Exception if we cannot find the certificate matching the fingerprint. */ - private static function findCertificate(array $certFingerprints, array $certificates) + private static function findCertificate(array $certFingerprints, array $certificates): string { $candidates = []; @@ -381,7 +381,7 @@ class Message Configuration $srcMetadata, Configuration $dstMetadata, $assertion - ) { + ): Assertion { assert($assertion instanceof Assertion || $assertion instanceof EncryptedAssertion); if ($assertion instanceof Assertion) { @@ -665,10 +665,9 @@ class Message Configuration $idpMetadata, Response $response, $assertion, - $responseSigned - ) { + bool $responseSigned + ): Assertion { assert($assertion instanceof Assertion || $assertion instanceof EncryptedAssertion); - assert(is_bool($responseSigned)); $assertion = self::decryptAssertion($idpMetadata, $spMetadata, $assertion); self::decryptAttributes($idpMetadata, $spMetadata, $assertion); @@ -911,7 +910,6 @@ class Message */ public static function getEncryptionKey(Configuration $metadata) { - $sharedKey = $metadata->getString('sharedkey', null); if ($sharedKey !== null) { $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC); diff --git a/modules/saml/lib/SP/LogoutStore.php b/modules/saml/lib/SP/LogoutStore.php index df1bff1c41ade577959bac25110715d17239d942..c78db758a16826bb85710794a12c3630de99c9ee 100644 --- a/modules/saml/lib/SP/LogoutStore.php +++ b/modules/saml/lib/SP/LogoutStore.php @@ -223,18 +223,12 @@ class LogoutStore */ private static function addSessionSQL( Store\SQL $store, - $authId, - $nameId, - $sessionIndex, - $expire, - $sessionId + string $authId, + string $nameId, + string $sessionIndex, + int $expire, + string $sessionId ) { - assert(is_string($authId)); - assert(is_string($nameId)); - assert(is_string($sessionIndex)); - assert(is_int($expire)); - assert(is_string($sessionId)); - self::createLogoutTable($store); if (rand(0, 1000) < 10) { @@ -264,11 +258,8 @@ class LogoutStore * @param string $nameId The hash of the users NameID. * @return array Associative array of SessionIndex => SessionId. */ - private static function getSessionsSQL(Store\SQL $store, $authId, $nameId) + private static function getSessionsSQL(Store\SQL $store, string $authId, string $nameId): array { - assert(is_string($authId)); - assert(is_string($nameId)); - self::createLogoutTable($store); $params = [ @@ -301,11 +292,12 @@ class LogoutStore * @param array $sessionIndexes The session indexes. * @return array Associative array of SessionIndex => SessionId. */ - private static function getSessionsStore(Store $store, $authId, $nameId, array $sessionIndexes) - { - assert(is_string($authId)); - assert(is_string($nameId)); - + private static function getSessionsStore( + Store $store, + string $authId, + string $nameId, + array $sessionIndexes + ): array { $res = []; foreach ($sessionIndexes as $sessionIndex) { $sessionId = $store->get('saml.LogoutStore', $nameId . ':' . $sessionIndex); @@ -365,6 +357,7 @@ class LogoutStore // serialize and anonymize the NameID // TODO: remove this conditional statement if (is_array($nameId)) { + /** @psalm-suppress UndefinedMethod */ $nameId = NameID::fromArray($nameId); } $strNameId = serialize($nameId); @@ -407,6 +400,7 @@ class LogoutStore // serialize and anonymize the NameID // TODO: remove this conditional statement if (is_array($nameId)) { + /** @psalm-suppress UndefinedMethod */ $nameId = NameID::fromArray($nameId); } $strNameId = serialize($nameId); @@ -425,10 +419,11 @@ class LogoutStore if ($store instanceof Store\SQL) { $sessions = self::getSessionsSQL($store, $authId, $strNameId); - } elseif (empty($sessionIndexes)) { - // We cannot fetch all sessions without a SQL store - return false; } else { + if (empty($sessionIndexes)) { + // We cannot fetch all sessions without a SQL store + return false; + } /** @var array $sessions At this point the store cannot be false */ $sessions = self::getSessionsStore($store, $authId, $strNameId, $sessionIndexes); } diff --git a/modules/saml/www/sp/saml2-acs.php b/modules/saml/www/sp/saml2-acs.php index 4d05bf2b8ecf0fe4defa5d0fc2a0598c1c126ced..7d5c39a792dc6a2d32e1afd4b1f30a22b54272c9 100644 --- a/modules/saml/www/sp/saml2-acs.php +++ b/modules/saml/www/sp/saml2-acs.php @@ -37,6 +37,7 @@ if (!($response instanceof \SAML2\Response)) { throw new \SimpleSAML\Error\BadRequest('Invalid message received to AssertionConsumerService endpoint.'); } +/** @psalm-var null|string|\SAML2\XML\saml\Issuer $issuer Remove in SSP 2.0 */ $issuer = $response->getIssuer(); if ($issuer === null) { // no Issuer in the response. Look for an unencrypted assertion with an issuer @@ -47,6 +48,7 @@ if ($issuer === null) { break; } } + /** @psalm-var string|null $issuer Remove in SSP 2.0 */ if ($issuer === null) { // no issuer found in the assertions throw new Exception('Missing <saml:Issuer> in message delivered to AssertionConsumerService.'); @@ -54,6 +56,7 @@ if ($issuer === null) { } if ($issuer instanceof \SAML2\XML\saml\Issuer) { + /** @psalm-var string|null $issuer */ $issuer = $issuer->getValue(); if ($issuer === null) { // no issuer found in the assertions @@ -63,6 +66,7 @@ if ($issuer instanceof \SAML2\XML\saml\Issuer) { $session = \SimpleSAML\Session::getSessionFromRequest(); $prevAuth = $session->getAuthData($sourceId, 'saml:sp:prevAuth'); +/** @psalm-var string $issuer */ if ($prevAuth !== null && $prevAuth['id'] === $response->getId() && $prevAuth['issuer'] === $issuer) { /* OK, it looks like this message has the same issuer * and ID as the SP session we already have active. We diff --git a/modules/saml/www/sp/saml2-logout.php b/modules/saml/www/sp/saml2-logout.php index 61950a71e17664bee2945037254192de434040ae..9b756d8d61e5fdffa09c6eee42a6880d008d2cc6 100644 --- a/modules/saml/www/sp/saml2-logout.php +++ b/modules/saml/www/sp/saml2-logout.php @@ -109,6 +109,7 @@ if ($message instanceof \SAML2\LogoutResponse) { $nameId = $message->getNameId(); $sessionIndexes = $message->getSessionIndexes(); + /** @psalm-suppress PossiblyNullArgument This will be fixed in saml2 5.0 */ $numLoggedOut = \SimpleSAML\Module\saml\SP\LogoutStore::logoutSessions($sourceId, $nameId, $sessionIndexes); if ($numLoggedOut === false) { // This type of logout was unsupported. Use the old method diff --git a/phpunit.xml b/phpunit.xml index 4a7750b5f74ba104a4bec91b0571d517d88ebca0..878768a43398e4abb9c03f6b07834182d45c7522 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -10,7 +10,8 @@ bootstrap="./tests/bootstrap.php"> <testsuites> <testsuite name="Unit tests"> - <directory>./tests/</directory> + <directory>./vendor/simplesamlphp/simplesamlphp-test-framework/src</directory> + <directory>./tests</directory> </testsuite> </testsuites> <filter> diff --git a/psalm.xml b/psalm.xml index 5a230843ec723656c9ef1dcd912045848ea34d71..98c6fd8fa7580fb30c1c8eddb948a957f55bf592 100644 --- a/psalm.xml +++ b/psalm.xml @@ -25,9 +25,14 @@ <!-- Ignore deprecated classes --> <ignoreFiles> + <directory name="lib/SimpleSAML/Bindings/Shib13" /> + <directory name="lib/SimpleSAML/XML/Shib13" /> + <directory name="tests/lib/SimpleSAML/XML/Shib13" /> + <file name="lib/SimpleSAML/Auth/DefaultAuth.php" /> <file name="lib/SimpleSAML/Auth/TimeLimitedToken.php" /> <file name="lib/SimpleSAML/Utilities.php" /> + <file name="tests/lib/SimpleSAML/Auth/TimeLimitedTokenTest.php" /> <!-- Ignore deprecated PHP-templates - Remove for 2.0 --> <file name="modules/**/templates/*.tpl.php" /> diff --git a/tests/SigningTestCase.php b/tests/SigningTestCase.php index 80baba3c421a8002c73c5ef6bc639a191eb67511..bbbaadfbc3f80d1f5eb49a7f25a5147055a03534 100644 --- a/tests/SigningTestCase.php +++ b/tests/SigningTestCase.php @@ -4,6 +4,7 @@ namespace SimpleSAML\Test; use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\TestCase; +use ReflectionClass; use SimpleSAML\Configuration; /** @@ -205,7 +206,7 @@ NOWDOC; $this->good_private_key_file = $this->certdir . DIRECTORY_SEPARATOR . self::GOOD_PRIVATE_KEY; $this->good_certificate_file = $this->certdir . DIRECTORY_SEPARATOR . self::GOOD_CERTIFICATE; - $this->config = \SimpleSAML\Configuration::loadFromArray([ + $this->config = Configuration::loadFromArray([ 'certdir' => $this->certdir, ], '[ARRAY]', 'simplesaml'); } @@ -216,19 +217,19 @@ NOWDOC; */ public function tearDown() { - $this->clearInstance($this->config, '\SimpleSAML\Configuration', []); + $this->clearInstance($this->config, Configuration::class, []); } /** * @param \SimpleSAML\Configuration $service - * @param string $className + * @param class-string $className * @param mixed|null $value * @return void */ protected function clearInstance(Configuration $service, $className, $value = null) { - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new ReflectionClass($className); $reflectedInstance = $reflectedClass->getProperty('instance'); $reflectedInstance->setAccessible(true); $reflectedInstance->setValue($service, $value); diff --git a/tests/Utils/StateClearer.php b/tests/Utils/StateClearer.php index ec5258819e840cb533130082d41567e1735541e8..da24f1ba850618061c21f530eaf282b48671eaf1 100644 --- a/tests/Utils/StateClearer.php +++ b/tests/Utils/StateClearer.php @@ -44,6 +44,7 @@ class StateClearer $this->backups['$_GET'] = $_GET; $this->backups['$_POST'] = $_POST; $this->backups['$_SERVER'] = $_SERVER; + /** @psalm-var array|null $_SESSION */ $this->backups['$_SESSION'] = isset($_SESSION) ? $_SESSION : []; $this->backups['$_REQUEST'] = $_REQUEST; } diff --git a/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php b/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php index 34dd59c7defa65ce93eb626b8455425a1a89153d..0e5f2d3480c69e7d47c4e93de65b60b51296bb38 100644 --- a/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php +++ b/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php @@ -37,12 +37,16 @@ class SAMLBuilderTest extends TestCase $samlBuilder->addMetadata($set, $metadata); $spDesc = $samlBuilder->getEntityDescriptor(); - /** @var \DOMNodeList $acs */ + /** @psalm-var \DOMNodeList $acs */ $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); $this->assertEquals(1, $acs->length); - $attributes = $acs->item(0)->getElementsByTagName("RequestedAttribute"); + + /** @psalm-var \DOMElement $first */ + $first = $acs->item(0); + $attributes = $first->getElementsByTagName("RequestedAttribute"); $this->assertEquals(4, $attributes->length); for ($c = 0; $c < $attributes->length; $c++) { + /** @psalm-var \DOMElement $curAttribute */ $curAttribute = $attributes->item($c); $this->assertTrue($curAttribute->hasAttribute("Name")); $this->assertFalse($curAttribute->hasAttribute("FriendlyName")); @@ -70,10 +74,14 @@ class SAMLBuilderTest extends TestCase /** @var \DOMNodeList $acs */ $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); $this->assertEquals(1, $acs->length); - $attributes = $acs->item(0)->getElementsByTagName("RequestedAttribute"); + + /** @psalm-var \DOMElement $first */ + $first = $acs->item(0); + $attributes = $first->getElementsByTagName("RequestedAttribute"); $this->assertEquals(4, $attributes->length); $keys = array_keys($metadata['attributes']); for ($c = 0; $c < $attributes->length; $c++) { + /** @psalm-var \DOMElement $curAttribute */ $curAttribute = $attributes->item($c); $this->assertTrue($curAttribute->hasAttribute("Name")); $this->assertTrue($curAttribute->hasAttribute("FriendlyName")); @@ -102,9 +110,13 @@ class SAMLBuilderTest extends TestCase /** @var \DOMNodeList $acs */ $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); $this->assertEquals(1, $acs->length); - $attributes = $acs->item(0)->getElementsByTagName("RequestedAttribute"); + + /** @psalm-var \DOMElement $first */ + $first = $acs->item(0); + $attributes = $first->getElementsByTagName("RequestedAttribute"); $this->assertEquals(4, $attributes->length); for ($c = 0; $c < $attributes->length; $c++) { + /** @psalm-var \DOMElement $curAttribute */ $curAttribute = $attributes->item($c); $this->assertTrue($curAttribute->hasAttribute("Name")); $this->assertFalse($curAttribute->hasAttribute("FriendlyName")); @@ -132,10 +144,14 @@ class SAMLBuilderTest extends TestCase /** @var \DOMNodeList $acs */ $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); $this->assertEquals(1, $acs->length); - $attributes = $acs->item(0)->getElementsByTagName("RequestedAttribute"); + + /** @psalm-var \DOMElement $first */ + $first = $acs->item(0); + $attributes = $first->getElementsByTagName("RequestedAttribute"); $this->assertEquals(4, $attributes->length); $keys = array_keys($metadata['attributes']); for ($c = 0; $c < $attributes->length; $c++) { + /** @psalm-var \DOMElement $curAttribute */ $curAttribute = $attributes->item($c); $this->assertTrue($curAttribute->hasAttribute("Name")); $this->assertTrue($curAttribute->hasAttribute("FriendlyName")); @@ -170,6 +186,8 @@ class SAMLBuilderTest extends TestCase $spDesc = $samlBuilder->getEntityDescriptor(); /** @var \DOMNodeList $acs */ $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); + + /** @psalm-var \DOMElement $acs1 */ $acs1 = $acs->item(0); $this->assertFalse($acs1->hasAttribute("isDefault")); @@ -179,6 +197,7 @@ class SAMLBuilderTest extends TestCase $samlBuilder->addMetadata($set, $metadata); $spDesc = $samlBuilder->getEntityDescriptor(); $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); + /** @var \DOMElement $acs1 */ $acs1 = $acs->item(0); $this->assertTrue($acs1->hasAttribute("isDefault")); @@ -190,6 +209,7 @@ class SAMLBuilderTest extends TestCase $samlBuilder->addMetadata($set, $metadata); $spDesc = $samlBuilder->getEntityDescriptor(); $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); + /** @var \DOMElement $acs1 */ $acs1 = $acs->item(0); $this->assertTrue($acs1->hasAttribute("isDefault")); @@ -221,6 +241,7 @@ class SAMLBuilderTest extends TestCase $spDesc = $samlBuilder->getEntityDescriptor(); $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); + /** @var \DOMElement $acs1 */ $acs1 = $acs->item(0); $this->assertTrue($acs1->hasAttribute("index")); @@ -233,6 +254,7 @@ class SAMLBuilderTest extends TestCase $spDesc = $samlBuilder->getEntityDescriptor(); $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); + /** @var \DOMElement $acs1 */ $acs1 = $acs->item(0); $this->assertTrue($acs1->hasAttribute("index")); diff --git a/tests/lib/SimpleSAML/Metadata/SAMLParserTest.php b/tests/lib/SimpleSAML/Metadata/SAMLParserTest.php index 7bcb4ad3b432ec6bf9f1a7e46e8b3128f4353225..3dd13a1c1dffc5f61c0c41f05f5bec7facd5b470 100644 --- a/tests/lib/SimpleSAML/Metadata/SAMLParserTest.php +++ b/tests/lib/SimpleSAML/Metadata/SAMLParserTest.php @@ -165,6 +165,7 @@ XML XML ); + /** @psalm-var \DOMElement $entities_root */ $entities_root = $doc->getElementsByTagName('EntitiesDescriptor')->item(0); $signer = new Signer([]); $signer->loadPrivateKey($this->good_private_key_file, null, true); @@ -180,7 +181,7 @@ XML * @param string $expected_fingerprint * @return void */ - private function validateFingerprint($algo, $expected_fingerprint) + private function validateFingerprint(string $algo, string $expected_fingerprint) { $doc = $this->makeTestDocument(); $entities = \SimpleSAML\Metadata\SAMLParser::parseDescriptorsElement($doc->documentElement); diff --git a/tests/lib/SimpleSAML/Store/RedisTest.php b/tests/lib/SimpleSAML/Store/RedisTest.php index b855925a1235e4a15954e10ee1a3517196e4acbc..fb133be9c0175f4b58001a42f24e17611ac87913 100644 --- a/tests/lib/SimpleSAML/Store/RedisTest.php +++ b/tests/lib/SimpleSAML/Store/RedisTest.php @@ -4,6 +4,7 @@ namespace SimpleSAML\Test\Store; use PHPUnit\Framework\TestCase; use Predis\Client; +use ReflectionClass; use SimpleSAML\Configuration; use SimpleSAML\Store; @@ -247,12 +248,12 @@ class RedisTest extends TestCase /** * @param \SimpleSAML\Configuration|\SimpleSAML\Store $service - * @param string $className + * @param class-string $className * @return void */ protected function clearInstance($service, $className) { - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new ReflectionClass($className); $reflectedInstance = $reflectedClass->getProperty('instance'); $reflectedInstance->setAccessible(true); $reflectedInstance->setValue($service, null); diff --git a/tests/lib/SimpleSAML/Store/SQLTest.php b/tests/lib/SimpleSAML/Store/SQLTest.php index 46188863323c4a01d92e80b8cbc8818779cd95ee..aac6edf9a6b3526ebcfbd31e53370565c86916ee 100644 --- a/tests/lib/SimpleSAML/Store/SQLTest.php +++ b/tests/lib/SimpleSAML/Store/SQLTest.php @@ -3,6 +3,7 @@ namespace SimpleSAML\Test\Store; use PHPUnit\Framework\TestCase; +use ReflectionClass; use SimpleSAML\Configuration; use SimpleSAML\Store; @@ -199,22 +200,23 @@ class SQLTest extends TestCase protected function tearDown() { $config = Configuration::getInstance(); + /** @var \SimpleSAML\Store\SQL $store */ $store = Store::getInstance(); - $this->clearInstance($config, '\SimpleSAML\Configuration'); - $this->clearInstance($store, '\SimpleSAML\Store'); + $this->clearInstance($config, Configuration::class); + $this->clearInstance($store, Store::class); } /** * @param \SimpleSAML\Configuration|\SimpleSAML\Store $service - * @param string $className + * @param class-string $className * @return void */ protected function clearInstance($service, $className) { - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new ReflectionClass($className); $reflectedInstance = $reflectedClass->getProperty('instance'); $reflectedInstance->setAccessible(true); $reflectedInstance->setValue($service, null); diff --git a/tests/lib/SimpleSAML/StoreTest.php b/tests/lib/SimpleSAML/StoreTest.php index 65d429d362a2c1c5318b0455c3f14a4e7ddfd8c9..09412ff482b55cfc12bf239c63f50a4fd1d85d87 100644 --- a/tests/lib/SimpleSAML/StoreTest.php +++ b/tests/lib/SimpleSAML/StoreTest.php @@ -3,6 +3,7 @@ namespace SimpleSAML\Test; use PHPUnit\Framework\TestCase; +use ReflectionClass; use SimpleSAML\Configuration; use SimpleSAML\Error\CriticalConfigurationError; use SimpleSAML\Store; @@ -139,12 +140,12 @@ class StoreTest extends TestCase /** * @param \SimpleSAML\Configuration|\SimpleSAML\Store $service - * @param string $className + * @param class-string $className * @return void */ protected function clearInstance($service, $className) { - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new ReflectionClass($className); $reflectedInstance = $reflectedClass->getProperty('instance'); $reflectedInstance->setAccessible(true); $reflectedInstance->setValue($service, null); diff --git a/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php b/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php index 39c959009549c51adfc48876d0f9d6db21953fe0..df7137d3204683da60ff62c93eaa796fc8aca324 100644 --- a/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php +++ b/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php @@ -2,6 +2,7 @@ namespace SimpleSAML\Test\Utils\Config; +use DOMDocument; use PHPUnit\Framework\TestCase; use SimpleSAML\Utils\Config\Metadata; @@ -242,6 +243,13 @@ class MetadataTest extends TestCase ]; $this->assertTrue(Metadata::isHiddenFromDiscovery($metadata)); + // test for failure + $this->assertFalse(Metadata::isHiddenFromDiscovery([ + 'EntityAttributes' => [ + Metadata::$ENTITY_CATEGORY => [], + ], + ])); + // test for failures $this->assertFalse(Metadata::isHiddenFromDiscovery(['foo'])); $this->assertFalse(Metadata::isHiddenFromDiscovery([ @@ -255,14 +263,9 @@ class MetadataTest extends TestCase Metadata::$ENTITY_CATEGORY => '', ], ])); - $this->assertFalse(Metadata::isHiddenFromDiscovery([ - 'EntityAttributes' => [ - Metadata::$ENTITY_CATEGORY => [], - ], - ])); } - + /** * Test \SimpleSAML\Utils\Config\Metadata::parseNameIdPolicy(). * @return void diff --git a/tests/lib/SimpleSAML/Utils/CryptoTest.php b/tests/lib/SimpleSAML/Utils/CryptoTest.php index ee5e011485b65e94cf23649e52dfb5667d078b38..9841299eb32a075a212ee15e589d5bff54936cd5 100644 --- a/tests/lib/SimpleSAML/Utils/CryptoTest.php +++ b/tests/lib/SimpleSAML/Utils/CryptoTest.php @@ -43,38 +43,6 @@ class CryptoTest extends TestCase } - /** - * Test invalid input provided to the aesDecrypt() method. - * - * @covers \SimpleSAML\Utils\Crypto::aesDecrypt - * @return void - */ - public function testAesDecryptBadInput() - { - $this->expectException(\InvalidArgumentException::class); - $m = new \ReflectionMethod('\SimpleSAML\Utils\Crypto', 'aesDecryptInternal'); - $m->setAccessible(true); - - $m->invokeArgs(null, [[], 'SECRET']); - } - - - /** - * Test invalid input provided to the aesEncrypt() method. - * - * @covers \SimpleSAML\Utils\Crypto::aesEncrypt - * @return void - */ - public function testAesEncryptBadInput() - { - $this->expectException(\InvalidArgumentException::class); - $m = new \ReflectionMethod('\SimpleSAML\Utils\Crypto', 'aesEncryptInternal'); - $m->setAccessible(true); - - $m->invokeArgs(null, [[], 'SECRET']); - } - - /** * Test that aesDecrypt() works properly, being able to decrypt some previously known (and correct) * ciphertext. diff --git a/tests/lib/SimpleSAML/Utils/HTTPTest.php b/tests/lib/SimpleSAML/Utils/HTTPTest.php index 504aaedf0a36c05479ac06642b58a1e846ee00c4..32cd3aac6513df6146dcc173bc719559888c2f11 100644 --- a/tests/lib/SimpleSAML/Utils/HTTPTest.php +++ b/tests/lib/SimpleSAML/Utils/HTTPTest.php @@ -15,7 +15,7 @@ class HTTPTest extends ClearStateTestCase * @param string $url The URL to use as the current one. * @return void */ - private function setupEnvFromURL($url) + private function setupEnvFromURL(string $url) { $addr = parse_url($url); $_SERVER['HTTP_HOST'] = $addr['host']; diff --git a/tests/lib/SimpleSAML/Utils/SystemTest.php b/tests/lib/SimpleSAML/Utils/SystemTest.php index d96fa62d1c5a18b2d1e730ab376e8ed1964bb198..f2e5c854537a37619436bd1bd392724dde8dbc2f 100644 --- a/tests/lib/SimpleSAML/Utils/SystemTest.php +++ b/tests/lib/SimpleSAML/Utils/SystemTest.php @@ -2,8 +2,10 @@ namespace SimpleSAML\Test\Utils; +use InvalidArgumentException; use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\TestCase; +use ReflectionClass; use SimpleSAML\Configuration; use SimpleSAML\Utils\System; @@ -162,7 +164,8 @@ class SystemTest extends TestCase */ public function testWriteFileInvalidArguments() { - $this->expectException(\InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); + /** @psalm-suppress NullArgument */ System::writeFile(null, null, null); } @@ -184,7 +187,7 @@ class SystemTest extends TestCase $this->assertFileExists($filename); - $this->clearInstance($config, '\SimpleSAML\Configuration'); + $this->clearInstance($config, Configuration::class); } @@ -208,7 +211,7 @@ class SystemTest extends TestCase $this->assertEquals($expected, $res); - $this->clearInstance($config, '\SimpleSAML\Configuration'); + $this->clearInstance($config, Configuration::class); } @@ -232,7 +235,7 @@ class SystemTest extends TestCase $this->assertEquals($expected, $res); - $this->clearInstance($config, '\SimpleSAML\Configuration'); + $this->clearInstance($config, Configuration::class); } @@ -252,7 +255,7 @@ class SystemTest extends TestCase $this->assertEquals($expected, $res); $this->assertFileExists($res); - $this->clearInstance($config, '\SimpleSAML\Configuration'); + $this->clearInstance($config, Configuration::class); } @@ -272,7 +275,7 @@ class SystemTest extends TestCase $this->assertEquals($expected, $res); $this->assertFileExists($res); - $this->clearInstance($config, '\SimpleSAML\Configuration'); + $this->clearInstance($config, Configuration::class); } @@ -298,7 +301,7 @@ class SystemTest extends TestCase $this->expectException(\SimpleSAML\Error\Exception::class); System::getTempDir(); - $this->clearInstance($config, '\SimpleSAML\Configuration'); + $this->clearInstance($config, Configuration::class); } @@ -306,7 +309,7 @@ class SystemTest extends TestCase * @param string $directory * @return \SimpleSAML\Configuration */ - private function setConfigurationTempDir($directory) + private function setConfigurationTempDir(string $directory): Configuration { $config = Configuration::loadFromArray([ 'tempdir' => $directory, @@ -318,12 +321,12 @@ class SystemTest extends TestCase /** * @param \SimpleSAML\Configuration $service - * @param string $className + * @param class-string $className * @return void */ protected function clearInstance(Configuration $service, $className) { - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new ReflectionClass($className); $reflectedInstance = $reflectedClass->getProperty('instance'); $reflectedInstance->setAccessible(true); $reflectedInstance->setValue($service, null); diff --git a/tests/lib/SimpleSAML/XML/SignerTest.php b/tests/lib/SimpleSAML/XML/SignerTest.php index 67b1f64f4c828d9f88e619c4532d270c957ebbd1..a8396d44fe42e0e0b59436984539151e3d48e36e 100644 --- a/tests/lib/SimpleSAML/XML/SignerTest.php +++ b/tests/lib/SimpleSAML/XML/SignerTest.php @@ -2,8 +2,12 @@ namespace SimpleSAML\Test\XML; +use DOMDocument; +use DOMElement; +use Exception; use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\TestCase; +use ReflectionClass; use SimpleSAML\Configuration; use SimpleSAML\Test\SigningTestCase; use SimpleSAML\XML\Signer; @@ -78,12 +82,14 @@ NOWDOC; */ public function testSignBasic() { - $node = new \DOMDocument(); + $node = new DOMDocument(); $node->loadXML('<?xml version="1.0"?><node>value</node>'); + + /** @psalm-var DOMElement $element */ $element = $node->getElementsByTagName("node")->item(0); - $doc = new \DOMDocument(); - $insertInto = $doc->appendChild(new \DOMElement('insert')); + $doc = new DOMDocument(); + $insertInto = $doc->appendChild(new DOMElement('insert')); $signer = new Signer([]); $signer->loadPrivateKey($this->good_private_key_file, null, true); @@ -117,12 +123,14 @@ NOWDOC; */ public function testSignWithCertificate() { - $node = new \DOMDocument(); + $node = new DOMDocument(); $node->loadXML('<?xml version="1.0"?><node>value</node>'); + + /** @psalm-var DOMElement $element */ $element = $node->getElementsByTagName("node")->item(0); - $doc = new \DOMDocument(); - $insertInto = $doc->appendChild(new \DOMElement('insert')); + $doc = new DOMDocument(); + $insertInto = $doc->appendChild(new DOMElement('insert')); $signer = new Signer([]); $signer->loadPrivateKey($this->good_private_key_file, null, true); @@ -145,12 +153,14 @@ NOWDOC; { $this->other_certificate_file = $this->certdir . DIRECTORY_SEPARATOR . self::OTHER_CERTIFICATE; - $node = new \DOMDocument(); + $node = new DOMDocument(); $node->loadXML('<?xml version="1.0"?><node>value</node>'); + + /** @psalm-var DOMElement $element */ $element = $node->getElementsByTagName("node")->item(0); - $doc = new \DOMDocument(); - $insertInto = $doc->appendChild(new \DOMElement('insert')); + $doc = new DOMDocument(); + $insertInto = $doc->appendChild(new DOMElement('insert')); $signer = new Signer([]); $signer->loadPrivateKey($this->good_private_key_file, null, true); @@ -174,29 +184,31 @@ NOWDOC; */ public function testSignMissingPrivateKey() { - $node = new \DOMDocument(); + $node = new DOMDocument(); $node->loadXML('<?xml version="1.0"?><node>value</node>'); + + /** @psalm-var DOMElement $element */ $element = $node->getElementsByTagName("node")->item(0); - $doc = new \DOMDocument(); - $insertInto = $doc->appendChild(new \DOMElement('insert')); + $doc = new DOMDocument(); + $insertInto = $doc->appendChild(new DOMElement('insert')); $signer = new Signer([]); - $this->expectException(\Exception::class); + $this->expectException(Exception::class); $signer->sign($element, $insertInto); } /** * @param \SimpleSAML\Configuration $service - * @param string $className + * @param class-string $className * @param mixed|null $value * @return void */ protected function clearInstance(Configuration $service, $className, $value = null) { - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new ReflectionClass($className); $reflectedInstance = $reflectedClass->getProperty('instance'); $reflectedInstance->setAccessible(true); $reflectedInstance->setValue($service, $value); diff --git a/tests/lib/SimpleSAML/XML/ValidatorTest.php b/tests/lib/SimpleSAML/XML/ValidatorTest.php index c4092d341d65ef6979e64abadadcd0982f9684d6..f6bb17f6d87695e5c8d91e67f01e0ab805340cc8 100644 --- a/tests/lib/SimpleSAML/XML/ValidatorTest.php +++ b/tests/lib/SimpleSAML/XML/ValidatorTest.php @@ -2,6 +2,8 @@ namespace SimpleSAML\Test\XML; +use DOMDocument; +use DOMElement; use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\TestCase; use SimpleSAML\Test\SigningTestCase; @@ -31,9 +33,10 @@ class ValidatorTest extends SigningTestCase */ public function testGetX509Certificate() { - $doc = new \DOMDocument(); + $doc = new DOMDocument(); $doc->loadXML('<?xml version="1.0"?><node>value</node>'); + /** @psalm-var DOMElement $node */ $node = $doc->getElementsByTagName('node')->item(0); $signature_parent = $doc->appendChild(new \DOMElement('signature_parent')); @@ -59,9 +62,10 @@ class ValidatorTest extends SigningTestCase */ public function testCertFingerprintSuccess() { - $doc = new \DOMDocument(); + $doc = new DOMDocument(); $doc->loadXML('<?xml version="1.0"?><node>value</node>'); + /** @psalm-var DOMElement $node */ $node = $doc->getElementsByTagName('node')->item(0); $signature_parent = $doc->appendChild(new \DOMElement('signature_parent')); @@ -88,9 +92,10 @@ class ValidatorTest extends SigningTestCase */ public function testCertFingerprintFailure() { - $doc = new \DOMDocument(); + $doc = new DOMDocument(); $doc->loadXML('<?xml version="1.0"?><node>value</node>'); + /** @psalm-var DOMElement $node */ $node = $doc->getElementsByTagName('node')->item(0); $signature_parent = $doc->appendChild(new \DOMElement('signature_parent')); @@ -110,9 +115,10 @@ class ValidatorTest extends SigningTestCase */ public function testValidateFingerprintSuccess() { - $doc = new \DOMDocument(); + $doc = new DOMDocument(); $doc->loadXML('<?xml version="1.0"?><node>value</node>'); + /** @psalm-var DOMElement $node */ $node = $doc->getElementsByTagName('node')->item(0); $signature_parent = $doc->appendChild(new \DOMElement('signature_parent')); @@ -136,9 +142,10 @@ class ValidatorTest extends SigningTestCase */ public function testValidateFingerprintFailure() { - $doc = new \DOMDocument(); + $doc = new DOMDocument(); $doc->loadXML('<?xml version="1.0"?><node>value</node>'); + /** @psalm-var DOMElement $node */ $node = $doc->getElementsByTagName('node')->item(0); $signature_parent = $doc->appendChild(new \DOMElement('signature_parent')); @@ -162,9 +169,10 @@ class ValidatorTest extends SigningTestCase */ public function testIsNodeValidatedSuccess() { - $doc = new \DOMDocument(); + $doc = new DOMDocument(); $doc->loadXML('<?xml version="1.0"?><node>value</node>'); + /** @psalm-var DOMElement $node */ $node = $doc->getElementsByTagName('node')->item(0); $signature_parent = $doc->appendChild(new \DOMElement('signature_parent')); @@ -190,10 +198,13 @@ class ValidatorTest extends SigningTestCase */ public function testIsNodeValidatedFailure() { - $doc = new \DOMDocument(); + $doc = new DOMDocument(); $doc->loadXML('<?xml version="1.0"?><parent><node1>value1</node1><node2>value2</node2></parent>'); + /** @psalm-var DOMElement $node1 */ $node1 = $doc->getElementsByTagName('node1')->item(0); + + /** @psalm-var DOMElement $node2 */ $node2 = $doc->getElementsByTagName('node2')->item(0); $signature_parent = $doc->appendChild(new \DOMElement('signature_parent')); diff --git a/tests/modules/core/lib/Auth/Process/CardinalitySingleTest.php b/tests/modules/core/lib/Auth/Process/CardinalitySingleTest.php index 1adc23ba5491e7dfc3efde5f0d712100d6e66c42..136c5813702a48e35763d8544329d295abc7e572 100644 --- a/tests/modules/core/lib/Auth/Process/CardinalitySingleTest.php +++ b/tests/modules/core/lib/Auth/Process/CardinalitySingleTest.php @@ -20,7 +20,7 @@ class CardinalitySingleTest extends \PHPUnit\Framework\TestCase * @param array $request The request state. * @return array The state array after processing. */ - private function processFilter(array $config, array $request) + private function processFilter(array $config, array $request): array { $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'GET'; diff --git a/tests/modules/core/lib/Auth/Process/CardinalityTest.php b/tests/modules/core/lib/Auth/Process/CardinalityTest.php index 21d2408f563de0e7dbc2ec223c87eb08780e3f5c..edcebb727cbfa501d64e94184dec55249573c62c 100644 --- a/tests/modules/core/lib/Auth/Process/CardinalityTest.php +++ b/tests/modules/core/lib/Auth/Process/CardinalityTest.php @@ -21,7 +21,7 @@ class CardinalityTest extends \PHPUnit\Framework\TestCase * @param array $request The request state. * @return array The state array after processing. */ - private function processFilter(array $config, array $request) + private function processFilter(array $config, array $request): array { $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'GET'; diff --git a/tests/modules/saml/lib/Auth/Process/FilterScopesTest.php b/tests/modules/saml/lib/Auth/Process/FilterScopesTest.php index 8805be13101198784f90e4b6c69f89cfa2a4c7aa..561c78bbd94aea82f571bb381e209b6fe59792f1 100644 --- a/tests/modules/saml/lib/Auth/Process/FilterScopesTest.php +++ b/tests/modules/saml/lib/Auth/Process/FilterScopesTest.php @@ -19,7 +19,7 @@ class FilterScopesTest extends TestCase * @param array $request The request state. * @return array The state array after processing. */ - private function processFilter(array $config, array $request) + private function processFilter(array $config, array $request): array { $filter = new \SimpleSAML\Module\saml\Auth\Process\FilterScopes($config, null); $filter->process($request); diff --git a/tests/modules/saml/lib/Auth/Process/NameIDAttributeTest.php b/tests/modules/saml/lib/Auth/Process/NameIDAttributeTest.php index ee5af3c337f20e7f420a2228df33a88880858912..13bd08314a128a2b3f8027376c3e366d75fd4f4c 100644 --- a/tests/modules/saml/lib/Auth/Process/NameIDAttributeTest.php +++ b/tests/modules/saml/lib/Auth/Process/NameIDAttributeTest.php @@ -23,7 +23,7 @@ class NameIDAttributeTest extends TestCase * @param array $request The request state. * @return array The state array after processing. */ - private function processFilter(array $config, array $request) + private function processFilter(array $config, array $request): array { $filter = new NameIDAttribute($config, null); $filter->process($request); diff --git a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php index 664c7f1cc064693a5364ee01004e2cdee7450ef1..181f7d4ff021f6c06b4cb078e0ca3f8fd3da1bc7 100644 --- a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php +++ b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php @@ -31,7 +31,7 @@ class SPTest extends ClearStateTestCase /** * @return \SimpleSAML\Configuration */ - private function getIdpMetadata() + private function getIdpMetadata(): Configuration { if (!$this->idpMetadata) { $this->idpMetadata = new Configuration( diff --git a/tests/modules/saml/lib/IdP/SAML2Test.php b/tests/modules/saml/lib/IdP/SAML2Test.php index cf3415680cc1b33d9036e324aa05c6708eb1897d..94dcef988afeef1dc5dc123f52a72fcdc3feef35 100644 --- a/tests/modules/saml/lib/IdP/SAML2Test.php +++ b/tests/modules/saml/lib/IdP/SAML2Test.php @@ -158,7 +158,7 @@ class SAML2Test extends ClearStateTestCase * @param array $queryParams * @return array The state array used for handling the authentication request. */ - private function idpInitiatedHelper(array $queryParams) + private function idpInitiatedHelper(array $queryParams): array { /** @var \PHPUnit_Framework_MockObject_MockObject $idpStub */ $idpStub = $this->getMockBuilder(IdP::class) diff --git a/tests/modules/saml/lib/IdP/SQLNameIDTest.php b/tests/modules/saml/lib/IdP/SQLNameIDTest.php index be43071d2703d7f1bfdc85a51c0cc1af3b2b765b..17ef569278af2207b411557eac592de775b5d63a 100644 --- a/tests/modules/saml/lib/IdP/SQLNameIDTest.php +++ b/tests/modules/saml/lib/IdP/SQLNameIDTest.php @@ -96,7 +96,7 @@ class SQLNameIDTest extends TestCase /** * @param \SimpleSAML\Configuration|\SimpleSAML\Store $service - * @param string $className + * @param class-string $className * @return void */ protected function clearInstance($service, $className) diff --git a/tests/www/TemplateTest.php b/tests/www/TemplateTest.php deleted file mode 100644 index 7bba7931b924de212b5423e438963f4535445f5d..0000000000000000000000000000000000000000 --- a/tests/www/TemplateTest.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php - -namespace SimpleSAML\Test\Web; - -use PHPUnit\Framework\TestCase; -use SimpleSAML\Configuration; -use SimpleSAML\XHTML\Template; -use SimpleSAML\Module; -use Twig\Error\SyntaxError; - -/** - * Simple test for syntax-checking Twig-templates. - * - * @author Tim van Dijen <tvdijen@gmail.com> - * @package SimpleSAMLphp - */ -class TemplateTest extends TestCase -{ - /** - * @return void - */ - public function testSyntax() - { - $config = Configuration::loadFromArray([ - 'usenewui' => true, - 'module.enable' => array_fill_keys(Module::getModules(), true), - ]); - Configuration::setPreLoadedConfig($config); - - $basedir = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'templates'; - - // Base templates - $files = array_diff(scandir($basedir), ['.', '..']); - foreach ($files as $file) { - if (preg_match('/.twig$/', $file)) { - $t = new Template($config, $file); - ob_start(); - try { - $t->show(); - $this->addToAssertionCount(1); - } catch (SyntaxError $e) { - $this->fail($e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine()); - } - ob_end_clean(); - } - } - - // Module templates - foreach (Module::getModules() as $module) { - $basedir = Module::getModuleDir($module) . DIRECTORY_SEPARATOR . 'templates'; - if (file_exists($basedir)) { - $files = array_diff(scandir($basedir), ['.', '..']); - foreach ($files as $file) { - if (preg_match('/.twig$/', $file)) { - $t = new Template($config, $module . ':' . $file); - ob_start(); - try { - $t->show(); - $this->addToAssertionCount(1); - } catch (SyntaxError $e) { - $this->fail($e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine()); - } - ob_end_clean(); - } - } - } - } - } -}