diff --git a/3rdparty/vendor/composer/autoload_real.php b/3rdparty/vendor/composer/autoload_real.php index 65389da..6e1d68c 100644 --- a/3rdparty/vendor/composer/autoload_real.php +++ b/3rdparty/vendor/composer/autoload_real.php @@ -13,6 +13,9 @@ class ComposerAutoloaderInitcc75f134f7630c1ee3a8e4d7c86f3bcc } } + /** + * @return \Composer\Autoload\ClassLoader + */ public static function getLoader() { if (null !== self::$loader) { diff --git a/3rdparty/vendor/composer/installed.json b/3rdparty/vendor/composer/installed.json index 5a8d6c5..3e4a3a0 100644 --- a/3rdparty/vendor/composer/installed.json +++ b/3rdparty/vendor/composer/installed.json @@ -46,22 +46,22 @@ }, { "name": "onelogin/php-saml", - "version": "3.1.1", - "version_normalized": "3.1.1.0", + "version": "3.4.1", + "version_normalized": "3.4.1.0", "source": { "type": "git", "url": "https://github.com/onelogin/php-saml.git", - "reference": "c9026b26395a65184550055d9a01bdf9dbd30861" + "reference": "5fbf3486704ac9835b68184023ab54862c95f213" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/onelogin/php-saml/zipball/c9026b26395a65184550055d9a01bdf9dbd30861", - "reference": "c9026b26395a65184550055d9a01bdf9dbd30861", + "url": "https://api.github.com/repos/onelogin/php-saml/zipball/5fbf3486704ac9835b68184023ab54862c95f213", + "reference": "5fbf3486704ac9835b68184023ab54862c95f213", "shasum": "" }, "require": { "php": ">=5.4", - "robrichards/xmlseclibs": ">=3.0.3" + "robrichards/xmlseclibs": ">=3.0.4" }, "require-dev": { "pdepend/pdepend": "^2.5.0", @@ -76,7 +76,7 @@ "ext-gettext": "Install gettext and php5-gettext libs to handle translations", "ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)" }, - "time": "2019-03-11T09:41:32+00:00", + "time": "2019-11-25T17:30:07+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -98,24 +98,24 @@ }, { "name": "robrichards/xmlseclibs", - "version": "3.0.3", - "version_normalized": "3.0.3.0", + "version": "3.1.1", + "version_normalized": "3.1.1.0", "source": { "type": "git", "url": "https://github.com/robrichards/xmlseclibs.git", - "reference": "406c68ac9124db033d079284b719958b829cb830" + "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/406c68ac9124db033d079284b719958b829cb830", - "reference": "406c68ac9124db033d079284b719958b829cb830", + "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/f8f19e58f26cdb42c54b214ff8a820760292f8df", + "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df", "shasum": "" }, "require": { "ext-openssl": "*", "php": ">= 5.4" }, - "time": "2018-11-15T11:59:02+00:00", + "time": "2020-09-05T13:00:25+00:00", "type": "library", "installation-source": "dist", "autoload": { diff --git a/3rdparty/vendor/onelogin/php-saml/CHANGELOG b/3rdparty/vendor/onelogin/php-saml/CHANGELOG index 384a1c9..019196b 100644 --- a/3rdparty/vendor/onelogin/php-saml/CHANGELOG +++ b/3rdparty/vendor/onelogin/php-saml/CHANGELOG @@ -1,5 +1,42 @@ CHANGELOG ========= +v3.4.1 +* Add setSchemasPath to Auth class and fix backward compatibility + +v.3.4.0 +* Support rejecting unsolicited SAMLResponses. +* Support stric destination matching. +* Reject SAMLResponse if requestID was provided to the validotr but the InResponseTo attributeof the SAMLResponse is missing +* Check destination against the getSelfURLNoQuery as well on LogoutRequest and LogoutResponse as we do on Response +* Improve getSelfRoutedURLNoQuery method +* Only add responseUrl to the settings if ResponseLocation present in the IdPMetadataParser +* Remove use of $_GET on static method validateBinarySign +* Fix error message when Assertion and NameId are both encrypted (not supported) + +v.3.3.1 +* Update xmlseclibs to 3.0.4 +* Remove Comparison atribute from RequestedAuthnContext when setting has empty value + +v.3.3.0 +* Set true as the default value for strict setting +* Relax comparision of false on SignMetadata +* Fix CI + +v.3.2.1 +* Add missed nameIdValueReq parameter to buildAuthnRequest method + +v.3.2.0 +* Add support for Subjects on AuthNRequests by the new parameter nameIdValueReq +* Support SLO ResponseLocation +* [#344](https://github.com/onelogin/php-saml/issues/344) Raise errors on IdPMetadataParser::parseRemoteXML and IdPMetadataParser::parseFileXML +* [#356](https://github.com/onelogin/php-saml/issues/356) Support 'x509cert' and 'privateKey' on signMetadata security setting + +v.3.1.1 +* Force to use at least xmlseclibs 3.0.3 for security reasons +* [#367](https://github.com/onelogin/php-saml/pull/367) Move the creation of the AuthnRequest to separate function +* Set strict=true on config examples +* Move phpunit.xml + v.3.1.0 * Security improvement suggested by Nils Engelbertz to prevent DDOS by expansion of internally defined entities (XEE) * Fix setting_example.php servicename parameter @@ -8,6 +45,51 @@ v.3.0.0 * Remove mcrypt dependency. Compatible with PHP 7.2 * xmlseclibs now is not part of the toolkit and need to be installed from original source +v.2.18.0 +* Support rejecting unsolicited SAMLResponses. +* Support stric destination matching. +* Reject SAMLResponse if requestID was provided to the validotr but the InResponseTo attributeof the SAMLResponse is missing +* Check destination against the getSelfURLNoQuery as well on LogoutRequest and LogoutResponse as we do on Response +* Improve getSelfRoutedURLNoQuery method +* Only add responseUrl to the settings if ResponseLocation present in the IdPMetadataParser +* Remove use of $_GET on static method validateBinarySign +* Fix error message when Assertion and NameId are both encrypted (not supported) + +v.2.17.1 +* Update xmlseclibs to 3.0.4 +* Remove Comparison atribute from RequestedAuthnContext when setting has empty value + +v.2.17.0 +* Set true as the default value for strict setting +* Support 'x509cert' and 'privateKey' on signMetadata security settings +* Relax comparision of false on SignMetadata +* Fix CI + +v.2.16.0 +* Support SLO ResponseLocation +* [#344](https://github.com/onelogin/php-saml/issues/344) Raise errors on IdPMetadataParser::parseRemoteXML and IdPMetadataParser::parseFileXML +* Adjusted acs endpoint to extract NameQualifier and SPNameQualifier from SAMLResponse. Adjusted single logout service to provide NameQualifier and SPNameQualifier to logout method. Add getNameIdNameQualifier to Auth and SamlResponse. Extend logout method from Auth and LogoutRequest constructor to support SPNameQualifier parameter. Align LogoutRequest constructor with SAML specs +* Add support for Subjects on AuthNRequests by the new parameter +* Set strict=true on config examples + +v.2.15.0 +* Security improvement suggested by Nils Engelbertz to prevent DDOS by expansion of internally defined entities (XEE) +* Fix bug on settings_example.php + +v.2.14.0 +* Add parameter to the decryptElement method to make optional the formatting +* [#283](https://github.com/onelogin/php-saml/pull/283) New method of importing a decrypted assertion into the XML document to replace the EncryptedAssertion. Fix signature issues on Signed Encrypted Assertions with default namespace +* Allow the getSPMetadata() method to always include the encryption Key Descriptor +* Change some Fatal Error to Exceptions +* [#265](https://github.com/onelogin/php-saml/issues/265) Support parameters at getSPMetadata method +* Avoid calling static method using this + +v.2.13.0 +* Update xmlseclibs with some fixes. +* Add extra protection verifying the Signature algorithm used on SignedInfo element, not only rely on the xmlseclibs verify / verifySignature methods. +* Add getAttributesWithFriendlyName method which returns the set of SAML attributes indexed by FriendlyName +* Fix bug on parseRemoteXML and parseFileXML. Internal calls to parseXML missed the desiredNameIdFormat parameter + v.2.12.0 * Improve Time management. Use DateTime/DateTimeZone classes. * Escape error messages in debug mode diff --git a/3rdparty/vendor/onelogin/php-saml/README.md b/3rdparty/vendor/onelogin/php-saml/README.md index 8c0582a..7ad8b48 100644 --- a/3rdparty/vendor/onelogin/php-saml/README.md +++ b/3rdparty/vendor/onelogin/php-saml/README.md @@ -10,6 +10,12 @@ and supported by OneLogin Inc. Warning ------- +Version 3.4.0 introduces the 'rejectUnsolicitedResponsesWithInResponseTo' setting parameter, by default disabled, that will allow invalidate unsolicited SAMLResponse. This version as well will reject SAMLResponse if requestId was provided to the validator but the SAMLResponse does not contain a InResponseTo attribute. And an additional setting parameter 'destinationStrictlyMatches', by default disabled, that will force that the Destination URL should strictly match to the address that process the SAMLResponse. + +Version 3.3.1 updates xmlseclibs to 3.0.4 (CVE-2019-3465), but php-saml was not directly affected since it implements additional checks that prevent to exploit that vulnerability. + +Version 3.3.0 sets strict mode active by default + Update php-saml to 3.1.0, this version includes a security patch related to XEE attacks. This version is compatible with PHP 7.X and does not include xmlseclibs (you will need to install it via composer, dependency described in composer.json) @@ -84,7 +90,13 @@ Installation ### Code ### -#### Option 1. Download from github #### +#### Option 1. clone the repository from github #### + +git clone git@github.com:onelogin/php-saml.git + +Then pull the 3.X.X branch/tag + +#### Option 2. Download from github #### The toolkit is hosted on github. You can download it from: @@ -96,7 +108,10 @@ Copy the core of the library inside the php application. (each application has i structure so take your time to locate the PHP SAML toolkit in the best place). See the "Guide to add SAML support to my app" to know how. -#### Option 2. Composer #### +Take in mind that the compressed file only contains the main files. +If you plan to play with the demos, use the Option 1. + +#### Option 3. Composer #### The toolkit supports [composer](https://getcomposer.org/). You can find the `onelogin/php-saml` package at https://packagist.org/packages/onelogin/php-saml @@ -337,6 +352,9 @@ $settings = array( 'singleLogoutService' => array( // URL Location of the IdP where SLO Request will be sent. 'url' => '', + // URL location of the IdP where SLO Response will be sent (ResponseLocation) + // if not set, url for the SLO Request will be used + 'responseUrl' => '', // SAML protocol binding to be used when returning the // message. OneLogin Toolkit supports the HTTP-Redirect binding // only for this endpoint. @@ -417,10 +435,14 @@ $advancedSettings = array( 'logoutResponseSigned' => false, /* Sign the Metadata - False || True (use sp certs) || array( - keyFileName => 'metadata.key', - certFileName => 'metadata.crt' - ) + False || True (use sp certs) || array ( + 'keyFileName' => 'metadata.key', + 'certFileName' => 'metadata.crt' + ) + || array ( + 'x509cert' => '', + 'privateKey' => '' + ) */ 'signMetadata' => false, @@ -460,6 +482,16 @@ $advancedSettings = array( // attribute will not be rejected for this fact. 'relaxDestinationValidation' => false, + // If true, Destination URL should strictly match to the address to + // which the response has been sent. + // Notice that if 'relaxDestinationValidation' is true an empty Destintation + // will be accepted. + 'destinationStrictlyMatches' => false, + + // If true, SAMLResponses with an InResponseTo value will be rejectd if not + // AuthNRequest ID provided to the validation method. + 'rejectUnsolicitedResponsesWithInResponseTo' => false, + // Algorithm that the toolkit will use on signing process. Options: // 'http://www.w3.org/2000/09/xmldsig#rsa-sha1' // 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' @@ -602,13 +634,14 @@ $auth = new OneLogin\Saml2\Auth(); $auth->login($newTargetUrl); ``` -The login method can receive other five optional parameters: +The login method can receive other six optional parameters: * `$parameters` - An array of parameters that will be added to the `GET` in the HTTP-Redirect. * `$forceAuthn` - When true the `AuthNRequest` will set the `ForceAuthn='true'` * `$isPassive` - When true the `AuthNRequest` will set the `Ispassive='true'` * `$strict` - True if we want to stay (returns the url string) False to redirect * `$setNameIdPolicy` - When true the AuthNRequest will set a nameIdPolicy element. +* `$nameIdValueReq` - Indicates to the IdP the subject that should be authenticated. If a match on the future SAMLResponse ID and the AuthNRequest ID to be sent is required, that AuthNRequest ID must to be extracted and saved. @@ -707,8 +740,8 @@ if (!$auth->isAuthenticated()) { $_SESSION['samlUserdata'] = $auth->getAttributes(); $_SESSION['samlNameId'] = $auth->getNameId(); $_SESSION['samlNameIdFormat'] = $auth->getNameIdFormat(); -$_SESSION['samlNameidNameQualifier' = $auth->getNameIdNameQualifier(); -$_SESSION['samlNameidSPNameQualifier' = $auth->getNameIdSPNameQualifier(); +$_SESSION['samlNameidNameQualifier'] = $auth->getNameIdNameQualifier(); +$_SESSION['samlNameidSPNameQualifier'] = $auth->getNameIdSPNameQualifier(); $_SESSION['samlSessionIndex'] = $auth->getSessionIndex(); if (isset($_POST['RelayState']) && OneLogin\Saml2\Utils::getSelfURL() != $_POST['RelayState']) { @@ -968,7 +1001,7 @@ A more complex logout with all the parameters: ``` $auth = new OneLogin\Saml2\Auth(); $returnTo = null; -$paramters = array(); +$parameters = array(); $nameId = null; $sessionIndex = null; $nameIdFormat = null; @@ -990,13 +1023,13 @@ if (isset($_SESSION['samlNameIdNameQualifier'])) { if (isset($_SESSION['samlNameIdSPNameQualifier'])) { $nameIdSPNameQualifier = $_SESSION['samlNameIdSPNameQualifier']; } -$auth->logout($returnTo, $paramters, $nameId, $sessionIndex, false, $nameIdFormat, $nameIdNameQualifier, $nameIdSPNameQualifier); +$auth->logout($returnTo, $parameters, $nameId, $sessionIndex, false, $nameIdFormat, $nameIdNameQualifier, $nameIdSPNameQualifier); ``` If a match on the future LogoutResponse ID and the LogoutRequest ID to be sent is required, that LogoutRequest ID must to be extracted and stored. ```php -$sloBuiltUrl = $auth->logout(null, $paramters, $nameId, $sessionIndex, true); +$sloBuiltUrl = $auth->logout(null, $parameters, $nameId, $sessionIndex, true); $_SESSION['LogoutRequestID'] = $auth->getLastRequestID(); header('Pragma: no-cache'); header('Cache-Control: no-cache, must-revalidate'); @@ -1098,7 +1131,7 @@ php-saml toolkit uses a bunch of methods in OneLogin\Saml2\Utils that try to gue * `getSelfURLNoQuery` Returns the URL of the current host + current view. * `getSelfRoutedURLNoQuery` Returns the routed URL of the current host + current view. -getSelfURLNoQuery and getSelfRoutedURLNoQuery are used to calculate the currentURL in order to valdate SAML elements like Destination or Recipient. +getSelfURLNoQuery and getSelfRoutedURLNoQuery are used to calculate the currentURL in order to validate SAML elements like Destination or Recipient. When the PHP application is behind a proxy or a load balancer we can execute `setProxyVars(true)` and `setSelfPort` and `isHTTPS` will take care of the `$_SERVER["HTTP_X_FORWARDED_PORT"]` and `$_SERVER['HTTP_X_FORWARDED_PROTO']` vars (otherwise they are ignored). @@ -1400,7 +1433,7 @@ Once the SP is configured, the metadata of the SP is published at the process, the `index.php` view. 2.2 in the second link we access to (`attrs.php`) have the same process - described at 2.1 with the diference that as `RelayState` is set the `attrs.php`. + described at 2.1 with the difference that as `RelayState` is set the `attrs.php`. 3. The SAML Response is processed in the ACS (`index.php?acs`), if the Response is not valid, the process stops here and a message is shown. Otherwise we @@ -1427,7 +1460,7 @@ Once the SP is configured, the metadata of the SP is published at the session at of the IdP. Notice that the SLO Workflow starts and ends at the IdP. Notice that all the SAML Requests and Responses are handled by a unique file, -the `index.php` file and how `GET` paramters are used to know the action that +the `index.php` file and how `GET` parameters are used to know the action that must be done. diff --git a/3rdparty/vendor/onelogin/php-saml/advanced_settings_example.php b/3rdparty/vendor/onelogin/php-saml/advanced_settings_example.php index 7da4bb3..1d1552c 100644 --- a/3rdparty/vendor/onelogin/php-saml/advanced_settings_example.php +++ b/3rdparty/vendor/onelogin/php-saml/advanced_settings_example.php @@ -33,10 +33,14 @@ $advancedSettings = array( 'logoutResponseSigned' => false, /* Sign the Metadata - False || True (use sp certs) || array( - keyFileName => 'metadata.key', - certFileName => 'metadata.crt' - ) + False || True (use sp certs) || array ( + 'keyFileName' => 'metadata.key', + 'certFileName' => 'metadata.crt' + ) + || array ( + 'x509cert' => '', + 'privateKey' => '' + ) */ 'signMetadata' => false, @@ -81,6 +85,16 @@ $advancedSettings = array( // attribute will not be rejected for this fact. 'relaxDestinationValidation' => false, + // If true, Destination URL should strictly match to the address to + // which the response has been sent. + // Notice that if 'relaxDestinationValidation' is true an empty Destintation + // will be accepted. + 'destinationStrictlyMatches' => false, + + // If true, SAMLResponses with an InResponseTo value will be rejectd if not + // AuthNRequest ID provided to the validation method. + 'rejectUnsolicitedResponsesWithInResponseTo' => false, + // Algorithm that the toolkit will use on signing process. Options: // 'http://www.w3.org/2000/09/xmldsig#rsa-sha1' // 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' diff --git a/3rdparty/vendor/onelogin/php-saml/composer.json b/3rdparty/vendor/onelogin/php-saml/composer.json index 118f2cf..2cae8af 100644 --- a/3rdparty/vendor/onelogin/php-saml/composer.json +++ b/3rdparty/vendor/onelogin/php-saml/composer.json @@ -16,11 +16,11 @@ }, "require": { "php": ">=5.4", - "robrichards/xmlseclibs": ">=3.0.3" + "robrichards/xmlseclibs": ">=3.0.4" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1", "php-coveralls/php-coveralls": "^1.0.2 || ^2.0", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1", "sebastian/phpcpd": "^2.0 || ^3.0 || ^4.0", "phploc/phploc": "^2.1 || ^3.0 || ^4.0", "pdepend/pdepend": "^2.5.0", diff --git a/3rdparty/vendor/onelogin/php-saml/phpunit.xml b/3rdparty/vendor/onelogin/php-saml/phpunit.xml new file mode 100644 index 0000000..3629f27 --- /dev/null +++ b/3rdparty/vendor/onelogin/php-saml/phpunit.xml @@ -0,0 +1,18 @@ + + + + ./tests/src + + + + + ./src + + + + + + + + + diff --git a/3rdparty/vendor/onelogin/php-saml/settings_example.php b/3rdparty/vendor/onelogin/php-saml/settings_example.php index b29195d..981a21a 100644 --- a/3rdparty/vendor/onelogin/php-saml/settings_example.php +++ b/3rdparty/vendor/onelogin/php-saml/settings_example.php @@ -27,7 +27,7 @@ $settings = array( 'url' => '', // SAML protocol binding to be used when returning the // message. Onelogin Toolkit supports for this endpoint the - // HTTP-Redirect binding only + // HTTP-POST binding only 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', ), // If you need to specify requested attributes, set a @@ -86,13 +86,16 @@ $settings = array( 'url' => '', // SAML protocol binding to be used when returning the // message. Onelogin Toolkit supports for this endpoint the - // HTTP-POST binding only + // HTTP-Redirect binding only 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', ), // SLO endpoint info of the IdP. 'singleLogoutService' => array( // URL Location of the IdP where the SP will send the SLO Request 'url' => '', + // URL location of the IdP where the SP SLO Response will be sent (ResponseLocation) + // if not set, url for the SLO Request will be used + 'responseUrl' => '', // SAML protocol binding to be used when returning the // message. Onelogin Toolkit supports for this endpoint the // HTTP-Redirect binding only diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Auth.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Auth.php index 3ba03d4..5f603a1 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Auth.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Auth.php @@ -206,6 +206,17 @@ class Auth $this->_settings->setStrict($value); } + /** + * Set schemas path + * + * @param string $path + * @return $this + */ + public function setSchemasPath($path) + { + $this->_paths['schemas'] = $path; + } + /** * Process the SAML Response sent by the IdP. * @@ -322,7 +333,7 @@ class Auth $parameters['Signature'] = $signature; } - return $this->redirectTo($this->getSLOurl(), $parameters, $stay); + return $this->redirectTo($this->getSLOResponseUrl(), $parameters, $stay); } } else { $this->_errors[] = 'invalid_binding'; @@ -520,14 +531,15 @@ class Auth * @param bool $isPassive When true the AuthNRequest will set the Ispassive='true' * @param bool $stay True if we want to stay (returns the url string) False to redirect * @param bool $setNameIdPolicy When true the AuthNRequest will set a nameIdPolicy element + * @param string $nameIdValueReq Indicates to the IdP the subject that should be authenticated * * @return string|null If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters - * + * * @throws Error */ - public function login($returnTo = null, array $parameters = array(), $forceAuthn = false, $isPassive = false, $stay = false, $setNameIdPolicy = true) + public function login($returnTo = null, array $parameters = array(), $forceAuthn = false, $isPassive = false, $stay = false, $setNameIdPolicy = true, $nameIdValueReq = null) { - $authnRequest = $this->buildAuthnRequest($this->_settings, $forceAuthn, $isPassive, $setNameIdPolicy); + $authnRequest = $this->buildAuthnRequest($this->_settings, $forceAuthn, $isPassive, $setNameIdPolicy, $nameIdValueReq); $this->_lastRequest = $authnRequest->getXML(); $this->_lastRequestID = $authnRequest->getId(); @@ -632,6 +644,20 @@ class Auth return $url; } + /** + * Gets the SLO response url. + * + * @return string|null The response url of the Single Logout Service + */ + public function getSLOResponseUrl() + { + $idpData = $this->_settings->getIdPData(); + if (isset($idpData['singleLogoutService']) && isset($idpData['singleLogoutService']['responseUrl'])) { + return $idpData['singleLogoutService']['responseUrl']; + } + return $this->getSLOurl(); + } + /** * Gets the ID of the last AuthNRequest or LogoutRequest generated by the Service Provider. * @@ -649,12 +675,13 @@ class Auth * @param bool $forceAuthn When true the AuthNRequest will set the ForceAuthn='true' * @param bool $isPassive When true the AuthNRequest will set the Ispassive='true' * @param bool $setNameIdPolicy When true the AuthNRequest will set a nameIdPolicy element + * @param string $nameIdValueReq Indicates to the IdP the subject that should be authenticated * * @return AuthnRequest The AuthnRequest object */ - public function buildAuthnRequest($settings, $forceAuthn, $isPassive, $setNameIdPolicy) + public function buildAuthnRequest($settings, $forceAuthn, $isPassive, $setNameIdPolicy, $nameIdValueReq = null) { - return new AuthnRequest($settings, $forceAuthn, $isPassive, $setNameIdPolicy); + return new AuthnRequest($settings, $forceAuthn, $isPassive, $setNameIdPolicy, $nameIdValueReq); } /** @@ -704,7 +731,7 @@ class Auth * @throws Exception * @throws Error */ - private function buildMessageSignature($samlMessage, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256, $type="SAMLRequest") + private function buildMessageSignature($samlMessage, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256, $type = "SAMLRequest") { $key = $this->_settings->getSPkey(); if (empty($key)) { diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/AuthnRequest.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/AuthnRequest.php index 2dd6bd2..a1311f7 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/AuthnRequest.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/AuthnRequest.php @@ -44,12 +44,13 @@ class AuthnRequest /** * Constructs the AuthnRequest object. * - * @param Settings $settings SAML Toolkit Settings - * @param bool $forceAuthn When true the AuthNReuqest will set the ForceAuthn='true' - * @param bool $isPassive When true the AuthNReuqest will set the Ispassive='true' - * @param bool $setNameIdPolicy When true the AuthNReuqest will set a nameIdPolicy + * @param Settings $settings SAML Toolkit Settings + * @param bool $forceAuthn When true the AuthNReuqest will set the ForceAuthn='true' + * @param bool $isPassive When true the AuthNReuqest will set the Ispassive='true' + * @param bool $setNameIdPolicy When true the AuthNReuqest will set a nameIdPolicy + * @param string $nameIdValueReq Indicates to the IdP the subject that should be authenticated */ - public function __construct(\OneLogin\Saml2\Settings $settings, $forceAuthn = false, $isPassive = false, $setNameIdPolicy = true) + public function __construct(\OneLogin\Saml2\Settings $settings, $forceAuthn = false, $isPassive = false, $setNameIdPolicy = true, $nameIdValueReq = null) { $this->_settings = $settings; @@ -60,6 +61,17 @@ class AuthnRequest $id = Utils::generateUniqueID(); $issueInstant = Utils::parseTime2SAML(time()); + $subjectStr = ""; + if (isset($nameIdValueReq)) { + $subjectStr = << + {$nameIdValueReq} + + +SUBJECT; + } + $nameIdPolicyStr = ''; if ($setNameIdPolicy) { $nameIDPolicyFormat = $spData['NameIDFormat']; @@ -68,6 +80,7 @@ class AuthnRequest } $nameIdPolicyStr = << @@ -114,14 +127,20 @@ ISPASSIVE; $authnComparison = $security['requestedAuthnContextComparison']; } + $authnComparisonAttr = ''; + if (!empty($authnComparison)) { + $authnComparisonAttr = sprintf('Comparison="%s"', $authnComparison); + } + if ($security['requestedAuthnContext'] === true) { $requestedAuthnStr = << + + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport REQUESTEDAUTHN; } else { - $requestedAuthnStr .= " \n"; + $requestedAuthnStr .= " \n"; foreach ($security['requestedAuthnContext'] as $contextValue) { $requestedAuthnStr .= " ".$contextValue."\n"; } @@ -142,9 +161,7 @@ REQUESTEDAUTHN; Destination="{$idpData['singleSignOnService']['url']}" ProtocolBinding="{$spData['assertionConsumerService']['binding']}" AssertionConsumerServiceURL="{$acsUrl}"> - {$spEntityId} -{$nameIdPolicyStr} -{$requestedAuthnStr} + {$spEntityId}{$subjectStr}{$nameIdPolicyStr}{$requestedAuthnStr} AUTHNREQUEST; diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/IdPMetadataParser.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/IdPMetadataParser.php index e305125..947d654 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/IdPMetadataParser.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/IdPMetadataParser.php @@ -56,6 +56,7 @@ class IdPMetadataParser throw new Exception(curl_error($ch), curl_errno($ch)); } } catch (Exception $e) { + throw new Exception('Error on parseRemoteXML. '.$e->getMessage()); } return $metadataInfo; } @@ -84,6 +85,7 @@ class IdPMetadataParser $metadataInfo = self::parseXML($data, $entityId, $desiredNameIdFormat, $desiredSSOBinding, $desiredSLOBinding); } } catch (Exception $e) { + throw new Exception('Error on parseFileXML. '.$e->getMessage()); } return $metadataInfo; } @@ -158,6 +160,10 @@ class IdPMetadataParser 'url' => $sloNodes->item(0)->getAttribute('Location'), 'binding' => $sloNodes->item(0)->getAttribute('Binding') ); + + if ($sloNodes->item(0)->hasAttribute('ResponseLocation')) { + $metadataInfo['idp']['singleLogoutService']['responseUrl'] = $sloNodes->item(0)->getAttribute('ResponseLocation'); + } } $keyDescriptorCertSigningNodes = Utils::query($dom, './md:KeyDescriptor[not(contains(@use, "encryption"))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate', $idpDescriptor); diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/LogoutRequest.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/LogoutRequest.php index 4cd7efb..d540c22 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/LogoutRequest.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/LogoutRequest.php @@ -104,7 +104,7 @@ class LogoutRequest $nameIdFormat = Constants::NAMEID_ENTITY; } - /* From saml-core-2.0-os 8.3.6, when the entity Format is used: + /* From saml-core-2.0-os 8.3.6, when the entity Format is used: "The NameQualifier, SPNameQualifier, and SPProvidedID attributes MUST be omitted. */ if (!empty($nameIdFormat) && $nameIdFormat == Constants::NAMEID_ENTITY) { @@ -278,7 +278,7 @@ LOGOUTREQUEST; * @param string|null $key The SP key * * @return string Name ID Value - * + * * @throws Error * @throws Exception * @throws ValidationError @@ -295,7 +295,7 @@ LOGOUTREQUEST; * @param string|DOMDocument $request Logout Request Message * * @return string|null $issuer The Issuer - * + * * @throws Exception */ public static function getIssuer($request) @@ -324,7 +324,7 @@ LOGOUTREQUEST; * @param string|DOMDocument $request Logout Request Message * * @return array The SessionIndex value - * + * * @throws Exception */ public static function getSessionIndexes($request) @@ -350,7 +350,7 @@ LOGOUTREQUEST; * @param bool $retrieveParametersFromServer True if we want to use parameters from $_SERVER to validate the signature * * @return bool If the Logout Request is or not valid - * + * * @throws Exception * @throws ValidationError */ @@ -368,7 +368,7 @@ LOGOUTREQUEST; $security = $this->_settings->getSecurityData(); if ($security['wantXMLValidation']) { - $res = Utils::validateXML($dom, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive()); + $res = Utils::validateXML($dom, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive(), $this->_settings->getSchemasPath()); if (!$res instanceof DOMDocument) { throw new ValidationError( "Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd", @@ -393,11 +393,25 @@ LOGOUTREQUEST; // Check destination if ($dom->documentElement->hasAttribute('Destination')) { $destination = $dom->documentElement->getAttribute('Destination'); - if (!empty($destination) && strpos($destination, $currentURL) === false) { - throw new ValidationError( - "The LogoutRequest was received at $currentURL instead of $destination", - ValidationError::WRONG_DESTINATION - ); + if (empty($destination)) { + if (!$security['relaxDestinationValidation']) { + throw new ValidationError( + "The LogoutRequest has an empty Destination value", + ValidationError::EMPTY_DESTINATION + ); + } + } else { + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURL); + if (strncmp($destination, $currentURL, $urlComparisonLength) !== 0) { + $currentURLNoRouted = Utils::getSelfURLNoQuery(); + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURLNoRouted); + if (strncmp($destination, $currentURLNoRouted, $urlComparisonLength) !== 0) { + throw new ValidationError( + "The LogoutRequest was received at $currentURL instead of $destination", + ValidationError::WRONG_DESTINATION + ); + } + } } } diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/LogoutResponse.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/LogoutResponse.php index 2f376bb..700feb0 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/LogoutResponse.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/LogoutResponse.php @@ -65,10 +65,9 @@ class LogoutResponse * * @param Settings $settings Settings. * @param string|null $response An UUEncoded SAML Logout response from the IdP. - * + * * @throws Error * @throws Exception - * */ public function __construct(\OneLogin\Saml2\Settings $settings, $response = null) { @@ -140,7 +139,7 @@ class LogoutResponse * @param bool $retrieveParametersFromServer True if we want to use parameters from $_SERVER to validate the signature * * @return bool Returns if the SAML LogoutResponse is or not valid - * + * * @throws ValidationError */ public function isValid($requestId = null, $retrieveParametersFromServer = false) @@ -154,7 +153,7 @@ class LogoutResponse $security = $this->_settings->getSecurityData(); if ($security['wantXMLValidation']) { - $res = Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive()); + $res = Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive(), $this->_settings->getSchemasPath()); if (!$res instanceof DOMDocument) { throw new ValidationError( "Invalid SAML Logout Response. Not match the saml-schema-protocol-2.0.xsd", @@ -185,14 +184,27 @@ class LogoutResponse $currentURL = Utils::getSelfRoutedURLNoQuery(); - // Check destination if ($this->document->documentElement->hasAttribute('Destination')) { $destination = $this->document->documentElement->getAttribute('Destination'); - if (!empty($destination) && strpos($destination, $currentURL) === false) { - throw new ValidationError( - "The LogoutResponse was received at $currentURL instead of $destination", - ValidationError::WRONG_DESTINATION - ); + if (empty($destination)) { + if (!$security['relaxDestinationValidation']) { + throw new ValidationError( + "The LogoutResponse has an empty Destination value", + ValidationError::EMPTY_DESTINATION + ); + } + } else { + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURL); + if (strncmp($destination, $currentURL, $urlComparisonLength) !== 0) { + $currentURLNoRouted = Utils::getSelfURLNoQuery(); + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURLNoRouted); + if (strncmp($destination, $currentURLNoRouted, $urlComparisonLength) !== 0) { + throw new ValidationError( + "The LogoutResponse was received at $currentURL instead of $destination", + ValidationError::WRONG_DESTINATION + ); + } + } } } diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Metadata.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Metadata.php index 2efd113..922ad60 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Metadata.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Metadata.php @@ -200,7 +200,7 @@ METADATA_TEMPLATE; * @param string $digestAlgorithm Digest algorithm method * * @return string Signed Metadata - * + * * @throws Exception */ public static function signMetadata($metadata, $key, $cert, $signAlgorithm = XMLSecurityKey::RSA_SHA256, $digestAlgorithm = XMLSecurityDSig::SHA256) @@ -217,7 +217,7 @@ METADATA_TEMPLATE; * @param bool $wantsEncrypted Whether to include the KeyDescriptor for encryption * * @return string Metadata with KeyDescriptors - * + * * @throws Exception */ public static function addX509KeyDescriptors($metadata, $cert, $wantsEncrypted = true) diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Response.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Response.php index 90c3d5c..b34297f 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Response.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Response.php @@ -172,7 +172,7 @@ class Response if ($security['wantXMLValidation']) { $errorXmlMsg = "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"; - $res = Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive()); + $res = Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive(), $this->_settings->getSchemasPath()); if (!$res instanceof DOMDocument) { throw new ValidationError( $errorXmlMsg, @@ -182,7 +182,7 @@ class Response // If encrypted, check also the decrypted document if ($this->encrypted) { - $res = Utils::validateXML($this->decryptedDocument, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive()); + $res = Utils::validateXML($this->decryptedDocument, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive(), $this->_settings->getSchemasPath()); if (!$res instanceof DOMDocument) { throw new ValidationError( $errorXmlMsg, @@ -195,18 +195,33 @@ class Response $currentURL = Utils::getSelfRoutedURLNoQuery(); + $responseInResponseTo = null; if ($this->document->documentElement->hasAttribute('InResponseTo')) { $responseInResponseTo = $this->document->documentElement->getAttribute('InResponseTo'); } - // Check if the InResponseTo of the Response matchs the ID of the AuthNRequest (requestId) if provided - if (isset($requestId) && isset($responseInResponseTo) && $requestId != $responseInResponseTo) { + if (!isset($requestId) && isset($responseInResponseTo) && $security['rejectUnsolicitedResponsesWithInResponseTo']) { throw new ValidationError( - "The InResponseTo of the Response: $responseInResponseTo, does not match the ID of the AuthNRequest sent by the SP: $requestId", + "The Response has an InResponseTo attribute: " . $responseInResponseTo . " while no InResponseTo was expected", ValidationError::WRONG_INRESPONSETO ); } + // Check if the InResponseTo of the Response matchs the ID of the AuthNRequest (requestId) if provided + if (isset($requestId) && $requestId != $responseInResponseTo) { + if ($responseInResponseTo == null) { + throw new ValidationError( + "No InResponseTo at the Response, but it was provided the requestId related to the AuthNRequest sent by the SP: $requestId", + ValidationError::WRONG_INRESPONSETO + ); + } else { + throw new ValidationError( + "The InResponseTo of the Response: $responseInResponseTo, does not match the ID of the AuthNRequest sent by the SP: $requestId", + ValidationError::WRONG_INRESPONSETO + ); + } + } + if (!$this->encrypted && $security['wantAssertionsEncrypted']) { throw new ValidationError( "The assertion of the Response is not encrypted and the SP requires it", @@ -263,10 +278,11 @@ class Response ); } } else { - if (strpos($destination, $currentURL) !== 0) { + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURL); + if (strncmp($destination, $currentURL, $urlComparisonLength) !== 0) { $currentURLNoRouted = Utils::getSelfURLNoQuery(); - - if (strpos($destination, $currentURLNoRouted) !== 0) { + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURLNoRouted); + if (strncmp($destination, $currentURLNoRouted, $urlComparisonLength) !== 0) { throw new ValidationError( "The response was received at $currentURL instead of $destination", ValidationError::WRONG_DESTINATION @@ -383,7 +399,7 @@ class Response $encryptedIDNodes = Utils::query($this->decryptedDocument, '/samlp:Response/saml:Assertion/saml:Subject/saml:EncryptedID'); if ($encryptedIDNodes->length > 0) { throw new ValidationError( - 'Unsigned SAML Response that contains a signed and encrypted Assertion with encrypted nameId is not supported.', + 'SAML Response that contains an encrypted Assertion with encrypted nameId is not supported.', ValidationError::NOT_SUPPORTED ); } @@ -448,7 +464,7 @@ class Response /** * @return string|null the ID of the assertion in the Response - * + * * @throws ValidationError */ public function getAssertionId() diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Settings.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Settings.php index a6a41b7..3c953fc 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Settings.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Settings.php @@ -45,7 +45,7 @@ class Settings * * @var bool */ - private $_strict = false; + private $_strict = true; /** * Activate debug mode @@ -164,7 +164,7 @@ class Settings 'base' => $basePath, 'config' => $basePath, 'cert' => $basePath.'certs/', - 'lib' => $basePath.'src/' + 'lib' => $basePath.'src/Saml2/' ); if (defined('ONELOGIN_CUSTOMPATH')) { @@ -220,7 +220,21 @@ class Settings */ public function getSchemasPath() { - return $this->_paths['lib'].'schemas/'; + if (isset($this->_paths['schemas'])) { + return $this->_paths['schemas']; + } + return __DIR__ . '/schemas/'; + } + + /** + * Set schemas path + * + * @param string $path + * @return $this + */ + public function setSchemasPath($path) + { + $this->_paths['schemas'] = $path; } /** @@ -378,6 +392,16 @@ class Settings $this->_security['relaxDestinationValidation'] = false; } + // Strict Destination match validation + if (!isset($this->_security['destinationStrictlyMatches'])) { + $this->_security['destinationStrictlyMatches'] = false; + } + + // InResponseTo + if (!isset($this->_security['rejectUnsolicitedResponsesWithInResponseTo'])) { + $this->_security['rejectUnsolicitedResponsesWithInResponseTo'] = false; + } + // encrypt expected if (!isset($this->_security['wantAssertionsEncrypted'])) { $this->_security['wantAssertionsEncrypted'] = false; @@ -520,6 +544,14 @@ class Settings $errors[] = 'idp_slo_url_invalid'; } + if (isset($idp['singleLogoutService']) + && isset($idp['singleLogoutService']['responseUrl']) + && !empty($idp['singleLogoutService']['responseUrl']) + && !filter_var($idp['singleLogoutService']['responseUrl'], FILTER_VALIDATE_URL) + ) { + $errors[] = 'idp_slo_response_url_invalid'; + } + if (isset($settings['security'])) { $security = $settings['security']; @@ -588,8 +620,10 @@ class Settings } if (isset($security['signMetadata']) && is_array($security['signMetadata'])) { - if (!isset($security['signMetadata']['keyFileName']) - || !isset($security['signMetadata']['certFileName']) + if ((!isset($security['signMetadata']['keyFileName']) + || !isset($security['signMetadata']['certFileName'])) && + (!isset($security['signMetadata']['privateKey']) + || !isset($security['signMetadata']['x509cert'])) ) { $errors[] = 'sp_signMetadata_invalid'; } @@ -792,7 +826,7 @@ class Settings * * @param bool $alwaysPublishEncryptionCert When 'true', the returned * metadata will always include an 'encryption' KeyDescriptor. Otherwise, - * the 'encryption' KeyDescriptor will only be included if + * the 'encryption' KeyDescriptor will only be included if * $advancedSettings['security']['wantNameIdEncrypted'] or * $advancedSettings['security']['wantAssertionsEncrypted'] are enabled. * @param int|null $validUntil Metadata's valid time @@ -825,7 +859,7 @@ class Settings } //Sign Metadata - if (isset($this->_security['signMetadata']) && $this->_security['signMetadata'] !== false) { + if (isset($this->_security['signMetadata']) && $this->_security['signMetadata'] != false) { if ($this->_security['signMetadata'] === true) { $keyMetadata = $this->getSPkey(); $certMetadata = $cert; @@ -843,15 +877,8 @@ class Settings Error::PUBLIC_CERT_FILE_NOT_FOUND ); } - } else { - if (!isset($this->_security['signMetadata']['keyFileName']) - || !isset($this->_security['signMetadata']['certFileName']) - ) { - throw new Error( - 'Invalid Setting: signMetadata value of the sp is not valid', - Error::SETTINGS_INVALID_SYNTAX - ); - } + } else if (isset($this->_security['signMetadata']['keyFileName']) && + isset($this->_security['signMetadata']['certFileName'])) { $keyFileName = $this->_security['signMetadata']['keyFileName']; $certFileName = $this->_security['signMetadata']['certFileName']; @@ -875,6 +902,29 @@ class Settings } $keyMetadata = file_get_contents($keyMetadataFile); $certMetadata = file_get_contents($certMetadataFile); + } else if (isset($this->_security['signMetadata']['privateKey']) && + isset($this->_security['signMetadata']['x509cert'])) { + $keyMetadata = Utils::formatPrivateKey($this->_security['signMetadata']['privateKey']); + $certMetadata = Utils::formatCert($this->_security['signMetadata']['x509cert']); + if (!$keyMetadata) { + throw new Error( + 'Private key not found.', + Error::PRIVATE_KEY_FILE_NOT_FOUND + ); + } + + if (!$certMetadata) { + throw new Error( + 'Public cert not found.', + Error::PUBLIC_CERT_FILE_NOT_FOUND + ); + } + } else { + throw new Error( + 'Invalid Setting: signMetadata value of the sp is not valid', + Error::SETTINGS_INVALID_SYNTAX + ); + } $signatureAlgorithm = $this->_security['signatureAlgorithm']; @@ -898,7 +948,7 @@ class Settings assert(is_string($xml)); $errors = array(); - $res = Utils::validateXML($xml, 'saml-schema-metadata-2.0.xsd', $this->_debug); + $res = Utils::validateXML($xml, 'saml-schema-metadata-2.0.xsd', $this->_debug, $this->getSchemasPath()); if (!$res instanceof DOMDocument) { $errors[] = $res; } else { diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Utils.php b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Utils.php index 73d1695..50d3d41 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/Utils.php +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/Utils.php @@ -111,12 +111,13 @@ class Utils * @param string|DOMDocument $xml The XML string or document which should be validated. * @param string $schema The schema filename which should be used. * @param bool $debug To disable/enable the debug mode + * @param string $schemaPath Change schema path * * @return string|DOMDocument $dom string that explains the problem or the DOMDocument * * @throws Exception */ - public static function validateXML($xml, $schema, $debug = false) + public static function validateXML($xml, $schema, $debug = false, $schemaPath = null) { assert(is_string($xml) || $xml instanceof DOMDocument); assert(is_string($schema)); @@ -134,7 +135,12 @@ class Utils } } - $schemaFile = __DIR__ . '/schemas/' . $schema; + if (isset($schemaPath)) { + $schemaFile = $schemaPath . $schema; + } else { + $schemaFile = __DIR__ . '/schemas/' . $schema; + } + $oldEntityLoader = libxml_disable_entity_loader(false); $res = $dom->schemaValidate($schemaFile); libxml_disable_entity_loader($oldEntityLoader); @@ -622,7 +628,7 @@ class Utils if (!empty($_SERVER['REQUEST_URI'])) { $route = $_SERVER['REQUEST_URI']; if (!empty($_SERVER['QUERY_STRING'])) { - $route = str_replace($_SERVER['QUERY_STRING'], '', $route); + $route = self::strLreplace($_SERVER['QUERY_STRING'], '', $route); if (substr($route, -1) == '?') { $route = substr($route, 0, -1); } @@ -635,9 +641,26 @@ class Utils } $selfRoutedURLNoQuery = $selfURLhost . $route; + + $pos = strpos($selfRoutedURLNoQuery, "?"); + if ($pos !== false) { + $selfRoutedURLNoQuery = substr($selfRoutedURLNoQuery, 0, $pos-1); + } + return $selfRoutedURLNoQuery; } + public static function strLreplace($search, $replace, $subject) + { + $pos = strrpos($subject, $search); + + if ($pos !== false) { + $subject = substr_replace($subject, $replace, $pos, strlen($search)); + } + + return $subject; + } + /** * Returns the URL of the current host + current view + query. * @@ -1531,7 +1554,7 @@ class Utils } } - if ($objKey->verifySignature($signedQuery, base64_decode($_GET['Signature'])) === 1) { + if ($objKey->verifySignature($signedQuery, base64_decode($getData['Signature'])) === 1) { $signatureValid = true; break; } diff --git a/3rdparty/vendor/onelogin/php-saml/src/Saml2/version.json b/3rdparty/vendor/onelogin/php-saml/src/Saml2/version.json index a0e37fa..0fdfc33 100644 --- a/3rdparty/vendor/onelogin/php-saml/src/Saml2/version.json +++ b/3rdparty/vendor/onelogin/php-saml/src/Saml2/version.json @@ -1,7 +1,7 @@ { "php-saml": { - "version": "3.1.1", - "released": "20/02/2019" + "version": "3.4.1", + "released": "25/11/2019" } } diff --git a/3rdparty/vendor/robrichards/xmlseclibs/CHANGELOG.txt b/3rdparty/vendor/robrichards/xmlseclibs/CHANGELOG.txt index a02bc7a..351b104 100644 --- a/3rdparty/vendor/robrichards/xmlseclibs/CHANGELOG.txt +++ b/3rdparty/vendor/robrichards/xmlseclibs/CHANGELOG.txt @@ -1,5 +1,33 @@ xmlseclibs.php ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +05, Sep 2020, 3.1.1 +Features: +- Support OAEP (iggyvolz) + +Bug Fixes: +- Fix AES128 (iggyvolz) + +Improvements: +- Fix tests for older PHP + +22, Apr 2020, 3.1.0 +Features: +- Support AES-GCM. Requires PHP 7.1. (François Kooman) + +Improvements: +- Fix Travis tests for older PHP versions. +- Use DOMElement interface to fix some IDEs reporting documentation errors + +Bug Fixes: +- FIX missing InclusiveNamespaces PrefixList from Java + Apache WSS4J. (njake) + +06, Nov 2019, 3.0.4 +Security Improvements: +- Insure only a single SignedInfo element exists within a signature during + verification. Refs CVE-2019-3465. +Bug Fixes: +- Fix variable casing. + 15, Nov 2018, 3.0.3 Bug Fixes: - Fix casing of class name. (Willem Stuursma-Ruwen) diff --git a/3rdparty/vendor/robrichards/xmlseclibs/LICENSE b/3rdparty/vendor/robrichards/xmlseclibs/LICENSE index 54b1e87..4fe5e5f 100644 --- a/3rdparty/vendor/robrichards/xmlseclibs/LICENSE +++ b/3rdparty/vendor/robrichards/xmlseclibs/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2007-2018, Robert Richards . +Copyright (c) 2007-2019, Robert Richards . All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/3rdparty/vendor/robrichards/xmlseclibs/README.md b/3rdparty/vendor/robrichards/xmlseclibs/README.md index e8ebd02..a576080 100644 --- a/3rdparty/vendor/robrichards/xmlseclibs/README.md +++ b/3rdparty/vendor/robrichards/xmlseclibs/README.md @@ -5,8 +5,9 @@ xmlseclibs is a library written in PHP for working with XML Encryption and Signa The author of xmlseclibs is Rob Richards. # Branches -Both the master and the 2.0 branches are actively maintained. -* master: Removes mcrypt usage requiring 5.4+ (5.6.24+ recommended for security reasons) +Master is currently the only actively maintained branch. +* master/3.1: Added AES-GCM support requiring 7.1+ +* 3.0: Removes mcrypt usage requiring 5.4+ (5.6.24+ recommended for security reasons) * 2.0: Contains namespace support requiring 5.3+ * 1.4: Contains auto-loader support while also maintaining backwards compatiblity with the older 1.3 version using the xmlseclibs.php file. Supports PHP 5.2+ diff --git a/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecEnc.php b/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecEnc.php index 7a95b5e..b9df761 100644 --- a/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecEnc.php +++ b/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecEnc.php @@ -2,6 +2,7 @@ namespace RobRichards\XMLSecLibs; use DOMDocument; +use DOMElement; use DOMNode; use DOMXPath; use Exception; @@ -10,7 +11,7 @@ use RobRichards\XMLSecLibs\Utils\XPath as XPath; /** * xmlseclibs.php * - * Copyright (c) 2007-2018, Robert Richards . + * Copyright (c) 2007-2020, Robert Richards . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,7 +44,7 @@ use RobRichards\XMLSecLibs\Utils\XPath as XPath; * POSSIBILITY OF SUCH DAMAGE. * * @author Robert Richards - * @copyright 2007-2018 Robert Richards + * @copyright 2007-2020 Robert Richards * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ diff --git a/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecurityDSig.php b/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecurityDSig.php index 9ae4a96..9986123 100644 --- a/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecurityDSig.php +++ b/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecurityDSig.php @@ -11,7 +11,7 @@ use RobRichards\XMLSecLibs\Utils\XPath as XPath; /** * xmlseclibs.php * - * Copyright (c) 2007-2018, Robert Richards . + * Copyright (c) 2007-2020, Robert Richards . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,7 +44,7 @@ use RobRichards\XMLSecLibs\Utils\XPath as XPath; * POSSIBILITY OF SUCH DAMAGE. * * @author Robert Richards - * @copyright 2007-2018 Robert Richards + * @copyright 2007-2020 Robert Richards * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ @@ -194,6 +194,11 @@ class XMLSecurityDSig $query = ".//secdsig:Signature"; $nodeset = $xpath->query($query, $objDoc); $this->sigNode = $nodeset->item($pos); + $query = "./secdsig:SignedInfo"; + $nodeset = $xpath->query($query, $this->sigNode); + if ($nodeset->length > 1) { + throw new Exception("Invalid structure - Too many SignedInfo elements found"); + } return $this->sigNode; } return null; @@ -303,13 +308,28 @@ class XMLSecurityDSig $xpath = $this->getXPathObj(); $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); + if ($nodeset->length > 1) { + throw new Exception("Invalid structure - Too many SignedInfo elements found"); + } if ($signInfoNode = $nodeset->item(0)) { $query = "./secdsig:CanonicalizationMethod"; $nodeset = $xpath->query($query, $signInfoNode); + $prefixList = null; if ($canonNode = $nodeset->item(0)) { $canonicalmethod = $canonNode->getAttribute('Algorithm'); + foreach ($canonNode->childNodes as $node) + { + if ($node->localName == 'InclusiveNamespaces') { + if ($pfx = $node->getAttribute('PrefixList')) { + $arpfx = array_filter(explode(' ', $pfx)); + if (count($arpfx) > 0) { + $prefixList = array_merge($prefixList ? $prefixList : array(), $arpfx); + } + } + } + } } - $this->signedInfo = $this->canonicalizeData($signInfoNode, $canonicalmethod); + $this->signedInfo = $this->canonicalizeData($signInfoNode, $canonicalmethod, null, $prefixList); return $this->signedInfo; } } @@ -440,7 +460,7 @@ class XMLSecurityDSig if ($node->localName == 'XPath') { $arXPath = array(); $arXPath['query'] = '(.//. | .//@* | .//namespace::*)['.$node->nodeValue.']'; - $arXpath['namespaces'] = array(); + $arXPath['namespaces'] = array(); $nslist = $xpath->query('./namespace::*', $node); foreach ($nslist AS $nsnode) { if ($nsnode->localName != "xml") { @@ -554,7 +574,7 @@ class XMLSecurityDSig $refids = array(); $xpath = $this->getXPathObj(); - $query = "./secdsig:SignedInfo/secdsig:Reference"; + $query = "./secdsig:SignedInfo[1]/secdsig:Reference"; $nodeset = $xpath->query($query, $this->sigNode); if ($nodeset->length == 0) { throw new Exception("Reference nodes not found"); @@ -578,7 +598,7 @@ class XMLSecurityDSig } } $xpath = $this->getXPathObj(); - $query = "./secdsig:SignedInfo/secdsig:Reference"; + $query = "./secdsig:SignedInfo[1]/secdsig:Reference"; $nodeset = $xpath->query($query, $this->sigNode); if ($nodeset->length == 0) { throw new Exception("Reference nodes not found"); diff --git a/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecurityKey.php b/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecurityKey.php index 5d855bf..7eed04d 100644 --- a/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecurityKey.php +++ b/3rdparty/vendor/robrichards/xmlseclibs/src/XMLSecurityKey.php @@ -7,7 +7,7 @@ use Exception; /** * xmlseclibs.php * - * Copyright (c) 2007-2018, Robert Richards . + * Copyright (c) 2007-2020, Robert Richards . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,7 +40,7 @@ use Exception; * POSSIBILITY OF SUCH DAMAGE. * * @author Robert Richards - * @copyright 2007-2018 Robert Richards + * @copyright 2007-2020 Robert Richards * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ @@ -50,14 +50,19 @@ class XMLSecurityKey const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'; const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'; const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'; + const AES128_GCM = 'http://www.w3.org/2009/xmlenc11#aes128-gcm'; + const AES192_GCM = 'http://www.w3.org/2009/xmlenc11#aes192-gcm'; + const AES256_GCM = 'http://www.w3.org/2009/xmlenc11#aes256-gcm'; const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'; const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'; + const RSA_OAEP = 'http://www.w3.org/2009/xmlenc11#rsa-oaep'; const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'; const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'; const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'; const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1'; + const AUTHTAG_LENGTH = 16; /** @var array */ private $cryptParams = array(); @@ -142,6 +147,30 @@ class XMLSecurityKey $this->cryptParams['keysize'] = 32; $this->cryptParams['blocksize'] = 16; break; + case (self::AES128_GCM): + $this->cryptParams['library'] = 'openssl'; + $this->cryptParams['cipher'] = 'aes-128-gcm'; + $this->cryptParams['type'] = 'symmetric'; + $this->cryptParams['method'] = 'http://www.w3.org/2009/xmlenc11#aes128-gcm'; + $this->cryptParams['keysize'] = 16; + $this->cryptParams['blocksize'] = 16; + break; + case (self::AES192_GCM): + $this->cryptParams['library'] = 'openssl'; + $this->cryptParams['cipher'] = 'aes-192-gcm'; + $this->cryptParams['type'] = 'symmetric'; + $this->cryptParams['method'] = 'http://www.w3.org/2009/xmlenc11#aes192-gcm'; + $this->cryptParams['keysize'] = 24; + $this->cryptParams['blocksize'] = 16; + break; + case (self::AES256_GCM): + $this->cryptParams['library'] = 'openssl'; + $this->cryptParams['cipher'] = 'aes-256-gcm'; + $this->cryptParams['type'] = 'symmetric'; + $this->cryptParams['method'] = 'http://www.w3.org/2009/xmlenc11#aes256-gcm'; + $this->cryptParams['keysize'] = 32; + $this->cryptParams['blocksize'] = 16; + break; case (self::RSA_1_5): $this->cryptParams['library'] = 'openssl'; $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; @@ -165,6 +194,18 @@ class XMLSecurityKey } } throw new Exception('Certificate "type" (private/public) must be passed via parameters'); + case (self::RSA_OAEP): + $this->cryptParams['library'] = 'openssl'; + $this->cryptParams['padding'] = OPENSSL_PKCS1_OAEP_PADDING; + $this->cryptParams['method'] = 'http://www.w3.org/2009/xmlenc11#rsa-oaep'; + $this->cryptParams['hash'] = 'http://www.w3.org/2009/xmlenc11#mgf1sha1'; + if (is_array($params) && ! empty($params['type'])) { + if ($params['type'] == 'public' || $params['type'] == 'private') { + $this->cryptParams['type'] = $params['type']; + break; + } + } + throw new Exception('Certificate "type" (private/public) must be passed via parameters'); case (self::RSA_SHA1): $this->cryptParams['library'] = 'openssl'; $this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; @@ -347,7 +388,7 @@ class XMLSecurityKey case'symmetric': if (strlen($this->key) < $this->cryptParams['keysize']) { - throw new Exception('Key must contain at least 25 characters for this cipher'); + throw new Exception('Key must contain at least '.$this->cryptParams['keysize'].' characters for this cipher, contains '.strlen($this->key)); } break; @@ -397,12 +438,22 @@ class XMLSecurityKey private function encryptSymmetric($data) { $this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cryptParams['cipher'])); - $data = $this->padISO10126($data, $this->cryptParams['blocksize']); - $encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv); + $authTag = null; + if(in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { + if (version_compare(PHP_VERSION, '7.1.0') < 0) { + throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms'); + } + $authTag = openssl_random_pseudo_bytes(self::AUTHTAG_LENGTH); + $encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA, $this->iv, $authTag); + } else { + $data = $this->padISO10126($data, $this->cryptParams['blocksize']); + $encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv); + } + if (false === $encrypted) { throw new Exception('Failure encrypting Data (openssl symmetric) - ' . openssl_error_string()); } - return $this->iv . $encrypted; + return $this->iv . $encrypted . $authTag; } /** @@ -416,11 +467,24 @@ class XMLSecurityKey $iv_length = openssl_cipher_iv_length($this->cryptParams['cipher']); $this->iv = substr($data, 0, $iv_length); $data = substr($data, $iv_length); - $decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv); + $authTag = null; + if(in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { + if (version_compare(PHP_VERSION, '7.1.0') < 0) { + throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms'); + } + // obtain and remove the authentication tag + $offset = 0 - self::AUTHTAG_LENGTH; + $authTag = substr($data, $offset); + $data = substr($data, 0, $offset); + $decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA, $this->iv, $authTag); + } else { + $decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv); + } + if (false === $decrypted) { throw new Exception('Failure decrypting Data (openssl symmetric) - ' . openssl_error_string()); } - return $this->unpadISO10126($decrypted); + return null !== $authTag ? $decrypted : $this->unpadISO10126($decrypted); } /** diff --git a/3rdparty/vendor/robrichards/xmlseclibs/xmlseclibs.php b/3rdparty/vendor/robrichards/xmlseclibs/xmlseclibs.php index e399860..1c10acc 100644 --- a/3rdparty/vendor/robrichards/xmlseclibs/xmlseclibs.php +++ b/3rdparty/vendor/robrichards/xmlseclibs/xmlseclibs.php @@ -2,7 +2,7 @@ /** * xmlseclibs.php * - * Copyright (c) 2007-2018, Robert Richards . + * Copyright (c) 2007-2020, Robert Richards . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,9 +35,9 @@ * POSSIBILITY OF SUCH DAMAGE. * * @author Robert Richards - * @copyright 2007-2018 Robert Richards + * @copyright 2007-2020 Robert Richards * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version 3.0.3-dev + * @version 3.1.1 */ $xmlseclibs_srcdir = dirname(__FILE__) . '/src/';