diff --git a/docs/simplesamlphp-upgrade-notes-2.0.md b/docs/simplesamlphp-upgrade-notes-2.0.md index 08c4f712cdb57d63781d4923adc935521c05b7aa..d90f914e8741a8e6716374f73802ab6e62c746fe 100644 --- a/docs/simplesamlphp-upgrade-notes-2.0.md +++ b/docs/simplesamlphp-upgrade-notes-2.0.md @@ -13,3 +13,20 @@ Upgrade notes for SimpleSAMLphp 2.0 - If you're using the core:TargetedID authproc-filter, note that the `attributename` setting has been renamed to `identifyingAttribute`. - The default encryption algorithm is set from AES128_CBC to AES128_GCM. If you're upgrading from an existing implementation, you may want to manually switch back the `sharedkey_algorithm`. Note that CBC is vulnerable to the Padding oracle attack. +- The following classes have been migrated to non-static: + + lib/SimpleSAMLphp\Utils\Arrays + + lib/SimpleSAMLphp\Utils\Attributes + + lib/SimpleSAMLphp\Utils\Auth + + lib/SimpleSAMLphp\Utils\Config + + lib/SimpleSAMLphp\Utils\Crypto + + If you use any of these classes in your modules or themes, you will now have to instantiate them so that: + + // Old style + $x = \SimpleSAML\Utils\Arrays::arrayize($someVar) + + becomes: + + // New style + $arrayUtils = new \SimpleSAML\Utils\Arrays(); + $x = $arrayUtils->arrayize($someVar); diff --git a/docs/simplesamlphp-upgrade-notes.md b/docs/simplesamlphp-upgrade-notes.md index 58833c9eda846a691314563eee449c513e690f56..0f8e63ad97e2c5934fe60ba5d50473964ded41e7 100644 --- a/docs/simplesamlphp-upgrade-notes.md +++ b/docs/simplesamlphp-upgrade-notes.md @@ -4,6 +4,8 @@ SimpeSAMLphp Upgrade Notes See the following pages for important information for users upgrading from older versions of SimpleSAMLphp: +* [Upgrade notes for version 2.0](simplesamlphp-upgrade-notes-2.0) +* [Upgrade notes for version 1.19](simplesamlphp-upgrade-notes-1.19) * [Upgrade notes for version 1.18](simplesamlphp-upgrade-notes-1.18) * [Upgrade notes for version 1.17](simplesamlphp-upgrade-notes-1.17) * [Upgrade notes for version 1.16](simplesamlphp-upgrade-notes-1.16) diff --git a/lib/SimpleSAML/Configuration.php b/lib/SimpleSAML/Configuration.php index 78e1cf80e067a0617b25b7ab058eb8eb6c35ee2e..0a8ebb8d1dc6bf58936ae5b9cf4233eea48cc3c9 100644 --- a/lib/SimpleSAML/Configuration.php +++ b/lib/SimpleSAML/Configuration.php @@ -233,7 +233,8 @@ class Configuration implements Utils\ClearableState if ($configSet !== 'simplesaml') { throw new \Exception('Configuration set \'' . $configSet . '\' not initialized.'); } else { - self::$configDirs['simplesaml'] = Utils\Config::getConfigDir(); + $configUtils = new Utils\Config(); + self::$configDirs['simplesaml'] = $configUtils->getConfigDir(); } } @@ -262,7 +263,8 @@ class Configuration implements Utils\ClearableState if ($configSet !== 'simplesaml') { throw new \Exception('Configuration set \'' . $configSet . '\' not initialized.'); } else { - self::$configDirs['simplesaml'] = Utils\Config::getConfigDir(); + $configUtils = new Utils\Config(); + self::$configDirs['simplesaml'] = $configUtils->getConfigDir(); } } @@ -1158,8 +1160,10 @@ class Configuration implements Utils\ClearableState ], ]; } elseif ($this->hasValue($prefix . 'certificate')) { + $configUtils = new Utils\Config(); + $file = $this->getString($prefix . 'certificate'); - $file = Utils\Config::getCertPath($file); + $file = $configUtils->getCertPath($file); $data = @file_get_contents($file); if ($data === false) { diff --git a/lib/SimpleSAML/Memcache.php b/lib/SimpleSAML/Memcache.php index 156e0bafc1a2636806d78f6e3557bfe760a9b43b..0a9dbf8288e9046002003f07ef700bb079296875 100644 --- a/lib/SimpleSAML/Memcache.php +++ b/lib/SimpleSAML/Memcache.php @@ -417,8 +417,9 @@ class Memcache } } + $arrayUtils = new Utils\Arrays(); /** @psalm-var array $stats */ - $stats = Utils\Arrays::transpose($stats); + $stats = $arrayUtils->transpose($stats); $ret = array_merge_recursive($ret, $stats); } diff --git a/lib/SimpleSAML/Metadata/SAMLBuilder.php b/lib/SimpleSAML/Metadata/SAMLBuilder.php index 2f79664813dc0c4054706cb0228d492010e8887c..a5961190a49b973fe9c9e828bb50d0841dbd82c9 100644 --- a/lib/SimpleSAML/Metadata/SAMLBuilder.php +++ b/lib/SimpleSAML/Metadata/SAMLBuilder.php @@ -340,9 +340,11 @@ class SAMLBuilder return; } - $orgName = Utils\Arrays::arrayize($metadata['OrganizationName'], 'en'); - $orgDisplayName = Utils\Arrays::arrayize($metadata['OrganizationDisplayName'], 'en'); - $orgURL = Utils\Arrays::arrayize($metadata['OrganizationURL'], 'en'); + $arrayUtils = new Utils\Arrays(); + + $orgName = $arrayUtils->arrayize($metadata['OrganizationName'], 'en'); + $orgDisplayName = $arrayUtils->arrayize($metadata['OrganizationDisplayName'], 'en'); + $orgURL = $arrayUtils->arrayize($metadata['OrganizationURL'], 'en'); $this->addOrganization($orgName, $orgDisplayName, $orgURL); } diff --git a/lib/SimpleSAML/Metadata/SAMLParser.php b/lib/SimpleSAML/Metadata/SAMLParser.php index e94509d12420e80848b8488ea5b748095dc00a29..a81a102801c68f3eb6e6637008e1dfd8250011ec 100644 --- a/lib/SimpleSAML/Metadata/SAMLParser.php +++ b/lib/SimpleSAML/Metadata/SAMLParser.php @@ -1298,9 +1298,11 @@ class SAMLParser */ public function validateSignature(array $certificates): bool { + $configUtils = new Utils\Config(); + foreach ($certificates as $cert) { Assert::string($cert); - $certFile = Utils\Config::getCertPath($cert); + $certFile = $configUtils->getCertPath($cert); if (!file_exists($certFile)) { throw new \Exception( 'Could not find certificate file [' . $certFile . '], which is needed to validate signature' diff --git a/lib/SimpleSAML/Metadata/Signer.php b/lib/SimpleSAML/Metadata/Signer.php index 7d5d6a0a8cd9714939d3772a210dfc959afcd674..01c1cffc3596fcce924c6cffa83cda8ff7edcf55 100644 --- a/lib/SimpleSAML/Metadata/Signer.php +++ b/lib/SimpleSAML/Metadata/Signer.php @@ -226,6 +226,7 @@ class Signer public static function sign(string $metadataString, array $entityMetadata, string $type): string { $config = Configuration::getInstance(); + $configUtils = new Utils\Config(); // check if metadata signing is enabled if (!self::isMetadataSigningEnabled($config, $entityMetadata, $type)) { @@ -235,7 +236,7 @@ class Signer // find the key & certificate which should be used to sign the metadata $keyCertFiles = self::findKeyCert($config, $entityMetadata, $type); - $keyFile = Utils\Config::getCertPath($keyCertFiles['privatekey']); + $keyFile = $configUtils->getCertPath($keyCertFiles['privatekey']); if (!file_exists($keyFile)) { throw new \Exception( 'Could not find private key file [' . $keyFile . '], which is needed to sign the metadata' @@ -243,7 +244,7 @@ class Signer } $keyData = file_get_contents($keyFile); - $certFile = Utils\Config::getCertPath($keyCertFiles['certificate']); + $certFile = $configUtils->getCertPath($keyCertFiles['certificate']); if (!file_exists($certFile)) { throw new \Exception( 'Could not find certificate file [' . $certFile . '], which is needed to sign the metadata' diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php index 438abff785d89539c23de8e2cc160b216f740c4b..5bf2f3e9381ece49072d44502f10d4f38af77c33 100644 --- a/lib/SimpleSAML/Session.php +++ b/lib/SimpleSAML/Session.php @@ -368,7 +368,8 @@ class Session implements Serializable, Utils\ClearableState Logger::warning('Missing AuthToken cookie.'); return null; } - if (!Utils\Crypto::secureCompare($session->authToken, $_COOKIE[$authTokenCookieName])) { + $cryptoUtils = new Utils\Crypto(); + if (!$cryptoUtils->secureCompare($session->authToken, $_COOKIE[$authTokenCookieName])) { Logger::warning('Invalid AuthToken cookie.'); return null; } diff --git a/lib/SimpleSAML/Utils/Arrays.php b/lib/SimpleSAML/Utils/Arrays.php index b667a7fe4d596dce1d4cf7225166e42f6fde015a..b736f130f185432a385515a0b2be84d43258474f 100644 --- a/lib/SimpleSAML/Utils/Arrays.php +++ b/lib/SimpleSAML/Utils/Arrays.php @@ -21,7 +21,7 @@ class Arrays * array. * */ - public static function arrayize($data, $index = 0): array + public function arrayize($data, $index = 0): array { return (is_array($data)) ? $data : [$index => $data]; } @@ -35,7 +35,7 @@ class Arrays * @return array|false The transposed array, or false if $array is not a valid two-dimensional array. * */ - public static function transpose(array $array) + public function transpose(array $array) { $ret = []; foreach ($array as $k1 => $a2) { diff --git a/lib/SimpleSAML/Utils/Attributes.php b/lib/SimpleSAML/Utils/Attributes.php index 047efd52235d230e145f186c0fd5fe3ded070894..e778cb12bfb8ee8cefc55ef3ec49c7f687908aa0 100644 --- a/lib/SimpleSAML/Utils/Attributes.php +++ b/lib/SimpleSAML/Utils/Attributes.php @@ -27,7 +27,7 @@ class Attributes * @throws \InvalidArgumentException If $attributes is not an array or $expected is not a string. * @throws \SimpleSAML\Error\Exception If the expected attribute was not found in the attributes array. */ - public static function getExpectedAttribute(array $attributes, string $expected, bool $allow_multiple = false) + public function getExpectedAttribute(array $attributes, string $expected, bool $allow_multiple = false) { if (!array_key_exists($expected, $attributes)) { throw new Error\Exception("No such attribute '" . $expected . "' found."); @@ -66,7 +66,7 @@ class Attributes * not strings. * */ - public static function normalizeAttributesArray(array $attributes): array + public function normalizeAttributesArray(array $attributes): array { $newAttrs = []; foreach ($attributes as $name => $values) { @@ -74,7 +74,8 @@ class Attributes throw new \InvalidArgumentException('Invalid attribute name: "' . print_r($name, true) . '".'); } - $values = Arrays::arrayize($values); + $arrayUtils = new Arrays(); + $values = $arrayUtils->arrayize($values); foreach ($values as $value) { if (!is_string($value)) { @@ -103,7 +104,7 @@ class Attributes * * @return array The attribute name, split to the namespace and the actual attribute name. */ - public static function getAttributeNamespace(string $name, string $defaultns): array + public function getAttributeNamespace(string $name, string $defaultns): array { $slash = strrpos($name, '/'); if ($slash !== false) { diff --git a/lib/SimpleSAML/Utils/Auth.php b/lib/SimpleSAML/Utils/Auth.php index 614749aee98382b54d0f76667d10faa4f40f277c..9a1526f4ccdb68b87855ff145506df0ca6fa8eb0 100644 --- a/lib/SimpleSAML/Utils/Auth.php +++ b/lib/SimpleSAML/Utils/Auth.php @@ -24,7 +24,7 @@ class Auth * @return string A URL which can be used for admin authentication. * @throws \InvalidArgumentException If $returnTo is neither a string nor null. */ - public static function getAdminLoginURL(?string $returnTo = null): string + public function getAdminLoginURL(?string $returnTo = null): string { if ($returnTo === null) { $returnTo = HTTP::getSelfURL(); @@ -42,7 +42,7 @@ class Auth * @return string A URL which can be used for logging out. * @throws \InvalidArgumentException If $returnTo is neither a string nor null. */ - public static function getAdminLogoutURL(?string $returnTo = null): string + public function getAdminLogoutURL(?string $returnTo = null): string { $as = new Authentication\Simple('admin'); return $as->getLogoutURL($returnTo); @@ -55,7 +55,7 @@ class Auth * @return boolean True if the current user is an admin user, false otherwise. * */ - public static function isAdmin(): bool + public function isAdmin(): bool { $session = Session::getSessionFromRequest(); return $session->isValid('admin') || $session->isValid('login-admin'); @@ -71,9 +71,9 @@ class Auth * @throws \SimpleSAML\Error\Exception If no "admin" authentication source was configured. * */ - public static function requireAdmin(): void + public function requireAdmin(): void { - if (self::isAdmin()) { + if ($this->isAdmin()) { return; } diff --git a/lib/SimpleSAML/Utils/Config.php b/lib/SimpleSAML/Utils/Config.php index 6e4c029f6e757adf3e90a39dd4d77013e5f188dd..354da68eee81107692cc90f09fec0fffbc0b5b8f 100644 --- a/lib/SimpleSAML/Utils/Config.php +++ b/lib/SimpleSAML/Utils/Config.php @@ -22,7 +22,7 @@ class Config * @throws \InvalidArgumentException If $path is not a string. * */ - public static function getCertPath(string $path): string + public function getCertPath(string $path): string { $globalConfig = Configuration::getInstance(); $base = $globalConfig->getPathValue('certdir', 'cert/'); @@ -44,7 +44,7 @@ class Config * @throws \InvalidArgumentException If the secret salt hasn't been configured. * */ - public static function getSecretSalt(): string + public function getSecretSalt(): string { $secretSalt = Configuration::getInstance()->getString('secretsalt'); if ($secretSalt === 'defaultsecretsalt') { @@ -62,7 +62,7 @@ class Config * * @return string The path to the configuration directory. */ - public static function getConfigDir(): string + public function getConfigDir(): string { $configDir = dirname(dirname(dirname(__DIR__))) . '/config'; $configDirEnv = getenv('SIMPLESAMLPHP_CONFIG_DIR'); diff --git a/lib/SimpleSAML/Utils/Crypto.php b/lib/SimpleSAML/Utils/Crypto.php index efd2aba4320b8334211986bb343d4df8ee79bc84..d7c9bfbae2b35fab0d3b5ca1c729f5c7f9aebdba 100644 --- a/lib/SimpleSAML/Utils/Crypto.php +++ b/lib/SimpleSAML/Utils/Crypto.php @@ -29,8 +29,12 @@ class Crypto * * @see \SimpleSAML\Utils\Crypto::aesDecrypt() */ - private static function aesDecryptInternal(string $ciphertext, string $secret): string + private function aesDecryptInternal(string $ciphertext, string $secret): string { + if (!extension_loaded('openssl')) { + throw new Error\Exception("The openssl PHP module is not loaded."); + } + /** @var int $len */ $len = mb_strlen($ciphertext, '8bit'); if ($len < 48) { @@ -38,9 +42,6 @@ class Crypto 'Input parameter "$ciphertext" must be a string with more than 48 characters.' ); } - if (!function_exists("openssl_decrypt")) { - throw new Error\Exception("The openssl PHP module is not loaded."); - } // derive encryption and authentication keys from the secret $key = openssl_digest($secret, 'sha512'); @@ -50,7 +51,7 @@ class Crypto $msg = mb_substr($ciphertext, 48, $len - 48, '8bit'); // authenticate the ciphertext - if (self::secureCompare(hash_hmac('sha256', $iv . $msg, substr($key, 64, 64), true), $hmac)) { + if ($this->secureCompare(hash_hmac('sha256', $iv . $msg, substr($key, 64, 64), true), $hmac)) { $plaintext = openssl_decrypt( $msg, 'AES-256-CBC', @@ -72,15 +73,22 @@ class Crypto * Decrypt data using AES-256-CBC and the system-wide secret salt as key. * * @param string $ciphertext The HMAC of the encrypted data, the IV used and the encrypted data, concatenated. + * @param string $secret The secret to use to decrypt the data. + * If not provided, the secret salt from the configuration will be used * * @return string The decrypted data. * @throws \InvalidArgumentException If $ciphertext is not a string. * @throws Error\Exception If the openssl module is not loaded. * */ - public static function aesDecrypt(string $ciphertext): string + public function aesDecrypt(string $ciphertext, string $secret = null): string { - return self::aesDecryptInternal($ciphertext, Config::getSecretSalt()); + if ($secret === null) { + $configUtils = new Config(); + $secret = $configUtils->getSecretSalt(); + } + + return $this->aesDecryptInternal($ciphertext, $secret); } @@ -96,9 +104,9 @@ class Crypto * * @see \SimpleSAML\Utils\Crypto::aesEncrypt() */ - private static function aesEncryptInternal(string $data, string $secret): string + private function aesEncryptInternal(string $data, string $secret): string { - if (!function_exists("openssl_encrypt")) { + if (!extension_loaded('openssl')) { throw new Error\Exception('The openssl PHP module is not loaded.'); } @@ -130,15 +138,22 @@ class Crypto * Encrypt data using AES-256-CBC and the system-wide secret salt as key. * * @param string $data The data to encrypt. + * @param string $secret The secret to use to decrypt the data. + * If not provided, the secret salt from the configuration will be used * * @return string An HMAC of the encrypted data, the IV and the encrypted data, concatenated. * @throws \InvalidArgumentException If $data is not a string. * @throws Error\Exception If the openssl module is not loaded. * */ - public static function aesEncrypt(string $data): string + public function aesEncrypt(string $data, string $secret = null): string { - return self::aesEncryptInternal($data, Config::getSecretSalt()); + if ($secret === null) { + $configUtils = new Config(); + $secret = $configUtils->getSecretSalt(); + } + + return $this->aesEncryptInternal($data, $secret); } @@ -150,7 +165,7 @@ class Crypto * @return string The same data encoded in PEM format. * @see RFC7648 for known types and PEM format specifics. */ - public static function der2pem(string $der, string $type = 'CERTIFICATE'): string + public function der2pem(string $der, string $type = 'CERTIFICATE'): string { return "-----BEGIN " . $type . "-----\n" . chunk_split(base64_encode($der), 64, "\n") . @@ -183,7 +198,7 @@ class Crypto * it. * */ - public static function loadPrivateKey( + public function loadPrivateKey( Configuration $metadata, bool $required = false, string $prefix = '', @@ -200,7 +215,8 @@ class Crypto } if (!$full_path) { - $file = Config::getCertPath($file); + $configUtils = new Config(); + $file = $configUtils->getCertPath($file); } $data = @file_get_contents($file); @@ -243,7 +259,7 @@ class Crypto * it. * */ - public static function loadPublicKey(Configuration $metadata, bool $required = false, string $prefix = ''): ?array + public function loadPublicKey(Configuration $metadata, bool $required = false, string $prefix = ''): ?array { $keys = $metadata->getPublicKeys(null, false, $prefix); if (!empty($keys)) { @@ -283,7 +299,7 @@ class Crypto * @throws \InvalidArgumentException If $pem is not encoded in PEM format. * @see RFC7648 for PEM format specifics. */ - public static function pem2der(string $pem): string + public function pem2der(string $pem): string { $pem = trim($pem); $begin = "-----BEGIN "; @@ -311,18 +327,15 @@ class Crypto * @param mixed $algorithm The algorithm to use. Defaults to the system default * * @return string The hashed password. - * @throws \InvalidArgumentException If the input parameter is not a string. + * @throws \Exception If the algorithm is not known ti PHP. * @throws Error\Exception If the algorithm specified is not supported. * * @see hash_algos() * */ - public static function pwHash(string $password, $algorithm = PASSWORD_DEFAULT): string + public function pwHash(string $password, $algorithm = PASSWORD_DEFAULT): string { - if (!is_string($hash = password_hash($password, $algorithm))) { - throw new InvalidArgumentException('Error while hashing password.'); - } - return $hash; + return password_hash($password, $algorithm); } @@ -337,7 +350,7 @@ class Crypto * * @return bool True if both strings are equal, false otherwise. */ - public static function secureCompare(string $known, string $user): bool + public function secureCompare(string $known, string $user): bool { return hash_equals($known, $user); } @@ -354,7 +367,7 @@ class Crypto * @throws Error\Exception If the algorithm specified is not supported. * */ - public static function pwValid(string $hash, string $password): bool + public function pwValid(string $hash, string $password): bool { if (!is_null(password_get_info($password)['algo'])) { throw new Error\Exception("Cannot use a hash value for authentication."); diff --git a/lib/SimpleSAML/Utils/HTTP.php b/lib/SimpleSAML/Utils/HTTP.php index 7ebe99637c369220bc8f68ee2c30401a9b4c29cc..8dc6e0258abcfa7e265523ae9173101dea770a8c 100644 --- a/lib/SimpleSAML/Utils/HTTP.php +++ b/lib/SimpleSAML/Utils/HTTP.php @@ -87,7 +87,8 @@ class HTTP $session_id = $session->getSessionId(); // encrypt the session ID and the random ID - $info = base64_encode(Crypto::aesEncrypt($session_id . ':' . $id)); + $cryptoUtils = new Crypto(); + $info = base64_encode($cryptoUtils->aesEncrypt($session_id . ':' . $id)); $url = Module::getModuleURL('core/postredirect.php', ['RedirInfo' => $info]); return preg_replace('#^https:#', 'http:', $url); diff --git a/lib/SimpleSAML/XML/Signer.php b/lib/SimpleSAML/XML/Signer.php index 898eb639a120ef205967df5c9b76e121fbf32264..24f62d7c3af2004e852f35b7922a5b3c452d8c40 100644 --- a/lib/SimpleSAML/XML/Signer.php +++ b/lib/SimpleSAML/XML/Signer.php @@ -125,7 +125,8 @@ class Signer public function loadPrivateKey(string $file, ?string $pass, bool $full_path = false): void { if (!$full_path) { - $keyFile = Utils\Config::getCertPath($file); + $configUtils = new Utils\Config(); + $keyFile = $configUtils->getCertPath($file); } else { $keyFile = $file; } @@ -182,7 +183,8 @@ class Signer public function loadCertificate(string $file, bool $full_path = false): void { if (!$full_path) { - $certFile = Utils\Config::getCertPath($file); + $configUtils = new Utils\Config(); + $certFile = $configUtils->getCertPath($file); } else { $certFile = $file; } @@ -224,7 +226,8 @@ class Signer public function addCertificate(string $file, bool $full_path = false): void { if (!$full_path) { - $certFile = Utils\Config::getCertPath($file); + $configUtils = new Utils\Config(); + $certFile = $configUtils->getCertPath($file); } else { $certFile = $file; } diff --git a/modules/admin/lib/Controller/Config.php b/modules/admin/lib/Controller/Config.php index e4823002060e6e5eb08a058654d0ddecf8edce07..a7058f8d19ab660f5292c65ac7e761615cc8a309 100644 --- a/modules/admin/lib/Controller/Config.php +++ b/modules/admin/lib/Controller/Config.php @@ -30,10 +30,9 @@ class Config protected Configuration $config; /** - * @var \SimpleSAML\Utils\Auth|string - * @psalm-var \SimpleSAML\Utils\Auth|class-string + * @var \SimpleSAML\Utils\Auth */ - protected $authUtils = Utils\Auth::class; + protected $authUtils; /** @var \SimpleSAML\Module\admin\Controller\Menu */ protected Menu $menu; @@ -53,6 +52,7 @@ class Config $this->config = $config; $this->session = $session; $this->menu = new Menu(); + $this->authUtils = new Utils\Auth(); } @@ -76,12 +76,12 @@ class Config */ public function diagnostics(Request $request): Template { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); $t = new Template($this->config, 'admin:diagnostics.twig'); $t->data = [ 'remaining' => $this->session->getAuthData('admin', 'Expire') - time(), - 'logouturl' => Utils\Auth::getAdminLogoutURL(), + 'logouturl' => $this->authUtils->getAdminLogoutURL(), 'items' => [ 'HTTP_HOST' => [$request->getHost()], 'HTTPS' => $request->isSecure() ? ['on'] : [], @@ -111,7 +111,7 @@ class Config */ public function main(/** @scrutinizer ignore-unused */ Request $request): Template { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); $t = new Template($this->config, 'admin:config.twig'); $t->data = [ @@ -132,12 +132,11 @@ class Config 'saml20idp' => $this->config->getBoolean('enable.saml20-idp', false), ], 'funcmatrix' => $this->getPrerequisiteChecks(), - 'logouturl' => Utils\Auth::getAdminLogoutURL(), + 'logouturl' => $this->authUtils->getAdminLogoutURL(), ]; Module::callHooks('configpage', $t); - $this->menu->addOption('logout', Utils\Auth::getAdminLogoutURL(), Translate::noop('Log out')); - /** @psalm-var \SimpleSAML\XHTML\Template $t */ + $this->menu->addOption('logout', $this->authUtils->getAdminLogoutURL(), Translate::noop('Log out')); return $this->menu->insert($t); } @@ -151,7 +150,7 @@ class Config */ public function phpinfo(/** @scrutinizer ignore-unused */ Request $request): RunnableResponse { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); return new RunnableResponse('phpinfo'); } diff --git a/modules/admin/lib/Controller/Federation.php b/modules/admin/lib/Controller/Federation.php index 2b349d877c895026faf3b0b3ca870e661bb23880..531608d266da26e14383b4702eb82d615102b749 100644 --- a/modules/admin/lib/Controller/Federation.php +++ b/modules/admin/lib/Controller/Federation.php @@ -42,11 +42,11 @@ class Federation */ protected $authSource = Auth\Source::class; - /** - * @var \SimpleSAML\Utils\Auth|string - * @psalm-var \SimpleSAML\Utils\Auth|class-string - */ - protected $authUtils = Utils\Auth::class; + /** @var \SimpleSAML\Utils\Auth */ + protected $authUtils; + + /** @var \SimpleSAML\Utils\Crypto */ + protected $cryptoUtils; /** @var \SimpleSAML\Metadata\MetaDataStorageHandler */ protected MetadataStorageHandler $mdHandler; @@ -65,6 +65,8 @@ class Federation $this->config = $config; $this->menu = new Menu(); $this->mdHandler = MetaDataStorageHandler::getMetadataHandler(); + $this->authUtils = new Utils\Auth(); + $this->cryptoUtils = new Utils\Crypto(); } @@ -111,7 +113,7 @@ class Federation */ public function main(/** @scrutinizer ignore-unused */ Request $request): Template { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); // initialize basic metadata array $hostedSPs = $this->getHostedSP(); @@ -188,7 +190,7 @@ class Federation 'adfs-idp-remote' => Translate::noop('ADFS IdP metadata'), 'adfs-idp-hosted' => Translate::noop('ADFS IdP metadata'), ], - 'logouturl' => Utils\Auth::getAdminLogoutURL(), + 'logouturl' => $this->authUtils->getAdminLogoutURL(), ]; Module::callHooks('federationpage', $t); @@ -396,7 +398,7 @@ class Federation */ public function metadataConverter(Request $request): Template { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); if ($xmlfile = $request->files->get('xmlfile')) { $xmldata = trim(file_get_contents($xmlfile->getPathname())); } elseif ($xmldata = $request->request->get('xmldata')) { @@ -425,7 +427,8 @@ class Federation } // transpose from $entities[entityid][type] to $output[type][entityid] - $output = Utils\Arrays::transpose($entities); + $arrayUtils = new Utils\Arrays(); + $output = $arrayUtils->transpose($entities); // merge all metadata of each type to a single string which should be added to the corresponding file foreach ($output as $type => &$entities) { @@ -461,7 +464,7 @@ class Federation $t = new Template($this->config, 'admin:metadata_converter.twig'); $t->data = [ - 'logouturl' => Utils\Auth::getAdminLogoutURL(), + 'logouturl' => $this->authUtils->getAdminLogoutURL(), 'xmldata' => $xmldata, 'output' => $output, 'error' => $error, @@ -481,7 +484,7 @@ class Federation */ public function downloadCert(Request $request): Response { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); $set = $request->get('set'); $prefix = $request->get('prefix', ''); @@ -500,7 +503,7 @@ class Federation } /** @var array $certInfo Second param ensures non-nullable return-value */ - $certInfo = Utils\Crypto::loadPublicKey($mdconfig, true, $prefix); + $certInfo = $this->cryptoUtils->loadPublicKey($mdconfig, true, $prefix); $response = new Response($certInfo['PEM']); $disposition = $response->headers->makeDisposition( @@ -524,7 +527,7 @@ class Federation */ public function showRemoteEntity(Request $request): Template { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); $entityId = $request->get('entityid'); $set = $request->get('set'); diff --git a/modules/admin/lib/Controller/Test.php b/modules/admin/lib/Controller/Test.php index 3be69e3d967213458d6e496681cfd47c3046e2d0..44ddc3d6f509b4cb59d8476968d6b373d971c653 100644 --- a/modules/admin/lib/Controller/Test.php +++ b/modules/admin/lib/Controller/Test.php @@ -31,10 +31,9 @@ class Test protected Configuration $config; /** - * @var \SimpleSAML\Utils\Auth|string - * @psalm-var \SimpleSAML\Utils\Auth|class-string + * @var \SimpleSAML\Utils\Auth */ - protected $authUtils = Utils\Auth::class; + protected $authUtils; /** * @var \SimpleSAML\Auth\Simple|string @@ -66,6 +65,7 @@ class Test $this->config = $config; $this->session = $session; $this->menu = new Menu(); + $this->authUtils = new Utils\Auth(); } @@ -111,7 +111,7 @@ class Test */ public function main(Request $request, string $as = null) { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); if (is_null($as)) { $t = new Template($this->config, 'admin:authsource_list.twig'); $t->data = [ @@ -161,8 +161,7 @@ class Test Module::callHooks('configpage', $t); Assert::isInstanceOf($t, Template::class); - $this->menu->addOption('logout', Utils\Auth::getAdminLogoutURL(), Translate::noop('Log out')); - /** @var \SimpleSAML\XHTML\Template $t */ + $this->menu->addOption('logout', $this->authUtils->getAdminLogoutURL(), Translate::noop('Log out')); return $this->menu->insert($t); } diff --git a/modules/core/lib/Auth/Process/TargetedID.php b/modules/core/lib/Auth/Process/TargetedID.php index 04b6aefc2c59d78e24f259fb12d415484da7cca2..b4648d02d16b759a73cf1394236ff47f3522891f 100644 --- a/modules/core/lib/Auth/Process/TargetedID.php +++ b/modules/core/lib/Auth/Process/TargetedID.php @@ -47,10 +47,10 @@ class TargetedID extends Auth\ProcessingFilter private bool $generateNameId = false; /** - * @var \SimpleSAML\Utils\Config|string - * @psalm-var \SimpleSAML\Utils\Config|class-string + * @var \SimpleSAML\Utils\Config */ - protected $configUtils = Utils\Config::class; + protected $configUtils; + /** * Initialize this filter. @@ -76,6 +76,8 @@ class TargetedID extends Auth\ProcessingFilter throw new Exception('Invalid value of \'nameId\'-option to core:TargetedID filter.'); } } + + $this->configUtils = new Utils\Config(); } @@ -122,7 +124,7 @@ class TargetedID extends Auth\ProcessingFilter $dstID = ''; } - $secretSalt = $this->configUtils::getSecretSalt(); + $secretSalt = $this->configUtils->getSecretSalt(); $uidData = 'uidhashbase' . $secretSalt; $uidData .= strlen($srcID) . ':' . $srcID; $uidData .= strlen($dstID) . ':' . $dstID; diff --git a/modules/core/lib/Auth/Source/AdminPassword.php b/modules/core/lib/Auth/Source/AdminPassword.php index 82ee499abb98e56e4a568a34ca49c483bfafa9a4..0af50a1ed782534d5c814bada7e7c90311135a59 100644 --- a/modules/core/lib/Auth/Source/AdminPassword.php +++ b/modules/core/lib/Auth/Source/AdminPassword.php @@ -8,6 +8,7 @@ use SimpleSAML\Assert\Assert; use SimpleSAML\Configuration; use SimpleSAML\Error; use SimpleSAML\Module\core\Auth\UserPassBase; +use SimpleSAML\Utils; /** * Authentication source which verifies the password against @@ -59,7 +60,8 @@ class AdminPassword extends UserPassBase throw new Error\Error('WRONGUSERPASS'); } - if (!\SimpleSAML\Utils\Crypto::pwValid($adminPassword, $password)) { + $cryptoUtils = new Utils\Crypto(); + if (!$cryptoUtils->pwValid($adminPassword, $password)) { throw new Error\Error('WRONGUSERPASS'); } return ['user' => ['admin']]; diff --git a/modules/core/lib/Controller/Login.php b/modules/core/lib/Controller/Login.php index a4941bc00fa12976abd3637e486405a52db31ef6..91bb4b6375d6cd1019c00de7869710c115dec3d7 100644 --- a/modules/core/lib/Controller/Login.php +++ b/modules/core/lib/Controller/Login.php @@ -139,8 +139,9 @@ class Login if ($as === null) { // no authentication source specified if (!$default) { + $authUtils = new Utils\Auth(); $t = new Template($this->config, 'core:login.twig'); - $t->data['loginurl'] = Utils\Auth::getAdminLoginURL(); + $t->data['loginurl'] = $authUtils->getAdminLoginURL(); $t->data['sources'] = $this->sources; return $t; } diff --git a/modules/core/lib/Controller/Redirection.php b/modules/core/lib/Controller/Redirection.php index 942dd675c1a3369cd6930de8e110ffbd22c72b36..23141d4346c1d4936dd00624ffbb8a9eb5d38dbc 100644 --- a/modules/core/lib/Controller/Redirection.php +++ b/modules/core/lib/Controller/Redirection.php @@ -31,6 +31,9 @@ class Redirection /** @var \SimpleSAML\Session */ protected Session $session; + /** @var \SimpleSAML\Utils\Crypto */ + protected $cryptoUtils; + /** * Controller constructor. @@ -48,6 +51,7 @@ class Redirection ) { $this->config = $config; $this->session = $session; + $this->cryptoUtils = new Utils\Crypto(); } @@ -72,7 +76,7 @@ class Redirection throw new Error\BadRequest('Invalid RedirInfo data.'); } - list($sessionId, $postId) = explode(':', Utils\Crypto::aesDecrypt($encData)); + list($sessionId, $postId) = explode(':', $this->cryptoUtils->aesDecrypt($encData)); if (empty($sessionId) || empty($postId)) { throw new Error\BadRequest('Invalid session info data.'); diff --git a/modules/core/www/login-admin.php b/modules/core/www/login-admin.php index 3b6443432b2fac05f4464804856f8be71cd4f9b6..a51f6d9c21bec558128c260de2b4ffad3a871864 100644 --- a/modules/core/www/login-admin.php +++ b/modules/core/www/login-admin.php @@ -8,5 +8,6 @@ if (!array_key_exists('ReturnTo', $_REQUEST)) { throw new \SimpleSAML\Error\BadRequest('Missing ReturnTo parameter.'); } -\SimpleSAML\Utils\Auth::requireAdmin(); +$authUtils = new \SimpleSAML\Utils\Auth(); +$authUtils->requireAdmin(); \SimpleSAML\Utils\HTTP::redirectUntrustedURL($_REQUEST['ReturnTo']); diff --git a/modules/cron/lib/Controller/Cron.php b/modules/cron/lib/Controller/Cron.php index 0b6542d7f5862d4070682595e59f641f50f6d8f7..b95cf9d51952171ed1d089ec118adad105652eca 100644 --- a/modules/cron/lib/Controller/Cron.php +++ b/modules/cron/lib/Controller/Cron.php @@ -38,10 +38,9 @@ class Cron protected Session $session; /** - * @var \SimpleSAML\Utils\Auth|string - * @psalm-var \SimpleSAML\Utils\Auth|class-string + * @var \SimpleSAML\Utils\Auth */ - protected $authUtils = Utils\Auth::class; + protected $authUtils; /** @@ -61,6 +60,7 @@ class Cron $this->config = $config; $this->cronconfig = Configuration::getConfig('module_cron.php'); $this->session = $session; + $this->authUtils = new Utils\Auth(); } @@ -83,7 +83,7 @@ class Cron */ public function info(): Template { - $this->authUtils::requireAdmin(); + $this->authUtils->requireAdmin(); $key = $this->cronconfig->getValue('key', 'secret'); $tags = $this->cronconfig->getValue('allowed_tags', []); diff --git a/modules/exampleauth/lib/Auth/Source/StaticSource.php b/modules/exampleauth/lib/Auth/Source/StaticSource.php index fc047932230c450258c5eec79e4413887f09af35..fef70b66816a9b51f75e99a7d342e19eac1bf42b 100644 --- a/modules/exampleauth/lib/Auth/Source/StaticSource.php +++ b/modules/exampleauth/lib/Auth/Source/StaticSource.php @@ -37,9 +37,11 @@ class StaticSource extends Auth\Source // Call the parent constructor first, as required by the interface parent::__construct($info, $config); + $attrUtils = new Utils\Attributes(); + // Parse attributes try { - $this->attributes = Utils\Attributes::normalizeAttributesArray($config); + $this->attributes = $attrUtils->normalizeAttributesArray($config); } catch (Exception $e) { throw new Exception('Invalid attributes for authentication source ' . $this->authId . ': ' . $e->getMessage()); diff --git a/modules/exampleauth/lib/Auth/Source/UserPass.php b/modules/exampleauth/lib/Auth/Source/UserPass.php index e2d08094cdec50b788b5dbb21212147611b99873..b1867f8075971132f538e4c466f4dd6f7f9c528a 100644 --- a/modules/exampleauth/lib/Auth/Source/UserPass.php +++ b/modules/exampleauth/lib/Auth/Source/UserPass.php @@ -60,8 +60,10 @@ class UserPass extends UserPassBase $username = $userpass[0]; $password = $userpass[1]; + $attrUtils = new Utils\Attributes(); + try { - $attributes = Utils\Attributes::normalizeAttributesArray($attributes); + $attributes = $attrUtils->normalizeAttributesArray($attributes); } catch (Exception $e) { throw new Exception('Invalid attributes for user ' . $username . ' in authentication source ' . $this->authId . ': ' . $e->getMessage()); diff --git a/modules/saml/lib/Auth/Process/PersistentNameID.php b/modules/saml/lib/Auth/Process/PersistentNameID.php index b7f825a69ded7d71e84afffb2f1be58d39ab8c66..be583d6d882eb9df35d6876167990338e2747c1f 100644 --- a/modules/saml/lib/Auth/Process/PersistentNameID.php +++ b/modules/saml/lib/Auth/Process/PersistentNameID.php @@ -93,7 +93,8 @@ class PersistentNameID extends BaseNameIDGenerator return null; } - $secretSalt = Utils\Config::getSecretSalt(); + $configUtils = new Utils\Config(); + $secretSalt = $configUtils->getSecretSalt(); $uidData = 'uidhashbase' . $secretSalt; $uidData .= strlen($idpEntityId) . ':' . $idpEntityId; diff --git a/modules/saml/lib/Auth/Source/SP.php b/modules/saml/lib/Auth/Source/SP.php index 9a159796a9978ab1cd53199b23693b94bf439968..4c6a185e7ff1670755d4af0702655ad6e5c4f4cb 100644 --- a/modules/saml/lib/Auth/Source/SP.php +++ b/modules/saml/lib/Auth/Source/SP.php @@ -205,8 +205,10 @@ class SP extends \SimpleSAML\Auth\Source $metadata['contacts'][] = Utils\Config\Metadata::getContact($contact); } + $cryptoUtils = new Utils\Crypto(); + // add certificate(s) - $certInfo = Utils\Crypto::loadPublicKey($this->metadata, false, 'new_'); + $certInfo = $cryptoUtils->loadPublicKey($this->metadata, false, 'new_'); $hasNewCert = false; if ($certInfo !== null && array_key_exists('certData', $certInfo)) { $hasNewCert = true; @@ -228,7 +230,7 @@ class SP extends \SimpleSAML\Auth\Source ]; } - $certInfo = Utils\Crypto::loadPublicKey($this->metadata); + $certInfo = $cryptoUtils->loadPublicKey($this->metadata); if ($certInfo !== null && array_key_exists('certData', $certInfo)) { $metadata['keys'][] = [ 'type' => 'X509Certificate', @@ -456,11 +458,13 @@ class SP extends \SimpleSAML\Auth\Source $ar->setRelayState($state['\SimpleSAML\Auth\Source.ReturnURL']); } + $arrayUtils = new Utils\Arrays(); + $accr = null; if ($idpMetadata->getString('AuthnContextClassRef', false)) { - $accr = Utils\Arrays::arrayize($idpMetadata->getString('AuthnContextClassRef')); + $accr = $arrayUtils->arrayize($idpMetadata->getString('AuthnContextClassRef')); } elseif (isset($state['saml:AuthnContextClassRef'])) { - $accr = Utils\Arrays::arrayize($state['saml:AuthnContextClassRef']); + $accr = $arrayUtils->arrayize($state['saml:AuthnContextClassRef']); } if ($accr !== null) { diff --git a/modules/saml/lib/IdP/SAML2.php b/modules/saml/lib/IdP/SAML2.php index 74a6dc1a7c493130aa3dc5d34c162c24a433c6ae..eeb53c1a05629ebddf1fb9c2b5dcda7d7a5e427d 100644 --- a/modules/saml/lib/IdP/SAML2.php +++ b/modules/saml/lib/IdP/SAML2.php @@ -771,9 +771,11 @@ class SAML2 'NameIDFormat' => $config->getArrayizeString('NameIDFormat', Constants::NAMEID_TRANSIENT), ]; + $cryptoUtils = new Utils\Crypto(); + // add certificates $keys = []; - $certInfo = Utils\Crypto::loadPublicKey($config, false, 'new_'); + $certInfo = $cryptoUtils->loadPublicKey($config, false, 'new_'); $hasNewCert = false; if ($certInfo !== null) { $keys[] = [ @@ -787,7 +789,7 @@ class SAML2 } /** @var array $certInfo */ - $certInfo = Utils\Crypto::loadPublicKey($config, true); + $certInfo = $cryptoUtils->loadPublicKey($config, true); $keys[] = [ 'type' => 'X509Certificate', 'signing' => true, @@ -798,7 +800,7 @@ class SAML2 if ($config->hasValue('https.certificate')) { /** @var array $httpsCert */ - $httpsCert = Utils\Crypto::loadPublicKey($config, true, 'https.'); + $httpsCert = $cryptoUtils->loadPublicKey($config, true, 'https.'); $keys[] = [ 'type' => 'X509Certificate', 'signing' => true, diff --git a/modules/saml/lib/Message.php b/modules/saml/lib/Message.php index 2104296eec3461dd11d1fa69345b6c4c38733409..1115198678820e21522a2760ace2c8356f847ae6 100644 --- a/modules/saml/lib/Message.php +++ b/modules/saml/lib/Message.php @@ -44,15 +44,16 @@ class Message SignedElement $element ): void { $dstPrivateKey = $dstMetadata->getString('signature.privatekey', null); + $cryptoUtils = new Utils\Crypto(); if ($dstPrivateKey !== null) { /** @var array $keyArray */ - $keyArray = Utils\Crypto::loadPrivateKey($dstMetadata, true, 'signature.'); - $certArray = Utils\Crypto::loadPublicKey($dstMetadata, false, 'signature.'); + $keyArray = $cryptoUtils->loadPrivateKey($dstMetadata, true, 'signature.'); + $certArray = $cryptoUtils->loadPublicKey($dstMetadata, false, 'signature.'); } else { /** @var array $keyArray */ - $keyArray = Utils\Crypto::loadPrivateKey($srcMetadata, true); - $certArray = Utils\Crypto::loadPublicKey($srcMetadata, false); + $keyArray = $cryptoUtils->loadPrivateKey($srcMetadata, true); + $certArray = $cryptoUtils->loadPublicKey($srcMetadata, false); } $algo = $dstMetadata->getString('signature.algorithm', null); @@ -264,9 +265,10 @@ class Message } $keys = []; + $cryptoUtils = new Utils\Crypto(); // load the new private key if it exists - $keyArray = Utils\Crypto::loadPrivateKey($dstMetadata, false, 'new_'); + $keyArray = $cryptoUtils->loadPrivateKey($dstMetadata, false, 'new_'); if ($keyArray !== null) { assert::keyExists($keyArray, 'PEM'); @@ -283,7 +285,7 @@ class Message * * @var array $keyArray Because the second param is true */ - $keyArray = Utils\Crypto::loadPrivateKey($dstMetadata, true); + $keyArray = $cryptoUtils->loadPrivateKey($dstMetadata, true); Assert::keyExists($keyArray, 'PEM'); $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, ['type' => 'private']); diff --git a/modules/saml/www/idp/certs.php b/modules/saml/www/idp/certs.php index 5f11e7461db7d38fccabcf090d65fe5996ecfa35..ae3889819943befd4db91ea2f6e1acaa65180222 100644 --- a/modules/saml/www/idp/certs.php +++ b/modules/saml/www/idp/certs.php @@ -10,24 +10,26 @@ if (!$config->getBoolean('enable.saml20-idp', false)) { // Check if valid local session exists.. if ($config->getBoolean('admin.protectmetadata', false)) { - \SimpleSAML\Utils\Auth::requireAdmin(); + $authUtils = new \SimpleSAML\Utils\Auth(); + $authUtils->requireAdmin(); } $idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted'); $idpmeta = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted'); +$cryptoUtils = new \SimpleSAML\Utils\Crypto(); switch ($_SERVER['PATH_INFO']) { case '/new_idp.crt': /** @var array $certInfo */ - $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true, 'new_'); + $certInfo = $cryptoUtils->loadPublicKey($idpmeta, true, 'new_'); break; case '/idp.crt': /** @var array $certInfo */ - $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true); + $certInfo = $cryptoUtils->loadPublicKey($idpmeta, true); break; case '/https.crt': /** @var array $certInfo */ - $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true, 'https.'); + $certInfo = $cryptoUtils->loadPublicKey($idpmeta, true, 'https.'); break; default: throw new \SimpleSAML\Error\NotFound('Unknown certificate.'); diff --git a/modules/saml/www/sp/metadata.php b/modules/saml/www/sp/metadata.php index d54431233014bcf455d6f704dab250c3931062cf..3b4e847eb5759108e229c74e8cdcd1a36fb52630 100644 --- a/modules/saml/www/sp/metadata.php +++ b/modules/saml/www/sp/metadata.php @@ -18,7 +18,8 @@ if (!array_key_exists('PATH_INFO', $_SERVER)) { $config = Configuration::getInstance(); if ($config->getBoolean('admin.protectmetadata', false)) { - Utils\Auth::requireAdmin(); + $authUtils = new Utils\Auth(); + $authUtils->requireAdmin(); } $sourceId = substr($_SERVER['PATH_INFO'], 1); $source = Auth\Source::getById($sourceId); @@ -123,7 +124,8 @@ foreach ($assertionsconsumerservices as $services) { $metaArray20['AssertionConsumerService'] = $spconfig->getArray('AssertionConsumerService', $eps); $keys = []; -$certInfo = Utils\Crypto::loadPublicKey($spconfig, false, 'new_'); +$cryptoUtils = new Utils\Crypto(); +$certInfo = $cryptoUtils->loadPublicKey($spconfig, false, 'new_'); if ($certInfo !== null && array_key_exists('certData', $certInfo)) { $hasNewCert = true; @@ -139,7 +141,7 @@ if ($certInfo !== null && array_key_exists('certData', $certInfo)) { $hasNewCert = false; } -$certInfo = Utils\Crypto::loadPublicKey($spconfig); +$certInfo = $cryptoUtils->loadPublicKey($spconfig); if ($certInfo !== null && array_key_exists('certData', $certInfo)) { $certData = $certInfo['certData']; diff --git a/tests/lib/SimpleSAML/Utils/ArraysTest.php b/tests/lib/SimpleSAML/Utils/ArraysTest.php index 7267b8ab3ca5875078208afc982241b18a021404..8d297cf6a31f062cb2f4e8dc7327db645adc1a31 100644 --- a/tests/lib/SimpleSAML/Utils/ArraysTest.php +++ b/tests/lib/SimpleSAML/Utils/ArraysTest.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace SimpleSAML\Test\Utils; use PHPUnit\Framework\TestCase; -use SimpleSAML\Utils\Arrays; +use SimpleSAML\Utils; /** * Tests for SimpleSAML\Utils\Arrays. @@ -14,6 +14,22 @@ use SimpleSAML\Utils\Arrays; */ class ArraysTest extends TestCase { + /** @var \SimpleSAML\Utils\Arrays */ + protected $arrayUtils; + + + /** + * Set up for each test. + * @return void + */ + protected function setUp(): void + { + parent::setUp(); + + $this->arrayUtils = new Utils\Arrays(); + } + + /** * Test the arrayize() function. */ @@ -21,23 +37,23 @@ class ArraysTest extends TestCase { // check with empty array as input $array = []; - $this->assertEquals($array, Arrays::arrayize($array)); + $this->assertEquals($array, $this->arrayUtils->arrayize($array)); // check non-empty array as input $array = ['key' => 'value']; - $this->assertEquals($array, Arrays::arrayize($array)); + $this->assertEquals($array, $this->arrayUtils->arrayize($array)); // check indexes are ignored when input is an array - $this->assertArrayNotHasKey('invalid', Arrays::arrayize($array, 'invalid')); + $this->assertArrayNotHasKey('invalid', $this->arrayUtils->arrayize($array, 'invalid')); // check default index $expected = ['string']; - $this->assertEquals($expected, Arrays::arrayize($expected[0])); + $this->assertEquals($expected, $this->arrayUtils->arrayize($expected[0])); // check string index $index = 'key'; $expected = [$index => 'string']; - $this->assertEquals($expected, Arrays::arrayize($expected[$index], $index)); + $this->assertEquals($expected, $this->arrayUtils->arrayize($expected[$index], $index)); } @@ -48,11 +64,11 @@ class ArraysTest extends TestCase { // check bad arrays $this->assertFalse( - Arrays::transpose(['1', '2', '3']), + $this->arrayUtils->transpose(['1', '2', '3']), 'Invalid two-dimensional array was accepted' ); $this->assertFalse( - Arrays::transpose(['1' => 0, '2' => '0', '3' => [0]]), + $this->arrayUtils->transpose(['1' => 0, '2' => '0', '3' => [0]]), 'Invalid elements on a two-dimensional array were accepted' ); @@ -77,7 +93,7 @@ class ArraysTest extends TestCase ]; $this->assertEquals( $transposed, - Arrays::transpose($array), + $this->arrayUtils->transpose($array), 'Unexpected result of transpose()' ); @@ -102,7 +118,7 @@ class ArraysTest extends TestCase ]; $this->assertEquals( $transposed, - Arrays::transpose($array), + $this->arrayUtils->transpose($array), 'Unexpected result of transpose()' ); @@ -129,7 +145,7 @@ class ArraysTest extends TestCase ]; $this->assertEquals( $transposed, - Arrays::transpose($array), + $this->arrayUtils->transpose($array), 'Unexpected result of transpose()' ); } diff --git a/tests/lib/SimpleSAML/Utils/AttributesTest.php b/tests/lib/SimpleSAML/Utils/AttributesTest.php index 452fd46fbb80f8d4575ba411b59cb88a490773ca..4f99ee4c0411c3b460aaff3421f9f88499dbf213 100644 --- a/tests/lib/SimpleSAML/Utils/AttributesTest.php +++ b/tests/lib/SimpleSAML/Utils/AttributesTest.php @@ -16,6 +16,22 @@ use SimpleSAML\Utils\Attributes; */ class AttributesTest extends TestCase { + /** @var \SimpleSAML\Utils\Attributes */ + protected $attrUtils; + + + /** + * Set up for each test. + * @return void + */ + protected function setUp(): void + { + parent::setUp(); + + $this->attrUtils = new Attributes(); + } + + /** * Test the getExpectedAttributeMethod() method with a non-normalized attributes array. */ @@ -30,7 +46,7 @@ class AttributesTest extends TestCase $this->expectExceptionMessage( 'The attributes array is not normalized, values should be arrays.' ); - Attributes::getExpectedAttribute($attributes, $expected); + $this->attrUtils->getExpectedAttribute($attributes, $expected); } @@ -46,7 +62,7 @@ class AttributesTest extends TestCase $expected = 'missing'; $this->expectException(Error\Exception::class); $this->expectExceptionMessage("No such attribute '" . $expected . "' found."); - Attributes::getExpectedAttribute($attributes, $expected); + $this->attrUtils->getExpectedAttribute($attributes, $expected); } @@ -62,7 +78,7 @@ class AttributesTest extends TestCase $expected = 'attribute'; $this->expectException(Error\Exception::class); $this->expectExceptionMessage("Empty attribute '" . $expected . "'.'"); - Attributes::getExpectedAttribute($attributes, $expected); + $this->attrUtils->getExpectedAttribute($attributes, $expected); } @@ -83,7 +99,7 @@ class AttributesTest extends TestCase $this->expectExceptionMessage( 'More than one value found for the attribute, multiple values not allowed.' ); - Attributes::getExpectedAttribute($attributes, $expected); + $this->attrUtils->getExpectedAttribute($attributes, $expected); } @@ -98,7 +114,7 @@ class AttributesTest extends TestCase 'attribute' => [$value], ]; $expected = 'attribute'; - $this->assertEquals($value, Attributes::getExpectedAttribute($attributes, $expected)); + $this->assertEquals($value, $this->attrUtils->getExpectedAttribute($attributes, $expected)); // check multiple (allowed) values $value = 'value'; @@ -106,7 +122,7 @@ class AttributesTest extends TestCase 'attribute' => [$value, 'value2', 'value3'], ]; $expected = 'attribute'; - $this->assertEquals($value, Attributes::getExpectedAttribute($attributes, $expected, true)); + $this->assertEquals($value, $this->attrUtils->getExpectedAttribute($attributes, $expected, true)); } @@ -116,7 +132,7 @@ class AttributesTest extends TestCase public function testNormalizeAttributesArrayBadKeys(): void { $this->expectException(InvalidArgumentException::class); - Attributes::normalizeAttributesArray(['attr1' => 'value1', 1 => 'value2']); + $this->attrUtils->normalizeAttributesArray(['attr1' => 'value1', 1 => 'value2']); } @@ -126,7 +142,7 @@ class AttributesTest extends TestCase public function testNormalizeAttributesArrayBadValues(): void { $this->expectException(InvalidArgumentException::class); - Attributes::normalizeAttributesArray(['attr1' => 'value1', 'attr2' => 0]); + $this->attrUtils->normalizeAttributesArray(['attr1' => 'value1', 'attr2' => 0]); } @@ -147,7 +163,7 @@ class AttributesTest extends TestCase ]; $this->assertEquals( $expected, - Attributes::normalizeAttributesArray($attributes), + $this->attrUtils->normalizeAttributesArray($attributes), 'Attribute array normalization failed' ); } @@ -161,13 +177,13 @@ class AttributesTest extends TestCase // test for only the name $this->assertEquals( ['default', 'name'], - Attributes::getAttributeNamespace('name', 'default') + $this->attrUtils->getAttributeNamespace('name', 'default') ); // test for a given namespace and multiple '/' $this->assertEquals( ['some/namespace', 'name'], - Attributes::getAttributeNamespace('some/namespace/name', 'default') + $this->attrUtils->getAttributeNamespace('some/namespace/name', 'default') ); } } diff --git a/tests/lib/SimpleSAML/Utils/ConfigTest.php b/tests/lib/SimpleSAML/Utils/ConfigTest.php index 3516d455483410ed1284af4b4c326efb9ff6d5f3..2e75b09d6117a6d20b44e3aaab278e29590cf7e3 100644 --- a/tests/lib/SimpleSAML/Utils/ConfigTest.php +++ b/tests/lib/SimpleSAML/Utils/ConfigTest.php @@ -6,7 +6,7 @@ namespace SimpleSAML\Test\Utils; use InvalidArgumentException; use PHPUnit\Framework\TestCase; -use SimpleSAML\Utils\Config; +use SimpleSAML\Utils; /** * Tests for SimpleSAML\Utils\Config @@ -15,6 +15,22 @@ use SimpleSAML\Utils\Config; */ class ConfigTest extends TestCase { + /** @var \SimpleSAML\Utils\Config */ + protected $configUtils; + + + /** + * Set up for each test. + * @return void + */ + protected function setUp(): void + { + parent::setUp(); + + $this->configUtils = new Utils\Config(); + } + + /** * Test default config dir with not environment variable */ @@ -22,7 +38,7 @@ class ConfigTest extends TestCase { // clear env var putenv('SIMPLESAMLPHP_CONFIG_DIR'); - $configDir = Config::getConfigDir(); + $configDir = $this->configUtils->getConfigDir(); $this->assertEquals($configDir, dirname(dirname(dirname(dirname(__DIR__)))) . '/config'); } @@ -34,7 +50,7 @@ class ConfigTest extends TestCase public function testEnvVariableConfigDir(): void { putenv('SIMPLESAMLPHP_CONFIG_DIR=' . __DIR__); - $configDir = Config::getConfigDir(); + $configDir = $this->configUtils->getConfigDir(); $this->assertEquals($configDir, __DIR__); } @@ -45,7 +61,7 @@ class ConfigTest extends TestCase public function testEnvRedirectVariableConfigDir(): void { putenv('REDIRECT_SIMPLESAMLPHP_CONFIG_DIR=' . __DIR__); - $configDir = Config::getConfigDir(); + $configDir = $this->configUtils->getConfigDir(); $this->assertEquals($configDir, __DIR__); } @@ -58,7 +74,7 @@ class ConfigTest extends TestCase { putenv('SIMPLESAMLPHP_CONFIG_DIR=' . dirname(__DIR__)); putenv('REDIRECT_SIMPLESAMLPHP_CONFIG_DIR=' . __DIR__); - $configDir = Config::getConfigDir(); + $configDir = $this->configUtils->getConfigDir(); $this->assertEquals($configDir, dirname(__DIR__)); } @@ -79,6 +95,6 @@ class ConfigTest extends TestCase 'Given: "' . $invalidDir . '"' ); - Config::getConfigDir(); + $this->configUtils->getConfigDir(); } } diff --git a/tests/lib/SimpleSAML/Utils/CryptoTest.php b/tests/lib/SimpleSAML/Utils/CryptoTest.php index fa06c98ecc5273667c39d4753645ea22302bde41..dcc25aebe4a4882f37e2bb0f0ea1075031f44410 100644 --- a/tests/lib/SimpleSAML/Utils/CryptoTest.php +++ b/tests/lib/SimpleSAML/Utils/CryptoTest.php @@ -4,13 +4,14 @@ declare(strict_types=1); namespace SimpleSAML\Test\Utils; +use InvalidArgumentException; use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStreamDirectory; use PHPUnit\Framework\TestCase; use ReflectionMethod; use SimpleSAML\Configuration; use SimpleSAML\Error; -use SimpleSAML\Utils\Crypto; +use SimpleSAML\Utils; /** * Tests for SimpleSAML\Utils\Crypto. @@ -32,11 +33,60 @@ class CryptoTest extends TestCase /** @var string */ protected string $certdir; + /** @var \SimpleSAML\Utils\Crypto */ + protected $cryptoUtils; + + /** @var string */ + protected $pem = <<<PHP +-----BEGIN CERTIFICATE----- +MIIF8zCCA9ugAwIBAgIJANSv0D4ZoP9iMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD +VQQGEwJFWDEQMA4GA1UECAwHRXhhbXBsZTEQMA4GA1UEBwwHRXhhbXBsZTEQMA4G +A1UECgwHRXhhbXBsZTEQMA4GA1UECwwHRXhhbXBsZTEUMBIGA1UEAwwLZXhhbXBs +ZS5jb20xIjAgBgkqhkiG9w0BCQEWE3NvbWVvbmVAZXhhbXBsZS5jb20wHhcNMTcw +MTEwMDk1MTIxWhcNMTgwMTEwMDk1MTIxWjCBjzELMAkGA1UEBhMCRVgxEDAOBgNV +BAgMB0V4YW1wbGUxEDAOBgNVBAcMB0V4YW1wbGUxEDAOBgNVBAoMB0V4YW1wbGUx +EDAOBgNVBAsMB0V4YW1wbGUxFDASBgNVBAMMC2V4YW1wbGUuY29tMSIwIAYJKoZI +hvcNAQkBFhNzb21lb25lQGV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOC +Ag8AMIICCgKCAgEA5Mp4xLdV41NtAI3YYr70G4gJYKegTHRwYhMeYAjudmZUng1/ +vbHLFGQybm8C6naEireQhHWzYfmDkOMU8dmdItwN4YLypYWwxYuWutWWIsDHHe0y +CfjVz6nnTPSjZEq5PpJYY+2XTZOP+g8FmDo4nmhEchF+8eiGvHQzdBqh26EwJjQ3 +LMXyc2F2+9Cm/On+M6BQKvvXkg8FqggW8YwcOujZNWGbfG3LVJcZ0p39PbnNgJX2 +ExbscPHfjmv2RlXd5EjruRhW1oX35sB4ycIFfHGWbCl2HPc1VfouJMq/fxgkKJdb +3RNxIBZnGpBdVJ25lCfk6t2dRdWKECrBHmcX/uR19of4H+hd4zOCPrej8IsCF2IS +1umyUBIDyPE4WciWMUERyG1dxSjUI4DBMi4l+LRX1YUrADSthH/0jV1WDsGpHT26 ++at2ZBgPy8tEvpLsITw/opUKWPCx3u5JVwFdduL8i0UF2yHmcsq44TUHVEoA1c55 +T+46ug7zHzhqFrPIwUN0DTKf33pg30xtL4d1rebc5K1KBNd9IDicd2iL8uD3HG6L +dPdt+1OaSbGlMMKdOte31TdOp7WhqcFANkKxd6TzMUHMVmkbYh2NesaQmCgxJdv6 +/pD7L+sbMKdhlcSoJW+1wwtIo5+CzZxPA2ehZ/IWQg+Oh6djvUJzo0/84ncCAwEA +AaNQME4wHQYDVR0OBBYEFOk6cEb397GMRCJe9xMIZ/y3yFvEMB8GA1UdIwQYMBaA +FOk6cEb397GMRCJe9xMIZ/y3yFvEMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggIBACc1c8j7oZeVDd8O2k97kY/7pHypVZswLfmg1UqbUmYYqQ9lM6FD0J8R +P+B8i7zST09pJ0FOsCsbyUKQmMIq/citTKmgk8NLK8otWHewHs5KTpsEvJm9XV4s +QjF07GBECJdQWu93Rn8FdR9eJ+H0Y0oHbBu3OtSbHFHyDvaCI5bxM/5FPf4HkJil +qIQunhO5gkz21ebukQUgiZ1YmFl0LjxGUDUDwnQ/3kOejlMUQv+ZXdQp/SaX1z5c +dQlGl/8HDs1YAM3duvdMCXn2LP3QuhrphT/+2o+ZkY32I1p/Q0fDNaE4u7JjaxAd +6+ijpmzZwgG5cFVU+sEeDqCI5MFn2JKiSCrHAHFMTnkpq687qBTLWoYTJ4coxtvs +kmvdoZytKiSf7aDzGQK345BSZWJ+D5RJr2250PHMMeNkFBc+GdGiRsABhhHQAqtE +7TVgdwvc8CYCfXlhRzdSowAVWibiftfPMmItM8Z0w5T/iPW0MsiCLGa5AvCHicN7 +pfajpJ9ZzdyLIo6dVjdQtl+S1rpFCx7ziVN8tCCX4fAVCqRqZJaG/UMLvguVqayb +3Aw1B/fVvWoAnAzVN5ZEClZvuyjImnNZpnYSWHzCJ/9JTqB7rq93nf6Olp9QXD5y +5iHKlJ6FlnuhcGCDsUCvG8qCw9FfoS0tuS4tKoQ5WHGQx3sKmr/D +-----END CERTIFICATE----- +PHP; /** */ public function setUp(): void { + $this->config = Configuration::loadFromArray( + [ + 'module.enable' => [], + 'secretsalt' => 'SUPER_SECRET_SALT' + ], + '[ARRAY]', + 'simplesaml' + ); + $this->root = vfsStream::setup( self::ROOTDIRNAME, null, @@ -46,6 +96,7 @@ class CryptoTest extends TestCase ); $this->root_directory = vfsStream::url(self::ROOTDIRNAME); $this->certdir = $this->root_directory . DIRECTORY_SEPARATOR . self::DEFAULTCERTDIR; + $this->cryptoUtils = new Utils\Crypto(); } @@ -57,17 +108,58 @@ class CryptoTest extends TestCase public function testAesDecrypt(): void { if (!extension_loaded('openssl')) { - $this->expectException(Error\Exception::class); + $this->markTestSkipped('The openssl PHP module is not loaded.'); + } + + $plaintext = 'SUPER_SECRET_TEXT'; + $ciphertext = <<<CIPHER +uR2Yu0r4itInKx91D/l9y/08L5CIQyev9nAr27fh3Sshous4vbXRRcMcjqHDOrquD+2vqLyw7ygnbA9jA9TpB4hLZocvAWcTN8tyO82hiSY= +CIPHER; + + $decrypted = $this->cryptoUtils->aesDecrypt(base64_decode($ciphertext)); + $this->assertEquals($plaintext, $decrypted); + } + + + /** + * @return void + */ + public function testAesDecryptWithSmallCipherTextThrowsException(): void + { + if (!extension_loaded('openssl')) { + $this->markTestSkipped('The openssl PHP module is not loaded.'); } $secret = 'SUPER_SECRET_SALT'; - $m = new ReflectionMethod(Crypto::class, 'aesDecryptInternal'); - $m->setAccessible(true); + $plaintext = 'SUPER_SECRET_TEXT'; + // This is too small! + $ciphertext = 'AWcTN8tyO82hiSY='; + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Input parameter "$ciphertext" must be a string with more than 48 characters.'); + $this->cryptoUtils->aesDecrypt(base64_decode($ciphertext), $secret); + } + + /** + * @return void + */ + public function testAesDecryptWithWrongSecretThrowsException(): void + { + if (!extension_loaded('openssl')) { + $this->markTestSkipped('The openssl PHP module is not loaded.'); + } + + // This is the wrong secret! + $secret = 'notsosecret'; $plaintext = 'SUPER_SECRET_TEXT'; - $ciphertext = 'uR2Yu0r4itInKx91D/l9y/08L5CIQyev9nAr27fh3Sshous4' - . 'vbXRRcMcjqHDOrquD+2vqLyw7ygnbA9jA9TpB4hLZocvAWcTN8tyO82hiSY='; - $this->assertEquals($plaintext, $m->invokeArgs(null, [base64_decode($ciphertext), $secret])); + $ciphertext = <<<CIPHER +uR2Yu0r4itInKx91D/l9y/08L5CIQyev9nAr27fh3Sshous4vbXRRcMcjqHDOrquD+2vqLyw7ygnbA9jA9TpB4hLZocvAWcTN8tyO82hiSY= +CIPHER; + + $this->expectException(Error\Exception::class); + $this->expectExceptionMessage('Failed to decrypt ciphertext.'); + $this->cryptoUtils->aesDecrypt(base64_decode($ciphertext), $secret); } @@ -78,18 +170,14 @@ class CryptoTest extends TestCase public function testAesEncrypt(): void { if (!extension_loaded('openssl')) { - $this->expectException(Error\Exception::class); + $this->markTestSkipped('The openssl PHP module is not loaded.'); } - $secret = 'SUPER_SECRET_SALT'; - $e = new ReflectionMethod(Crypto::class, 'aesEncryptInternal'); - $d = new ReflectionMethod(Crypto::class, 'aesDecryptInternal'); - $e->setAccessible(true); - $d->setAccessible(true); - $original_plaintext = 'SUPER_SECRET_TEXT'; - $ciphertext = $e->invokeArgs(null, [$original_plaintext, $secret]); - $decrypted_plaintext = $d->invokeArgs(null, [$ciphertext, $secret]); + + $ciphertext = $this->cryptoUtils->aesEncrypt($original_plaintext); + $decrypted_plaintext = $this->cryptoUtils->aesDecrypt($ciphertext); + $this->assertEquals($original_plaintext, $decrypted_plaintext); } @@ -100,43 +188,29 @@ class CryptoTest extends TestCase */ public function testFormatConversion(): void { - $pem = <<<PHP ------BEGIN CERTIFICATE----- -MIIF8zCCA9ugAwIBAgIJANSv0D4ZoP9iMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD -VQQGEwJFWDEQMA4GA1UECAwHRXhhbXBsZTEQMA4GA1UEBwwHRXhhbXBsZTEQMA4G -A1UECgwHRXhhbXBsZTEQMA4GA1UECwwHRXhhbXBsZTEUMBIGA1UEAwwLZXhhbXBs -ZS5jb20xIjAgBgkqhkiG9w0BCQEWE3NvbWVvbmVAZXhhbXBsZS5jb20wHhcNMTcw -MTEwMDk1MTIxWhcNMTgwMTEwMDk1MTIxWjCBjzELMAkGA1UEBhMCRVgxEDAOBgNV -BAgMB0V4YW1wbGUxEDAOBgNVBAcMB0V4YW1wbGUxEDAOBgNVBAoMB0V4YW1wbGUx -EDAOBgNVBAsMB0V4YW1wbGUxFDASBgNVBAMMC2V4YW1wbGUuY29tMSIwIAYJKoZI -hvcNAQkBFhNzb21lb25lQGV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOC -Ag8AMIICCgKCAgEA5Mp4xLdV41NtAI3YYr70G4gJYKegTHRwYhMeYAjudmZUng1/ -vbHLFGQybm8C6naEireQhHWzYfmDkOMU8dmdItwN4YLypYWwxYuWutWWIsDHHe0y -CfjVz6nnTPSjZEq5PpJYY+2XTZOP+g8FmDo4nmhEchF+8eiGvHQzdBqh26EwJjQ3 -LMXyc2F2+9Cm/On+M6BQKvvXkg8FqggW8YwcOujZNWGbfG3LVJcZ0p39PbnNgJX2 -ExbscPHfjmv2RlXd5EjruRhW1oX35sB4ycIFfHGWbCl2HPc1VfouJMq/fxgkKJdb -3RNxIBZnGpBdVJ25lCfk6t2dRdWKECrBHmcX/uR19of4H+hd4zOCPrej8IsCF2IS -1umyUBIDyPE4WciWMUERyG1dxSjUI4DBMi4l+LRX1YUrADSthH/0jV1WDsGpHT26 -+at2ZBgPy8tEvpLsITw/opUKWPCx3u5JVwFdduL8i0UF2yHmcsq44TUHVEoA1c55 -T+46ug7zHzhqFrPIwUN0DTKf33pg30xtL4d1rebc5K1KBNd9IDicd2iL8uD3HG6L -dPdt+1OaSbGlMMKdOte31TdOp7WhqcFANkKxd6TzMUHMVmkbYh2NesaQmCgxJdv6 -/pD7L+sbMKdhlcSoJW+1wwtIo5+CzZxPA2ehZ/IWQg+Oh6djvUJzo0/84ncCAwEA -AaNQME4wHQYDVR0OBBYEFOk6cEb397GMRCJe9xMIZ/y3yFvEMB8GA1UdIwQYMBaA -FOk6cEb397GMRCJe9xMIZ/y3yFvEMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggIBACc1c8j7oZeVDd8O2k97kY/7pHypVZswLfmg1UqbUmYYqQ9lM6FD0J8R -P+B8i7zST09pJ0FOsCsbyUKQmMIq/citTKmgk8NLK8otWHewHs5KTpsEvJm9XV4s -QjF07GBECJdQWu93Rn8FdR9eJ+H0Y0oHbBu3OtSbHFHyDvaCI5bxM/5FPf4HkJil -qIQunhO5gkz21ebukQUgiZ1YmFl0LjxGUDUDwnQ/3kOejlMUQv+ZXdQp/SaX1z5c -dQlGl/8HDs1YAM3duvdMCXn2LP3QuhrphT/+2o+ZkY32I1p/Q0fDNaE4u7JjaxAd -6+ijpmzZwgG5cFVU+sEeDqCI5MFn2JKiSCrHAHFMTnkpq687qBTLWoYTJ4coxtvs -kmvdoZytKiSf7aDzGQK345BSZWJ+D5RJr2250PHMMeNkFBc+GdGiRsABhhHQAqtE -7TVgdwvc8CYCfXlhRzdSowAVWibiftfPMmItM8Z0w5T/iPW0MsiCLGa5AvCHicN7 -pfajpJ9ZzdyLIo6dVjdQtl+S1rpFCx7ziVN8tCCX4fAVCqRqZJaG/UMLvguVqayb -3Aw1B/fVvWoAnAzVN5ZEClZvuyjImnNZpnYSWHzCJ/9JTqB7rq93nf6Olp9QXD5y -5iHKlJ6FlnuhcGCDsUCvG8qCw9FfoS0tuS4tKoQ5WHGQx3sKmr/D ------END CERTIFICATE----- -PHP; - $this->assertEquals(trim($pem), trim(Crypto::der2pem(Crypto::pem2der($pem)))); + $this->assertEquals(trim($this->pem), trim($this->cryptoUtils->der2pem($this->cryptoUtils->pem2der($this->pem)))); + } + + + /** + * @return void + */ + public function testFormatConversionThrowsExceptionWhenNotPEMStart(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('pem2der: input is not encoded in PEM format.'); + $this->cryptoUtils->pem2der(substr($this->pem, 6)); + } + + + /** + * @return void + */ + public function testFormatConversionThrowsExceptionWhenNotPEMEnd(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('pem2der: input is not encoded in PEM format.'); + $this->cryptoUtils->pem2der(substr($this->pem, 0, -20)); } @@ -146,8 +220,8 @@ PHP; { $pw = "password"; - $hash = Crypto::pwHash($pw); - $res = Crypto::pwValid($hash, $pw); + $hash = $this->cryptoUtils->pwHash($pw); + $res = $this->cryptoUtils->pwValid($hash, $pw); $this->assertTrue($res); } @@ -160,8 +234,8 @@ PHP; $pw = "password"; $pw2 = "password2"; - $hash = Crypto::pwHash($pw); - $res = Crypto::pwValid($hash, $pw2); + $hash = $this->cryptoUtils->pwHash($pw); + $res = $this->cryptoUtils->pwValid($hash, $pw2); $this->assertFalse($res); } @@ -173,9 +247,9 @@ PHP; { $pw = "password"; - $hash = Crypto::pwHash($pw); + $hash = $this->cryptoUtils->pwHash($pw); $this->expectException(Error\Exception::class); - Crypto::pwValid($hash, $hash); + $this->cryptoUtils->pwValid($hash, $hash); } @@ -183,7 +257,7 @@ PHP; */ public function testSecureCompareEqual(): void { - $res = Crypto::secureCompare("string", "string"); + $res = $this->cryptoUtils->secureCompare("string", "string"); $this->assertTrue($res); } @@ -193,7 +267,7 @@ PHP; */ public function testSecureCompareNotEqual(): void { - $res = Crypto::secureCompare("string1", "string2"); + $res = $this->cryptoUtils->secureCompare("string1", "string2"); $this->assertFalse($res); } @@ -207,7 +281,7 @@ PHP; $config = new Configuration([], 'test'); $required = true; - Crypto::loadPrivateKey($config, $required); + $this->cryptoUtils->loadPrivateKey($config, $required); } @@ -218,7 +292,7 @@ PHP; $config = new Configuration([], 'test'); $required = false; - $res = Crypto::loadPrivateKey($config, $required); + $res = $this->cryptoUtils->loadPrivateKey($config, $required); $this->assertNull($res); } @@ -231,7 +305,7 @@ PHP; $this->expectException(Error\Exception::class); $config = new Configuration(['privatekey' => 'nonexistant'], 'test'); - Crypto::loadPrivateKey($config, false, '', true); + $this->cryptoUtils->loadPrivateKey($config, false, '', true); } @@ -246,7 +320,7 @@ PHP; file_put_contents($filename, $data); - $res = Crypto::loadPrivateKey($config, false, '', $full_path); + $res = $this->cryptoUtils->loadPrivateKey($config, false, '', $full_path); $expected = ['PEM' => $data, 'password' => null]; $this->assertEquals($expected, $res); @@ -271,7 +345,7 @@ PHP; file_put_contents($filename, $data); - $res = Crypto::loadPrivateKey($config, false, '', $full_path); + $res = $this->cryptoUtils->loadPrivateKey($config, false, '', $full_path); $expected = ['PEM' => $data, 'password' => $password]; $this->assertEquals($expected, $res); @@ -297,7 +371,7 @@ PHP; file_put_contents($filename, $data); - $res = Crypto::loadPrivateKey($config, false, $prefix, $full_path); + $res = $this->cryptoUtils->loadPrivateKey($config, false, $prefix, $full_path); $expected = ['PEM' => $data, 'password' => $password]; $this->assertEquals($expected, $res); @@ -312,7 +386,7 @@ PHP; $config = new Configuration([], 'test'); $required = true; - Crypto::loadPublicKey($config, $required); + $this->cryptoUtils->loadPublicKey($config, $required); } @@ -323,7 +397,7 @@ PHP; $config = new Configuration([], 'test'); $required = false; - $res = Crypto::loadPublicKey($config, $required); + $res = $this->cryptoUtils->loadPublicKey($config, $required); $this->assertNull($res); } @@ -346,7 +420,7 @@ PHP; 'test' ); - $res = Crypto::loadPublicKey($config); + $res = $this->cryptoUtils->loadPublicKey($config); $this->assertNull($res); } @@ -369,7 +443,7 @@ PHP; 'test' ); - $res = Crypto::loadPublicKey($config); + $res = $this->cryptoUtils->loadPublicKey($config); $this->assertNull($res); } @@ -394,7 +468,7 @@ PHP; ); /** @var array $pubkey */ - $pubkey = Crypto::loadPublicKey($config); + $pubkey = $this->cryptoUtils->loadPublicKey($config); $res = $pubkey['certData']; $expected = $x509certificate; diff --git a/tests/modules/admin/lib/Controller/ConfigTest.php b/tests/modules/admin/lib/Controller/ConfigTest.php index e7e513dca95b52b5ef757a6cf85d964d63064c38..c10f17e79370049b8c15cab5aa875f223ee66660 100644 --- a/tests/modules/admin/lib/Controller/ConfigTest.php +++ b/tests/modules/admin/lib/Controller/ConfigTest.php @@ -61,7 +61,7 @@ class ConfigTest extends TestCase ); $this->authUtils = new class () extends Utils\Auth { - public static function requireAdmin(): void + public function requireAdmin(): void { // stub } diff --git a/tests/modules/admin/lib/Controller/FederationTest.php b/tests/modules/admin/lib/Controller/FederationTest.php index f15cb033c92c1d48b00b6eb9f9fb83b5789f7e4f..417834bd7946b8941ba6bd626ab74e79d1e6698e 100644 --- a/tests/modules/admin/lib/Controller/FederationTest.php +++ b/tests/modules/admin/lib/Controller/FederationTest.php @@ -79,7 +79,7 @@ class FederationTest extends TestCase ); $this->authUtils = new class () extends Utils\Auth { - public static function requireAdmin(): void + public function requireAdmin(): void { // stub } diff --git a/tests/modules/admin/lib/Controller/TestTest.php b/tests/modules/admin/lib/Controller/TestTest.php index 78743f128572c4cd039645395dcc83aa6a14bb5a..a27a83c4f3d967d1afc3c6a916063dbbc79f9995 100644 --- a/tests/modules/admin/lib/Controller/TestTest.php +++ b/tests/modules/admin/lib/Controller/TestTest.php @@ -51,7 +51,7 @@ class TestTest extends TestCase ); $this->authUtils = new class () extends Utils\Auth { - public static function requireAdmin(): void + public function requireAdmin(): void { // stub } diff --git a/tests/modules/core/lib/Auth/Process/TargetedIDTest.php b/tests/modules/core/lib/Auth/Process/TargetedIDTest.php index 0bccc514e0afbed8a2340224f2af1bf822f3470f..34a740d4171ecd4eb858cff96b86b3df3cea0bb2 100644 --- a/tests/modules/core/lib/Auth/Process/TargetedIDTest.php +++ b/tests/modules/core/lib/Auth/Process/TargetedIDTest.php @@ -33,7 +33,7 @@ class TargetedIDTest extends TestCase parent::setUp(); self::$configUtils = new class () extends Utils\Config { - public static function getSecretSalt(): string + public function getSecretSalt(): string { // stub return 'secretsalt'; diff --git a/tests/modules/cron/lib/Controller/CronTest.php b/tests/modules/cron/lib/Controller/CronTest.php index da032e241f859bf93df551b754d637c7ebd97110..e543a6dad2125b956e817032cb3b740309e68bc1 100644 --- a/tests/modules/cron/lib/Controller/CronTest.php +++ b/tests/modules/cron/lib/Controller/CronTest.php @@ -50,7 +50,7 @@ class CronTest extends TestCase $this->session = Session::getSessionFromRequest(); $this->authUtils = new class () extends Utils\Auth { - public static function requireAdmin(): void + public function requireAdmin(): void { // stub } diff --git a/www/saml2/idp/metadata.php b/www/saml2/idp/metadata.php index 7bf640076a46786ea18b9e4135af9756ae115881..7bb1fa632ec75634f39235f46b54b0a25408066e 100644 --- a/www/saml2/idp/metadata.php +++ b/www/saml2/idp/metadata.php @@ -9,9 +9,7 @@ use SimpleSAML\Assert\Assert; use SimpleSAML\Configuration; use SimpleSAML\Error; use SimpleSAML\Module; -use SimpleSAML\Utils\Auth as Auth; -use SimpleSAML\Utils\Crypto as Crypto; -use SimpleSAML\Utils\HTTP as HTTP; +use SimpleSAML\Utils; use SimpleSAML\Utils\Config\Metadata as Metadata; $config = Configuration::getInstance(); @@ -21,7 +19,8 @@ if (!$config->getBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled // check if valid local session exists if ($config->getBoolean('admin.protectmetadata', false)) { - Auth::requireAdmin(); + $authUtils = new Utils\Auth(); + $authUtils->requireAdmin(); } $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler(); @@ -31,10 +30,11 @@ try { $_GET['idpentityid'] : $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted'); $idpmeta = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted'); + $cryptoUtils = new Utils\Crypto(); $availableCerts = []; - $keys = []; - $certInfo = Crypto::loadPublicKey($idpmeta, false, 'new_'); + + $certInfo = $cryptoUtils->loadPublicKey($idpmeta, false, 'new_'); if ($certInfo !== null) { $availableCerts['new_idp.crt'] = $certInfo; $keys[] = [ @@ -48,7 +48,7 @@ try { $hasNewCert = false; } - $certInfo = Crypto::loadPublicKey($idpmeta, true); + $certInfo = $cryptoUtils->loadPublicKey($idpmeta, true); $availableCerts['idp.crt'] = $certInfo; $keys[] = [ 'type' => 'X509Certificate', @@ -58,7 +58,7 @@ try { ]; if ($idpmeta->hasValue('https.certificate')) { - $httpsCert = Crypto::loadPublicKey($idpmeta, true, 'https.'); + $httpsCert = $cryptoUtils->loadPublicKey($idpmeta, true, 'https.'); Assert::notNull($httpsCert['certData']); $availableCerts['https.crt'] = $httpsCert; $keys[] = [ @@ -117,7 +117,7 @@ try { // Artifact sending enabled $metaArray['ArtifactResolutionService'][] = [ 'index' => 0, - 'Location' => HTTP::getBaseURL() . 'saml2/idp/ArtifactResolutionService.php', + 'Location' => Utils\HTTP::getBaseURL() . 'saml2/idp/ArtifactResolutionService.php', 'Binding' => Constants::BINDING_SOAP, ]; } @@ -127,7 +127,7 @@ try { array_unshift($metaArray['SingleSignOnService'], [ 'hoksso:ProtocolBinding' => Constants::BINDING_HTTP_REDIRECT, 'Binding' => Constants::BINDING_HOK_SSO, - 'Location' => HTTP::getBaseURL() . 'saml2/idp/SSOService.php' + 'Location' => Utils\HTTP::getBaseURL() . 'saml2/idp/SSOService.php' ]); } @@ -135,7 +135,7 @@ try { $metaArray['SingleSignOnService'][] = [ 'index' => 0, 'Binding' => Constants::BINDING_SOAP, - 'Location' => HTTP::getBaseURL() . 'saml2/idp/SSOService.php', + 'Location' => Utils\HTTP::getBaseURL() . 'saml2/idp/SSOService.php', ]; } @@ -238,7 +238,7 @@ try { $t->data['certdata'] = $certdata; $t->data['header'] = 'saml20-idp'; // TODO: Replace with headerString in 2.0 $t->data['headerString'] = \SimpleSAML\Locale\Translate::noop('metadata_saml20-idp'); - $t->data['metaurl'] = HTTP::getSelfURLNoQuery(); + $t->data['metaurl'] = Utils\HTTP::getSelfURLNoQuery(); $t->data['metadata'] = htmlspecialchars($metaxml); $t->data['metadataflat'] = htmlspecialchars($metaflat); $t->send();