Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/user_saml.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Reschke <lukas@owncloud.com>2016-06-29 01:04:23 +0300
committerLukas Reschke <lukas@owncloud.com>2016-06-29 01:04:23 +0300
commitada6b6ebc800c8b44e7e10144b72ce07ce1cd8da (patch)
treeb9bb9b6e6d532ee2b8eecc9e371cdd4dc8f88b0c /3rdparty
parent4d2517473a458191f164b1ad90822519dd28d85f (diff)
Initial import
Diffstat (limited to '3rdparty')
-rw-r--r--3rdparty/composer.json5
-rw-r--r--3rdparty/composer.lock73
-rw-r--r--3rdparty/vendor/autoload.php7
-rw-r--r--3rdparty/vendor/composer/ClassLoader.php413
-rw-r--r--3rdparty/vendor/composer/LICENSE21
-rw-r--r--3rdparty/vendor/composer/autoload_classmap.php27
-rw-r--r--3rdparty/vendor/composer/autoload_namespaces.php9
-rw-r--r--3rdparty/vendor/composer/autoload_psr4.php9
-rw-r--r--3rdparty/vendor/composer/autoload_real.php45
-rw-r--r--3rdparty/vendor/composer/installed.json58
-rw-r--r--3rdparty/vendor/onelogin/php-saml/.coveralls.yml7
-rw-r--r--3rdparty/vendor/onelogin/php-saml/.gitignore14
-rw-r--r--3rdparty/vendor/onelogin/php-saml/.travis.yml33
-rw-r--r--3rdparty/vendor/onelogin/php-saml/CHANGELOG121
-rw-r--r--3rdparty/vendor/onelogin/php-saml/LICENSE19
-rw-r--r--3rdparty/vendor/onelogin/php-saml/README.md1411
-rw-r--r--3rdparty/vendor/onelogin/php-saml/_toolkit_loader.php25
-rw-r--r--3rdparty/vendor/onelogin/php-saml/advanced_settings_example.php106
-rw-r--r--3rdparty/vendor/onelogin/php-saml/compatibility.php12
-rw-r--r--3rdparty/vendor/onelogin/php-saml/composer.json39
-rw-r--r--3rdparty/vendor/onelogin/php-saml/endpoints/acs.php51
-rw-r--r--3rdparty/vendor/onelogin/php-saml/endpoints/metadata.php25
-rw-r--r--3rdparty/vendor/onelogin/php-saml/endpoints/sls.php21
-rw-r--r--3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/CHANGELOG.txt130
-rw-r--r--3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/LICENSE31
-rw-r--r--3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php1721
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml/AuthRequest.php65
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml/Metadata.php39
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml/Response.php39
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml/Settings.php80
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml/XmlSec.php110
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/Auth.php514
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/AuthnRequest.php158
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/Constants.php69
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/Error.php41
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/LogoutRequest.php384
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/LogoutResponse.php264
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/Metadata.php184
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/Response.php754
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/Settings.php873
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/Utils.php1077
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-assertion-2.0.xsd283
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-authn-context-2.0.xsd23
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-authn-context-types-2.0.xsd821
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-metadata-2.0.xsd336
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-protocol-2.0.xsd302
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-metadata-attr.xsd35
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-attribute-ext.xsd25
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-metadata-algsupport-v1.0.xsd41
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-metadata-ui-v1.0.xsd89
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xenc-schema.xsd136
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xml.xsd287
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xmldsig-core-schema.xsd309
-rw-r--r--3rdparty/vendor/onelogin/php-saml/lib/Saml2/version.json6
-rw-r--r--3rdparty/vendor/onelogin/php-saml/locale/en_US/LC_MESSAGES/phptoolkit.mobin0 -> 200 bytes
-rw-r--r--3rdparty/vendor/onelogin/php-saml/locale/en_US/LC_MESSAGES/phptoolkit.po26
-rw-r--r--3rdparty/vendor/onelogin/php-saml/locale/es_ES/LC_MESSAGES/phptoolkit.mobin0 -> 405 bytes
-rw-r--r--3rdparty/vendor/onelogin/php-saml/locale/es_ES/LC_MESSAGES/phptoolkit.po27
-rw-r--r--3rdparty/vendor/onelogin/php-saml/phpdoc.xml37
-rw-r--r--3rdparty/vendor/onelogin/php-saml/settings_example.php84
60 files changed, 11951 insertions, 0 deletions
diff --git a/3rdparty/composer.json b/3rdparty/composer.json
new file mode 100644
index 00000000..37dc1169
--- /dev/null
+++ b/3rdparty/composer.json
@@ -0,0 +1,5 @@
+{
+ "require": {
+ "onelogin/php-saml": "^2.9"
+ }
+}
diff --git a/3rdparty/composer.lock b/3rdparty/composer.lock
new file mode 100644
index 00000000..9201ebee
--- /dev/null
+++ b/3rdparty/composer.lock
@@ -0,0 +1,73 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "hash": "993f6c41684d235f66993e52d9b7dce0",
+ "content-hash": "bf3d6d016eca22c120719d73eb98378d",
+ "packages": [
+ {
+ "name": "onelogin/php-saml",
+ "version": "2.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/onelogin/php-saml.git",
+ "reference": "64aff7d58e68d98eaa9220e1041da2bc9214ab51"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/onelogin/php-saml/zipball/64aff7d58e68d98eaa9220e1041da2bc9214ab51",
+ "reference": "64aff7d58e68d98eaa9220e1041da2bc9214ab51",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-mcrypt": "*",
+ "ext-openssl": "*",
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "pdepend/pdepend": "1.1.0",
+ "phploc/phploc": "*",
+ "phpunit/phpunit": "4.8",
+ "satooshi/php-coveralls": "1.0.1",
+ "sebastian/phpcpd": "*",
+ "squizlabs/php_codesniffer": "*"
+ },
+ "suggest": {
+ "ext-gettext": "Install gettext and php5-gettext libs to handle translations",
+ "ext-mcrypt": "Install mcrypt and php5-mcrypt libs in order to support encryption",
+ "lib-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "extlib/xmlseclibs",
+ "lib/Saml",
+ "lib/Saml2"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "OneLogin PHP SAML Toolkit",
+ "homepage": "https://onelogin.zendesk.com/hc/en-us/sections/200245634-SAML-Toolkits",
+ "keywords": [
+ "SAML2",
+ "onelogin",
+ "saml"
+ ],
+ "time": "2016-06-27 09:24:27"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": []
+}
diff --git a/3rdparty/vendor/autoload.php b/3rdparty/vendor/autoload.php
new file mode 100644
index 00000000..c4b92730
--- /dev/null
+++ b/3rdparty/vendor/autoload.php
@@ -0,0 +1,7 @@
+<?php
+
+// autoload.php @generated by Composer
+
+require_once __DIR__ . '/composer' . '/autoload_real.php';
+
+return ComposerAutoloaderInitcc75f134f7630c1ee3a8e4d7c86f3bcc::getLoader();
diff --git a/3rdparty/vendor/composer/ClassLoader.php b/3rdparty/vendor/composer/ClassLoader.php
new file mode 100644
index 00000000..ff6ecfb8
--- /dev/null
+++ b/3rdparty/vendor/composer/ClassLoader.php
@@ -0,0 +1,413 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @see http://www.php-fig.org/psr/psr-0/
+ * @see http://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ // PSR-4
+ private $prefixLengthsPsr4 = array();
+ private $prefixDirsPsr4 = array();
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ private $prefixesPsr0 = array();
+ private $fallbackDirsPsr0 = array();
+
+ private $useIncludePath = false;
+ private $classMap = array();
+
+ private $classMapAuthoritative = false;
+
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
+ }
+
+ return array();
+ }
+
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array $classMap Class to filename map
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 base directories
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return bool|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ includeFile($file);
+
+ return true;
+ }
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
+ if ('\\' == $class[0]) {
+ $class = substr($class, 1);
+ }
+
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative) {
+ return false;
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if ($file === null && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if ($file === null) {
+ // Remember that this class does not exist.
+ return $this->classMap[$class] = false;
+ }
+
+ return $file;
+ }
+
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+ }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ */
+function includeFile($file)
+{
+ include $file;
+}
diff --git a/3rdparty/vendor/composer/LICENSE b/3rdparty/vendor/composer/LICENSE
new file mode 100644
index 00000000..1a281248
--- /dev/null
+++ b/3rdparty/vendor/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) 2016 Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/3rdparty/vendor/composer/autoload_classmap.php b/3rdparty/vendor/composer/autoload_classmap.php
new file mode 100644
index 00000000..e1d1173b
--- /dev/null
+++ b/3rdparty/vendor/composer/autoload_classmap.php
@@ -0,0 +1,27 @@
+<?php
+
+// autoload_classmap.php @generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+ 'OneLogin_Saml2_Auth' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Auth.php',
+ 'OneLogin_Saml2_AuthnRequest' => $vendorDir . '/onelogin/php-saml/lib/Saml2/AuthnRequest.php',
+ 'OneLogin_Saml2_Constants' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Constants.php',
+ 'OneLogin_Saml2_Error' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Error.php',
+ 'OneLogin_Saml2_LogoutRequest' => $vendorDir . '/onelogin/php-saml/lib/Saml2/LogoutRequest.php',
+ 'OneLogin_Saml2_LogoutResponse' => $vendorDir . '/onelogin/php-saml/lib/Saml2/LogoutResponse.php',
+ 'OneLogin_Saml2_Metadata' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Metadata.php',
+ 'OneLogin_Saml2_Response' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Response.php',
+ 'OneLogin_Saml2_Settings' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Settings.php',
+ 'OneLogin_Saml2_Utils' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Utils.php',
+ 'OneLogin_Saml_AuthRequest' => $vendorDir . '/onelogin/php-saml/lib/Saml/AuthRequest.php',
+ 'OneLogin_Saml_Metadata' => $vendorDir . '/onelogin/php-saml/lib/Saml/Metadata.php',
+ 'OneLogin_Saml_Response' => $vendorDir . '/onelogin/php-saml/lib/Saml/Response.php',
+ 'OneLogin_Saml_Settings' => $vendorDir . '/onelogin/php-saml/lib/Saml/Settings.php',
+ 'OneLogin_Saml_XmlSec' => $vendorDir . '/onelogin/php-saml/lib/Saml/XmlSec.php',
+ 'XMLSecEnc' => $vendorDir . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
+ 'XMLSecurityDSig' => $vendorDir . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
+ 'XMLSecurityKey' => $vendorDir . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
+);
diff --git a/3rdparty/vendor/composer/autoload_namespaces.php b/3rdparty/vendor/composer/autoload_namespaces.php
new file mode 100644
index 00000000..b7fc0125
--- /dev/null
+++ b/3rdparty/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,9 @@
+<?php
+
+// autoload_namespaces.php @generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+);
diff --git a/3rdparty/vendor/composer/autoload_psr4.php b/3rdparty/vendor/composer/autoload_psr4.php
new file mode 100644
index 00000000..b265c64a
--- /dev/null
+++ b/3rdparty/vendor/composer/autoload_psr4.php
@@ -0,0 +1,9 @@
+<?php
+
+// autoload_psr4.php @generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+);
diff --git a/3rdparty/vendor/composer/autoload_real.php b/3rdparty/vendor/composer/autoload_real.php
new file mode 100644
index 00000000..f83acede
--- /dev/null
+++ b/3rdparty/vendor/composer/autoload_real.php
@@ -0,0 +1,45 @@
+<?php
+
+// autoload_real.php @generated by Composer
+
+class ComposerAutoloaderInitcc75f134f7630c1ee3a8e4d7c86f3bcc
+{
+ private static $loader;
+
+ public static function loadClassLoader($class)
+ {
+ if ('Composer\Autoload\ClassLoader' === $class) {
+ require __DIR__ . '/ClassLoader.php';
+ }
+ }
+
+ public static function getLoader()
+ {
+ if (null !== self::$loader) {
+ return self::$loader;
+ }
+
+ spl_autoload_register(array('ComposerAutoloaderInitcc75f134f7630c1ee3a8e4d7c86f3bcc', 'loadClassLoader'), true, true);
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader();
+ spl_autoload_unregister(array('ComposerAutoloaderInitcc75f134f7630c1ee3a8e4d7c86f3bcc', 'loadClassLoader'));
+
+ $map = require __DIR__ . '/autoload_namespaces.php';
+ foreach ($map as $namespace => $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+
+ $loader->register(true);
+
+ return $loader;
+ }
+}
diff --git a/3rdparty/vendor/composer/installed.json b/3rdparty/vendor/composer/installed.json
new file mode 100644
index 00000000..2b236bfb
--- /dev/null
+++ b/3rdparty/vendor/composer/installed.json
@@ -0,0 +1,58 @@
+[
+ {
+ "name": "onelogin/php-saml",
+ "version": "2.9.0",
+ "version_normalized": "2.9.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/onelogin/php-saml.git",
+ "reference": "64aff7d58e68d98eaa9220e1041da2bc9214ab51"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/onelogin/php-saml/zipball/64aff7d58e68d98eaa9220e1041da2bc9214ab51",
+ "reference": "64aff7d58e68d98eaa9220e1041da2bc9214ab51",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-mcrypt": "*",
+ "ext-openssl": "*",
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "pdepend/pdepend": "1.1.0",
+ "phploc/phploc": "*",
+ "phpunit/phpunit": "4.8",
+ "satooshi/php-coveralls": "1.0.1",
+ "sebastian/phpcpd": "*",
+ "squizlabs/php_codesniffer": "*"
+ },
+ "suggest": {
+ "ext-gettext": "Install gettext and php5-gettext libs to handle translations",
+ "ext-mcrypt": "Install mcrypt and php5-mcrypt libs in order to support encryption",
+ "lib-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)"
+ },
+ "time": "2016-06-27 09:24:27",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ "extlib/xmlseclibs",
+ "lib/Saml",
+ "lib/Saml2"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "OneLogin PHP SAML Toolkit",
+ "homepage": "https://onelogin.zendesk.com/hc/en-us/sections/200245634-SAML-Toolkits",
+ "keywords": [
+ "SAML2",
+ "onelogin",
+ "saml"
+ ]
+ }
+]
diff --git a/3rdparty/vendor/onelogin/php-saml/.coveralls.yml b/3rdparty/vendor/onelogin/php-saml/.coveralls.yml
new file mode 100644
index 00000000..173ff356
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/.coveralls.yml
@@ -0,0 +1,7 @@
+service_name: travis-ci
+
+src_dir: lib
+
+coverage_clover: tests/build/logs/clover.xml
+
+json_path: tests/build/logs/coveralls-upload.json
diff --git a/3rdparty/vendor/onelogin/php-saml/.gitignore b/3rdparty/vendor/onelogin/php-saml/.gitignore
new file mode 100644
index 00000000..239418ab
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/.gitignore
@@ -0,0 +1,14 @@
+*.swp
+*~
+.DS_Store
+/settings.php
+/demo1/settings.php
+/demo-old/settings.php
+/certs/sp.key
+/certs/sp.crt
+/certs/metadata.key
+/certs/metadata.crt
+/tests/build
+/vendor
+/composer.lock
+/.idea
diff --git a/3rdparty/vendor/onelogin/php-saml/.travis.yml b/3rdparty/vendor/onelogin/php-saml/.travis.yml
new file mode 100644
index 00000000..c024fa09
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/.travis.yml
@@ -0,0 +1,33 @@
+language: php
+
+php:
+ - 5.6
+ - 5.5
+ - 5.4
+ - 5.3
+ - 7.0
+
+env:
+ - TRAVIS=true
+
+before_install:
+ - curl -s https://getcomposer.org/installer | php
+ - php composer.phar install --prefer-source --no-interaction
+
+before_script:
+ - phpenv config-rm xdebug.ini
+
+script:
+ - phpunit --bootstrap tests/bootstrap.php --configuration tests/phpunit.xml
+ - php vendor/bin/phpcpd --exclude tests --exclude vendor .
+ - php vendor/bin/phploc . --exclude vendor
+ - php vendor/bin/phploc lib/.
+ - mkdir -p tests/build/dependences
+ - php vendor/bin/pdepend --summary-xml=tests/build/logs/dependence-summary.xml --jdepend-chart=tests/build/dependences/jdepend.svg --overview-pyramid=tests/build/dependences/pyramid.svg lib/.
+ - php vendor/bin/phpcs --standard=tests/ZendModStandard lib/Saml2 demo1 demo2 demo-old endpoints tests/src
+
+after_script:
+ - export TRAVIS=https://travis-ci.org/onelogin/php-saml
+ - echo $TRAVIS
+ - echo $TRAVIS_JOB_ID
+ - php vendor/bin/coveralls --config .coveralls.yml -v
diff --git a/3rdparty/vendor/onelogin/php-saml/CHANGELOG b/3rdparty/vendor/onelogin/php-saml/CHANGELOG
new file mode 100644
index 00000000..005d07b8
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/CHANGELOG
@@ -0,0 +1,121 @@
+CHANGELOG
+=========
+
+v.2.9.0
+-------
+* Change the decrypt assertion process.
+* Add 2 extra validations to prevent Signature wrapping attacks.
+* Remove reference to wrong NameIDFormat: urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified should be urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
+* [128](https://github.com/onelogin/php-saml/pull/128) Test php7 and upgrade phpunit
+* Update Readme with more descriptive requestedAuthnContext description and Security Guidelines
+
+v.2.8.0
+-------
+* Make NameIDPolicy of AuthNRequest optional
+* Make nameID requirement on SAMLResponse optional
+* Fix empty URI support
+* Symmetric encryption key support
+* Add more Auth Context options to the constant class
+* Fix DSA_SHA1 constant on xmlseclibs
+* Set none requestedAuthnContext as default behaviour
+* Update xmlseclibs lib
+* Improve formatPrivateKey method
+* Fix bug when signing metadata, the SignatureMethod was not provided
+* Fix getter for lastRequestID parameter in OneLogin_Saml2_Auth class
+* Add $wantEncrypted parameter on addX509KeyDescriptors method that will allow to set KeyDescriptor[use='encryption'] if wantNameIdEncrypted or wantAssertionsEncrypted enabled
+* Add $stay parameter on redirectTo method. (login/logout supports $stay but I forgot add this on previous 2.7.0 version)
+* Improve code style
+
+v.2.7.0
+-------
+* Trim acs, slo and issuer urls.
+* Fix PHP 7 error (used continue outside a loop/switch).
+* Fix bug on organization element of the SP metadata builder.
+* Fix typos on documentation. Fix ALOWED Misspell.
+* Be able to extract RequestID. Add RequestID validation on demo1.
+* Add $stay parameter to login, logout and processSLO method.
+
+v.2.6.1
+-------
+* Fix bug on cacheDuration of the Metadata XML generated.
+* Make SPNameQualifier optional on the generateNameId method. Avoid the use of SPNameQualifier when generating the NameID on the LogoutRequest builder.
+* Allows the authn comparsion attribute to be set via config.
+* Retrieve Session Timeout after processResponse with getSessionExpiration().
+* Improve readme readability.
+* Allow single log out to work for applications not leveraging php session_start. Added a callback parameter in order to close the session at processSLO.
+
+v.2.6.0
+-------
+* Set NAMEID_UNSPECIFIED as default NameIDFormat to prevent conflicts with IdPs that don't support NAMEID_PERSISTENT.
+* Now the SP is able to select the algorithm to be used on signatures (DSA_SHA1, RSA_SHA1, RSA_SHA256, RSA_SHA384, RSA_SHA512).
+* Change visibility of _decryptAssertion to protected.
+* Update xmlseclibs library.
+* Handle valid but uncommon dsig block with no URI in the reference.
+* login, logout and processSLO now return ->redirectTo instead of just call it.
+* Split the setting check methods. Now 1 method for IdP settings and other for SP settings.
+* Let the setting object to avoid the IdP setting check. required if we want to publish SP SAML Metadata when the IdP data is still not provided.
+
+v.2.5.0
+-------
+* Do accesible the ID of the object Logout Request (id attribute).
+* Add note about the fact that PHP 5.3 is unssuported.
+* Add fingerprint algorithm support.
+* Add dependences to composer.
+
+v.2.4.0
+-------
+* Fix wrong element order in generated metadata.
+* Added SLO with nameID and SessionIndex in demo1.
+* Improve isHTTPS method in order to support HTTP_X_FORWARDED_PORT.
+* Set optional the XMLvalidation (enable/disable it with wantXMLValidation security setting).
+
+v.2.3.0
+-------
+* Resolve namespace problem. Some IdPs uses saml2p:Response and saml2:Assertion instead of samlp:Response saml:Assertion.
+* Improve test and documentation.
+* Improve ADFS compatibility.
+* Remove unnecessary XSDs files.
+* Make available the reason for the saml message invalidation.
+* Adding ability to set idp cert once the Setting object initialized.
+* Fix status info issue.
+* Reject SAML Response if not signed and strict = false.
+* Support NameId and SessionIndex in LogoutRequest.
+* Add ForceAuh and IsPassive support.
+
+v.2.2.0
+-------
+* Fix bug with Encrypted nameID on LogoutRequest.
+* Fixed usability bug. SP will inform about AuthFail status after process a Response.
+* Added SessionIndex support on LogoutRequest, and know is accesible from the Auth class.
+* LogoutRequest and LogoutResponse classes now accept non deflated xml.
+* Improved the XML metadata/ Decrypted Assertion output. (prettyprint).
+* Fix bug in formatPrivateKey method, the key could be not RSA.
+* Explicit warning message for signed element problem.
+* Decrypt method improved.
+* Support more algorithm at the SigAlg in the Signed LogoutRequests and LogoutResponses
+* AuthNRequest now stores ID (it can be retrieved later).
+* Fixed a typo on the 'NameIdPolicy' attribute that appeared at the README and settings_example file.
+
+
+v.2.1.0
+-------
+
+* The isValid method of the Logout Request is now non-static. (affects processSLO method of Auth.php).
+* Logout Request constructor now accepts encoded logout requests.
+* Now after validate a message, if fails a method getError of the object will return the cause.
+* Fix typos.
+* Added extra parameters option to login and logout methods.
+* Improve Test (new test, use the new getError method for testing).
+* Bugfix namespace problem when getting Attributes.
+
+
+v.2.0.0
+-------
+
+* New PHP SAML Toolkit (SLO, Sign, Encryptation).
+
+
+v.1.0.0
+-------
+
+* Old PHP SAML Toolkit.
diff --git a/3rdparty/vendor/onelogin/php-saml/LICENSE b/3rdparty/vendor/onelogin/php-saml/LICENSE
new file mode 100644
index 00000000..e6113ab2
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2010-2014 OneLogin, LLC
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/3rdparty/vendor/onelogin/php-saml/README.md b/3rdparty/vendor/onelogin/php-saml/README.md
new file mode 100644
index 00000000..49bca542
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/README.md
@@ -0,0 +1,1411 @@
+# OneLogin's SAML PHP Toolkit
+
+[![Build Status](https://api.travis-ci.org/onelogin/php-saml.png?branch=master)](http://travis-ci.org/onelogin/php-saml) [![Coverage Status](https://coveralls.io/repos/onelogin/php-saml/badge.png)](https://coveralls.io/r/onelogin/php-saml) [![License](https://poser.pugx.org/onelogin/php-saml/license.png)](https://packagist.org/packages/onelogin/php-saml)
+
+Add SAML support to your PHP softwares using this library.
+Forget those complicated libraries and use that open source library provided
+and supported by OneLogin Inc.
+
+
+Why add SAML support to my software?
+------------------------------------
+
+SAML is an XML-based standard for web browser single sign-on and is defined by
+the OASIS Security Services Technical Committee. The standard has been around
+since 2002, but lately it is becoming popular due its advantages:
+
+ * **Usability** - One-click access from portals or intranets, deep linking,
+ password elimination and automatically renewing sessions make life
+ easier for the user.
+ * **Security** - Based on strong digital signatures for authentication and
+ integrity, SAML is a secure single sign-on protocol that the largest
+ and most security conscious enterprises in the world rely on.
+ * **Speed** - SAML is fast. One browser redirect is all it takes to securely
+ sign a user into an application.
+ * **Phishing Prevention** - If you don’t have a password for an app, you
+ can’t be tricked into entering it on a fake login page.
+ * **IT Friendly** - SAML simplifies life for IT because it centralizes
+ authentication, provides greater visibility and makes directory
+ integration easier.
+ * **Opportunity** - B2B cloud vendor should support SAML to facilitate the
+ integration of their product.
+
+
+General description
+-------------------
+
+OneLogin's SAML PHP toolkit let you build a SP (Service Provider) over
+your PHP application and connect it to any IdP (Identity Provider).
+
+Supports:
+
+ * SSO and SLO (SP-Initiated and IdP-Initiated).
+ * Assertion and nameId encryption.
+ * Assertion signature.
+ * Message signature: AuthNRequest, LogoutRequest, LogoutResponses.
+ * Enable an Assertion Consumer Service endpoint.
+ * Enable a Single Logout Service endpoint.
+ * Publish the SP metadata (which can be signed).
+
+Key features:
+
+ * **saml2int** - Implements the SAML 2.0 Web Browser SSO Profile.
+ * **Session-less** - Forget those common conflicts between the SP and
+ the final app, the toolkit delegate session in the final app.
+ * **Easy to use** - Programmer will be allowed to code high-level and
+ low-level programming, 2 easy to use APIs are available.
+ * **Tested** - Thoroughly tested.
+ * **Popular** - OneLogin's customers use it. Many PHP SAML plugins uses it.
+
+Integrate your PHP toolkit at OneLogin using this guide: [https://developers.onelogin.com/page/saml-toolkit-for-php](https://developers.onelogin.com/page/saml-toolkit-for-php)
+
+Installation
+------------
+
+### Dependencies ###
+
+ * `php >= 5.3.3` and some core extensions like `php-xml`, `php-date`, `php-zlib`.
+ * `openssl`. Install the openssl library. It handles x509 certificates.
+ * `mcrypt`. Install that library and its php driver if you gonna handle
+ encrypted data (`nameID`, `assertions`).
+ * `gettext`. Install that library and its php driver. It handles translations.
+
+Since [PHP 5.3 is officially unssuported](http://php.net/eol.php) we recommend you to use a newer PHP version.
+
+### Code ###
+
+#### Option 1. Download from github ####
+
+The toolkit is hosted on github. You can download it from:
+
+ * Lastest release: https://github.com/onelogin/php-saml/releases/latest
+ * Master repo: https://github.com/onelogin/php-saml/tree/master
+
+Copy the core of the library inside the php application. (each application has its
+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 ####
+
+The toolkit supports [composer](https://getcomposer.org/). You can find the `onelogin/php-saml` package at https://packagist.org/packages/onelogin/php-saml
+
+In order to import the saml toolkit to your current php project, execute
+```
+composer require onelogin/php-saml
+```
+
+After installation has completed you will find at the `vendor/` folder a new folder named `onelogin` and inside the `php-saml`. Make sure you are including the autoloader provided by composer. It can be found at `vendor/autoload.php`.
+
+**Important** In this option, the x509 certs must be stored at `vendor/onelogin/php-saml/certs`
+and settings file stored at `vendor/onelogin/php-saml`.
+
+Your settings are at risk of being deleted when updating packages using `composer update` or similiar commands. So is **highly** recommended that instead of use settings files, you pass the settings as an array directly to the constructor (explained later in this document). If you do not use this approach your settings are at risk of being deleted when updating packages using `composer update` or similiar commands.
+
+Compatibility
+-------------
+
+This 2.0 version has a new library. The toolkit is still compatible.
+
+The old code that you used in order to add SAML support gonna continue working
+with minor changes. You only need to load the files of the `lib/Saml` folder.
+(notice that the `compatibility.php` file do that).
+
+The old-demo folder contains code from an old app that uses the old version of
+the toolkit (v.1). Take a look.
+
+Sometimes the names of the classes of the old code could be a bit different
+and if is your case you must change them for `OneLogin_Saml_Settings`,
+`OneLogin_Saml_Response`, `OneLogin_Saml_AuthRequest` or `OneLogin_Saml_Metadata`.
+
+We recommend that you migrate the old code to the new one to be able to use
+the new features that the new library Saml2 carries.
+
+
+Namespaces
+----------
+
+If you are using the library with a framework like Symfony2 that contains
+namespaces, remember that calls to the class must be done by adding a backslash (`\`) to the
+start, for example to use the static method getSelfURLNoQuery use:
+
+ \OneLogin_Saml2_Utils::getSelfURLNoQuery()
+
+
+Security warning
+----------------
+
+In production, the `strict` parameter **MUST** be set as `"true"`. Otherwise
+your environment is not secure and will be exposed to attacks.
+
+
+Security Guidelines
+-------------------
+
+If you believe you have discovered a security vulnerability in this toolkit, please report it at https://www.onelogin.com/security with a description. We follow responsible disclosure guidelines, and will work with you to quickly find a resolution.
+
+
+Getting started
+---------------
+
+### Knowing the toolkit ###
+
+The new OneLogin SAML Toolkit contains different folders (`certs`, `endpoints`,
+`extlib`, `lib`, `demo`, etc.) and some files.
+
+Let's start describing the folders:
+
+#### `certs/` ####
+
+SAML requires a x.509 cert to sign and encrypt elements like `NameID`, `Message`,
+`Assertion`, `Metadata`.
+
+If our environment requires sign or encrypt support, this folder may contain
+the x509 cert and the private key that the SP will use:
+
+ * `sp.crt` - The public cert of the SP
+ * `sp.key` - The privake key of the SP
+
+Or also we can provide those data in the setting file at the `$settings['sp']['x509cert']`
+and the `$settings['sp']['privateKey']`.
+
+Sometimes we could need a signature on the metadata published by the SP, in
+this case we could use the x.509 cert previously mentioned or use a new x.509
+cert: `metadata.crt` and `metadata.key`.
+
+
+#### `extlib/` ####
+
+This folder contains the 3rd party libraries that the toolkit uses. At the
+moment only uses the `xmlseclibs` (autor Robert Richards, BSD Licensed) which
+handle the sign and the encryption of xml elements.
+
+
+#### `lib/` ####
+
+This folder contains the heart of the toolkit, the libraries:
+
+ * `Saml` folder contains a modified version of the toolkit v.1 and allows the
+ old code to keep working. (This library is provided to maintain
+ backward compatibility).
+ * `Saml2` folder contains the new version of the classes and methods that
+ are described in a later section.
+
+
+#### `doc/` ####
+
+This folder contains the API documentation of the toolkit.
+
+
+#### `endpoints/` ####
+
+The toolkit has three endpoints:
+
+ * `metadata.php` - Where the metadata of the SP is published.
+ * `acs.php` - Assertion Consumer Service. Processes the SAML Responses.
+ * `sls.php` - Single Logout Service. Processes Logout Requests and Logout
+ Responses.
+
+You can use the files provided by the toolkit or create your own endpoints
+files when adding SAML support to your applications. Take in mind that those
+endpoints files uses the setting file of the toolkit's base folder.
+
+
+#### `locale/` ####
+
+Locale folder contains some translations: `en_US` and `es_ES` as a proof of concept.
+Currently there are no translations but we will eventually localize the messages
+and support multiple languages.
+
+
+#### Other important files ####
+
+* `settings_example_example.php` - A template to be used in order to create a
+ settings.php file which contains the basic configuration info of the toolkit.
+* `advanced_settings_example.php` - A template to be used in order to create a
+ advanced_settings.php file which contains extra configuration info related to
+ the security, the contact person, and the organization associated to the SP.
+* `_toolkit_loader.php` - This file load the toolkit libraries (The SAML2 lib).
+* `compatibility` - Import that file to make compatible your old code with the
+ new toolkit (loads the SAML library).
+
+
+#### Miscellaneous ####
+
+* `tests/` - Contains the unit test of the toolkit.
+* `demo1/` - Contains an example of a simple PHP app with SAML support.
+ Read the `Readme.txt` inside for more info.
+* `demo2/` - Contains another example.
+* `demo-old/` - Contains an example that uses the code of the older version of the
+ the toolkit to demonstrate the backwards compatibility.
+
+
+### How it works ###
+
+#### Settings ####
+
+First of all we need to configure the toolkit. The SP's info, the IdP's info,
+and in some cases, configure advanced security issues like signatures and
+encryption.
+
+There are two ways to provide the settings information:
+
+ * Use a `settings.php` file that we should locate at the base folder of the
+ toolkit.
+ * Use an array with the setting data and provide it directly to the
+ constructor of the class.
+
+
+There is a template file, `settings_example.php`, so you can make a copy of this
+file, rename and edit it.
+
+```php
+<?php
+
+$settings = array (
+ // If 'strict' is True, then the PHP Toolkit will reject unsigned
+ // or unencrypted messages if it expects them to be signed or encrypted.
+ // Also it will reject the messages if the SAML standard is not strictly
+ // followed: Destination, NameId, Conditions ... are validated too.
+ 'strict' => false,
+
+ // Enable debug mode (to print errors).
+ 'debug' => false,
+
+ // Service Provider Data that we are deploying.
+ 'sp' => array (
+ // Identifier of the SP entity (must be a URI)
+ 'entityId' => '',
+ // Specifies info about where and how the <AuthnResponse> message MUST be
+ // returned to the requester, in this case our SP.
+ 'assertionConsumerService' => array (
+ // URL Location where the <Response> from the IdP will be returned
+ 'url' => '',
+ // SAML protocol binding to be used when returning the <Response>
+ // message. OneLogin Toolkit supports this endpoint for the
+ // HTTP-POST binding only.
+ 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+ ),
+ // Specifies info about where and how the <Logout Response> message MUST be
+ // returned to the requester, in this case our SP.
+ 'singleLogoutService' => array (
+ // URL Location where the <Response> from the IdP will be returned
+ 'url' => '',
+ // SAML protocol binding to be used when returning the <Response>
+ // message. OneLogin Toolkit supports the HTTP-Redirect binding
+ // only for this endpoint.
+ 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+ ),
+ // Specifies the constraints on the name identifier to be used to
+ // represent the requested subject.
+ // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported.
+ 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
+ // Usually x509cert and privateKey of the SP are provided by files placed at
+ // the certs folder. But we can also provide them with the following parameters
+ 'x509cert' => '',
+ 'privateKey' => '',
+
+ ),
+
+ // Identity Provider Data that we want connected with our SP.
+ 'idp' => array (
+ // Identifier of the IdP entity (must be a URI)
+ 'entityId' => '',
+ // SSO endpoint info of the IdP. (Authentication Request protocol)
+ 'singleSignOnService' => array (
+ // URL Target of the IdP where the Authentication Request Message
+ // will be sent.
+ 'url' => '',
+ // SAML protocol binding to be used when returning the <Response>
+ // message. OneLogin Toolkit supports the HTTP-Redirect binding
+ // only for this endpoint.
+ '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 SLO Request will be sent.
+ 'url' => '',
+ // SAML protocol binding to be used when returning the <Response>
+ // message. OneLogin Toolkit supports the HTTP-Redirect binding
+ // only for this endpoint.
+ 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+ ),
+ // Public x509 certificate of the IdP
+ 'x509cert' => '',
+ /*
+ * Instead of use the whole x509cert you can use a fingerprint in order to
+ * validate a SAMLResponse.
+ * (openssl x509 -noout -fingerprint -in "idp.crt" to generate it,
+ * or add for example the -sha256 , -sha384 or -sha512 parameter)
+ *
+ * If a fingerprint is provided, then the certFingerprintAlgorithm is required in order to
+ * let the toolkit know which algorithm was used. Possible values: sha1, sha256, sha384 or sha512
+ * 'sha1' is the default value.
+ *
+ * Notice that if you want to validate any SAML Message sent by the HTTP-Redirect binding, you
+ * will need to provide the whole x509cert.
+ */
+ // 'certFingerprint' => '',
+ // 'certFingerprintAlgorithm' => 'sha1',
+ ),
+);
+```
+In addition to the required settings data (IdP, SP), there is extra
+information that could be defined. In the same way that a template exists
+for the basic info, there is a template for that advanced info located
+at the base folder of the toolkit and named `advanced_settings_example.php`
+that you can copy and rename it as `advanced_settings.php`
+
+```php
+<?php
+
+$advancedSettings = array (
+
+ // Security settings
+ 'security' => array (
+
+ /** signatures and encryptions offered */
+
+ // Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
+ // will be encrypted.
+ 'nameIdEncrypted' => false,
+
+ // Indicates whether the <samlp:AuthnRequest> messages sent by this SP
+ // will be signed. [Metadata of the SP will offer this info]
+ 'authnRequestsSigned' => false,
+
+ // Indicates whether the <samlp:logoutRequest> messages sent by this SP
+ // will be signed.
+ 'logoutRequestSigned' => false,
+
+ // Indicates whether the <samlp:logoutResponse> messages sent by this SP
+ // will be signed.
+ 'logoutResponseSigned' => false,
+
+ /* Sign the Metadata
+ False || True (use sp certs) || array (
+ keyFileName => 'metadata.key',
+ certFileName => 'metadata.crt'
+ )
+ */
+ 'signMetadata' => false,
+
+
+ /** signatures and encryptions required **/
+
+ // Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest>
+ // and <samlp:LogoutResponse> elements received by this SP to be signed.
+ 'wantMessagesSigned' => false,
+
+ // Indicates a requirement for the <saml:Assertion> elements received by
+ // this SP to be signed. [Metadata of the SP will offer this info]
+ 'wantAssertionsSigned' => false,
+
+ // Indicates a requirement for the NameID element on the SAMLResponse
+ // received by this SP to be present.
+ 'wantNameId' => true,
+
+ // Indicates a requirement for the NameID received by
+ // this SP to be encrypted.
+ 'wantNameIdEncrypted' => false,
+
+
+ // Authentication context.
+ // Set to false or don't present this parameter and no AuthContext will be sent in the AuthNRequest,
+ // Set true and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
+ // Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),
+ 'requestedAuthnContext' => true,
+
+ // Indicates if the SP will validate all received xmls.
+ // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true).
+ 'wantXMLValidation' => true,
+
+ // 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'
+ // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
+ // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
+ // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
+ 'signatureAlgorithm' => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1',
+ ),
+
+ // Contact information template, it is recommended to suply a
+ // technical and support contacts.
+ 'contactPerson' => array (
+ 'technical' => array (
+ 'givenName' => '',
+ 'emailAddress' => ''
+ ),
+ 'support' => array (
+ 'givenName' => '',
+ 'emailAddress' => ''
+ ),
+ ),
+
+ // Organization information template, the info in en_US lang is
+ // recomended, add more if required.
+ 'organization' => array (
+ 'en-US' => array(
+ 'name' => '',
+ 'displayname' => '',
+ 'url' => ''
+ ),
+ ),
+);
+```
+
+In the security section, you can set the way that the SP will handle the messages
+and assertions. Contact the admin of the IdP and ask him what the IdP expects,
+and decide what validations will handle the SP and what requirements the SP will have
+and communicate them to the IdP's admin too.
+
+Once we know what kind of data could be configured, let's talk about the way
+settings are handled within the toolkit.
+
+The settings files described (`settings.php` and `advanced_settings.php`) are loaded
+by the toolkit if not other array with settings info is provided in the constructors of the toolkit. Let's see some examples.
+
+```php
+// Initializes toolkit with settings.php & advanced_settings files.
+$auth = new OneLogin_Saml2_Auth();
+//or
+$settings = new OneLogin_Saml2_Settings();
+
+// Initializes toolkit with the array provided.
+$auth = new OneLogin_Saml2_Auth($settingsInfo);
+//or
+$settings = new OneLogin_Saml2_Settings($settingsInfo);
+```
+
+You can declare the `$settingsInfo` in the file that constains the constructor
+execution or locate them in any file and load the file in order to get the
+array available as we see in the following example:
+
+```php
+<?php
+
+require_once 'custom_settings.php'; // The custom_settings.php contains a
+ // $settingsInfo array.
+
+$auth = new OneLogin_Saml2_Auth($settingsInfo);
+```
+
+
+#### How load the library ####
+
+In order to use the toolkit library you need to import the `_toolkit_loader.php`
+file located on the base folder of the toolkit. You can load this file in this
+way:
+
+```php
+<?php
+
+define("TOOLKIT_PATH", '/var/www/php-saml/');
+require_once(TOOLKIT_PATH . '_toolkit_loader.php');
+```
+
+After that line we will be able to use the classes (and their methods) of the
+toolkit (because the external and the Saml2 libraries files are loaded).
+
+If you wrote the code of your SAML app for the version 1 of the PHP-SAML toolkit
+you will need to load the `compatibility.php`, file which loads the SAML library files,
+in addition to the the `_toolkit_loader.php`.
+
+That SAML library uses the new classes and methods of the latest version of the
+toolkits but maintain the old classes, methods, and workflow of the old process
+to accomplish the same things.
+
+We strongly recommend migrating your old code and use the new API of the
+new toolkit due there are a lot of new features that you can't handle with the
+old code.
+
+
+#### Initiate SSO ####
+
+In order to send an `AuthNRequest` to the IdP:
+
+```php
+<?php
+
+define("TOOLKIT_PATH", '/var/www/php-saml/');
+require_once(TOOLKIT_PATH . '_toolkit_loader.php'); // We load the SAML2 lib
+
+$auth = new OneLogin_Saml2_Auth(); // Constructor of the SP, loads settings.php
+ // and advanced_settings.php
+$auth->login(); // Method that sent the AuthNRequest
+```
+
+The `AuthNRequest` will be sent signed or unsigned based on the security info
+of the `advanced_settings.php` (`'authnRequestsSigned'`).
+
+
+The IdP will then return the SAML Response to the user's client. The client is then forwarded to the Attribute Consumer Service of the SP with this information. If we do not set a 'url' param in the login method and we are using the default ACS provided by the toolkit (`endpoints/acs.php`), then the ACS endpoint will redirect the user to the file that launched the SSO request.
+
+We can set an `'returnTo'` url to change the workflow and redirect the user to the other PHP file.
+
+```php
+$newTargetUrl = 'http://example.com/consume2.php';
+$auth = new OneLogin_Saml2_Auth();
+$auth->login($newTargetUrl);
+```
+
+The login method can recieve other five 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.
+
+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.
+
+```php
+$ssoBuiltUrl = $auth->login(null, array(), false, false, true);
+$_SESSION['AuthNRequestID'] = $auth->getLastRequestID();
+header('Pragma: no-cache');
+header('Cache-Control: no-cache, must-revalidate');
+header('Location: ' . $ssoBuiltUrl);
+exit();
+```
+
+#### The SP Endpoints ####
+
+Related to the SP there are three important views: The metadata view, the ACS view and the SLS view. The toolkit
+provides examples of those views in the endpoints directory.
+
+##### SP Metadata `endpoints/metadata.php` #####
+
+This code will provide the XML metadata file of our SP, based on the info that we provided in the settings files.
+
+```php
+<?php
+
+define("TOOLKIT_PATH", '/var/www/php-saml/');
+require_once dirname(TOOLKIT_PATH.'/_toolkit_loader.php';
+
+try {
+ $auth = new OneLogin_Saml2_Auth();
+ $settings = $auth->getSettings();
+ $metadata = $settings->getSPMetadata();
+ $errors = $settings->validateMetadata($metadata);
+ if (empty($errors)) {
+ header('Content-Type: text/xml');
+ echo $metadata;
+ } else {
+ throw new OneLogin_Saml2_Error(
+ 'Invalid SP metadata: '.implode(', ', $errors),
+ OneLogin_Saml2_Error::METADATA_SP_INVALID
+ );
+ }
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+```
+The `getSPMetadata` will return the metadata signed or not based
+on the security info of the `advanced_settings.php` (`'signMetadata'`).
+
+Before the XML metadata is exposed, a check takes place to ensure
+that the info to be provided is valid.
+
+Instead of use the Auth object, you can directly use
+```
+$settings = new OneLogin_Saml2_Settings($settingsInfo, true);
+```
+to get the settings object and with the true parameter we will avoid the IdP Settings validation.
+
+
+##### Attribute Consumer Service(ACS) `endpoints/acs.php` #####
+
+This code handles the SAML response that the IdP forwards to the SP through the user's client.
+
+```php
+<?php
+
+session_start(); // IMPORTANT: This is required in order to be able
+ // to store the user data in the session.
+
+define("TOOLKIT_PATH", '/var/www/php-saml/');
+require_once dirname(TOOLKIT_PATH.'/_toolkit_loader.php';
+
+$auth = new OneLogin_Saml2_Auth();
+
+if (isset($_SESSION) && isset($_SESSION['AuthNRequestID'])) {
+ $requestID = $_SESSION['AuthNRequestID'];
+} else {
+ $requestID = null;
+}
+
+$auth->processResponse($requestID);
+
+$errors = $auth->getErrors();
+
+if (!empty($errors)) {
+ print_r('<p>'.implode(', ', $errors).'</p>');
+ exit();
+}
+
+if (!$auth->isAuthenticated()) {
+ echo "<p>Not authenticated</p>";
+ exit();
+}
+
+$_SESSION['samlUserdata'] = $auth->getAttributes();
+$_SESSION['samlNameId'] = $auth->getNameId();
+if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) {
+ $auth->redirectTo($_POST['RelayState']);
+}
+
+$attributes = $_SESSION['samlUserdata'];
+$nameId = $_SESSION['samlNameId'];
+
+echo '<h1>Identified user: '. htmlentities($nameId) .'</h1>';
+
+if (!empty($attributes)) {
+ echo '<h2>'._('User attributes:').'</h2>';
+ echo '<table><thead><th>'._('Name').'</th><th>'._('Values').'</th></thead><tbody>';
+ foreach ($attributes as $attributeName => $attributeValues) {
+ echo '<tr><td>' . htmlentities($attributeName) . '</td><td><ul>';
+ foreach ($attributeValues as $attributeValue) {
+ echo '<li>' . htmlentities($attributeValue) . '</li>';
+ }
+ echo '</ul></td></tr>';
+ }
+ echo '</tbody></table>';
+} else {
+ echo _('No attributes found.');
+}
+```
+
+The SAML response is processed and then checked that there are no errors.
+It also verifies that the user is authenticated and stored the userdata in session.
+
+At that point there are two possible alternatives:
+
+ 1. If no `RelayState` is provided, we could show the user data in this view
+ or however we wanted.
+
+ 2. If `RelayState` is provided, a redirection takes place.
+
+Notice that we saved the user data in the session before the redirection to
+have the user data available at the `RelayState` view.
+
+
+###### The `getAttributes` method ######
+
+In order to retrieve attributes we can use:
+
+```php
+$attributes = $auth->getAttributes();
+```
+
+With this method we get all the user data provided by the IdP in the Assertion
+of the SAML Response.
+
+If we execute ```print_r($attributes)``` we could get:
+
+```php
+Array
+(
+ [cn] => Array
+ (
+ [0] => John
+ )
+ [sn] => Array
+ (
+ [0] => Doe
+ )
+ [mail] => Array
+ (
+ [0] => john.doe@example.com
+ )
+ [groups] => Array
+ (
+ [0] => users
+ [1] => members
+ )
+)
+```
+
+Each attribute name can be used as an index into `$attributes` to obtain the value. Every attribute value
+is an array - a single-valued attribute is an array of a single element.
+
+
+The following code is equivalent:
+
+```php
+$attributes = $auth->getAttributes();
+print_r($attributes['cn']);
+```
+
+```php
+print_r($auth->getAttribute('cn'));
+```
+
+
+Before trying to get an attribute, check that the user is
+authenticated. If the user isn't authenticated or if there were
+no attributes in the SAML assertion, an empty array will be
+returned. For example, if we call to `getAttributes` before a
+`$auth->processResponse`, the `getAttributes()` will return an
+empty array.
+
+
+##### Single Logout Service (SLS) `endpoints/sls.php` #####
+
+This code handles the Logout Request and the Logout Responses.
+
+```php
+<?php
+
+session_start(); // IMPORTANT: This is required in order to be able
+ // to close the user session.
+
+define("TOOLKIT_PATH", '/var/www/php-saml/');
+require_once dirname(TOOLKIT_PATH.'/_toolkit_loader.php';
+
+$auth = new OneLogin_Saml2_Auth();
+
+if (isset($_SESSION) && isset($_SESSION['LogoutRequestID'])) {
+ $requestID = $_SESSION['LogoutRequestID'];
+} else {
+ $requestID = null;
+}
+
+$auth->processSLO(false, $requestID);
+
+$errors = $auth->getErrors();
+
+if (empty($errors)) {
+ print_r('Sucessfully logged out');
+} else {
+ print_r(implode(', ', $errors));
+}
+```
+
+If the SLS endpoints receives a Logout Response, the response is
+validated and the session could be closed
+
+
+
+```php
+// part of the processSLO method
+
+$logoutResponse = new OneLogin_Saml2_LogoutResponse($this->_settings, $_GET['SAMLResponse']);
+if (!$logoutResponse->isValid($requestId)) {
+ $this->_errors[] = 'invalid_logout_response';
+} else if ($logoutResponse->getStatus() !== OneLogin_Saml2_Constants::STATUS_SUCCESS) {
+ $this->_errors[] = 'logout_not_success';
+} else {
+ if (!$keepLocalSession) {
+ OneLogin_Saml2_Utils::deleteLocalSession();
+ }
+}
+```
+
+If the SLS endpoints receives an Logout Request, the request is validated,
+the session is closed and a Logout Response is sent to the SLS endpoint of
+the IdP.
+
+```php
+// part of the processSLO method
+
+$decoded = base64_decode($_GET['SAMLRequest']);
+$request = gzinflate($decoded);
+if (!OneLogin_Saml2_LogoutRequest::isValid($this->_settings, $request)) {
+ $this->_errors[] = 'invalid_logout_request';
+} else {
+ if (!$keepLocalSession) {
+ OneLogin_Saml2_Utils::deleteLocalSession();
+ }
+
+ $inResponseTo = $request->id;
+ $responseBuilder = new OneLogin_Saml2_LogoutResponse($this->_settings);
+ $responseBuilder->build($inResponseTo);
+ $logoutResponse = $responseBuilder->getResponse();
+
+ $parameters = array('SAMLResponse' => $logoutResponse);
+ if (isset($_GET['RelayState'])) {
+ $parameters['RelayState'] = $_GET['RelayState'];
+ }
+
+ $security = $this->_settings->getSecurityData();
+ if (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned']) {
+ $signature = $this->buildResponseSignature($logoutResponse, $parameters['RelayState'], $security['signatureAlgorithm']);
+ $parameters['SigAlg'] = $security['signatureAlgorithm'];
+ $parameters['Signature'] = $signature;
+ }
+
+ $this->redirectTo($this->getSLOurl(), $parameters);
+}
+```
+
+If you aren't using the default PHP session, or otherwise need a manual
+way to destroy the session, you can pass a callback method to the
+`processSLO` method as the fourth parameter
+
+```php
+$keepLocalSession = False;
+$callback = function () {
+ // Destroy user session
+};
+
+$auth->processSLO($keepLocalSession, null, false, $callback);
+```
+
+
+If we don't want that `processSLO` to destroy the session, pass a true
+parameter to the `processSLO` method
+
+```php
+$keepLocalSession = True;
+$auth->processSLO($keepLocalSession);
+```
+
+#### Initiate SLO ####
+
+In order to send a Logout Request to the IdP:
+
+```php
+<?php
+
+define("TOOLKIT_PATH", '/var/www/php-saml/');
+require_once(TOOLKIT_PATH . '_toolkit_loader.php');
+
+$auth = new OneLogin_Saml2_Auth();
+
+$auth->logout(); // Method that sent the Logout Request.
+```
+
+Also there are three optional parameters that can be set:
+
+* `$name_id` - That will be used to build the LogoutRequest. If `name_id` parameter is not set and the auth object processed a
+SAML Response with a `NameId`, then this `NameId` will be used.
+* `$session_index` - SessionIndex that identifies the session of the user.
+* `$strict` - True if we want to stay (returns the url string) False to redirect.
+
+The Logout Request will be sent signed or unsigned based on the security
+info of the `advanced_settings.php` (`'logoutRequestSigned'`).
+
+The IdP will return the Logout Response through the user's client to the
+Single Logout Service of the SP.
+If we do not set a `'url'` param in the logout method and are using the
+default SLS provided by the toolkit (`endpoints/sls.php`), then the SLS
+endpoint will redirect the user to the file that launched the SLO request.
+
+We can set an `'returnTo'` url to change the workflow and redirect the user
+to other php file.
+
+```php
+$newTargetUrl = 'http://example.com/loggedOut.php';
+$auth = new OneLogin_Saml2_Auth();
+$auth->logout($newTargetUrl);
+```
+
+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);
+$_SESSION['LogoutRequestID'] = $auth->getLastRequestID();
+header('Pragma: no-cache');
+header('Cache-Control: no-cache, must-revalidate');
+header('Location: ' . $sloBuiltUrl);
+exit();
+```
+
+#### Example of a view that initiates the SSO request and handles the response (is the acs target) ####
+
+We can code a unique file that initiates the SSO process, handle the response, get the attributes, initiate
+the SLO and processes the logout response.
+
+Note: Review the `demo1` folder that contains that use case; in a later section we
+explain the demo1 use case further in detail.
+
+```php
+<?php
+
+session_start(); // Initialize the session, we do that because
+ // Note that processResponse and processSLO
+ // methods could manipulate/close that session
+
+require_once dirname(dirname(__FILE__)).'/_toolkit_loader.php'; // Load Saml2 and
+ // external libs
+require_once 'settings.php'; // Load the setting info as an Array
+
+$auth = new OneLogin_Saml2_Auth($settingsInfo); // Initialize the SP SAML instance
+
+if (isset($_GET['sso'])) { // SSO action. Will send an AuthNRequest to the IdP
+ $auth->login();
+} else if (isset($_GET['sso2'])) { // Another SSO action
+ $returnTo = $spBaseUrl.'/demo1/attrs.php'; // but set a custom RelayState URL
+ $auth->login($returnTo);
+} else if (isset($_GET['slo'])) { // SLO action. Will sent a Logout Request to IdP
+ $auth->logout();
+} else if (isset($_GET['acs'])) { // Assertion Consumer Service
+ $auth->processResponse(); // Process the Response of the IdP, get the
+ // attributes and put then at
+ // $_SESSION['samlUserdata']
+
+ $errors = $auth->getErrors(); // This method receives an array with the errors
+ // that could took place during the process
+
+ if (!empty($errors)) {
+ print_r('<p>'.implode(', ', $errors).'</p>');
+ }
+ // This check if the response was
+ if (!$auth->isAuthenticated()) { // sucessfully validated and the user
+ echo "<p>Not authenticated</p>"; // data retrieved or not
+ exit();
+ }
+
+ $_SESSION['samlUserdata'] = $auth->getAttributes(); // Retrieves user data
+ if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) {
+ $auth->redirectTo($_POST['RelayState']); // Redirect if there is a
+ } // relayState set
+} else if (isset($_GET['sls'])) { // Single Logout Service
+ $auth->processSLO(); // Process the Logout Request & Logout Response
+ $errors = $auth->getErrors(); // Retrieves possible validation errors
+ if (empty($errors)) {
+ print_r('<p>Sucessfully logged out</p>');
+ } else {
+ print_r('<p>'.implode(', ', $errors).'</p>');
+ }
+}
+
+if (isset($_SESSION['samlUserdata'])) { // If there is user data we print it.
+ if (!empty($_SESSION['samlUserdata'])) {
+ $attributes = $_SESSION['samlUserdata'];
+ echo 'You have the following attributes:<br>';
+ echo '<table><thead><th>Name</th><th>Values</th></thead><tbody>';
+ foreach ($attributes as $attributeName => $attributeValues) {
+ echo '<tr><td>' . htmlentities($attributeName) . '</td><td><ul>';
+ foreach ($attributeValues as $attributeValue) {
+ echo '<li>' . htmlentities($attributeValue) . '</li>';
+ }
+ echo '</ul></td></tr>';
+ }
+ echo '</tbody></table>';
+ } else { // If there is not user data, we notify
+ echo "<p>You don't have any attribute</p>";
+ }
+
+ echo '<p><a href="?slo" >Logout</a></p>'; // Print some links with possible
+} else { // actions
+ echo '<p><a href="?sso" >Login</a></p>';
+ echo '<p><a href="?sso2" >Login and access to attrs.php page</a></p>';
+}
+```
+
+### Main classes and methods ###
+
+Described below are the main classes and methods that can be invoked.
+
+#### The Old Saml library ####
+
+Lets start describing the classes and methods of the SAML library, an evolution
+of the old v.1 toolkit that is provided to keep the backward compability.
+Most of them use classes and methods of the new SAML2 library.
+
+##### OneLogin_Saml_AuthRequest - `AuthRequest.php` #####
+
+Has the protected attribute `$auth`, an `OneLogin_Saml2_Auth` object.
+
+* `OneLogin_Saml_AuthRequest` - Constructs `OneLogin_Saml2_Auth`,
+ initializing the SP SAML instance.
+* `getRedirectUrl($returnTo)` - Obtains the SSO URL containing the AuthRequest
+ message deflated.
+
+
+##### OneLogin_Saml_Response - `Response.php` #####
+
+* `OneLogin_Saml_Response` - Constructor that process the SAML Response,
+ Internally initializes an SP SAML instance and an `OneLogin_Saml2_Response`.
+* `get_saml_attributes` - Retrieves an Array with the logged user data.
+
+
+##### OneLogin_Saml_Settings - `Settings.php` #####
+
+A simple class used to build the Setting object used in the v1.0 of the toolkit.
+
+##### OneLogin_Saml_Metadata - `Metadata.php` #####
+
+* `OneLogin_Saml_Metadata` - Constructor that build the Metadata XML info based
+ on the settings of the SP
+* `getXml` - An XML with the metadata info of the SP
+
+
+##### OneLogin_Saml_XmlSec - `XmlSec.php` #####
+
+Auxiliary class that contains methos to validate the SAML Response:
+`validateNumAssertions`, `validateTimestamps`, `isValid` (which
+uses the other two previous methods and also validate the signature of
+SAML Response).
+
+
+#### Saml2 library ####
+
+Lets describe now the classes and methods of the SAML2 library.
+
+##### OneLogin_Saml2_Auth - Auth.php #####
+
+Main class of OneLogin PHP Toolkit
+
+ * `OneLogin_Saml2_Auth` - Initializes the SP SAML instance
+ * `login` - Initiates the SSO process.
+ * `logout` - Initiates the SLO process.
+ * `processResponse` - Process the SAML Response sent by the IdP.
+ * `processSLO` - Process the SAML Logout Response / Logout Request sent by the
+ IdP.
+ * `redirectTo` - Redirects the user to the url past by parameter or to the url
+ that we defined in our SSO Request.
+ * `isAuthenticated` - Checks if the user is authenticated or not.
+ * `getAttributes` - Returns the set of SAML attributes.
+ * `getAttribute` - Returns the requested SAML attribute
+ * `getNameId` - Returns the nameID
+ * `getSessionIndex` - Gets the SessionIndex from the AuthnStatement.
+ * `getErrors` - Returns if there were any error
+ * `getSSOurl` - Gets the SSO url.
+ * `getSLOurl` - Gets the SLO url.
+ * `getLastRequestID` - The ID of the last Request SAML message generated.
+ * `buildRequestSignature` - Generates the Signature for a SAML Request
+ * `buildResponseSignature` - Generates the Signature for a SAML Response
+ * `getSettings` - Returns the settings info
+ * `setStrict` - Set the strict mode active/disable
+
+##### OneLogin_Saml2_AuthnRequest - `AuthnRequest.php` #####
+
+SAML 2 Authentication Request class
+
+ * `OneLogin_Saml2_AuthnRequest` - Constructs the `AuthnRequest` object.
+ * `getRequest` - Returns deflated, base64 encoded, unsigned `AuthnRequest`.
+ * `getId` - Returns the `AuthNRequest` ID.
+
+##### OneLogin_Saml2_Response - `Response.php` #####
+
+SAML 2 Authentication Response class
+
+ * `OneLogin_Saml2_Response` - Constructs the SAML Response object.
+ * `isValid` - Determines if the SAML Response is valid using the certificate.
+ * `checkStatus` - Checks if the Status is success.
+ * `getAudiences` - Gets the audiences.
+ * `getIssuers` - Gets the Issuers (from Response and Assertion)
+ * `getNameIdData` - Gets the NameID Data provided by the SAML response from the
+ IdP.
+ * `getNameId` - Gets the NameID provided by the SAML response from the IdP.
+ * `getSessionNotOnOrAfter` - Gets the SessionNotOnOrAfter from the
+ AuthnStatement
+ * `getSessionIndex` - Gets the SessionIndex from the AuthnStatement.
+ * `getAttributes` - Gets the Attributes from the AttributeStatement element.
+ * `validateNumAssertions` - Verifies that the document only contains a single
+ Assertion (encrypted or not).
+ * `validateTimestamps` - Verifies that the document is still valid according
+ Conditions Element.
+ * `getError` - After execute a validation process, if fails this method returns the cause
+
+##### OneLogin_Saml2_LogoutRequest - `LogoutRequest.php` #####
+
+SAML 2 Logout Request class
+
+ * `OneLogin_Saml2_LogoutRequest` - Constructs the Logout Request object.
+ * `getRequest` - Returns the Logout Request defated, base64encoded, unsigned
+ * `getID` - Returns the ID of the Logout Request. (If you have the object you can access to the id attribute)
+ * `getNameIdData` - Gets the NameID Data of the the Logout Request.
+ * `getNameId` - Gets the NameID of the Logout Request.
+ * `getIssuer` - Gets the Issuer of the Logout Request.
+ * `getSessionIndexes` - Gets the SessionIndexes from the Logout Request.
+ * `isValid` - Checks if the Logout Request recieved is valid.
+ * `getError` - After execute a validation process, if fails this method returns the cause
+
+##### OneLogin_Saml2_LogoutResponse - `LogoutResponse.php` #####
+
+SAML 2 Logout Response class
+
+ * `OneLogin_Saml2_LogoutResponse` - Constructs a Logout Response object
+ (Initialize params from settings and if provided load the Logout Response)
+ * `getIssuer` - Gets the Issuer of the Logout Response.
+ * `getStatus` - Gets the Status of the Logout Response.
+ * `isValid` - Determines if the SAML LogoutResponse is valid
+ * `build` - Generates a Logout Response object.
+ * `getResponse` - Returns a Logout Response object.
+ * `getError` - After execute a validation process, if fails this method returns the cause
+
+##### OneLogin_Saml2_Settings - `Settings.php` #####
+
+Configuration of the OneLogin PHP Toolkit
+
+ * `OneLogin_Saml2_Settings` - Initializes the settings: Sets the paths of
+ the different folders and Loads settings info from settings file or
+ array/object provided
+ * `checkSettings` - Checks the settings info.
+ * `getBasePath` - Returns base path.
+ * `getCertPath` - Returns cert path.
+ * `getLibPath` - Returns lib path.
+ * `getExtLibPath` - Returns external lib path.
+ * `getSchemasPath` - Returns schema path.
+ * `checkSPCerts` - Checks if the x509 certs of the SP exists and are valid.
+ * `getSPkey` - Returns the x509 private key of the SP.
+ * `getSPcert` - Returns the x509 public cert of the SP.
+ * `getIdPData` - Gets the IdP data.
+ * `getSPData`Gets the SP data.
+ * `getSecurityData` - Gets security data.
+ * `getContacts` - Gets contact data.
+ * `getOrganization` - Gets organization data.
+ * `getSPMetadata` - Gets the SP metadata. The XML representation.
+ * `validateMetadata` - Validates an XML SP Metadata.
+ * `formatIdPCert` - Formats the IdP cert.
+ * `formatSPCert` - Formats the SP cert.
+ * `formatSPKey` - Formats the SP private key.
+ * `getErrors` - Returns an array with the errors, the array is empty when
+ the settings is ok.
+ * `getLastErrorReason`* Returns the reason of the last error
+ * `setStrict` - Activates or deactivates the strict mode.
+ * `isStrict` - Returns if the 'strict' mode is active.
+ * `isDebugActive` - Returns if the debug is active.
+
+##### OneLogin_Saml2_Metadata - `Metadata.php` #####
+
+A class that contains functionality related to the metadata of the SP
+
+* `builder` - Generates the metadata of the SP based on the settings.
+* `signmetadata` - Signs the metadata with the key/cert provided
+* `addX509KeyDescriptors` - Adds the x509 descriptors (sign/encriptation) to
+ the metadata
+
+##### OneLogin_Saml2_Utils - `Utils.php` #####
+
+Auxiliary class that contains several methods
+
+ * `validateXML` - This function attempts to validate an XML string against
+ the specified schema.
+ * `formatCert` - Returns a x509 cert (adding header & footer if required).
+ * `formatPrivateKey` - returns a RSA private key (adding header & footer if required).
+ * `redirect` - Executes a redirection to the provided url (or return the
+ target url).
+ * `isHTTPS` - Checks if https or http.
+ * `getSelfHost` - Returns the current host.
+ * `getSelfURLhost` - Returns the protocol + the current host + the port
+ (if different than common ports).
+ * `getSelfURLNoQuery` - Returns the URL of the current host + current view.
+ * `getSelfURL` - Returns the URL of the current host + current view + query.
+ * `generateUniqueID` - Generates an unique string (used for example as ID
+ for assertions).
+ * `parseTime2SAML` - Converts a UNIX timestamp to SAML2 timestamp on the
+ form `yyyy-mm-ddThh:mm:ss(\.s+)?Z`.
+ * `parseSAML2Time` - Converts a SAML2 timestamp on the form
+ `yyyy-mm-ddThh:mm:ss(\.s+)?Z` to a UNIX timestamp. The sub-second part is
+ ignored.
+ * `parseDuration` - Interprets a ISO8601 duration value relative to a given
+ timestamp.
+ * `getExpireTime` - Compares two dates and returns the earliest.
+ * `query` - Extracts nodes from the DOMDocument.
+ * `isSessionStarted` - Checks if the session is started or not.
+ * `deleteLocalSession` - Deletes the local session.
+ * `calculateX509Fingerprint` - Calculates the fingerprint of a x509cert.
+ * `formatFingerPrint` - Formates a fingerprint.
+ * `generateNameId` - Generates a `nameID`.
+ * `getStatus` - Gets Status from a Response.
+ * `decryptElement` - Decrypts an encrypted element.
+ * `castKey` - Converts a `XMLSecurityKey` to the correct algorithm.
+ * `addSign` - Adds signature key and senders certificate to an element
+ (Message or Assertion).
+ * `validateSign` - Validates a signature (Message or Assertion).
+
+For more info, look at the source code; each method is documented and details
+about what does and how to use it are provided. Make sure to also check the doc folder where
+HTML documentation about the classes and methods is provided for SAML and
+SAML2.
+
+
+Demos included in the toolkit
+-----------------------------
+
+The toolkit includes three demo apps to teach how use the toolkit, take a look on it.
+
+Demos require that SP and IdP are well configured before test it.
+
+## Demo1 ##
+
+### SP setup ###
+
+The Onelogin's PHP Toolkit allows you to provide the settings info in two ways:
+
+ * Use a `settings.php` file that we should locate at the base folder of the
+ toolkit.
+ * Use an array with the setting data.
+
+In this demo we provide the data in the second way, using a setting array named
+`$settingsInfo`. This array users the `settings_example.php` included as a template
+to create the `settings.php` settings and store it in the `demo1/` folder.
+Configure the SP part and later review the metadata of the IdP and complete the IdP info.
+
+If you check the code of the index.php file you will see that the `settings.php`
+file is loaded in order to get the `$settingsInfo` var to be used in order to initialize
+the `Setting` class.
+
+Notice that in this demo, the `setting.php` file that could be defined at the base
+folder of the toolkit is ignored and the libs are loaded using the
+`_toolkit_loader.php` located at the base folder of the toolkit.
+
+
+### IdP setup ###
+
+Once the SP is configured, the metadata of the SP is published at the
+`metadata.php` file. Configure the IdP based on that information.
+
+
+### How it works ###
+
+ 1. First time you access to `index.php` view, you can select to login and return
+ to the same view or login and be redirected to the `attrs.php` view.
+
+ 2. When you click:
+
+ 2.1 in the first link, we access to (`index.php?sso`) an `AuthNRequest`
+ is sent to the IdP, we authenticate at the IdP and then a Response is sent
+ through the user's client to the SP, specifically the Assertion Consumer Service view: `index.php?acs`.
+ Notice that a `RelayState` parameter is set to the url that initiated 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`.
+
+ 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
+ are redirected to the RelayState view. a) `index.php` or b) `attrs.php`.
+
+ 4. We are logged in the app and the user attributes are showed.
+ At this point, we can test the single log out functionality.
+
+ 5. The single log out funcionality could be tested by two ways.
+
+ 5.1 SLO Initiated by SP. Click on the "logout" link at the SP, after that a
+ Logout Request is sent to the IdP, the session at the IdP is closed and
+ replies through the client to the SP with a Logout Response (sent to the
+ Single Logout Service endpoint). The SLS endpoint (`index.php?sls`) of the SP
+ process the Logout Response and if is valid, close the user session of the
+ local app. Notice that the SLO Workflow starts and ends at the SP.
+
+ 5.2 SLO Initiated by IdP. In this case, the action takes place on the IdP
+ side, the logout process is initiated at the idP, sends a Logout
+ Request to the SP (SLS endpoint, `index.php?sls`). The SLS endpoint of the SP
+ process the Logout Request and if is valid, close the session of the user
+ at the local app and send a Logout Response to the IdP (to the SLS endpoint
+ of the IdP). The IdP receives the Logout Response, process it and close 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 at a unique file,
+the `index.php` file and how `GET` paramters are used to know the action that
+must be done.
+
+
+## Demo2 ##
+
+### SP setup ###
+
+The Onelogin's PHP Toolkit allows you to provide the settings info in two ways:
+
+ * Use a `settings.php` file that we should locate at the base folder of the
+ toolkit.
+ * Use an array with the setting data.
+
+The first is the case of the demo2 app. The `setting.php` file and the
+`setting_extended.php` file should be defined at the base folder of the toolkit.
+Review the `setting_example.php` and the `advanced_settings_example.php` to
+learn how to build them.
+
+In this case as Attribute Consume Service and Single Logout Service we are going to
+use the files located in the endpoint folder (`acs.php` and `sls.php`).
+
+
+### IdP setup ###
+
+Once the SP is configured, the metadata of the SP is published at the
+`metadata.php` file. Based on that info, configure the IdP.
+
+
+### How it works ###
+
+At demo1, we saw how all the SAML Request and Responses were handler at an
+unique file, the `index.php` file. This demo1 uses high-level programming.
+
+At demo2, we have several views: `index.php`, `sso.php`, `slo.php`, `consume.php`
+and `metadata.php`. As we said, we gonna use the endpoints that are defined
+in the toolkit (`acs.php`, `sls.php` of the endpoints folder). This demo2 uses
+low-level programming.
+
+Notice that the SSO action can be initiated at `index.php` or `sso.php`.
+
+The SAML workflow that take place is similar that the workflow defined in the
+demo1, only changes the targets.
+
+ 1. When you access `index.php` or `sso.php` for the first time, an `AuthNRequest` is
+ sent to the IdP automatically, (as `RelayState` is sent the origin url).
+ We authenticate at the IdP and then a `Response` is sent to the SP, to the
+ ACS endpoint, in this case `acs.php` of the endpoints folder.
+
+ 2. The SAML Response is processed in the ACS, if the `Response` is not valid,
+ the process stops here and a message is shown. Otherwise we are redirected
+ to the `RelayState` view (`sso.php` or `index.php`). The `sso.php` detects if the
+ user is logged and redirects to `index.php`, so we will be in the
+ `index.php` at the end.
+
+ 3. We are logged into the app and the user attributes (if any) are shown.
+ At this point, we can test the single log out functionality.
+
+ 4. The single log out funcionality could be tested by two ways.
+
+ 4.1 SLO Initiated by SP. Click on the "logout" link at the SP, after that
+ we are redirected to the `slo.php` view and there a Logout Request is sent
+ to the IdP, the session at the IdP is closed and replies to the SP a
+ Logout Response (sent to the Single Logout Service endpoint). In this case
+ The SLS endpoint of the SP process the Logout Response and if is
+ valid, close the user session of the local app. Notice that the SLO
+ Workflow starts and ends at the SP.
+
+ 5.2 SLO Initiated by IdP. In this case, the action takes place on the IdP
+ side, the logout process is initiated at the idP, sends a Logout
+ Request to the SP (SLS endpoint `sls.php` of the endpoint folder).
+ The SLS endpoint of the SP process the Logout Request and if is valid,
+ close the session of the user at the local app and sends a Logout Response
+ to the IdP (to the SLS endpoint of the IdP).The IdP receives the Logout
+ Response, process it and close the session at of the IdP. Notice that the
+ SLO Workflow starts and ends at the IdP.
+
+
+## Demo Old ##
+
+### SP setup ###
+
+This demo uses the old style of the version 1 of the toolkit.
+An object of the class `OneLogin_Saml_Settings` must be provided to the
+constructor of the `AuthRequest`.
+
+You will find an `example_settings.php` file at the demo-old's folder that
+could be used as a template for you `settings.php` file.
+
+In that template, SAML settings are divided into two parts, the application
+specific (`const_assertion_consumer_service_url`, `const_issuer`,
+`const_name_identifier_format`) and the user/account specific
+`idp_sso_target_url`, `x509certificate`). You'll need to add your own code here
+to identify the user or user origin (e.g. by `subdomain`, `ip_address` etc.).
+
+
+### IdP setup ###
+
+Once the SP is configured, the metadata of the SP is published at the
+`metadata.php` file. After that, configure the IdP based on that information.
+
+
+### How it works ###
+
+At the `metadata.php` view is published the metadata of the SP.
+
+The `index.php` file acts as an initiater for the SAML conversation if it should
+should be initiated by the application. This is called Service Provider
+Initiated SAML. The service provider creates a SAML Authentication Request and
+sends it to the identity provider (IdP).
+
+The `consume.php` is the ACS endpoint. Receives the SAML assertion. After Response
+validation, the userdata and the nameID will be available, using `getNameId()` or
+`getAttributes()` we obtain them.
+
+Since the version 1 of the php toolkit does not support SLO we don't show how
+handle SLO in this demo-old.
diff --git a/3rdparty/vendor/onelogin/php-saml/_toolkit_loader.php b/3rdparty/vendor/onelogin/php-saml/_toolkit_loader.php
new file mode 100644
index 00000000..1af21e9b
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/_toolkit_loader.php
@@ -0,0 +1,25 @@
+<?php
+
+// Create an __autoload function
+// (can conflicts other autoloaders)
+// http://php.net/manual/en/language.oop5.autoload.php
+
+$libDir = dirname(__FILE__) . '/lib/Saml2/';
+$extlibDir = dirname(__FILE__) . '/extlib/';
+
+// Load composer
+if (file_exists('vendor/autoload.php')) {
+ require 'vendor/autoload.php';
+}
+
+// Load now external libs
+require_once $extlibDir . 'xmlseclibs/xmlseclibs.php';
+
+$folderInfo = scandir($libDir);
+
+foreach ($folderInfo as $element) {
+ if (is_file($libDir.$element) && (substr($element, -4) === '.php')) {
+ include_once $libDir.$element;
+ }
+}
+
diff --git a/3rdparty/vendor/onelogin/php-saml/advanced_settings_example.php b/3rdparty/vendor/onelogin/php-saml/advanced_settings_example.php
new file mode 100644
index 00000000..cae600b7
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/advanced_settings_example.php
@@ -0,0 +1,106 @@
+<?php
+
+$advancedSettings = array (
+
+ // Security settings
+ 'security' => array (
+
+ /** signatures and encryptions offered */
+
+ // Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
+ // will be encrypted.
+ 'nameIdEncrypted' => false,
+
+ // Indicates whether the <samlp:AuthnRequest> messages sent by this SP
+ // will be signed. [The Metadata of the SP will offer this info]
+ 'authnRequestsSigned' => false,
+
+ // Indicates whether the <samlp:logoutRequest> messages sent by this SP
+ // will be signed.
+ 'logoutRequestSigned' => false,
+
+ // Indicates whether the <samlp:logoutResponse> messages sent by this SP
+ // will be signed.
+ 'logoutResponseSigned' => false,
+
+ /* Sign the Metadata
+ False || True (use sp certs) || array (
+ keyFileName => 'metadata.key',
+ certFileName => 'metadata.crt'
+ )
+ */
+ 'signMetadata' => false,
+
+
+ /** signatures and encryptions required **/
+
+ // Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> and
+ // <samlp:LogoutResponse> elements received by this SP to be signed.
+ 'wantMessagesSigned' => false,
+
+ // Indicates a requirement for the <saml:Assertion> elements received by
+ // this SP to be signed. [The Metadata of the SP will offer this info]
+ 'wantAssertionsSigned' => false,
+
+ // Indicates a requirement for the NameID element on the SAMLResponse received
+ // by this SP to be present.
+ 'wantNameId' => true,
+
+ // Indicates a requirement for the NameID received by
+ // this SP to be encrypted.
+ 'wantNameIdEncrypted' => false,
+
+ // Authentication context.
+ // Set to false and no AuthContext will be sent in the AuthNRequest,
+ // Set true or don't present this parameter and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
+ // Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),
+ 'requestedAuthnContext' => false,
+
+ // Allows the authn comparison parameter to be set, defaults to 'exact' if
+ // the setting is not present.
+ 'requestedAuthnContextComparison' => 'exact',
+
+ // Indicates if the SP will validate all received xmls.
+ // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true).
+ 'wantXMLValidation' => true,
+
+ // 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'
+ // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
+ // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
+ // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
+ 'signatureAlgorithm' => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1',
+ ),
+
+ // Contact information template, it is recommended to suply a technical and support contacts
+ 'contactPerson' => array (
+ 'technical' => array (
+ 'givenName' => '',
+ 'emailAddress' => ''
+ ),
+ 'support' => array (
+ 'givenName' => '',
+ 'emailAddress' => ''
+ ),
+ ),
+
+ // Organization information template, the info in en_US lang is recomended, add more if required
+ 'organization' => array (
+ 'en-US' => array(
+ 'name' => '',
+ 'displayname' => '',
+ 'url' => ''
+ ),
+ ),
+);
+
+
+/* Interoperable SAML 2.0 Web Browser SSO Profile [saml2int] http://saml2int.org/profile/current
+
+ 'authnRequestsSigned' => false, // SP SHOULD NOT sign the <samlp:AuthnRequest>,
+ // MUST NOT assume that the IdP validates the sign
+ 'wantAssertionsSigned' => true,
+ 'wantAssertionsEncrypted' => true, // MUST be enabled if SSL/HTTPs is disabled
+ 'wantNameIdEncrypted' => false,
+*/
diff --git a/3rdparty/vendor/onelogin/php-saml/compatibility.php b/3rdparty/vendor/onelogin/php-saml/compatibility.php
new file mode 100644
index 00000000..02a8108c
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/compatibility.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * Compability with the old PHP Toolkit
+ */
+
+define('ONELOGIN_SAML_DIR', 'lib/Saml/');
+require_once ONELOGIN_SAML_DIR . 'AuthRequest.php';
+require_once ONELOGIN_SAML_DIR . 'Response.php';
+require_once ONELOGIN_SAML_DIR . 'Settings.php';
+require_once ONELOGIN_SAML_DIR . 'XmlSec.php';
+require_once ONELOGIN_SAML_DIR . 'Metadata.php';
diff --git a/3rdparty/vendor/onelogin/php-saml/composer.json b/3rdparty/vendor/onelogin/php-saml/composer.json
new file mode 100644
index 00000000..3ab2225b
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/composer.json
@@ -0,0 +1,39 @@
+{
+ "name": "onelogin/php-saml",
+ "description": "OneLogin PHP SAML Toolkit",
+ "license": "MIT",
+ "version": "2.9.0",
+ "homepage": "https://onelogin.zendesk.com/hc/en-us/sections/200245634-SAML-Toolkits",
+ "keywords": ["saml", "saml2", "onelogin"],
+ "autoload": {
+ "classmap": [
+ "extlib/xmlseclibs",
+ "lib/Saml",
+ "lib/Saml2"
+ ]
+ },
+ "support": {
+ "email": "sixto.garcia@onelogin.com",
+ "issues": "https://github.com/onelogin/php-saml/issues",
+ "source": "https://github.com/onelogin/php-saml/"
+ },
+ "require": {
+ "php": ">=5.3.2",
+ "ext-openssl": "*",
+ "ext-dom": "*",
+ "ext-mcrypt": "*"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.8",
+ "satooshi/php-coveralls": "1.0.1",
+ "sebastian/phpcpd": "*",
+ "phploc/phploc": "*",
+ "pdepend/pdepend" : "1.1.0",
+ "squizlabs/php_codesniffer": "*"
+ },
+ "suggest": {
+ "lib-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)",
+ "ext-mcrypt": "Install mcrypt and php5-mcrypt libs in order to support encryption",
+ "ext-gettext": "Install gettext and php5-gettext libs to handle translations"
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/endpoints/acs.php b/3rdparty/vendor/onelogin/php-saml/endpoints/acs.php
new file mode 100644
index 00000000..4b1ac242
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/endpoints/acs.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * SP Assertion Consumer Service Endpoint
+ */
+
+session_start();
+
+require_once dirname(dirname(__FILE__)).'/_toolkit_loader.php';
+
+$auth = new OneLogin_Saml2_Auth();
+
+$auth->processResponse();
+
+$errors = $auth->getErrors();
+
+if (!empty($errors)) {
+ print_r('<p>'.implode(', ', $errors).'</p>');
+ exit();
+}
+
+if (!$auth->isAuthenticated()) {
+ echo "<p>Not authenticated</p>";
+ exit();
+}
+
+$_SESSION['samlUserdata'] = $auth->getAttributes();
+$_SESSION['IdPSessionIndex'] = $auth->getSessionIndex();
+if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) {
+ $auth->redirectTo($_POST['RelayState']);
+}
+
+$attributes = $_SESSION['samlUserdata'];
+
+if (!empty($attributes)) {
+ echo '<h1>'._('User attributes:').'</h1>';
+ echo '<table><thead><th>'._('Name').'</th><th>'._('Values').'</th></thead><tbody>';
+ foreach ($attributes as $attributeName => $attributeValues) {
+ echo '<tr><td>'.htmlentities($attributeName).'</td><td><ul>';
+ foreach ($attributeValues as $attributeValue) {
+ echo '<li>'.htmlentities($attributeValue).'</li>';
+ }
+ echo '</ul></td></tr>';
+ }
+ echo '</tbody></table>';
+ if (!empty($_SESSION['IdPSessionIndex'])) {
+ echo '<p>The SessionIndex of the IdP is: '.$_SESSION['IdPSessionIndex'].'</p>';
+ }
+} else {
+ echo _('Attributes not found');
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/endpoints/metadata.php b/3rdparty/vendor/onelogin/php-saml/endpoints/metadata.php
new file mode 100644
index 00000000..68ccfde6
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/endpoints/metadata.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * SP Metadata Endpoint
+ */
+
+require_once dirname(dirname(__FILE__)).'/_toolkit_loader.php';
+
+try {
+ $auth = new OneLogin_Saml2_Auth();
+ $settings = $auth->getSettings();
+ $metadata = $settings->getSPMetadata();
+ $errors = $settings->validateMetadata($metadata);
+ if (empty($errors)) {
+ header('Content-Type: text/xml');
+ echo $metadata;
+ } else {
+ throw new OneLogin_Saml2_Error(
+ 'Invalid SP metadata: '.implode(', ', $errors),
+ OneLogin_Saml2_Error::METADATA_SP_INVALID
+ );
+ }
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/endpoints/sls.php b/3rdparty/vendor/onelogin/php-saml/endpoints/sls.php
new file mode 100644
index 00000000..d6b7e4da
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/endpoints/sls.php
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * SP Single Logout Service Endpoint
+ */
+
+session_start();
+
+require_once dirname(dirname(__FILE__)).'/_toolkit_loader.php';
+
+$auth = new OneLogin_Saml2_Auth();
+
+$auth->processSLO();
+
+$errors = $auth->getErrors();
+
+if (empty($errors)) {
+ print_r('Sucessfully logged out');
+} else {
+ print_r(implode(', ', $errors));
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/CHANGELOG.txt b/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/CHANGELOG.txt
new file mode 100644
index 00000000..c0b8cfe4
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/CHANGELOG.txt
@@ -0,0 +1,130 @@
+xmlseclibs.php
+??, ??? ????, 2.0.0
+Features:
+- Support for locating specific signature when multiple exist in
+ document. (griga3k)
+
+23, Jun 2015, 1.4.0
+Features:
+- Support for PSR-0 standard.
+- Support for X509SubjectName. (Milos Tomic)
+- Add HMAC-SHA1 support.
+
+Improvements:
+- Add how to install to README. (Bernardo Vieira da Silva)
+- Code cleanup. (Jaime Pérez)
+- Normalilze tests. (Hidde Wieringa)
+- Add basic usage to README. (Hidde Wieringa)
+
+21, May 2015, 1.3.2
+Bug Fixes:
+- Fix Undefined variable notice. (dpieper85)
+- Fix typo when setting MimeType attribute. (Eugene OZ)
+- Fix validateReference() with enveloping signatures
+
+Features:
+- canonicalizeData performance optimization. (Jaime Pérez)
+- Add composer support (Maks3w)
+
+19, Jun 2013, 1.3.1
+Features:
+- return encrypted node from XMLSecEnc::encryptNode() when replace is set to
+ false. (Olav)
+- Add support for RSA SHA384 and RSA_SHA512 and SHA384 digest. (Jaime PÂŽrez)
+- Add options parameter to the add cert methods.
+- Add optional issuerSerial creation with cert
+
+Bug Fixes:
+- Fix persisted Id when namespaced. (Koen Thomeer)
+
+Improvements:
+- Add LICENSE file
+- Convert CHANGELOG.txt to UTF-8
+
+26, Sep 2011, 1.3.0
+Features:
+- Add param to append sig to node when signing. Fixes a problem when using
+ inclusive canonicalization to append a signature within a namespaced subtree.
+ ex. $objDSig->sign($objKey, $appendToNode);
+- Add ability to encrypt by reference
+- Add support for refences within an encrypted key
+- Add thumbprint generation capability (XMLSecurityKey->getX509Thumbprint() and
+ XMLSecurityKey::getRawThumbprint($cert))
+- Return signature element node from XMLSecurityDSig::insertSignature() and
+ XMLSecurityDSig::appendSignature() methods
+- Support for <ds:RetrievalMethod> with simple URI Id reference.
+- Add XMLSecurityKey::getSymmetricKeySize() method (Olav)
+- Add XMLSecEnc::getCipherValue() method (Olav)
+- Improve XMLSecurityKey:generateSessionKey() logic (Olav)
+
+Bug Fixes:
+- Change split() to explode() as split is now depreciated
+- ds:References using empty or simple URI Id reference should never include
+ comments in canonicalized data.
+- Make sure that the elements in EncryptedData are emitted in the correct
+ sequence.
+
+11 Jan 2010, 1.2.2
+Features:
+- Add support XPath support when creating signature. Provides support for
+ working with EBXML documents.
+- Add reference option to force creation of URI attribute. For use
+ when adding a DOM Document where by default no URI attribute is added.
+- Add support for RSA-SHA256
+
+Bug Fixes:
+- fix bug #5: createDOMDocumentFragment() in decryptNode when data is node
+ content (patch by Francois Wang)
+
+
+08 Jul 2008, 1.2.1
+Features:
+- Attempt to use mhash when hash extension is not present. (Alfredo Cubitos).
+- Add fallback to built-in sha1 if both hash and mhash are not available and
+ throw error for other for other missing hashes. (patch by Olav Morken).
+- Add getX509Certificate method to retrieve the x509 cert used for Key.
+ (patch by Olav Morken).
+- Add getValidatedNodes method to retrieve the elements signed by the
+ signature. (patch by Olav Morken).
+- Add insertSignature method for precision signature insertion. Merge
+ functionality from appendSignature in the process. (Olav Morken, Rob).
+- Finally add some tests
+
+Bug Fixes:
+- Fix canonicalization for Document node when using PHP < 5.2.
+- Add padding for RSA_SHA1. (patch by Olav Morken).
+
+
+27 Nov 2007, 1.2.0
+Features:
+- New addReference/List option (overwrite). Boolean flag indicating if URI
+ value should be overwritten if already existing within document.
+ Default is TRUE to maintain BC.
+
+18 Nov 2007, 1.1.2
+Bug Fixes:
+- Remove closing PHP tag to fix extra whitespace characters from being output
+
+11 Nov 2007, 1.1.1
+Features:
+- Add getRefNodeID() and getRefIDs() methods missed in previous release.
+ Provide functionality to find URIs of existing reference nodes.
+ Required by simpleSAMLphp project
+
+Bug Fixes:
+- Remove erroneous whitespace causing issues under certain circumastances.
+
+18 Oct 2007, 1.1.0
+Features:
+- Enable creation of enveloping signature. This allows the creation of
+ managed information cards.
+- Add addObject method for enveloping signatures.
+- Add staticGet509XCerts method. Chained certificates within a PEM file can
+ now be added within the X509Data node.
+- Add xpath support within transformations
+- Add InclusiveNamespaces prefix list support within exclusive transformations.
+
+Bug Fixes:
+- Initialize random number generator for mcrypt_create_iv. (Joan Cornadó).
+- Fix an interoperability issue with .NET when encrypting data in CBC mode.
+ (Joan Cornadó).
diff --git a/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/LICENSE b/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/LICENSE
new file mode 100644
index 00000000..2a102b76
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2007-2013, Robert Richards <rrichards@cdatazone.org>.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of Robert Richards nor the names of his
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php b/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php
new file mode 100644
index 00000000..05be8643
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php
@@ -0,0 +1,1721 @@
+<?php
+/**
+ * xmlseclibs.php
+ *
+ * Copyright (c) 2007-2015, Robert Richards <rrichards@cdatazone.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Robert Richards nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @author Robert Richards <rrichards@cdatazone.org>
+ * @copyright 2007-2015 Robert Richards <rrichards@cdatazone.org>
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version 2.0.0 modified
+ */
+
+class XMLSecurityKey {
+ const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
+ 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 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 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';
+
+ private $cryptParams = array();
+ public $type = 0;
+ public $key = null;
+ public $passphrase = "";
+ public $iv = null;
+ public $name = null;
+ public $keyChain = null;
+ public $isEncrypted = false;
+ public $encryptedCtx = null;
+ public $guid = null;
+
+ /**
+ * This variable contains the certificate as a string if this key represents an X509-certificate.
+ * If this key doesn't represent a certificate, this will be null.
+ */
+ private $x509Certificate = null;
+
+ /* This variable contains the certificate thunbprint if we have loaded an X509-certificate. */
+ private $X509Thumbprint = null;
+
+ public function __construct($type, $params=null) {
+ switch ($type) {
+ case (XMLSecurityKey::TRIPLEDES_CBC):
+ $this->cryptParams['library'] = 'mcrypt';
+ $this->cryptParams['cipher'] = MCRYPT_TRIPLEDES;
+ $this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
+ $this->cryptParams['keysize'] = 24;
+ break;
+ case (XMLSecurityKey::AES128_CBC):
+ $this->cryptParams['library'] = 'mcrypt';
+ $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
+ $this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
+ $this->cryptParams['keysize'] = 16;
+ break;
+ case (XMLSecurityKey::AES192_CBC):
+ $this->cryptParams['library'] = 'mcrypt';
+ $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
+ $this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
+ $this->cryptParams['keysize'] = 24;
+ break;
+ case (XMLSecurityKey::AES256_CBC):
+ $this->cryptParams['library'] = 'mcrypt';
+ $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
+ $this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
+ $this->cryptParams['keysize'] = 32;
+ break;
+ case (XMLSecurityKey::RSA_1_5):
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
+ 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 (XMLSecurityKey::RSA_OAEP_MGF1P):
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['padding'] = OPENSSL_PKCS1_OAEP_PADDING;
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
+ $this->cryptParams['hash'] = null;
+ 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 (XMLSecurityKey::RSA_SHA1):
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
+ $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
+ 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 (XMLSecurityKey::RSA_SHA256):
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
+ $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
+ $this->cryptParams['digest'] = 'SHA256';
+ 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 (XMLSecurityKey::RSA_SHA384):
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
+ $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
+ $this->cryptParams['digest'] = 'SHA384';
+ 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 (XMLSecurityKey::RSA_SHA512):
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
+ $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
+ $this->cryptParams['digest'] = 'SHA512';
+ 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 (XMLSecurityKey::HMAC_SHA1):
+ $this->cryptParams['library'] = $type;
+ $this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
+ break;
+ default:
+ throw new Exception('Invalid Key Type');
+ }
+ $this->type = $type;
+ }
+
+ /**
+ * Retrieve the key size for the symmetric encryption algorithm..
+ *
+ * If the key size is unknown, or this isn't a symmetric encryption algorithm,
+ * null is returned.
+ *
+ * @return int|null The number of bytes in the key.
+ */
+ public function getSymmetricKeySize() {
+ if (! isset($this->cryptParams['keysize'])) {
+ return null;
+ }
+ return $this->cryptParams['keysize'];
+ }
+
+ public function generateSessionKey() {
+ if (!isset($this->cryptParams['keysize'])) {
+ throw new Exception('Unknown key size for type "' . $this->type . '".');
+ }
+ $keysize = $this->cryptParams['keysize'];
+
+ if (function_exists('openssl_random_pseudo_bytes')) {
+ /* We have PHP >= 5.3 - use openssl to generate session key. */
+ $key = openssl_random_pseudo_bytes($keysize);
+ } else {
+ /* Generating random key using iv generation routines */
+ $key = mcrypt_create_iv($keysize, MCRYPT_RAND);
+ }
+
+ if ($this->type === XMLSecurityKey::TRIPLEDES_CBC) {
+ /* Make sure that the generated key has the proper parity bits set.
+ * Mcrypt doesn't care about the parity bits, but others may care.
+ */
+ for ($i = 0; $i < strlen($key); $i++) {
+ $byte = ord($key[$i]) & 0xfe;
+ $parity = 1;
+ for ($j = 1; $j < 8; $j++) {
+ $parity ^= ($byte >> $j) & 1;
+ }
+ $byte |= $parity;
+ $key[$i] = chr($byte);
+ }
+ }
+
+ $this->key = $key;
+ return $key;
+ }
+
+ public static function getRawThumbprint($cert) {
+
+ $arCert = explode("\n", $cert);
+ $data = '';
+ $inData = false;
+
+ foreach ($arCert AS $curData) {
+ if (! $inData) {
+ if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) {
+ $inData = true;
+ }
+ } else {
+ if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) {
+ break;
+ }
+ $data .= trim($curData);
+ }
+ }
+
+ if (! empty($data)) {
+ return strtolower(sha1(base64_decode($data)));
+ }
+
+ return null;
+ }
+
+ public function loadKey($key, $isFile=false, $isCert = false) {
+ if ($isFile) {
+ $this->key = file_get_contents($key);
+ } else {
+ $this->key = $key;
+ }
+ if ($isCert) {
+ $this->key = openssl_x509_read($this->key);
+ openssl_x509_export($this->key, $str_cert);
+ $this->x509Certificate = $str_cert;
+ $this->key = $str_cert;
+ } else {
+ $this->x509Certificate = null;
+ }
+ if ($this->cryptParams['library'] == 'openssl') {
+ if ($this->cryptParams['type'] == 'public') {
+ if ($isCert) {
+ /* Load the thumbprint if this is an X509 certificate. */
+ $this->X509Thumbprint = self::getRawThumbprint($this->key);
+ }
+ $this->key = openssl_get_publickey($this->key);
+ } else {
+ $this->key = openssl_get_privatekey($this->key, $this->passphrase);
+ }
+ } else if ($this->cryptParams['cipher'] == MCRYPT_RIJNDAEL_128) {
+ /* Check key length */
+ switch ($this->type) {
+ case (XMLSecurityKey::AES256_CBC):
+ if (strlen($this->key) < 25) {
+ throw new Exception('Key must contain at least 25 characters for this cipher');
+ }
+ break;
+ case (XMLSecurityKey::AES192_CBC):
+ if (strlen($this->key) < 17) {
+ throw new Exception('Key must contain at least 17 characters for this cipher');
+ }
+ break;
+ }
+ }
+ }
+
+ private function encryptMcrypt($data) {
+ $td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], '');
+ $this->iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
+ mcrypt_generic_init($td, $this->key, $this->iv);
+ if ($this->cryptParams['mode'] == MCRYPT_MODE_CBC) {
+ $bs = mcrypt_enc_get_block_size($td);
+ for ($datalen0=$datalen=strlen($data); (($datalen%$bs)!=($bs-1)); $datalen++)
+ $data.=chr(mt_rand(1, 127));
+ $data.=chr($datalen-$datalen0+1);
+ }
+ $encrypted_data = $this->iv.mcrypt_generic($td, $data);
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+ return $encrypted_data;
+ }
+
+ private function decryptMcrypt($data) {
+ $td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], '');
+ $iv_length = mcrypt_enc_get_iv_size($td);
+
+ $this->iv = substr($data, 0, $iv_length);
+ $data = substr($data, $iv_length);
+
+ mcrypt_generic_init($td, $this->key, $this->iv);
+ $decrypted_data = mdecrypt_generic($td, $data);
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+ if ($this->cryptParams['mode'] == MCRYPT_MODE_CBC) {
+ $dataLen = strlen($decrypted_data);
+ $paddingLength = substr($decrypted_data, $dataLen - 1, 1);
+ $decrypted_data = substr($decrypted_data, 0, $dataLen - ord($paddingLength));
+ }
+ return $decrypted_data;
+ }
+
+ private function encryptOpenSSL($data) {
+ if ($this->cryptParams['type'] == 'public') {
+ if (! openssl_public_encrypt($data, $encrypted_data, $this->key, $this->cryptParams['padding'])) {
+ throw new Exception('Failure encrypting Data');
+ }
+ } else {
+ if (! openssl_private_encrypt($data, $encrypted_data, $this->key, $this->cryptParams['padding'])) {
+ throw new Exception('Failure encrypting Data');
+ }
+ }
+ return $encrypted_data;
+ }
+
+ private function decryptOpenSSL($data) {
+ if ($this->cryptParams['type'] == 'public') {
+ if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
+ throw new Exception('Failure decrypting Data');
+ }
+ } else {
+ if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
+ throw new Exception('Failure decrypting Data');
+ }
+ }
+ return $decrypted;
+ }
+
+ private function signOpenSSL($data) {
+ $algo = OPENSSL_ALGO_SHA1;
+ if (! empty($this->cryptParams['digest'])) {
+ $algo = $this->cryptParams['digest'];
+ }
+ if (! openssl_sign ($data, $signature, $this->key, $algo)) {
+ throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo);
+ }
+ return $signature;
+ }
+
+ private function verifyOpenSSL($data, $signature) {
+ $algo = OPENSSL_ALGO_SHA1;
+ if (! empty($this->cryptParams['digest'])) {
+ $algo = $this->cryptParams['digest'];
+ }
+ return openssl_verify ($data, $signature, $this->key, $algo);
+ }
+
+ public function encryptData($data) {
+ switch ($this->cryptParams['library']) {
+ case 'mcrypt':
+ return $this->encryptMcrypt($data);
+ case 'openssl':
+ return $this->encryptOpenSSL($data);
+ }
+ }
+
+ public function decryptData($data) {
+ switch ($this->cryptParams['library']) {
+ case 'mcrypt':
+ return $this->decryptMcrypt($data);
+ case 'openssl':
+ return $this->decryptOpenSSL($data);
+ }
+ }
+
+ public function signData($data) {
+ switch ($this->cryptParams['library']) {
+ case 'openssl':
+ return $this->signOpenSSL($data);
+ case (XMLSecurityKey::HMAC_SHA1):
+ return hash_hmac("sha1", $data, $this->key, true);
+ }
+ }
+
+ public function verifySignature($data, $signature) {
+ switch ($this->cryptParams['library']) {
+ case 'openssl':
+ return $this->verifyOpenSSL($data, $signature);
+ case (XMLSecurityKey::HMAC_SHA1):
+ $expectedSignature = hash_hmac("sha1", $data, $this->key, true);
+ return strcmp($signature, $expectedSignature) == 0;
+ }
+ }
+
+ public function getAlgorithm() {
+ return $this->cryptParams['method'];
+ }
+
+ static function makeAsnSegment($type, $string) {
+ switch ($type){
+ case 0x02:
+ if (ord($string) > 0x7f)
+ $string = chr(0).$string;
+ break;
+ case 0x03:
+ $string = chr(0).$string;
+ break;
+ }
+
+ $length = strlen($string);
+
+ if ($length < 128){
+ $output = sprintf("%c%c%s", $type, $length, $string);
+ } else if ($length < 0x0100){
+ $output = sprintf("%c%c%c%s", $type, 0x81, $length, $string);
+ } else if ($length < 0x010000) {
+ $output = sprintf("%c%c%c%c%s", $type, 0x82, $length/0x0100, $length%0x0100, $string);
+ } else {
+ $output = null;
+ }
+ return($output);
+ }
+
+ /* Modulus and Exponent must already be base64 decoded */
+ static function convertRSA($modulus, $exponent) {
+ /* make an ASN publicKeyInfo */
+ $exponentEncoding = XMLSecurityKey::makeAsnSegment(0x02, $exponent);
+ $modulusEncoding = XMLSecurityKey::makeAsnSegment(0x02, $modulus);
+ $sequenceEncoding = XMLSecurityKey:: makeAsnSegment(0x30, $modulusEncoding.$exponentEncoding);
+ $bitstringEncoding = XMLSecurityKey::makeAsnSegment(0x03, $sequenceEncoding);
+ $rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500");
+ $publicKeyInfo = XMLSecurityKey::makeAsnSegment (0x30, $rsaAlgorithmIdentifier.$bitstringEncoding);
+
+ /* encode the publicKeyInfo in base64 and add PEM brackets */
+ $publicKeyInfoBase64 = base64_encode($publicKeyInfo);
+ $encoding = "-----BEGIN PUBLIC KEY-----\n";
+ $offset = 0;
+ while ($segment=substr($publicKeyInfoBase64, $offset, 64)){
+ $encoding = $encoding.$segment."\n";
+ $offset += 64;
+ }
+ return $encoding."-----END PUBLIC KEY-----\n";
+ }
+
+ public function serializeKey($parent) {
+
+ }
+
+
+
+ /**
+ * Retrieve the X509 certificate this key represents.
+ *
+ * Will return the X509 certificate in PEM-format if this key represents
+ * an X509 certificate.
+ *
+ * @return The X509 certificate or null if this key doesn't represent an X509-certificate.
+ */
+ public function getX509Certificate() {
+ return $this->x509Certificate;
+ }
+
+ /* Get the thumbprint of this X509 certificate.
+ *
+ * Returns:
+ * The thumbprint as a lowercase 40-character hexadecimal number, or null
+ * if this isn't a X509 certificate.
+ */
+ public function getX509Thumbprint() {
+ return $this->X509Thumbprint;
+ }
+
+
+ /**
+ * Create key from an EncryptedKey-element.
+ *
+ * @param DOMElement $element The EncryptedKey-element.
+ * @return XMLSecurityKey The new key.
+ */
+ public static function fromEncryptedKeyElement(DOMElement $element) {
+
+ $objenc = new XMLSecEnc();
+ $objenc->setNode($element);
+ if (! $objKey = $objenc->locateKey()) {
+ throw new Exception("Unable to locate algorithm for this Encrypted Key");
+ }
+ $objKey->isEncrypted = true;
+ $objKey->encryptedCtx = $objenc;
+ XMLSecEnc::staticLocateKeyInfo($objKey, $element);
+ return $objKey;
+ }
+
+}
+
+
+class XMLSecurityDSig {
+ const XMLDSIGNS = 'http://www.w3.org/2000/09/xmldsig#';
+ const SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1';
+ const SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256';
+ const SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#sha384';
+ const SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512';
+ const RIPEMD160 = 'http://www.w3.org/2001/04/xmlenc#ripemd160';
+
+ const C14N = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
+ const C14N_COMMENTS = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments';
+ const EXC_C14N = 'http://www.w3.org/2001/10/xml-exc-c14n#';
+ const EXC_C14N_COMMENTS = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments';
+
+ const template = '<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <ds:SignedInfo>
+ <ds:SignatureMethod />
+ </ds:SignedInfo>
+</ds:Signature>';
+
+ public $sigNode = null;
+ public $idKeys = array();
+ public $idNS = array();
+ private $signedInfo = null;
+ private $xPathCtx = null;
+ private $canonicalMethod = null;
+ private $prefix = 'ds';
+ private $searchpfx = 'secdsig';
+
+ /* This variable contains an associative array of validated nodes. */
+ private $validatedNodes = null;
+
+ public function __construct() {
+ $sigdoc = new DOMDocument();
+ $sigdoc->loadXML(XMLSecurityDSig::template);
+ $this->sigNode = $sigdoc->documentElement;
+ }
+
+ private function resetXPathObj() {
+ $this->xPathCtx = null;
+ }
+
+ private function getXPathObj() {
+ if (empty($this->xPathCtx) && ! empty($this->sigNode)) {
+ $xpath = new DOMXPath($this->sigNode->ownerDocument);
+ $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+ $this->xPathCtx = $xpath;
+ }
+ return $this->xPathCtx;
+ }
+
+ static function generateGUID($prefix='pfx') {
+ $uuid = md5(uniqid(mt_rand(), true));
+ $guid = $prefix.substr($uuid,0,8)."-".
+ substr($uuid,8,4)."-".
+ substr($uuid,12,4)."-".
+ substr($uuid,16,4)."-".
+ substr($uuid,20,12);
+ return $guid;
+ }
+
+ public function locateSignature($objDoc, $pos=0) {
+ if ($objDoc instanceof DOMDocument) {
+ $doc = $objDoc;
+ } else {
+ $doc = $objDoc->ownerDocument;
+ }
+ if ($doc) {
+ $xpath = new DOMXPath($doc);
+ $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+ $query = ".//secdsig:Signature";
+ $nodeset = $xpath->query($query, $objDoc);
+ $this->sigNode = $nodeset->item($pos);
+ return $this->sigNode;
+ }
+ return null;
+ }
+
+ public function createNewSignNode($name, $value=null) {
+ $doc = $this->sigNode->ownerDocument;
+ if (! is_null($value)) {
+ $node = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, $this->prefix.':'.$name, $value);
+ } else {
+ $node = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, $this->prefix.':'.$name);
+ }
+ return $node;
+ }
+
+ public function setCanonicalMethod($method) {
+ switch ($method) {
+ case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315':
+ case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments':
+ case 'http://www.w3.org/2001/10/xml-exc-c14n#':
+ case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments':
+ $this->canonicalMethod = $method;
+ break;
+ default:
+ throw new Exception('Invalid Canonical Method');
+ }
+ if ($xpath = $this->getXPathObj()) {
+ $query = './'.$this->searchpfx.':SignedInfo';
+ $nodeset = $xpath->query($query, $this->sigNode);
+ if ($sinfo = $nodeset->item(0)) {
+ $query = './'.$this->searchpfx.'CanonicalizationMethod';
+ $nodeset = $xpath->query($query, $sinfo);
+ if (! ($canonNode = $nodeset->item(0))) {
+ $canonNode = $this->createNewSignNode('CanonicalizationMethod');
+ $sinfo->insertBefore($canonNode, $sinfo->firstChild);
+ }
+ $canonNode->setAttribute('Algorithm', $this->canonicalMethod);
+ }
+ }
+ }
+
+ private function canonicalizeData($node, $canonicalmethod, $arXPath=null, $prefixList=null) {
+ $exclusive = false;
+ $withComments = false;
+ switch ($canonicalmethod) {
+ case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315':
+ $exclusive = false;
+ $withComments = false;
+ break;
+ case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments':
+ $withComments = true;
+ break;
+ case 'http://www.w3.org/2001/10/xml-exc-c14n#':
+ $exclusive = true;
+ break;
+ case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments':
+ $exclusive = true;
+ $withComments = true;
+ break;
+ }
+
+ if (is_null($arXPath) && ($node instanceof DOMNode) && ($node->ownerDocument !== null) && $node->isSameNode($node->ownerDocument->documentElement)) {
+ /* Check for any PI or comments as they would have been excluded */
+ $element = $node;
+ while ($refnode = $element->previousSibling) {
+ if ($refnode->nodeType == XML_PI_NODE || (($refnode->nodeType == XML_COMMENT_NODE) && $withComments)) {
+ break;
+ }
+ $element = $refnode;
+ }
+ if ($refnode == null) {
+ $node = $node->ownerDocument;
+ }
+ }
+
+ return $node->C14N($exclusive, $withComments, $arXPath, $prefixList);
+ }
+
+ public function canonicalizeSignedInfo() {
+
+ $doc = $this->sigNode->ownerDocument;
+ $canonicalmethod = null;
+ if ($doc) {
+ $xpath = $this->getXPathObj();
+ $query = "./secdsig:SignedInfo";
+ $nodeset = $xpath->query($query, $this->sigNode);
+ if ($signInfoNode = $nodeset->item(0)) {
+ $query = "./secdsig:CanonicalizationMethod";
+ $nodeset = $xpath->query($query, $signInfoNode);
+ if ($canonNode = $nodeset->item(0)) {
+ $canonicalmethod = $canonNode->getAttribute('Algorithm');
+ }
+ $this->signedInfo = $this->canonicalizeData($signInfoNode, $canonicalmethod);
+ return $this->signedInfo;
+ }
+ }
+ return null;
+ }
+
+ public function calculateDigest ($digestAlgorithm, $data, $encode = true) {
+ switch ($digestAlgorithm) {
+ case XMLSecurityDSig::SHA1:
+ $alg = 'sha1';
+ break;
+ case XMLSecurityDSig::SHA256:
+ $alg = 'sha256';
+ break;
+ case XMLSecurityDSig::SHA384:
+ $alg = 'sha384';
+ break;
+ case XMLSecurityDSig::SHA512:
+ $alg = 'sha512';
+ break;
+ case XMLSecurityDSig::RIPEMD160:
+ $alg = 'ripemd160';
+ break;
+ default:
+ throw new Exception("Cannot validate digest: Unsupported Algorithm <$digestAlgorithm>");
+ }
+
+ $digest = hash($alg, $data, true);
+ if ($encode) {
+ $digest = base64_encode($digest);
+ }
+ return $digest;
+ }
+
+ public function validateDigest($refNode, $data) {
+ $xpath = new DOMXPath($refNode->ownerDocument);
+ $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+ $query = 'string(./secdsig:DigestMethod/@Algorithm)';
+ $digestAlgorithm = $xpath->evaluate($query, $refNode);
+ $digValue = $this->calculateDigest($digestAlgorithm, $data, false);
+ $query = 'string(./secdsig:DigestValue)';
+ $digestValue = $xpath->evaluate($query, $refNode);
+ return ($digValue == base64_decode($digestValue));
+ }
+
+ public function processTransforms($refNode, $objData, $includeCommentNodes = true) {
+ $data = $objData;
+ $xpath = new DOMXPath($refNode->ownerDocument);
+ $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+ $query = './secdsig:Transforms/secdsig:Transform';
+ $nodelist = $xpath->query($query, $refNode);
+ $canonicalMethod = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
+ $arXPath = null;
+ $prefixList = null;
+ foreach ($nodelist AS $transform) {
+ $algorithm = $transform->getAttribute("Algorithm");
+ switch ($algorithm) {
+ case 'http://www.w3.org/2001/10/xml-exc-c14n#':
+ case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments':
+
+ if(!$includeCommentNodes) {
+ /* We remove comment nodes by forcing it to use a canonicalization
+ * without comments.
+ */
+ $canonicalMethod = 'http://www.w3.org/2001/10/xml-exc-c14n#';
+ } else {
+ $canonicalMethod = $algorithm;
+ }
+
+ $node = $transform->firstChild;
+ while ($node) {
+ if ($node->localName == 'InclusiveNamespaces') {
+ if ($pfx = $node->getAttribute('PrefixList')) {
+ $arpfx = array();
+ $pfxlist = explode(" ", $pfx);
+ foreach ($pfxlist AS $pfx) {
+ $val = trim($pfx);
+ if (! empty($val)) {
+ $arpfx[] = $val;
+ }
+ }
+ if (count($arpfx) > 0) {
+ $prefixList = $arpfx;
+ }
+ }
+ break;
+ }
+ $node = $node->nextSibling;
+ }
+ break;
+ case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315':
+ case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments':
+ if(!$includeCommentNodes) {
+ /* We remove comment nodes by forcing it to use a canonicalization
+ * without comments.
+ */
+ $canonicalMethod = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
+ } else {
+ $canonicalMethod = $algorithm;
+ }
+
+ break;
+ case 'http://www.w3.org/TR/1999/REC-xpath-19991116':
+ $node = $transform->firstChild;
+ while ($node) {
+ if ($node->localName == 'XPath') {
+ $arXPath = array();
+ $arXPath['query'] = '(.//. | .//@* | .//namespace::*)['.$node->nodeValue.']';
+ $arXpath['namespaces'] = array();
+ $nslist = $xpath->query('./namespace::*', $node);
+ foreach ($nslist AS $nsnode) {
+ if ($nsnode->localName != "xml") {
+ $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
+ }
+ }
+ break;
+ }
+ $node = $node->nextSibling;
+ }
+ break;
+ }
+ }
+ if ($data instanceof DOMNode) {
+ $data = $this->canonicalizeData($objData, $canonicalMethod, $arXPath, $prefixList);
+ }
+ return $data;
+ }
+
+ public function processRefNode($refNode) {
+ $dataObject = null;
+
+ /*
+ * Depending on the URI, we may not want to include comments in the result
+ * See: http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel
+ */
+ $includeCommentNodes = true;
+
+ if ($uri = $refNode->getAttribute("URI")) {
+ $arUrl = parse_url($uri);
+ if (empty($arUrl['path'])) {
+ if ($identifier = $arUrl['fragment']) {
+
+ /* This reference identifies a node with the given id by using
+ * a URI on the form "#identifier". This should not include comments.
+ */
+ $includeCommentNodes = false;
+
+ $xPath = new DOMXPath($refNode->ownerDocument);
+ if ($this->idNS && is_array($this->idNS)) {
+ foreach ($this->idNS AS $nspf=>$ns) {
+ $xPath->registerNamespace($nspf, $ns);
+ }
+ }
+ $iDlist = '@Id="'.$identifier.'"';
+ if (is_array($this->idKeys)) {
+ foreach ($this->idKeys AS $idKey) {
+ $iDlist .= " or @$idKey='$identifier'";
+ }
+ }
+ $query = '//*['.$iDlist.']';
+ $dataObject = $xPath->query($query)->item(0);
+ } else {
+ $dataObject = $refNode->ownerDocument;
+ }
+ } else {
+ $dataObject = file_get_contents($arUrl);
+ }
+ } else {
+ /* This reference identifies the root node with an empty URI. This should
+ * not include comments.
+ */
+ $includeCommentNodes = false;
+
+ $dataObject = $refNode->ownerDocument;
+ }
+ $data = $this->processTransforms($refNode, $dataObject, $includeCommentNodes);
+ if (!$this->validateDigest($refNode, $data)) {
+ return false;
+ }
+
+ if ($dataObject instanceof DOMNode) {
+ /* Add this node to the list of validated nodes. */
+ if(! empty($identifier)) {
+ $this->validatedNodes[$identifier] = $dataObject;
+ } else {
+ $this->validatedNodes[] = $dataObject;
+ }
+ }
+
+ return true;
+ }
+
+ public function getRefNodeID($refNode) {
+ if ($uri = $refNode->getAttribute("URI")) {
+ $arUrl = parse_url($uri);
+ if (empty($arUrl['path'])) {
+ if ($identifier = $arUrl['fragment']) {
+ return $identifier;
+ }
+ }
+ }
+ return null;
+ }
+
+ public function getRefIDs() {
+ $refids = array();
+
+ $xpath = $this->getXPathObj();
+ $query = "./secdsig:SignedInfo/secdsig:Reference";
+ $nodeset = $xpath->query($query, $this->sigNode);
+ if ($nodeset->length == 0) {
+ throw new Exception("Reference nodes not found");
+ }
+ foreach ($nodeset AS $refNode) {
+ $refids[] = $this->getRefNodeID($refNode);
+ }
+ return $refids;
+ }
+
+ public function validateReference() {
+ $docElem = $this->sigNode->ownerDocument->documentElement;
+ if (! $docElem->isSameNode($this->sigNode)) {
+ $this->sigNode->parentNode->removeChild($this->sigNode);
+ }
+ $xpath = $this->getXPathObj();
+ $query = "./secdsig:SignedInfo/secdsig:Reference";
+ $nodeset = $xpath->query($query, $this->sigNode);
+ if ($nodeset->length == 0) {
+ throw new Exception("Reference nodes not found");
+ }
+
+ /* Initialize/reset the list of validated nodes. */
+ $this->validatedNodes = array();
+
+ foreach ($nodeset AS $refNode) {
+ if (! $this->processRefNode($refNode)) {
+ /* Clear the list of validated nodes. */
+ $this->validatedNodes = null;
+ throw new Exception("Reference validation failed");
+ }
+ }
+ return true;
+ }
+
+ private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=null, $options=null) {
+ $prefix = null;
+ $prefix_ns = null;
+ $id_name = 'Id';
+ $overwrite_id = true;
+ $force_uri = false;
+
+ if (is_array($options)) {
+ $prefix = empty($options['prefix'])?null:$options['prefix'];
+ $prefix_ns = empty($options['prefix_ns'])?null:$options['prefix_ns'];
+ $id_name = empty($options['id_name'])?'Id':$options['id_name'];
+ $overwrite_id = !isset($options['overwrite'])?true:(bool)$options['overwrite'];
+ $force_uri = !isset($options['force_uri'])?false:(bool)$options['force_uri'];
+ }
+
+ $attname = $id_name;
+ if (! empty($prefix)) {
+ $attname = $prefix.':'.$attname;
+ }
+
+ $refNode = $this->createNewSignNode('Reference');
+ $sinfoNode->appendChild($refNode);
+
+ if (! $node instanceof DOMDocument) {
+ $uri = null;
+ if (! $overwrite_id) {
+ $uri = $prefix_ns ? $node->getAttributeNS($prefix_ns, $id_name) : $node->getAttribute($id_name);
+ }
+ if (empty($uri)) {
+ $uri = XMLSecurityDSig::generateGUID();
+ $node->setAttributeNS($prefix_ns, $attname, $uri);
+ }
+ $refNode->setAttribute("URI", '#'.$uri);
+ } elseif ($force_uri) {
+ $refNode->setAttribute("URI", '');
+ }
+
+ $transNodes = $this->createNewSignNode('Transforms');
+ $refNode->appendChild($transNodes);
+
+ if (is_array($arTransforms)) {
+ foreach ($arTransforms AS $transform) {
+ $transNode = $this->createNewSignNode('Transform');
+ $transNodes->appendChild($transNode);
+ if (is_array($transform) &&
+ (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116'])) &&
+ (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query']))) {
+ $transNode->setAttribute('Algorithm', 'http://www.w3.org/TR/1999/REC-xpath-19991116');
+ $XPathNode = $this->createNewSignNode('XPath', $transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query']);
+ $transNode->appendChild($XPathNode);
+ if (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'])) {
+ foreach ($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'] AS $prefix => $namespace) {
+ $XPathNode->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:$prefix", $namespace);
+ }
+ }
+ } else {
+ $transNode->setAttribute('Algorithm', $transform);
+ }
+ }
+ } elseif (! empty($this->canonicalMethod)) {
+ $transNode = $this->createNewSignNode('Transform');
+ $transNodes->appendChild($transNode);
+ $transNode->setAttribute('Algorithm', $this->canonicalMethod);
+ }
+
+ $canonicalData = $this->processTransforms($refNode, $node);
+ $digValue = $this->calculateDigest($algorithm, $canonicalData);
+
+ $digestMethod = $this->createNewSignNode('DigestMethod');
+ $refNode->appendChild($digestMethod);
+ $digestMethod->setAttribute('Algorithm', $algorithm);
+
+ $digestValue = $this->createNewSignNode('DigestValue', $digValue);
+ $refNode->appendChild($digestValue);
+ }
+
+ public function addReference($node, $algorithm, $arTransforms=null, $options=null) {
+ if ($xpath = $this->getXPathObj()) {
+ $query = "./secdsig:SignedInfo";
+ $nodeset = $xpath->query($query, $this->sigNode);
+ if ($sInfo = $nodeset->item(0)) {
+ $this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options);
+ }
+ }
+ }
+
+ public function addReferenceList($arNodes, $algorithm, $arTransforms=null, $options=null) {
+ if ($xpath = $this->getXPathObj()) {
+ $query = "./secdsig:SignedInfo";
+ $nodeset = $xpath->query($query, $this->sigNode);
+ if ($sInfo = $nodeset->item(0)) {
+ foreach ($arNodes AS $node) {
+ $this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options);
+ }
+ }
+ }
+ }
+
+ public function addObject($data, $mimetype=null, $encoding=null) {
+ $objNode = $this->createNewSignNode('Object');
+ $this->sigNode->appendChild($objNode);
+ if (! empty($mimetype)) {
+ $objNode->setAttribute('MimeType', $mimetype);
+ }
+ if (! empty($encoding)) {
+ $objNode->setAttribute('Encoding', $encoding);
+ }
+
+ if ($data instanceof DOMElement) {
+ $newData = $this->sigNode->ownerDocument->importNode($data, true);
+ } else {
+ $newData = $this->sigNode->ownerDocument->createTextNode($data);
+ }
+ $objNode->appendChild($newData);
+
+ return $objNode;
+ }
+
+ public function locateKey($node=null) {
+ if (empty($node)) {
+ $node = $this->sigNode;
+ }
+ if (! $node instanceof DOMNode) {
+ return null;
+ }
+ if ($doc = $node->ownerDocument) {
+ $xpath = new DOMXPath($doc);
+ $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+ $query = "string(./secdsig:SignedInfo/secdsig:SignatureMethod/@Algorithm)";
+ $algorithm = $xpath->evaluate($query, $node);
+ if ($algorithm) {
+ try {
+ $objKey = new XMLSecurityKey($algorithm, array('type'=>'public'));
+ } catch (Exception $e) {
+ return null;
+ }
+ return $objKey;
+ }
+ }
+ return null;
+ }
+
+ public function verify($objKey) {
+ $doc = $this->sigNode->ownerDocument;
+ $xpath = new DOMXPath($doc);
+ $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+ $query = "string(./secdsig:SignatureValue)";
+ $sigValue = $xpath->evaluate($query, $this->sigNode);
+ if (empty($sigValue)) {
+ throw new Exception("Unable to locate SignatureValue");
+ }
+ return $objKey->verifySignature($this->signedInfo, base64_decode($sigValue));
+ }
+
+ public function signData($objKey, $data) {
+ return $objKey->signData($data);
+ }
+
+ public function sign($objKey, $appendToNode = null) {
+ // If we have a parent node append it now so C14N properly works
+ if ($appendToNode != null) {
+ $this->resetXPathObj();
+ $this->appendSignature($appendToNode);
+ $this->sigNode = $appendToNode->lastChild;
+ }
+ if ($xpath = $this->getXPathObj()) {
+ $query = "./secdsig:SignedInfo";
+ $nodeset = $xpath->query($query, $this->sigNode);
+ if ($sInfo = $nodeset->item(0)) {
+ $query = "./secdsig:SignatureMethod";
+ $nodeset = $xpath->query($query, $sInfo);
+ $sMethod = $nodeset->item(0);
+ $sMethod->setAttribute('Algorithm', $objKey->type);
+ $data = $this->canonicalizeData($sInfo, $this->canonicalMethod);
+ $sigValue = base64_encode($this->signData($objKey, $data));
+ $sigValueNode = $this->createNewSignNode('SignatureValue', $sigValue);
+ if ($infoSibling = $sInfo->nextSibling) {
+ $infoSibling->parentNode->insertBefore($sigValueNode, $infoSibling);
+ } else {
+ $this->sigNode->appendChild($sigValueNode);
+ }
+ }
+ }
+ }
+
+ public function appendCert() {
+
+ }
+
+ public function appendKey($objKey, $parent=null) {
+ $objKey->serializeKey($parent);
+ }
+
+
+ /**
+ * This function inserts the signature element.
+ *
+ * The signature element will be appended to the element, unless $beforeNode is specified. If $beforeNode
+ * is specified, the signature element will be inserted as the last element before $beforeNode.
+ *
+ * @param $node The node the signature element should be inserted into.
+ * @param $beforeNode The node the signature element should be located before.
+ *
+ * @return DOMNode The signature element node
+ */
+ public function insertSignature($node, $beforeNode = null) {
+
+ $document = $node->ownerDocument;
+ $signatureElement = $document->importNode($this->sigNode, true);
+
+ if($beforeNode == null) {
+ return $node->insertBefore($signatureElement);
+ } else {
+ return $node->insertBefore($signatureElement, $beforeNode);
+ }
+ }
+
+ public function appendSignature($parentNode, $insertBefore = false) {
+ $beforeNode = $insertBefore ? $parentNode->firstChild : null;
+ return $this->insertSignature($parentNode, $beforeNode);
+ }
+
+ static function get509XCert($cert, $isPEMFormat=true) {
+ $certs = XMLSecurityDSig::staticGet509XCerts($cert, $isPEMFormat);
+ if (! empty($certs)) {
+ return $certs[0];
+ }
+ return '';
+ }
+
+ static function staticGet509XCerts($certs, $isPEMFormat=true) {
+ if ($isPEMFormat) {
+ $data = '';
+ $certlist = array();
+ $arCert = explode("\n", $certs);
+ $inData = false;
+ foreach ($arCert AS $curData) {
+ if (! $inData) {
+ if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) {
+ $inData = true;
+ }
+ } else {
+ if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) {
+ $inData = false;
+ $certlist[] = $data;
+ $data = '';
+ continue;
+ }
+ $data .= trim($curData);
+ }
+ }
+ return $certlist;
+ } else {
+ return array($certs);
+ }
+ }
+
+ static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $isURL=false, $xpath=null, $options=null) {
+ if ($isURL) {
+ $cert = file_get_contents($cert);
+ }
+ if (! $parentRef instanceof DOMElement) {
+ throw new Exception('Invalid parent Node parameter');
+ }
+
+ list($parentRef, $keyInfo) = self::auxKeyInfo($parentRef, $xpath);
+
+ // Add all certs if there are more than one
+ $certs = XMLSecurityDSig::staticGet509XCerts($cert, $isPEMFormat);
+
+ $baseDoc = $parentRef->ownerDocument;
+ // Attach X509 data node
+ $x509DataNode = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509Data');
+ $keyInfo->appendChild($x509DataNode);
+
+ $issuerSerial = false;
+ $subjectName = false;
+ if (is_array($options)) {
+ if (! empty($options['issuerSerial'])) {
+ $issuerSerial = true;
+ }
+ if (! empty($options['subjectName'])) {
+ $subjectName = true;
+ }
+ }
+
+ // Attach all certificate nodes and any additional data
+ foreach ($certs as $X509Cert){
+ if ($issuerSerial || $subjectName) {
+ if ($certData = openssl_x509_parse("-----BEGIN CERTIFICATE-----\n".chunk_split($X509Cert, 64, "\n")."-----END CERTIFICATE-----\n")) {
+ if ($subjectName && ! empty($certData['subject'])) {
+ if (is_array($certData['subject'])) {
+ $parts = array();
+ foreach ($certData['subject'] AS $key => $value) {
+ if (is_array($value)) {
+ foreach ($value as $valueElement) {
+ array_unshift($parts, "$key=$valueElement");
+ }
+ } else {
+ array_unshift($parts, "$key=$value");
+ }
+ }
+ $subjectNameValue = implode(',', $parts);
+ } else {
+ $subjectNameValue = $certData['issuer'];
+ }
+ $x509SubjectNode = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509SubjectName', $subjectNameValue);
+ $x509DataNode->appendChild($x509SubjectNode);
+ }
+ if ($issuerSerial && ! empty($certData['issuer']) && ! empty($certData['serialNumber'])) {
+ if (is_array($certData['issuer'])) {
+ $parts = array();
+ foreach ($certData['issuer'] AS $key => $value) {
+ array_unshift($parts, "$key=$value");
+ }
+ $issuerName = implode(',', $parts);
+ } else {
+ $issuerName = $certData['issuer'];
+ }
+
+ $x509IssuerNode = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509IssuerSerial');
+ $x509DataNode->appendChild($x509IssuerNode);
+
+ $x509Node = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509IssuerName', $issuerName);
+ $x509IssuerNode->appendChild($x509Node);
+ $x509Node = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509SerialNumber', $certData['serialNumber']);
+ $x509IssuerNode->appendChild($x509Node);
+ }
+ }
+
+ }
+ $x509CertNode = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509Certificate', $X509Cert);
+ $x509DataNode->appendChild($x509CertNode);
+ }
+ }
+
+ public function add509Cert($cert, $isPEMFormat=true, $isURL=false, $options=null) {
+ if ($xpath = $this->getXPathObj()) {
+ self::staticAdd509Cert($this->sigNode, $cert, $isPEMFormat, $isURL, $xpath, $options);
+ }
+ }
+
+ /**
+ * This function appends a node to the KeyInfo.
+ *
+ * The KeyInfo element will be created if one does not exist in the document.
+ *
+ * @param DOMNode $node The node to append to the KeyInfo.
+ *
+ * @return DOMNode The KeyInfo element node
+ */
+ public function appendToKeyInfo($node) {
+ $parentRef = $this->sigNode;
+
+ $xpath = $this->getXPathObj();
+
+ list($parentRef, $keyInfo) = self::auxKeyInfo($parentRef, $xpath);
+
+ $keyInfo->appendChild($node);
+
+ return $keyInfo;
+ }
+
+ static function auxKeyInfo($parentRef, $xpath=null)
+ {
+ $baseDoc = $parentRef->ownerDocument;
+ if (empty($xpath)) {
+ $xpath = new DOMXPath($parentRef->ownerDocument);
+ $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+ }
+
+ $query = "./secdsig:KeyInfo";
+ $nodeset = $xpath->query($query, $parentRef);
+ $keyInfo = $nodeset->item(0);
+ if (! $keyInfo) {
+ $inserted = false;
+ $keyInfo = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:KeyInfo');
+
+ $query = "./secdsig:Object";
+ $nodeset = $xpath->query($query, $parentRef);
+ if ($sObject = $nodeset->item(0)) {
+ $sObject->parentNode->insertBefore($keyInfo, $sObject);
+ $inserted = true;
+ }
+
+ if (! $inserted) {
+ $parentRef->appendChild($keyInfo);
+ }
+ }
+ return array($parentRef, $keyInfo);
+ }
+
+ /* This function retrieves an associative array of the validated nodes.
+ *
+ * The array will contain the id of the referenced node as the key and the node itself
+ * as the value.
+ *
+ * Returns:
+ * An associative array of validated nodes or null if no nodes have been validated.
+ */
+ public function getValidatedNodes() {
+ return $this->validatedNodes;
+ }
+}
+
+
+class XMLSecEnc {
+ const template = "<xenc:EncryptedData xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'>
+ <xenc:CipherData>
+ <xenc:CipherValue></xenc:CipherValue>
+ </xenc:CipherData>
+</xenc:EncryptedData>";
+
+ const Element = 'http://www.w3.org/2001/04/xmlenc#Element';
+ const Content = 'http://www.w3.org/2001/04/xmlenc#Content';
+ const URI = 3;
+ const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#';
+
+ private $encdoc = null;
+ private $rawNode = null;
+ public $type = null;
+ public $encKey = null;
+ private $references = array();
+
+ public function __construct() {
+ $this->_resetTemplate();
+ }
+
+ private function _resetTemplate(){
+ $this->encdoc = new DOMDocument();
+ $this->encdoc->loadXML(XMLSecEnc::template);
+ }
+
+ public function addReference($name, $node, $type) {
+ if (! $node instanceOf DOMNode) {
+ throw new Exception('$node is not of type DOMNode');
+ }
+ $curencdoc = $this->encdoc;
+ $this->_resetTemplate();
+ $encdoc = $this->encdoc;
+ $this->encdoc = $curencdoc;
+ $refuri = XMLSecurityDSig::generateGUID();
+ $element = $encdoc->documentElement;
+ $element->setAttribute("Id", $refuri);
+ $this->references[$name] = array("node" => $node, "type" => $type, "encnode" => $encdoc, "refuri" => $refuri);
+ }
+
+ public function setNode($node) {
+ $this->rawNode = $node;
+ }
+
+ /**
+ * Encrypt the selected node with the given key.
+ *
+ * @param XMLSecurityKey $objKey The encryption key and algorithm.
+ * @param bool $replace Whether the encrypted node should be replaced in the original tree. Default is true.
+ * @return DOMElement The <xenc:EncryptedData>-element.
+ */
+ public function encryptNode($objKey, $replace=true) {
+ $data = '';
+ if (empty($this->rawNode)) {
+ throw new Exception('Node to encrypt has not been set');
+ }
+ if (! $objKey instanceof XMLSecurityKey) {
+ throw new Exception('Invalid Key');
+ }
+ $doc = $this->rawNode->ownerDocument;
+ $xPath = new DOMXPath($this->encdoc);
+ $objList = $xPath->query('/xenc:EncryptedData/xenc:CipherData/xenc:CipherValue');
+ $cipherValue = $objList->item(0);
+ if ($cipherValue == null) {
+ throw new Exception('Error locating CipherValue element within template');
+ }
+ switch ($this->type) {
+ case (XMLSecEnc::Element):
+ $data = $doc->saveXML($this->rawNode);
+ $this->encdoc->documentElement->setAttribute('Type', XMLSecEnc::Element);
+ break;
+ case (XMLSecEnc::Content):
+ $children = $this->rawNode->childNodes;
+ foreach ($children AS $child) {
+ $data .= $doc->saveXML($child);
+ }
+ $this->encdoc->documentElement->setAttribute('Type', XMLSecEnc::Content);
+ break;
+ default:
+ throw new Exception('Type is currently not supported');
+ }
+
+ $encMethod = $this->encdoc->documentElement->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptionMethod'));
+ $encMethod->setAttribute('Algorithm', $objKey->getAlgorithm());
+ $cipherValue->parentNode->parentNode->insertBefore($encMethod, $cipherValue->parentNode->parentNode->firstChild);
+
+ $strEncrypt = base64_encode($objKey->encryptData($data));
+ $value = $this->encdoc->createTextNode($strEncrypt);
+ $cipherValue->appendChild($value);
+
+ if ($replace) {
+ switch ($this->type) {
+ case (XMLSecEnc::Element):
+ if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
+ return $this->encdoc;
+ }
+ $importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, true);
+ $this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode);
+ return $importEnc;
+ case (XMLSecEnc::Content):
+ $importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, true);
+ while($this->rawNode->firstChild) {
+ $this->rawNode->removeChild($this->rawNode->firstChild);
+ }
+ $this->rawNode->appendChild($importEnc);
+ return $importEnc;
+ }
+ } else {
+ return $this->encdoc->documentElement;
+ }
+ }
+
+ public function encryptReferences($objKey) {
+ $curRawNode = $this->rawNode;
+ $curType = $this->type;
+ foreach ($this->references AS $name=>$reference) {
+ $this->encdoc = $reference["encnode"];
+ $this->rawNode = $reference["node"];
+ $this->type = $reference["type"];
+ try {
+ $encNode = $this->encryptNode($objKey);
+ $this->references[$name]["encnode"] = $encNode;
+ } catch (Exception $e) {
+ $this->rawNode = $curRawNode;
+ $this->type = $curType;
+ throw $e;
+ }
+ }
+ $this->rawNode = $curRawNode;
+ $this->type = $curType;
+ }
+
+ /**
+ * Retrieve the CipherValue text from this encrypted node.
+ *
+ * @return string|null The Ciphervalue text, or null if no CipherValue is found.
+ */
+ public function getCipherValue() {
+ if (empty($this->rawNode)) {
+ throw new Exception('Node to decrypt has not been set');
+ }
+
+ $doc = $this->rawNode->ownerDocument;
+ $xPath = new DOMXPath($doc);
+ $xPath->registerNamespace('xmlencr', XMLSecEnc::XMLENCNS);
+ /* Only handles embedded content right now and not a reference */
+ $query = "./xmlencr:CipherData/xmlencr:CipherValue";
+ $nodeset = $xPath->query($query, $this->rawNode);
+ $node = $nodeset->item(0);
+
+ if (!$node) {
+ return null;
+ }
+
+ return base64_decode($node->nodeValue);
+ }
+
+ /**
+ * Decrypt this encrypted node.
+ *
+ * The behaviour of this function depends on the value of $replace.
+ * If $replace is false, we will return the decrypted data as a string.
+ * If $replace is true, we will insert the decrypted element(s) into the
+ * document, and return the decrypted element(s).
+ *
+ * @params XMLSecurityKey $objKey The decryption key that should be used when decrypting the node.
+ * @params boolean $replace Whether we should replace the encrypted node in the XML document with the decrypted data. The default is true.
+ * @return string|DOMElement The decrypted data.
+ */
+ public function decryptNode($objKey, $replace=true) {
+ if (! $objKey instanceof XMLSecurityKey) {
+ throw new Exception('Invalid Key');
+ }
+
+ $encryptedData = $this->getCipherValue();
+ if ($encryptedData) {
+ $decrypted = $objKey->decryptData($encryptedData);
+ if ($replace) {
+ switch ($this->type) {
+ case (XMLSecEnc::Element):
+ $newdoc = new DOMDocument();
+ $newdoc->loadXML($decrypted);
+ if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
+ return $newdoc;
+ }
+ $importEnc = $this->rawNode->ownerDocument->importNode($newdoc->documentElement, true);
+ $this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode);
+ return $importEnc;
+ case (XMLSecEnc::Content):
+ if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
+ $doc = $this->rawNode;
+ } else {
+ $doc = $this->rawNode->ownerDocument;
+ }
+ $newFrag = $doc->createDocumentFragment();
+ $newFrag->appendXML($decrypted);
+ $parent = $this->rawNode->parentNode;
+ $parent->replaceChild($newFrag, $this->rawNode);
+ return $parent;
+ default:
+ return $decrypted;
+ }
+ } else {
+ return $decrypted;
+ }
+ } else {
+ throw new Exception("Cannot locate encrypted data");
+ }
+ }
+
+ public function encryptKey($srcKey, $rawKey, $append=true) {
+ if ((! $srcKey instanceof XMLSecurityKey) || (! $rawKey instanceof XMLSecurityKey)) {
+ throw new Exception('Invalid Key');
+ }
+ $strEncKey = base64_encode($srcKey->encryptData($rawKey->key));
+ $root = $this->encdoc->documentElement;
+ $encKey = $this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptedKey');
+ if ($append) {
+ $keyInfo = $root->insertBefore($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'), $root->firstChild);
+ $keyInfo->appendChild($encKey);
+ } else {
+ $this->encKey = $encKey;
+ }
+ $encMethod = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptionMethod'));
+ $encMethod->setAttribute('Algorithm', $srcKey->getAlgorithm());
+ if (! empty($srcKey->name)) {
+ $keyInfo = $encKey->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'));
+ $keyInfo->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyName', $srcKey->name));
+ }
+ $cipherData = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:CipherData'));
+ $cipherData->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:CipherValue', $strEncKey));
+ if (is_array($this->references) && count($this->references) > 0) {
+ $refList = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:ReferenceList'));
+ foreach ($this->references AS $name=>$reference) {
+ $refuri = $reference["refuri"];
+ $dataRef = $refList->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:DataReference'));
+ $dataRef->setAttribute("URI", '#' . $refuri);
+ }
+ }
+ return;
+ }
+
+ public function decryptKey($encKey) {
+ if (! $encKey->isEncrypted) {
+ throw new Exception("Key is not Encrypted");
+ }
+ if (empty($encKey->key)) {
+ throw new Exception("Key is missing data to perform the decryption");
+ }
+ return $this->decryptNode($encKey, false);
+ }
+
+ public function locateEncryptedData($element) {
+ if ($element instanceof DOMDocument) {
+ $doc = $element;
+ } else {
+ $doc = $element->ownerDocument;
+ }
+ if ($doc) {
+ $xpath = new DOMXPath($doc);
+ $query = "//*[local-name()='EncryptedData' and namespace-uri()='".XMLSecEnc::XMLENCNS."']";
+ $nodeset = $xpath->query($query);
+ return $nodeset->item(0);
+ }
+ return null;
+ }
+
+ public function locateKey($node=null) {
+ if (empty($node)) {
+ $node = $this->rawNode;
+ }
+ if (! $node instanceof DOMNode) {
+ return null;
+ }
+ if ($doc = $node->ownerDocument) {
+ $xpath = new DOMXPath($doc);
+ $xpath->registerNamespace('xmlsecenc', XMLSecEnc::XMLENCNS);
+ $query = ".//xmlsecenc:EncryptionMethod";
+ $nodeset = $xpath->query($query, $node);
+ if ($encmeth = $nodeset->item(0)) {
+ $attrAlgorithm = $encmeth->getAttribute("Algorithm");
+ try {
+ $objKey = new XMLSecurityKey($attrAlgorithm, array('type'=>'private'));
+ } catch (Exception $e) {
+ return null;
+ }
+ return $objKey;
+ }
+ }
+ return null;
+ }
+
+ static function staticLocateKeyInfo($objBaseKey=null, $node=null) {
+ if (empty($node) || (! $node instanceof DOMNode)) {
+ return null;
+ }
+ $doc = $node->ownerDocument;
+ if (!$doc) {
+ return null;
+ }
+
+ $xpath = new DOMXPath($doc);
+ $xpath->registerNamespace('xmlsecenc', XMLSecEnc::XMLENCNS);
+ $xpath->registerNamespace('xmlsecdsig', XMLSecurityDSig::XMLDSIGNS);
+ $query = "./xmlsecdsig:KeyInfo";
+ $nodeset = $xpath->query($query, $node);
+ $encmeth = $nodeset->item(0);
+ if (!$encmeth) {
+ /* No KeyInfo in EncryptedData / EncryptedKey. */
+ return $objBaseKey;
+ }
+
+ foreach ($encmeth->childNodes AS $child) {
+ switch ($child->localName) {
+ case 'KeyName':
+ if (! empty($objBaseKey)) {
+ $objBaseKey->name = $child->nodeValue;
+ }
+ break;
+ case 'KeyValue':
+ foreach ($child->childNodes AS $keyval) {
+ switch ($keyval->localName) {
+ case 'DSAKeyValue':
+ throw new Exception("DSAKeyValue currently not supported");
+ case 'RSAKeyValue':
+ $modulus = null;
+ $exponent = null;
+ if ($modulusNode = $keyval->getElementsByTagName('Modulus')->item(0)) {
+ $modulus = base64_decode($modulusNode->nodeValue);
+ }
+ if ($exponentNode = $keyval->getElementsByTagName('Exponent')->item(0)) {
+ $exponent = base64_decode($exponentNode->nodeValue);
+ }
+ if (empty($modulus) || empty($exponent)) {
+ throw new Exception("Missing Modulus or Exponent");
+ }
+ $publicKey = XMLSecurityKey::convertRSA($modulus, $exponent);
+ $objBaseKey->loadKey($publicKey);
+ break;
+ }
+ }
+ break;
+ case 'RetrievalMethod':
+ $type = $child->getAttribute('Type');
+ if ($type !== 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') {
+ /* Unsupported key type. */
+ break;
+ }
+ $uri = $child->getAttribute('URI');
+ if ($uri[0] !== '#') {
+ /* URI not a reference - unsupported. */
+ break;
+ }
+ $id = substr($uri, 1);
+
+ $query = "//xmlsecenc:EncryptedKey[@Id='$id']";
+ $keyElement = $xpath->query($query)->item(0);
+ if (!$keyElement) {
+ throw new Exception("Unable to locate EncryptedKey with @Id='$id'.");
+ }
+
+ return XMLSecurityKey::fromEncryptedKeyElement($keyElement);
+ case 'EncryptedKey':
+ return XMLSecurityKey::fromEncryptedKeyElement($child);
+ case 'X509Data':
+ if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) {
+ if ($x509certNodes->length > 0) {
+ $x509cert = $x509certNodes->item(0)->textContent;
+ $x509cert = str_replace(array("\r", "\n", " "), "", $x509cert);
+ $x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n";
+ $objBaseKey->loadKey($x509cert, false, true);
+ }
+ }
+ break;
+ }
+ }
+ return $objBaseKey;
+ }
+
+ public function locateKeyInfo($objBaseKey=null, $node=null) {
+ if (empty($node)) {
+ $node = $this->rawNode;
+ }
+ return XMLSecEnc::staticLocateKeyInfo($objBaseKey, $node);
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml/AuthRequest.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml/AuthRequest.php
new file mode 100644
index 00000000..4f08f5ff
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml/AuthRequest.php
@@ -0,0 +1,65 @@
+<?php
+
+class OneLogin_Saml_AuthRequest
+{
+
+ /**
+ * @var OneLogin_Saml2_Auth object
+ */
+ protected $auth;
+
+ /**
+ * Constructs the OneLogin_Saml2_Auth, initializing
+ * the SP SAML instance.
+ *
+ * @param array|object $settings SAML Toolkit Settings
+ */
+ public function __construct($settings)
+ {
+ $this->auth = new OneLogin_Saml2_Auth($settings);
+ }
+
+ /**
+ * Obtains the SSO URL containing the AuthRequest
+ * message deflated.
+ *
+ * @param string|null $returnTo
+ *
+ * @return string
+ *
+ * @throws OneLogin_Saml2_Error
+ */
+ public function getRedirectUrl($returnTo = null)
+ {
+ $settings = $this->auth->getSettings();
+ $authnRequest = new OneLogin_Saml2_AuthnRequest($settings);
+ $parameters = array('SAMLRequest' => $authnRequest->getRequest());
+ if (!empty($returnTo)) {
+ $parameters['RelayState'] = $returnTo;
+ } else {
+ $parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
+ }
+ $url = OneLogin_Saml2_Utils::redirect($this->auth->getSSOurl(), $parameters, true);
+ return $url;
+ }
+
+ /**
+ * @return string
+ */
+ protected function _generateUniqueID()
+ {
+ return OneLogin_Saml2_Utils::generateUniqueID();
+ }
+
+ /**
+ * @return string
+ */
+ protected function _getTimestamp()
+ {
+ $defaultTimezone = date_default_timezone_get();
+ date_default_timezone_set('UTC');
+ $timestamp = strftime("%Y-%m-%dT%H:%M:%SZ");
+ date_default_timezone_set($defaultTimezone);
+ return $timestamp;
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml/Metadata.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml/Metadata.php
new file mode 100644
index 00000000..1073a90c
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml/Metadata.php
@@ -0,0 +1,39 @@
+<?php
+
+class OneLogin_Saml_Metadata
+{
+ const VALIDITY_SECONDS = 604800; // 1 week
+
+ protected $_settings;
+
+ /**
+ * @param array|object|null $settings Setting data
+ */
+ public function __construct($settings = null)
+ {
+ $auth = new OneLogin_Saml2_Auth($settings);
+ $this->_settings = $auth->getSettings();
+ }
+
+ /**
+ * @return string
+ *
+ * @throws OneLogin_Saml2_Error
+ */
+ public function getXml()
+ {
+ return $this->_settings->getSPMetadata();
+ }
+
+ /**
+ * @return string
+ */
+ protected function _getMetadataValidTimestamp()
+ {
+ $timeZone = date_default_timezone_get();
+ date_default_timezone_set('UTC');
+ $time = strftime("%Y-%m-%dT%H:%M:%SZ", time() + self::VALIDITY_SECONDS);
+ date_default_timezone_set($timeZone);
+ return $time;
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml/Response.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml/Response.php
new file mode 100644
index 00000000..d9332a71
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml/Response.php
@@ -0,0 +1,39 @@
+<?php
+
+class OneLogin_Saml_Response extends OneLogin_Saml2_Response
+{
+ /**
+ * Constructor that process the SAML Response,
+ * Internally initializes an SP SAML instance
+ * and an OneLogin_Saml2_Response.
+ *
+ * @param array|object $oldSettings Settings
+ * @param string $assertion SAML Response
+ */
+ public function __construct($oldSettings, $assertion)
+ {
+ $auth = new OneLogin_Saml2_Auth($oldSettings);
+ $settings = $auth->getSettings();
+ parent::__construct($settings, $assertion);
+ }
+
+ /**
+ * Retrieves an Array with the logged user data.
+ *
+ * @return array
+ */
+ public function get_saml_attributes()
+ {
+ return $this->getAttributes();
+ }
+
+ /**
+ * Retrieves the nameId
+ *
+ * @return string
+ */
+ public function get_nameid()
+ {
+ return $this->getNameId();
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml/Settings.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml/Settings.php
new file mode 100644
index 00000000..e9dbedc8
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml/Settings.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * Holds SAML settings for the SamlResponse and SamlAuthRequest classes.
+ *
+ * These settings need to be filled in by the user prior to being used.
+ */
+class OneLogin_Saml_Settings
+{
+ const NAMEID_EMAIL_ADDRESS = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress';
+ const NAMEID_X509_SUBJECT_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName';
+ const NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName';
+ const NAMEID_KERBEROS = 'urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos';
+ const NAMEID_ENTITY = 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity';
+ const NAMEID_TRANSIENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
+ const NAMEID_PERSISTENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent';
+
+ /**
+ * The URL to submit SAML authentication requests to.
+ * @var string
+ */
+ public $idpSingleSignOnUrl = '';
+
+ /**
+ * The URL to submit SAML Logout Request to.
+ * @var string
+ */
+ public $idpSingleLogOutUrl = '';
+
+ /**
+ * The x509 certificate used to authenticate the request.
+ * @var string
+ */
+ public $idpPublicCertificate = '';
+
+ /**
+ * The URL where to the SAML Response/SAML Assertion will be posted.
+ * @var string
+ */
+ public $spReturnUrl = '';
+
+ /**
+ * The name of the application.
+ * @var string
+ */
+ public $spIssuer = 'php-saml';
+
+ /**
+ * Specifies what format to return the authentication token, i.e, the email address.
+ * @var string
+ */
+ public $requestedNameIdFormat = self::NAMEID_EMAIL_ADDRESS;
+
+ /**
+ * @return array<string,array> Values (compatibility with the new version)
+ */
+ public function getValues()
+ {
+ $values = array();
+
+ $values['sp'] = array();
+ $values['sp']['entityId'] = $this->spIssuer;
+ $values['sp']['assertionConsumerService'] = array(
+ 'url' => $this->spReturnUrl,
+ );
+ $values['sp']['NameIDFormat'] = $this->requestedNameIdFormat;
+
+ $values['idp'] = array();
+ $values['idp']['entityId'] = $this->idpSingleSignOnUrl;
+ $values['idp']['singleSignOnService'] = array(
+ 'url' => $this->idpSingleSignOnUrl,
+ );
+ $values['idp']['singleLogoutService'] = array(
+ 'url' => $this->idpSingleLogOutUrl,
+ );
+ $values['idp']['x509cert'] = $this->idpPublicCertificate;
+
+ return $values;
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml/XmlSec.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml/XmlSec.php
new file mode 100644
index 00000000..919a62ef
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml/XmlSec.php
@@ -0,0 +1,110 @@
+<?php
+
+/**
+ * Determine if the SAML response is valid using a provided x509 certificate.
+ */
+class OneLogin_Saml_XmlSec
+{
+ /**
+ * A SamlResponse class provided to the constructor.
+ * @var OneLogin_Saml_Settings
+ */
+ protected $_settings;
+
+ /**
+ * The document to be tested.
+ * @var DomDocument
+ */
+ protected $_document;
+
+ /**
+ * Construct the SamlXmlSec object.
+ *
+ * @param OneLogin_Saml_Settings $settings A SamlResponse settings object containing the necessary
+ * x509 certicate to test the document.
+ * @param OneLogin_Saml_Response $response The document to test.
+ */
+ public function __construct(OneLogin_Saml_Settings $settings, OneLogin_Saml_Response $response)
+ {
+ $this->_settings = $settings;
+ $this->_document = clone $response->document;
+ }
+
+ /**
+ * Verify that the document only contains a single Assertion
+ *
+ * @return bool TRUE if the document passes.
+ */
+ public function validateNumAssertions()
+ {
+ $rootNode = $this->_document;
+ $assertionNodes = $rootNode->getElementsByTagName('Assertion');
+ return ($assertionNodes->length == 1);
+ }
+
+ /**
+ * Verify that the document is still valid according
+ *
+ * @return bool
+ */
+ public function validateTimestamps()
+ {
+ $rootNode = $this->_document;
+ $timestampNodes = $rootNode->getElementsByTagName('Conditions');
+ for ($i = 0; $i < $timestampNodes->length; $i++) {
+ $nbAttribute = $timestampNodes->item($i)->attributes->getNamedItem("NotBefore");
+ $naAttribute = $timestampNodes->item($i)->attributes->getNamedItem("NotOnOrAfter");
+ if ($nbAttribute && strtotime($nbAttribute->textContent) > time()) {
+ return false;
+ }
+ if ($naAttribute && strtotime($naAttribute->textContent) <= time()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return bool
+ *
+ * @throws Exception
+ */
+ public function isValid()
+ {
+ $singleAssertion = $this->validateNumAssertions();
+ if (!$singleAssertion) {
+ throw new Exception('Multiple assertions are not supported');
+ }
+
+ $validTimestamps = $this->validateTimestamps();
+ if (!$validTimestamps) {
+ throw new Exception('Timing issues (please check your clock settings)');
+ }
+
+ $objXMLSecDSig = new XMLSecurityDSig();
+
+ $objDSig = $objXMLSecDSig->locateSignature($this->_document);
+ if (!$objDSig) {
+ throw new Exception('Cannot locate Signature Node');
+ }
+ $objXMLSecDSig->canonicalizeSignedInfo();
+ $objXMLSecDSig->idKeys = array('ID');
+
+ $objKey = $objXMLSecDSig->locateKey();
+ if (!$objKey) {
+ throw new Exception('We have no idea about the key');
+ }
+
+ try {
+ $objXMLSecDSig->validateReference();
+ } catch (Exception $e) {
+ throw new Exception('Reference Validation Failed');
+ }
+
+ XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);
+
+ $objKey->loadKey($this->_settings->idpPublicCertificate, false, true);
+
+ return ($objXMLSecDSig->verify($objKey) === 1);
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Auth.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Auth.php
new file mode 100644
index 00000000..6ac1696c
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Auth.php
@@ -0,0 +1,514 @@
+<?php
+
+/**
+ * Main class of OneLogin's PHP Toolkit
+ *
+ */
+class OneLogin_Saml2_Auth
+{
+
+ /**
+ * Settings data.
+ *
+ * @var OneLogin_Saml2_Settings
+ */
+ private $_settings;
+
+ /**
+ * User attributes data.
+ *
+ * @var array
+ */
+ private $_attributes = array();
+
+ /**
+ * NameID
+ *
+ * @var string
+ */
+ private $_nameid;
+
+ /**
+ * If user is authenticated.
+ *
+ * @var bool
+ */
+ private $_authenticated = false;
+
+
+ /**
+ * SessionIndex. When the user is logged, this stored it
+ * from the AuthnStatement of the SAML Response
+ *
+ * @var string
+ */
+ private $_sessionIndex;
+
+ /**
+ * SessionNotOnOrAfter. When the user is logged, this stored it
+ * from the AuthnStatement of the SAML Response
+ *
+ * @var DateTime
+ */
+ private $_sessionExpiration;
+
+ /**
+ * If any error.
+ *
+ * @var array
+ */
+ private $_errors = array();
+
+ /**
+ * Reason of the last error.
+ *
+ * @var string
+ */
+ private $_errorReason;
+
+ /**
+ * Last AuthNRequest ID or LogoutRequest ID generated by this Service Provider
+ *
+ * @var string
+ */
+ private $_lastRequestID;
+
+ /**
+ * Initializes the SP SAML instance.
+ *
+ * @param array|object|null $oldSettings Setting data (You can provide a OneLogin_Saml_Settings, the settings object of the Saml folder implementation)
+ */
+ public function __construct($oldSettings = null)
+ {
+ $this->_settings = new OneLogin_Saml2_Settings($oldSettings);
+ }
+
+ /**
+ * Returns the settings info
+ *
+ * @return OneLogin_Saml2_Settings The settings data.
+ */
+ public function getSettings()
+ {
+ return $this->_settings;
+ }
+
+ /**
+ * Set the strict mode active/disable
+ *
+ * @param bool $value Strict parameter
+ *
+ * @return array The settings data.
+ */
+ public function setStrict($value)
+ {
+ assert('is_bool($value)');
+ $this->_settings->setStrict($value);
+ }
+
+ /**
+ * Process the SAML Response sent by the IdP.
+ *
+ * @param string|null $requestId The ID of the AuthNRequest sent by this SP to the IdP
+ *
+ * @throws OneLogin_Saml2_Error
+ */
+ public function processResponse($requestId = null)
+ {
+ $this->_errors = array();
+ if (isset($_POST) && isset($_POST['SAMLResponse'])) {
+ // AuthnResponse -- HTTP_POST Binding
+ $response = new OneLogin_Saml2_Response($this->_settings, $_POST['SAMLResponse']);
+
+ if ($response->isValid($requestId)) {
+ $this->_attributes = $response->getAttributes();
+ $this->_nameid = $response->getNameId();
+ $this->_authenticated = true;
+ $this->_sessionIndex = $response->getSessionIndex();
+ $this->_sessionExpiration = $response->getSessionNotOnOrAfter();
+ } else {
+ $this->_errors[] = 'invalid_response';
+ $this->_errorReason = $response->getError();
+ }
+ } else {
+ $this->_errors[] = 'invalid_binding';
+ throw new OneLogin_Saml2_Error(
+ 'SAML Response not found, Only supported HTTP_POST Binding',
+ OneLogin_Saml2_Error::SAML_RESPONSE_NOT_FOUND
+ );
+ }
+ }
+
+ /**
+ * Process the SAML Logout Response / Logout Request sent by the IdP.
+ *
+ * @param bool $keepLocalSession When false will destroy the local session, otherwise will keep it
+ * @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP
+ * @param bool $retrieveParametersFromServer
+ * @param callable $cbDeleteSession
+ * @param bool $stay True if we want to stay (returns the url string) False to redirect
+ *
+ * @return string|void
+ *
+ * @throws OneLogin_Saml2_Error
+ */
+ public function processSLO($keepLocalSession = false, $requestId = null, $retrieveParametersFromServer = false, $cbDeleteSession = null, $stay=false)
+ {
+ $this->_errors = array();
+ if (isset($_GET) && isset($_GET['SAMLResponse'])) {
+ $logoutResponse = new OneLogin_Saml2_LogoutResponse($this->_settings, $_GET['SAMLResponse']);
+ if (!$logoutResponse->isValid($requestId, $retrieveParametersFromServer)) {
+ $this->_errors[] = 'invalid_logout_response';
+ $this->_errorReason = $logoutResponse->getError();
+ } else if ($logoutResponse->getStatus() !== OneLogin_Saml2_Constants::STATUS_SUCCESS) {
+ $this->_errors[] = 'logout_not_success';
+ } else {
+ if (!$keepLocalSession) {
+ if ($cbDeleteSession === null) {
+ OneLogin_Saml2_Utils::deleteLocalSession();
+ } else {
+ call_user_func($cbDeleteSession);
+ }
+ }
+ }
+ } else if (isset($_GET) && isset($_GET['SAMLRequest'])) {
+ $logoutRequest = new OneLogin_Saml2_LogoutRequest($this->_settings, $_GET['SAMLRequest']);
+ if (!$logoutRequest->isValid($retrieveParametersFromServer)) {
+ $this->_errors[] = 'invalid_logout_request';
+ $this->_errorReason = $logoutRequest->getError();
+ } else {
+ if (!$keepLocalSession) {
+ if ($cbDeleteSession === null) {
+ OneLogin_Saml2_Utils::deleteLocalSession();
+ } else {
+ call_user_func($cbDeleteSession);
+ }
+ }
+ $inResponseTo = $logoutRequest->id;
+ $responseBuilder = new OneLogin_Saml2_LogoutResponse($this->_settings);
+ $responseBuilder->build($inResponseTo);
+ $logoutResponse = $responseBuilder->getResponse();
+
+ $parameters = array('SAMLResponse' => $logoutResponse);
+ if (isset($_GET['RelayState'])) {
+ $parameters['RelayState'] = $_GET['RelayState'];
+ }
+
+ $security = $this->_settings->getSecurityData();
+ if (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned']) {
+ $signature = $this->buildResponseSignature($logoutResponse, $parameters['RelayState'], $security['signatureAlgorithm']);
+ $parameters['SigAlg'] = $security['signatureAlgorithm'];
+ $parameters['Signature'] = $signature;
+ }
+
+ return $this->redirectTo($this->getSLOurl(), $parameters, $stay);
+ }
+ } else {
+ $this->_errors[] = 'invalid_binding';
+ throw new OneLogin_Saml2_Error(
+ 'SAML LogoutRequest/LogoutResponse not found. Only supported HTTP_REDIRECT Binding',
+ OneLogin_Saml2_Error::SAML_LOGOUTMESSAGE_NOT_FOUND
+ );
+ }
+ }
+
+ /**
+ * Redirects the user to the url past by parameter
+ * or to the url that we defined in our SSO Request.
+ *
+ * @param string $url The target URL to redirect the user.
+ * @param array $parameters Extra parameters to be passed as part of the url
+ * @param bool $stay True if we want to stay (returns the url string) False to redirect
+ */
+ public function redirectTo($url = '', $parameters = array(), $stay = false)
+ {
+ assert('is_string($url)');
+ assert('is_array($parameters)');
+
+ if (empty($url) && isset($_REQUEST['RelayState'])) {
+ $url = $_REQUEST['RelayState'];
+ }
+
+ return OneLogin_Saml2_Utils::redirect($url, $parameters, $stay);
+ }
+
+ /**
+ * Checks if the user is authenticated or not.
+ *
+ * @return bool True if the user is authenticated
+ */
+ public function isAuthenticated()
+ {
+ return $this->_authenticated;
+ }
+
+ /**
+ * Returns the set of SAML attributes.
+ *
+ * @return array Attributes of the user.
+ */
+ public function getAttributes()
+ {
+ return $this->_attributes;
+ }
+
+ /**
+ * Returns the nameID
+ *
+ * @return string The nameID of the assertion
+ */
+ public function getNameId()
+ {
+ return $this->_nameid;
+ }
+
+ /**
+ * Returns the SessionIndex
+ *
+ * @return string|null The SessionIndex of the assertion
+ */
+ public function getSessionIndex()
+ {
+ return $this->_sessionIndex;
+ }
+
+ /**
+ * Returns the SessionNotOnOrAfter
+ *
+ * @return DateTime|null The SessionNotOnOrAfter of the assertion
+ */
+ public function getSessionExpiration()
+ {
+ return $this->_sessionExpiration;
+ }
+
+ /**
+ * Returns if there were any error
+ *
+ * @return array Errors
+ */
+ public function getErrors()
+ {
+ return $this->_errors;
+ }
+
+ /**
+ * Returns the reason for the last error
+ *
+ * @return string Error reason
+ */
+ public function getLastErrorReason()
+ {
+ return $this->_errorReason;
+ }
+
+ /**
+ * Returns the requested SAML attribute
+ *
+ * @param string $name The requested attribute of the user.
+ *
+ * @return array|null Requested SAML attribute ($name).
+ */
+ public function getAttribute($name)
+ {
+ assert('is_string($name)');
+
+ $value = null;
+ if (isset($this->_attributes[$name])) {
+ return $this->_attributes[$name];
+ }
+ return $value;
+ }
+
+ /**
+ * Initiates the SSO process.
+ *
+ * @param string|null $returnTo The target URL the user should be returned to after login.
+ * @param array $parameters Extra parameters to be added to the GET
+ * @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 $stay True if we want to stay (returns the url string) False to redirect
+ * @param bool $setNameIdPolicy When true the AuthNReuqest will set a nameIdPolicy element
+ *
+ * @return If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters
+ */
+ public function login($returnTo = null, $parameters = array(), $forceAuthn = false, $isPassive = false, $stay=false, $setNameIdPolicy = true)
+ {
+ assert('is_array($parameters)');
+
+ $authnRequest = new OneLogin_Saml2_AuthnRequest($this->_settings, $forceAuthn, $isPassive, $setNameIdPolicy);
+
+ $this->_lastRequestID = $authnRequest->getId();
+
+ $samlRequest = $authnRequest->getRequest();
+ $parameters['SAMLRequest'] = $samlRequest;
+
+ if (!empty($returnTo)) {
+ $parameters['RelayState'] = $returnTo;
+ } else {
+ $parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
+ }
+
+ $security = $this->_settings->getSecurityData();
+ if (isset($security['authnRequestsSigned']) && $security['authnRequestsSigned']) {
+ $signature = $this->buildRequestSignature($samlRequest, $parameters['RelayState'], $security['signatureAlgorithm']);
+ $parameters['SigAlg'] = $security['signatureAlgorithm'];
+ $parameters['Signature'] = $signature;
+ }
+ return $this->redirectTo($this->getSSOurl(), $parameters, $stay);
+ }
+
+ /**
+ * Initiates the SLO process.
+ *
+ * @param string|null $returnTo The target URL the user should be returned to after logout.
+ * @param array $parameters Extra parameters to be added to the GET
+ * @param string|null $nameId The NameID that will be set in the LogoutRequest.
+ * @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
+ * @param bool $stay True if we want to stay (returns the url string) False to redirect
+ *
+ * @return If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters
+ *
+ * @throws OneLogin_Saml2_Error
+ */
+ public function logout($returnTo = null, $parameters = array(), $nameId = null, $sessionIndex = null, $stay=false)
+ {
+ assert('is_array($parameters)');
+
+ $sloUrl = $this->getSLOurl();
+ if (empty($sloUrl)) {
+ throw new OneLogin_Saml2_Error(
+ 'The IdP does not support Single Log Out',
+ OneLogin_Saml2_Error::SAML_SINGLE_LOGOUT_NOT_SUPPORTED
+ );
+ }
+
+ if (empty($nameId) && !empty($this->_nameid)) {
+ $nameId = $this->_nameid;
+ }
+
+ $logoutRequest = new OneLogin_Saml2_LogoutRequest($this->_settings, null, $nameId, $sessionIndex);
+
+ $this->_lastRequestID = $logoutRequest->id;
+
+ $samlRequest = $logoutRequest->getRequest();
+
+ $parameters['SAMLRequest'] = $samlRequest;
+ if (!empty($returnTo)) {
+ $parameters['RelayState'] = $returnTo;
+ } else {
+ $parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
+ }
+
+ $security = $this->_settings->getSecurityData();
+ if (isset($security['logoutRequestSigned']) && $security['logoutRequestSigned']) {
+ $signature = $this->buildRequestSignature($samlRequest, $parameters['RelayState'], $security['signatureAlgorithm']);
+ $parameters['SigAlg'] = $security['signatureAlgorithm'];
+ $parameters['Signature'] = $signature;
+ }
+
+ return $this->redirectTo($sloUrl, $parameters, $stay);
+ }
+
+ /**
+ * Gets the SSO url.
+ *
+ * @return string The url of the Single Sign On Service
+ */
+ public function getSSOurl()
+ {
+ $idpData = $this->_settings->getIdPData();
+ return $idpData['singleSignOnService']['url'];
+ }
+
+ /**
+ * Gets the SLO url.
+ *
+ * @return string The url of the Single Logout Service
+ */
+ public function getSLOurl()
+ {
+ $url = null;
+ $idpData = $this->_settings->getIdPData();
+ if (isset($idpData['singleLogoutService']) && isset($idpData['singleLogoutService']['url'])) {
+ $url = $idpData['singleLogoutService']['url'];
+ }
+ return $url;
+ }
+
+ /**
+ * Gets the ID of the last AuthNRequest or LogoutRequest generated by the Service Provider.
+ *
+ * @return string The ID of the Request SAML message.
+ */
+ public function getLastRequestID()
+ {
+ return $this->_lastRequestID;
+ }
+
+ /**
+ * Generates the Signature for a SAML Request
+ *
+ * @param string $samlRequest The SAML Request
+ * @param string $relayState The RelayState
+ * @param string $signAlgorithm Signature algorithm method
+ *
+ * @return string A base64 encoded signature
+ *
+ * @throws Exception
+ * @throws OneLogin_Saml2_Error
+ */
+ public function buildRequestSignature($samlRequest, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA1)
+ {
+ if (!$this->_settings->checkSPCerts()) {
+ throw new OneLogin_Saml2_Error(
+ "Trying to sign the SAML Request but can't load the SP certs",
+ OneLogin_Saml2_Error::SP_CERTS_NOT_FOUND
+ );
+ }
+
+ $key = $this->_settings->getSPkey();
+
+ $objKey = new XMLSecurityKey($signAlgorithm, array('type' => 'private'));
+ $objKey->loadKey($key, false);
+
+ $msg = 'SAMLRequest='.urlencode($samlRequest);
+ $msg .= '&RelayState='.urlencode($relayState);
+ $msg .= '&SigAlg=' . urlencode($signAlgorithm);
+ $signature = $objKey->signData($msg);
+ return base64_encode($signature);
+ }
+
+ /**
+ * Generates the Signature for a SAML Response
+ *
+ * @param string $samlResponse The SAML Response
+ * @param string $relayState The RelayState
+ * @param string $signAlgorithm Signature algorithm method
+ *
+ * @return string A base64 encoded signature
+ *
+ * @throws Exception
+ * @throws OneLogin_Saml2_Error
+ */
+ public function buildResponseSignature($samlResponse, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA1)
+ {
+ if (!$this->_settings->checkSPCerts()) {
+ throw new OneLogin_Saml2_Error(
+ "Trying to sign the SAML Response but can't load the SP certs",
+ OneLogin_Saml2_Error::SP_CERTS_NOT_FOUND
+ );
+ }
+
+ $key = $this->_settings->getSPkey();
+
+ $objKey = new XMLSecurityKey($signAlgorithm, array('type' => 'private'));
+ $objKey->loadKey($key, false);
+
+ $msg = 'SAMLResponse='.urlencode($samlResponse);
+ $msg .= '&RelayState='.urlencode($relayState);
+ $msg .= '&SigAlg=' . urlencode($signAlgorithm);
+ $signature = $objKey->signData($msg);
+ return base64_encode($signature);
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/AuthnRequest.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/AuthnRequest.php
new file mode 100644
index 00000000..7f31da30
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/AuthnRequest.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * SAML 2 Authentication Request
+ *
+ */
+class OneLogin_Saml2_AuthnRequest
+{
+
+ /**
+ * Object that represents the setting info
+ * @var OneLogin_Saml2_Settings
+ */
+ protected $_settings;
+
+ /**
+ * SAML AuthNRequest string
+ * @var string
+ */
+ private $_authnRequest;
+
+ /**
+ * SAML AuthNRequest ID.
+ * @var string
+ */
+ private $_id;
+
+ /**
+ * Constructs the AuthnRequest object.
+ *
+ * @param OneLogin_Saml2_Settings $settings 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
+ */
+ public function __construct(OneLogin_Saml2_Settings $settings, $forceAuthn = false, $isPassive = false, $setNameIdPolicy = true)
+ {
+ $this->_settings = $settings;
+
+ $spData = $this->_settings->getSPData();
+ $idpData = $this->_settings->getIdPData();
+ $security = $this->_settings->getSecurityData();
+
+ $id = OneLogin_Saml2_Utils::generateUniqueID();
+ $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time());
+
+ $nameIdPolicyStr = '';
+ if ($setNameIdPolicy) {
+ $nameIDPolicyFormat = $spData['NameIDFormat'];
+ if (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted']) {
+ $nameIDPolicyFormat = OneLogin_Saml2_Constants::NAMEID_ENCRYPTED;
+ }
+
+ $nameIdPolicyStr = <<<NAMEIDPOLICY
+ <samlp:NameIDPolicy
+ Format="{$nameIDPolicyFormat}"
+ AllowCreate="true" />
+NAMEIDPOLICY;
+ }
+
+
+ $providerNameStr = '';
+ $organizationData = $settings->getOrganization();
+ if (!empty($organizationData)) {
+ $langs = array_keys($organizationData);
+ if (in_array('en-US', $langs)) {
+ $lang = 'en-US';
+ } else {
+ $lang = $langs[0];
+ }
+ if (isset($organizationData[$lang]['displayname']) && !empty($organizationData[$lang]['displayname'])) {
+ $providerNameStr = <<<PROVIDERNAME
+ ProviderName="{$organizationData[$lang]['displayname']}"
+PROVIDERNAME;
+ }
+ }
+
+ $forceAuthnStr = '';
+ if ($forceAuthn) {
+ $forceAuthnStr = <<<FORCEAUTHN
+
+ ForceAuthn="true"
+FORCEAUTHN;
+ }
+
+ $isPassiveStr = '';
+ if ($isPassive) {
+ $isPassiveStr = <<<ISPASSIVE
+
+ IsPassive="true"
+ISPASSIVE;
+ }
+
+ $requestedAuthnStr = '';
+ if (isset($security['requestedAuthnContext']) && $security['requestedAuthnContext'] !== false) {
+
+ $authnComparison = 'exact';
+ if (isset($security['requestedAuthnContextComparison'])) {
+ $authnComparison = $security['requestedAuthnContextComparison'];
+ }
+
+ if ($security['requestedAuthnContext'] === true) {
+ $requestedAuthnStr = <<<REQUESTEDAUTHN
+ <samlp:RequestedAuthnContext Comparison="$authnComparison">
+ <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
+ </samlp:RequestedAuthnContext>
+REQUESTEDAUTHN;
+ } else {
+ $requestedAuthnStr .= " <samlp:RequestedAuthnContext Comparison=\"$authnComparison\">\n";
+ foreach ($security['requestedAuthnContext'] as $contextValue) {
+ $requestedAuthnStr .= " <saml:AuthnContextClassRef>".$contextValue."</saml:AuthnContextClassRef>\n";
+ }
+ $requestedAuthnStr .= ' </samlp:RequestedAuthnContext>';
+ }
+ }
+
+ $request = <<<AUTHNREQUEST
+<samlp:AuthnRequest
+ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ ID="$id"
+ Version="2.0"
+{$providerNameStr}{$forceAuthnStr}{$isPassiveStr}
+ IssueInstant="$issueInstant"
+ Destination="{$idpData['singleSignOnService']['url']}"
+ ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+ AssertionConsumerServiceURL="{$spData['assertionConsumerService']['url']}">
+ <saml:Issuer>{$spData['entityId']}</saml:Issuer>
+{$nameIdPolicyStr}
+{$requestedAuthnStr}
+</samlp:AuthnRequest>
+AUTHNREQUEST;
+
+ $this->_id = $id;
+ $this->_authnRequest = $request;
+ }
+
+ /**
+ * Returns deflated, base64 encoded, unsigned AuthnRequest.
+ *
+ */
+ public function getRequest()
+ {
+ $deflatedRequest = gzdeflate($this->_authnRequest);
+ $base64Request = base64_encode($deflatedRequest);
+ return $base64Request;
+ }
+
+ /**
+ * Returns the AuthNRequest ID.
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ return $this->_id;
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Constants.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Constants.php
new file mode 100644
index 00000000..dd702fa3
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Constants.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * Constants of OneLogin PHP Toolkit
+ *
+ * Defines all required constants
+ */
+class OneLogin_Saml2_Constants
+{
+ // Value added to the current time in time condition validations
+ const ALLOWED_CLOCK_DRIFT = 180; // 3 min in seconds
+
+ // NameID Formats
+ const NAMEID_EMAIL_ADDRESS = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress';
+ const NAMEID_X509_SUBJECT_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName';
+ const NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName';
+ const NAMEID_UNSPECIFIED = 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified';
+ const NAMEID_KERBEROS = 'urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos';
+ const NAMEID_ENTITY = 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity';
+ const NAMEID_TRANSIENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
+ const NAMEID_PERSISTENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent';
+ const NAMEID_ENCRYPTED = 'urn:oasis:names:tc:SAML:2.0:nameid-format:encrypted';
+
+ // Attribute Name Formats
+ const ATTRNAME_FORMAT_UNSPECIFIED = 'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified';
+ const ATTRNAME_FORMAT_URI = 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri';
+ const ATTRNAME_FORMAT_BASIC = 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic';
+
+ // Namespaces
+ const NS_SAML = 'urn:oasis:names:tc:SAML:2.0:assertion';
+ const NS_SAMLP = 'urn:oasis:names:tc:SAML:2.0:protocol';
+ const NS_SOAP = 'http://schemas.xmlsoap.org/soap/envelope/';
+ const NS_MD = 'urn:oasis:names:tc:SAML:2.0:metadata';
+ const NS_XS = 'http://www.w3.org/2001/XMLSchema';
+ const NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance';
+ const NS_XENC = 'http://www.w3.org/2001/04/xmlenc#';
+ const NS_DS = 'http://www.w3.org/2000/09/xmldsig#';
+
+ // Bindings
+ const BINDING_HTTP_POST = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST';
+ const BINDING_HTTP_REDIRECT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect';
+ const BINDING_HTTP_ARTIFACT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact';
+ const BINDING_SOAP = 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP';
+ const BINDING_DEFLATE = 'urn:oasis:names:tc:SAML:2.0:bindings:URL-Encoding:DEFLATE';
+
+ // Auth Context Class
+ const AC_UNSPECIFIED = 'urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified';
+ const AC_PASSWORD = 'urn:oasis:names:tc:SAML:2.0:ac:classes:Password';
+ const AC_PASSWORD_PROTECTED = 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport';
+ const AC_X509 = 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509';
+ const AC_SMARTCARD = 'urn:oasis:names:tc:SAML:2.0:ac:classes:Smartcard';
+ const AC_KERBEROS = 'urn:oasis:names:tc:SAML:2.0:ac:classes:Kerberos';
+ const AC_WINDOWS = 'urn:federation:authentication:windows';
+ const AC_TLS = 'urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient';
+
+ // Subject Confirmation
+ const CM_BEARER = 'urn:oasis:names:tc:SAML:2.0:cm:bearer';
+ const CM_HOLDER_KEY = 'urn:oasis:names:tc:SAML:2.0:cm:holder-of-key';
+ const CM_SENDER_VOUCHES = 'urn:oasis:names:tc:SAML:2.0:cm:sender-vouches';
+
+ // Status Codes
+ const STATUS_SUCCESS = 'urn:oasis:names:tc:SAML:2.0:status:Success';
+ const STATUS_REQUESTER = 'urn:oasis:names:tc:SAML:2.0:status:Requester';
+ const STATUS_RESPONDER = 'urn:oasis:names:tc:SAML:2.0:status:Responder';
+ const STATUS_VERSION_MISMATCH = 'urn:oasis:names:tc:SAML:2.0:status:VersionMismatch';
+ const STATUS_NO_PASSIVE = 'urn:oasis:names:tc:SAML:2.0:status:NoPassive';
+ const STATUS_PARTIAL_LOGOUT = 'urn:oasis:names:tc:SAML:2.0:status:PartialLogout';
+ const STATUS_PROXY_COUNT_EXCEEDED = 'urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded';
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Error.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Error.php
new file mode 100644
index 00000000..4db7dcb4
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Error.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * Error class of OneLogin PHP Toolkit
+ *
+ * Defines the Error class
+ */
+class OneLogin_Saml2_Error extends Exception
+{
+ // Errors
+ const SETTINGS_FILE_NOT_FOUND = 0;
+ const SETTINGS_INVALID_SYNTAX = 1;
+ const SETTINGS_INVALID = 2;
+ const METADATA_SP_INVALID = 3;
+ const SP_CERTS_NOT_FOUND = 4;
+ const REDIRECT_INVALID_URL = 5;
+ const PUBLIC_CERT_FILE_NOT_FOUND = 6;
+ const PRIVATE_KEY_FILE_NOT_FOUND = 7;
+ const SAML_RESPONSE_NOT_FOUND = 8;
+ const SAML_LOGOUTMESSAGE_NOT_FOUND = 9;
+ const SAML_LOGOUTREQUEST_INVALID = 10;
+ const SAML_LOGOUTRESPONSE_INVALID = 11;
+ const SAML_SINGLE_LOGOUT_NOT_SUPPORTED = 12;
+
+ /**
+ * Constructor
+ *
+ * @param string $msg Describes the error.
+ * @param int $code The code error (defined in the error class).
+ * @param array|null $args Arguments used in the message that describes the error.
+ */
+ public function __construct($msg, $code = 0, $args = null)
+ {
+ assert('is_string($msg)');
+ assert('is_int($code)');
+
+ $message = OneLogin_Saml2_Utils::t($msg, $args);
+
+ parent::__construct($message, $code);
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/LogoutRequest.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/LogoutRequest.php
new file mode 100644
index 00000000..2577ec2d
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/LogoutRequest.php
@@ -0,0 +1,384 @@
+<?php
+
+/**
+ * SAML 2 Logout Request
+ *
+ */
+class OneLogin_Saml2_LogoutRequest
+{
+
+ /**
+ * Contains the ID of the Logout Request
+ * @var string
+ */
+ public $id;
+
+ /**
+ * Object that represents the setting info
+ * @var OneLogin_Saml2_Settings
+ */
+ protected $_settings;
+
+ /**
+ * SAML Logout Request
+ * @var string
+ */
+ protected $_logoutRequest;
+
+ /**
+ * After execute a validation process, this var contains the cause
+ * @var string
+ */
+ private $_error;
+
+ /**
+ * Constructs the Logout Request object.
+ *
+ * @param OneLogin_Saml2_Settings $settings Settings
+ * @param string|null $request A UUEncoded Logout Request.
+ * @param string|null $nameId The NameID that will be set in the LogoutRequest.
+ * @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
+ */
+ public function __construct(OneLogin_Saml2_Settings $settings, $request = null, $nameId = null, $sessionIndex = null)
+ {
+
+ $this->_settings = $settings;
+
+ if (!isset($request) || empty($request)) {
+
+ $spData = $this->_settings->getSPData();
+ $idpData = $this->_settings->getIdPData();
+ $security = $this->_settings->getSecurityData();
+
+ $id = OneLogin_Saml2_Utils::generateUniqueID();
+ $this->id = $id;
+
+ $nameIdValue = OneLogin_Saml2_Utils::generateUniqueID();
+ $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time());
+
+ $cert = null;
+ if (isset($security['nameIdEncrypted']) && $security['nameIdEncrypted']) {
+ $cert = $idpData['x509cert'];
+ }
+
+ if (!empty($nameId)) {
+ $nameIdFormat = $spData['NameIDFormat'];
+ $spNameQualifier = null;
+ } else {
+ $nameId = $idpData['entityId'];
+ $nameIdFormat = OneLogin_Saml2_Constants::NAMEID_ENTITY;
+ $spNameQualifier = $spData['entityId'];
+ }
+
+ $nameIdObj = OneLogin_Saml2_Utils::generateNameId(
+ $nameId,
+ $spNameQualifier,
+ $nameIdFormat,
+ $cert
+ );
+
+ $sessionIndexStr = isset($sessionIndex) ? "<samlp:SessionIndex>{$sessionIndex}</samlp:SessionIndex>" : "";
+
+ $logoutRequest = <<<LOGOUTREQUEST
+<samlp:LogoutRequest
+ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ ID="{$id}"
+ Version="2.0"
+ IssueInstant="{$issueInstant}"
+ Destination="{$idpData['singleLogoutService']['url']}">
+ <saml:Issuer>{$spData['entityId']}</saml:Issuer>
+ {$nameIdObj}
+ {$sessionIndexStr}
+</samlp:LogoutRequest>
+LOGOUTREQUEST;
+ } else {
+ $decoded = base64_decode($request);
+ // We try to inflate
+ $inflated = @gzinflate($decoded);
+ if ($inflated != false) {
+ $logoutRequest = $inflated;
+ } else {
+ $logoutRequest = $decoded;
+ }
+ $this->id = self::getID($logoutRequest);
+ }
+ $this->_logoutRequest = $logoutRequest;
+ }
+
+
+ /**
+ * Returns the Logout Request defated, base64encoded, unsigned
+ *
+ * @return string Deflated base64 encoded Logout Request
+ */
+ public function getRequest()
+ {
+ $deflatedRequest = gzdeflate($this->_logoutRequest);
+ return base64_encode($deflatedRequest);
+ }
+
+ /**
+ * Returns the ID of the Logout Request.
+ *
+ * @param string|DOMDocument $request Logout Request Message
+ *
+ * @return string ID
+ */
+ public static function getID($request)
+ {
+ if ($request instanceof DOMDocument) {
+ $dom = $request;
+ } else {
+ $dom = new DOMDocument();
+ $dom = OneLogin_Saml2_Utils::loadXML($dom, $request);
+ }
+
+ $id = $dom->documentElement->getAttribute('ID');
+ return $id;
+ }
+
+ /**
+ * Gets the NameID Data of the the Logout Request.
+ *
+ * @param string|DOMDocument $request Logout Request Message
+ * @param string|null $key The SP key
+ *
+ * @return array Name ID Data (Value, Format, NameQualifier, SPNameQualifier)
+ *
+ * @throws Exception
+ */
+ public static function getNameIdData($request, $key = null)
+ {
+ if ($request instanceof DOMDocument) {
+ $dom = $request;
+ } else {
+ $dom = new DOMDocument();
+ $dom = OneLogin_Saml2_Utils::loadXML($dom, $request);
+ }
+
+ $encryptedEntries = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:EncryptedID');
+
+ if ($encryptedEntries->length == 1) {
+ $encryptedDataNodes = $encryptedEntries->item(0)->getElementsByTagName('EncryptedData');
+ $encryptedData = $encryptedDataNodes->item(0);
+
+ if (empty($key)) {
+ throw new Exception("Key is required in order to decrypt the NameID");
+ }
+
+ $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'private'));
+ $seckey->loadKey($key);
+
+ $nameId = OneLogin_Saml2_Utils::decryptElement($encryptedData, $seckey);
+
+ } else {
+ $entries = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:NameID');
+ if ($entries->length == 1) {
+ $nameId = $entries->item(0);
+ }
+ }
+
+ if (!isset($nameId)) {
+ throw new Exception("Not NameID found in the Logout Request");
+ }
+
+ $nameIdData = array();
+ $nameIdData['Value'] = $nameId->nodeValue;
+ foreach (array('Format', 'SPNameQualifier', 'NameQualifier') as $attr) {
+ if ($nameId->hasAttribute($attr)) {
+ $nameIdData[$attr] = $nameId->getAttribute($attr);
+ }
+ }
+
+ return $nameIdData;
+ }
+
+ /**
+ * Gets the NameID of the Logout Request.
+ *
+ * @param string|DOMDocument $request Logout Request Message
+ * @param string|null $key The SP key
+ *
+ * @return string Name ID Value
+ */
+ public static function getNameId($request, $key = null)
+ {
+ $nameId = self::getNameIdData($request, $key);
+ return $nameId['Value'];
+ }
+
+ /**
+ * Gets the Issuer of the Logout Request.
+ *
+ * @param string|DOMDocument $request Logout Request Message
+ *
+ * @return string|null $issuer The Issuer
+ */
+ public static function getIssuer($request)
+ {
+ if ($request instanceof DOMDocument) {
+ $dom = $request;
+ } else {
+ $dom = new DOMDocument();
+ $dom = OneLogin_Saml2_Utils::loadXML($dom, $request);
+ }
+
+ $issuer = null;
+ $issuerNodes = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:Issuer');
+ if ($issuerNodes->length == 1) {
+ $issuer = $issuerNodes->item(0)->textContent;
+ }
+ return $issuer;
+ }
+
+ /**
+ * Gets the SessionIndexes from the Logout Request.
+ * Notice: Our Constructor only support 1 SessionIndex but this parser
+ * extracts an array of all the SessionIndex found on a
+ * Logout Request, that could be many.
+ *
+ * @param string|DOMDocument $request Logout Request Message
+ *
+ * @return array The SessionIndex value
+ */
+ public static function getSessionIndexes($request)
+ {
+ if ($request instanceof DOMDocument) {
+ $dom = $request;
+ } else {
+ $dom = new DOMDocument();
+ $dom = OneLogin_Saml2_Utils::loadXML($dom, $request);
+ }
+
+ $sessionIndexes = array();
+ $sessionIndexNodes = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/samlp:SessionIndex');
+ foreach ($sessionIndexNodes as $sessionIndexNode) {
+ $sessionIndexes[] = $sessionIndexNode->textContent;
+ }
+ return $sessionIndexes;
+ }
+
+ /**
+ * Checks if the Logout Request recieved is valid.
+ *
+ * @return bool If the Logout Request is or not valid
+ */
+ public function isValid($retrieveParametersFromServer=false)
+ {
+ $this->_error = null;
+ try {
+ $dom = new DOMDocument();
+ $dom = OneLogin_Saml2_Utils::loadXML($dom, $this->_logoutRequest);
+
+ $idpData = $this->_settings->getIdPData();
+ $idPEntityId = $idpData['entityId'];
+
+ if ($this->_settings->isStrict()) {
+ $security = $this->_settings->getSecurityData();
+
+ if ($security['wantXMLValidation']) {
+ $res = OneLogin_Saml2_Utils::validateXML($dom, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
+ if (!$res instanceof DOMDocument) {
+ throw new Exception("Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd");
+ }
+ }
+
+ $currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
+
+ // Check NotOnOrAfter
+ if ($dom->documentElement->hasAttribute('NotOnOrAfter')) {
+ $na = OneLogin_Saml2_Utils::parseSAML2Time($dom->documentElement->getAttribute('NotOnOrAfter'));
+ if ($na <= time()) {
+ throw new Exception('Timing issues (please check your clock settings)');
+ }
+ }
+
+ // Check destination
+ if ($dom->documentElement->hasAttribute('Destination')) {
+ $destination = $dom->documentElement->getAttribute('Destination');
+ if (!empty($destination)) {
+ if (strpos($destination, $currentURL) === false) {
+ throw new Exception("The LogoutRequest was received at $currentURL instead of $destination");
+ }
+ }
+ }
+
+ $nameId = $this->getNameId($dom, $this->_settings->getSPkey());
+
+ // Check issuer
+ $issuer = $this->getIssuer($dom);
+ if (!empty($issuer) && $issuer != $idPEntityId) {
+ throw new Exception("Invalid issuer in the Logout Request");
+ }
+
+ if ($security['wantMessagesSigned']) {
+ if (!isset($_GET['Signature'])) {
+ throw new Exception("The Message of the Logout Request is not signed and the SP require it");
+ }
+ }
+ }
+
+ if (isset($_GET['Signature'])) {
+
+ if (!isset($_GET['SigAlg'])) {
+ $signAlg = XMLSecurityKey::RSA_SHA1;
+ } else {
+ $signAlg = $_GET['SigAlg'];
+ }
+
+ if ($retrieveParametersFromServer) {
+ $signedQuery = 'SAMLRequest='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SAMLRequest');
+ if (isset($_GET['RelayState'])) {
+ $signedQuery .= '&RelayState='.OneLogin_Saml2_Utils::extractOriginalQueryParam('RelayState');
+ }
+ $signedQuery .= '&SigAlg='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SigAlg');
+ } else {
+ $signedQuery = 'SAMLRequest='.urlencode($_GET['SAMLRequest']);
+ if (isset($_GET['RelayState'])) {
+ $signedQuery .= '&RelayState='.urlencode($_GET['RelayState']);
+ }
+ $signedQuery .= '&SigAlg='.urlencode($signAlg);
+ }
+
+ if (!isset($idpData['x509cert']) || empty($idpData['x509cert'])) {
+ throw new Exception('In order to validate the sign on the Logout Request, the x509cert of the IdP is required');
+ }
+ $cert = $idpData['x509cert'];
+
+ $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
+ $objKey->loadKey($cert, false, true);
+
+ if ($signAlg != XMLSecurityKey::RSA_SHA1) {
+ try {
+ $objKey = OneLogin_Saml2_Utils::castKey($objKey, $signAlg, 'public');
+ } catch (Exception $e) {
+ throw new Exception('Invalid signAlg in the recieved Logout Request');
+ }
+ }
+
+ if (!$objKey->verifySignature($signedQuery, base64_decode($_GET['Signature']))) {
+ throw new Exception('Signature validation failed. Logout Request rejected');
+ }
+ }
+
+ return true;
+ } catch (Exception $e) {
+ $this->_error = $e->getMessage();
+ $debug = $this->_settings->isDebugActive();
+ if ($debug) {
+ echo $this->_error;
+ }
+ return false;
+ }
+ }
+
+ /* After execute a validation process, if fails this method returns the cause
+ *
+ * @return string Cause
+ */
+ public function getError()
+ {
+ return $this->_error;
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/LogoutResponse.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/LogoutResponse.php
new file mode 100644
index 00000000..d6b710c0
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/LogoutResponse.php
@@ -0,0 +1,264 @@
+<?php
+
+/**
+ * SAML 2 Logout Response
+ *
+ */
+class OneLogin_Saml2_LogoutResponse
+{
+
+ /**
+ * Object that represents the setting info
+ * @var OneLogin_Saml2_Settings
+ */
+ protected $_settings;
+
+ /**
+ * The decoded, unprocessed XML response provided to the constructor.
+ * @var string
+ */
+ protected $_logoutResponse;
+
+ /**
+ * A DOMDocument class loaded from the SAML LogoutResponse.
+ * @var DomDocument
+ */
+ public $document;
+
+ /**
+ * After execute a validation process, if it fails, this var contains the cause
+ * @var string
+ */
+ private $_error;
+
+ /**
+ * Constructs a Logout Response object (Initialize params from settings and if provided
+ * load the Logout Response.
+ *
+ * @param OneLogin_Saml2_Settings $settings Settings.
+ * @param string|null $response An UUEncoded SAML Logout response from the IdP.
+ */
+ public function __construct(OneLogin_Saml2_Settings $settings, $response = null)
+ {
+ $this->_settings = $settings;
+ if ($response) {
+ $decoded = base64_decode($response);
+ $inflated = @gzinflate($decoded);
+ if ($inflated != false) {
+ $this->_logoutResponse = $inflated;
+ } else {
+ $this->_logoutResponse = $decoded;
+ }
+ $this->document = new DOMDocument();
+ $this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->_logoutResponse);
+ }
+ }
+
+ /**
+ * Gets the Issuer of the Logout Response.
+ *
+ * @return string|null $issuer The Issuer
+ */
+ public function getIssuer()
+ {
+ $issuer = null;
+ $issuerNodes = $this->_query('/samlp:LogoutResponse/saml:Issuer');
+ if ($issuerNodes->length == 1) {
+ $issuer = $issuerNodes->item(0)->textContent;
+ }
+ return $issuer;
+ }
+
+ /**
+ * Gets the Status of the Logout Response.
+ *
+ * @return string The Status
+ */
+ public function getStatus()
+ {
+ $entries = $this->_query('/samlp:LogoutResponse/samlp:Status/samlp:StatusCode');
+ if ($entries->length == 0) {
+ return null;
+ }
+ $status = $entries->item(0)->getAttribute('Value');
+ return $status;
+ }
+
+ /**
+ * Determines if the SAML LogoutResponse is valid
+ *
+ * @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP
+ * @param bool $retrieveParametersFromServer
+ *
+ * @return bool Returns if the SAML LogoutResponse is or not valid
+ *
+ * @throws Exception
+ */
+ public function isValid($requestId = null, $retrieveParametersFromServer=false)
+ {
+ $this->_error = null;
+ try {
+
+ $idpData = $this->_settings->getIdPData();
+ $idPEntityId = $idpData['entityId'];
+
+ if ($this->_settings->isStrict()) {
+ $security = $this->_settings->getSecurityData();
+
+ if ($security['wantXMLValidation']) {
+ $res = OneLogin_Saml2_Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
+ if (!$res instanceof DOMDocument) {
+ throw new Exception("Invalid SAML Logout Response. Not match the saml-schema-protocol-2.0.xsd");
+ }
+ }
+
+ // Check if the InResponseTo of the Logout Response matchs the ID of the Logout Request (requestId) if provided
+ if (isset($requestId) && $this->document->documentElement->hasAttribute('InResponseTo')) {
+ $inResponseTo = $this->document->documentElement->getAttribute('InResponseTo');
+ if ($requestId != $inResponseTo) {
+ throw new Exception("The InResponseTo of the Logout Response: $inResponseTo, does not match the ID of the Logout request sent by the SP: $requestId");
+ }
+ }
+
+ // Check issuer
+ $issuer = $this->getIssuer();
+ if (!empty($issuer) && $issuer != $idPEntityId) {
+ throw new Exception("Invalid issuer in the Logout Response");
+ }
+
+ $currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
+
+ // Check destination
+ if ($this->document->documentElement->hasAttribute('Destination')) {
+ $destination = $this->document->documentElement->getAttribute('Destination');
+ if (!empty($destination)) {
+ if (strpos($destination, $currentURL) === false) {
+ throw new Exception("The LogoutResponse was received at $currentURL instead of $destination");
+ }
+ }
+ }
+
+ if ($security['wantMessagesSigned']) {
+ if (!isset($_GET['Signature'])) {
+ throw new Exception("The Message of the Logout Response is not signed and the SP requires it");
+ }
+ }
+ }
+
+ if (isset($_GET['Signature'])) {
+ if (!isset($_GET['SigAlg'])) {
+ $signAlg = XMLSecurityKey::RSA_SHA1;
+ } else {
+ $signAlg = $_GET['SigAlg'];
+ }
+
+ if ($retrieveParametersFromServer) {
+ $signedQuery = 'SAMLResponse='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SAMLResponse');
+ if (isset($_GET['RelayState'])) {
+ $signedQuery .= '&RelayState='.OneLogin_Saml2_Utils::extractOriginalQueryParam('RelayState');
+ }
+ $signedQuery .= '&SigAlg='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SigAlg');
+ } else {
+ $signedQuery = 'SAMLResponse='.urlencode($_GET['SAMLResponse']);
+ if (isset($_GET['RelayState'])) {
+ $signedQuery .= '&RelayState='.urlencode($_GET['RelayState']);
+ }
+ $signedQuery .= '&SigAlg='.urlencode($signAlg);
+ }
+
+ if (!isset($idpData['x509cert']) || empty($idpData['x509cert'])) {
+ throw new Exception('In order to validate the sign on the Logout Response, the x509cert of the IdP is required');
+ }
+ $cert = $idpData['x509cert'];
+
+ $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
+ $objKey->loadKey($cert, false, true);
+
+ if ($signAlg != XMLSecurityKey::RSA_SHA1) {
+ try {
+ $objKey = OneLogin_Saml2_Utils::castKey($objKey, $signAlg, 'public');
+ } catch (Exception $e) {
+ throw new Exception('Invalid signAlg in the recieved Logout Response');
+ }
+ }
+
+ if (!$objKey->verifySignature($signedQuery, base64_decode($_GET['Signature']))) {
+ throw new Exception('Signature validation failed. Logout Response rejected');
+ }
+ }
+ return true;
+ } catch (Exception $e) {
+ $this->_error = $e->getMessage();
+ $debug = $this->_settings->isDebugActive();
+ if ($debug) {
+ echo $this->_error;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Extracts a node from the DOMDocument (Logout Response Menssage)
+ *
+ * @param string $query Xpath Expresion
+ *
+ * @return DOMNodeList The queried node
+ */
+ private function _query($query)
+ {
+ return OneLogin_Saml2_Utils::query($this->document, $query);
+
+ }
+
+ /**
+ * Generates a Logout Response object.
+ *
+ * @param string $inResponseTo InResponseTo value for the Logout Response.
+ */
+ public function build($inResponseTo)
+ {
+
+ $spData = $this->_settings->getSPData();
+ $idpData = $this->_settings->getIdPData();
+
+ $id = OneLogin_Saml2_Utils::generateUniqueID();
+ $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time());
+
+ $logoutResponse = <<<LOGOUTRESPONSE
+<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ ID="{$id}"
+ Version="2.0"
+ IssueInstant="{$issueInstant}"
+ Destination="{$idpData['singleLogoutService']['url']}"
+ InResponseTo="{$inResponseTo}"
+ >
+ <saml:Issuer>{$spData['entityId']}</saml:Issuer>
+ <samlp:Status>
+ <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
+ </samlp:Status>
+</samlp:LogoutResponse>
+LOGOUTRESPONSE;
+ $this->_logoutResponse = $logoutResponse;
+ }
+
+ /**
+ * Returns a Logout Response object.
+ *
+ * @return string Logout Response deflated and base64 encoded
+ */
+ public function getResponse()
+ {
+ $deflatedResponse = gzdeflate($this->_logoutResponse);
+ return base64_encode($deflatedResponse);
+ }
+
+ /* After execute a validation process, if fails this method returns the cause.
+ *
+ * @return string Cause
+ */
+ public function getError()
+ {
+ return $this->_error;
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Metadata.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Metadata.php
new file mode 100644
index 00000000..92b26bf0
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Metadata.php
@@ -0,0 +1,184 @@
+<?php
+
+/**
+ * Metadata lib of OneLogin PHP Toolkit
+ *
+ */
+
+class OneLogin_Saml2_Metadata
+{
+ const TIME_VALID = 172800; // 2 days
+ const TIME_CACHED = 604800; // 1 week
+
+ /**
+ * Generates the metadata of the SP based on the settings
+ *
+ * @param array $sp The SP data
+ * @param bool|string $authnsign authnRequestsSigned attribute
+ * @param bool|string $wsign wantAssertionsSigned attribute
+ * @param DateTime|null $validUntil Metadata's valid time
+ * @param int|null $cacheDuration Duration of the cache in seconds
+ * @param array $contacts Contacts info
+ * @param array $organization Organization ingo
+ * @param array $attributes
+ * @return string SAML Metadata XML
+ */
+ public static function builder($sp, $authnsign = false, $wsign = false, $validUntil = null, $cacheDuration = null, $contacts = array(), $organization = array(), $attributes = array())
+ {
+
+ if (!isset($validUntil)) {
+ $validUntil = time() + self::TIME_VALID;
+ }
+ $validUntilTime = gmdate('Y-m-d\TH:i:s\Z', $validUntil);
+
+ if (!isset($cacheDuration)) {
+ $cacheDuration = self::TIME_CACHED;
+ }
+
+ $sls = '';
+
+ if (isset($sp['singleLogoutService'])) {
+ $sls = <<<SLS_TEMPLATE
+ <md:SingleLogoutService Binding="{$sp['singleLogoutService']['binding']}"
+ Location="{$sp['singleLogoutService']['url']}" />
+
+SLS_TEMPLATE;
+ }
+
+ if ($authnsign) {
+ $strAuthnsign = 'true';
+ } else {
+ $strAuthnsign = 'false';
+ }
+
+ if ($wsign) {
+ $strWsign = 'true';
+ } else {
+ $strWsign = 'false';
+ }
+
+ $strOrganization = '';
+ if (!empty($organization)) {
+ $organizationInfoNames = array();
+ $organizationInfoDisplaynames = array();
+ $organizationInfoUrls = array();
+ foreach ($organization as $lang => $info) {
+ $organizationInfoNames[] = <<<ORGANIZATION_NAME
+ <md:OrganizationName xml:lang="{$lang}">{$info['name']}</md:OrganizationName>
+ORGANIZATION_NAME;
+ $organizationInfoDisplaynames[] = <<<ORGANIZATION_DISPLAY
+ <md:OrganizationDisplayName xml:lang="{$lang}">{$info['displayname']}</md:OrganizationDisplayName>
+ORGANIZATION_DISPLAY;
+ $organizationInfoUrls[] = <<<ORGANIZATION_URL
+ <md:OrganizationURL xml:lang="{$lang}">{$info['url']}</md:OrganizationURL>
+ORGANIZATION_URL;
+ }
+ $orgData = implode("\n", $organizationInfoNames)."\n".implode("\n", $organizationInfoDisplaynames)."\n".implode("\n", $organizationInfoUrls);
+ $strOrganization = <<<ORGANIZATIONSTR
+
+ <md:Organization>
+{$orgData}
+ </md:Organization>
+ORGANIZATIONSTR;
+ }
+
+ $strContacts = '';
+ if (!empty($contacts)) {
+ $contactsInfo = array();
+ foreach ($contacts as $type => $info) {
+ $contactsInfo[] = <<<CONTACT
+ <md:ContactPerson contactType="{$type}">
+ <md:GivenName>{$info['givenName']}</md:GivenName>
+ <md:EmailAddress>{$info['emailAddress']}</md:EmailAddress>
+ </md:ContactPerson>
+CONTACT;
+ }
+ $strContacts = "\n".implode("\n", $contactsInfo);
+ }
+
+ $metadata = <<<METADATA_TEMPLATE
+<?xml version="1.0"?>
+<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
+ validUntil="{$validUntilTime}"
+ cacheDuration="PT{$cacheDuration}S"
+ entityID="{$sp['entityId']}">
+ <md:SPSSODescriptor AuthnRequestsSigned="{$strAuthnsign}" WantAssertionsSigned="{$strWsign}" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+{$sls} <md:NameIDFormat>{$sp['NameIDFormat']}</md:NameIDFormat>
+ <md:AssertionConsumerService Binding="{$sp['assertionConsumerService']['binding']}"
+ Location="{$sp['assertionConsumerService']['url']}"
+ index="1" />
+ </md:SPSSODescriptor>{$strOrganization}{$strContacts}
+</md:EntityDescriptor>
+METADATA_TEMPLATE;
+ return $metadata;
+ }
+
+ /**
+ * Signs the metadata with the key/cert provided
+ *
+ * @param string $metadata SAML Metadata XML
+ * @param string $key x509 key
+ * @param string $cert x509 cert
+ *
+ * @return string Signed Metadata
+ */
+ public static function signMetadata($metadata, $key, $cert, $signAlgorithm = XMLSecurityKey::RSA_SHA1)
+ {
+ return OneLogin_Saml2_Utils::addSign($metadata, $key, $cert, $signAlgorithm);
+ }
+
+ /**
+ * Adds the x509 descriptors (sign/encriptation) to the metadata
+ * The same cert will be used for sign/encrypt
+ *
+ * @param string $metadata SAML Metadata XML
+ * @param string $cert x509 cert
+ * @param bool $wantsEncrypted Whether to include the KeyDescriptor for encryption
+ *
+ * @return string Metadata with KeyDescriptors
+ */
+ public static function addX509KeyDescriptors($metadata, $cert, $wantsEncrypted = true)
+ {
+ $xml = new DOMDocument();
+ $xml->preserveWhiteSpace = false;
+ $xml->formatOutput = true;
+ try {
+ $xml = OneLogin_Saml2_Utils::loadXML($xml, $metadata);
+ if (!$xml) {
+ throw new Exception('Error parsing metadata');
+ }
+ } catch (Exception $e) {
+ throw new Exception('Error parsing metadata. '.$e->getMessage());
+ }
+
+ $formatedCert = OneLogin_Saml2_Utils::formatCert($cert, false);
+ $x509Certificate = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'X509Certificate', $formatedCert);
+
+ $keyData = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'ds:X509Data');
+ $keyData->appendChild($x509Certificate);
+
+ $keyInfo = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'ds:KeyInfo');
+ $keyInfo->appendChild($keyData);
+
+ $keyDescriptor = $xml->createElementNS(OneLogin_Saml2_Constants::NS_MD, "md:KeyDescriptor");
+
+ $SPSSODescriptor = $xml->getElementsByTagName('SPSSODescriptor')->item(0);
+ $SPSSODescriptor->insertBefore($keyDescriptor->cloneNode(), $SPSSODescriptor->firstChild);
+ if ($wantsEncrypted === true) {
+ $SPSSODescriptor->insertBefore($keyDescriptor->cloneNode(), $SPSSODescriptor->firstChild);
+ }
+
+ $signing = $xml->getElementsByTagName('KeyDescriptor')->item(0);
+ $signing->setAttribute('use', 'signing');
+ $signing->appendChild($keyInfo);
+
+ if ($wantsEncrypted === true) {
+ $encryption = $xml->getElementsByTagName('KeyDescriptor')->item(1);
+ $encryption->setAttribute('use', 'encryption');
+
+ $encryption->appendChild($keyInfo->cloneNode(true));
+ }
+
+ return $xml->saveXML();
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Response.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Response.php
new file mode 100644
index 00000000..ffb92e19
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Response.php
@@ -0,0 +1,754 @@
+<?php
+
+/**
+ * SAML 2 Authentication Response
+ *
+ */
+
+class OneLogin_Saml2_Response
+{
+
+ /**
+ * Settings
+ * @var OneLogin_Saml2_Settings
+ */
+ protected $_settings;
+
+ /**
+ * The decoded, unprocessed XML response provided to the constructor.
+ * @var string
+ */
+ public $response;
+
+ /**
+ * A DOMDocument class loaded from the SAML Response.
+ * @var DomDocument
+ */
+ public $document;
+
+ /**
+ * A DOMDocument class loaded from the SAML Response (Decrypted).
+ * @var DomDocument
+ */
+ public $decryptedDocument;
+
+ /**
+ * The response contains an encrypted assertion.
+ * @var bool
+ */
+ public $encrypted = false;
+
+ /**
+ * After validation, if it fail this var has the cause of the problem
+ * @var string
+ */
+ private $_error;
+
+ /**
+ * Constructs the SAML Response object.
+ *
+ * @param OneLogin_Saml2_Settings $settings Settings.
+ * @param string $response A UUEncoded SAML response from the IdP.
+ *
+ * @throws Exception
+ */
+ public function __construct(OneLogin_Saml2_Settings $settings, $response)
+ {
+ $this->_settings = $settings;
+
+ $this->response = base64_decode($response);
+
+ $this->document = new DOMDocument();
+ $this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->response);
+ if (!$this->document) {
+ throw new Exception('SAML Response could not be processed');
+ }
+
+ // Quick check for the presence of EncryptedAssertion
+ $encryptedAssertionNodes = $this->document->getElementsByTagName('EncryptedAssertion');
+ if ($encryptedAssertionNodes->length !== 0) {
+ $this->decryptedDocument = clone $this->document;
+ $this->encrypted = true;
+ $this->_decryptAssertion($this->decryptedDocument);
+ }
+ }
+
+ /**
+ * Determines if the SAML Response is valid using the certificate.
+ *
+ * @param string|null $requestId The ID of the AuthNRequest sent by this SP to the IdP
+ *
+ * @return bool Validate the document
+ *
+ * @throws Exception
+ */
+ public function isValid($requestId = null)
+ {
+ $this->_error = null;
+ try {
+ // Check SAML version
+ if ($this->document->documentElement->getAttribute('Version') != '2.0') {
+ throw new Exception('Unsupported SAML version');
+ }
+
+ if (!$this->document->documentElement->hasAttribute('ID')) {
+ throw new Exception('Missing ID attribute on SAML Response');
+ }
+
+ $status = $this->checkStatus();
+
+ $singleAssertion = $this->validateNumAssertions();
+ if (!$singleAssertion) {
+ throw new Exception('SAML Response must contain 1 assertion');
+ }
+
+ $idpData = $this->_settings->getIdPData();
+ $idPEntityId = $idpData['entityId'];
+ $spData = $this->_settings->getSPData();
+ $spEntityId = $spData['entityId'];
+
+ $signedElements = $this->processSignedElements();
+
+ if ($this->_settings->isStrict()) {
+ $security = $this->_settings->getSecurityData();
+
+ if ($security['wantXMLValidation']) {
+ $errorXmlMsg = "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd";
+ $res = OneLogin_Saml2_Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
+ if (!$res instanceof DOMDocument) {
+ throw new Exception($errorXmlMsg);
+ }
+
+ # If encrypted, check also the decrypted document
+
+ if ($this->encrypted) {
+ $res = OneLogin_Saml2_Utils::validateXML($this->decryptedDocument, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
+ if (!$res instanceof DOMDocument) {
+ throw new Exception($errorXmlMsg);
+ }
+ }
+
+ }
+
+ $currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
+
+ 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)) {
+ if ($requestId != $responseInResponseTo) {
+ throw new Exception("The InResponseTo of the Response: $responseInResponseTo, does not match the ID of the AuthNRequest sent by the SP: $requestId");
+ }
+ }
+
+ if (!$this->encrypted && $security['wantAssertionsEncrypted']) {
+ throw new Exception("The assertion of the Response is not encrypted and the SP requires it");
+ }
+
+ if ($security['wantNameIdEncrypted']) {
+ $encryptedIdNodes = $this->_queryAssertion('/saml:Subject/saml:EncryptedID/xenc:EncryptedData');
+ if ($encryptedIdNodes->length == 0) {
+ throw new Exception("The NameID of the Response is not encrypted and the SP requires it");
+ }
+ }
+
+ // Validate Asserion timestamps
+ $validTimestamps = $this->validateTimestamps();
+ if (!$validTimestamps) {
+ throw new Exception('Timing issues (please check your clock settings)');
+ }
+
+ // EncryptedAttributes are not supported
+ $encryptedAttributeNodes = $this->_queryAssertion('/saml:AttributeStatement/saml:EncryptedAttribute');
+ if ($encryptedAttributeNodes->length > 0) {
+ throw new Exception("There is an EncryptedAttribute in the Response and this SP not support them");
+ }
+
+ // Check destination
+ if ($this->document->documentElement->hasAttribute('Destination')) {
+ $destination = trim($this->document->documentElement->getAttribute('Destination'));
+ if (!empty($destination)) {
+ if (strpos($destination, $currentURL) !== 0) {
+ $currentURLrouted = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
+
+ if (strpos($destination, $currentURLrouted) !== 0) {
+ throw new Exception("The response was received at $currentURL instead of $destination");
+ }
+ }
+ }
+ }
+
+ // Check audience
+ $validAudiences = $this->getAudiences();
+ if (!empty($validAudiences) && !in_array($spEntityId, $validAudiences)) {
+ throw new Exception("$spEntityId is not a valid audience for this Response");
+ }
+
+ // Check the issuers
+ $issuers = $this->getIssuers();
+ foreach ($issuers as $issuer) {
+ $trimmedIssuer = trim($issuer);
+
+ if (empty($trimmedIssuer) || $trimmedIssuer !== $idPEntityId) {
+ throw new Exception("Invalid issuer in the Assertion/Response");
+ }
+ }
+
+ // Check the session Expiration
+ $sessionExpiration = $this->getSessionNotOnOrAfter();
+ if (!empty($sessionExpiration) && $sessionExpiration <= time()) {
+ throw new Exception("The attributes have expired, based on the SessionNotOnOrAfter of the AttributeStatement of this Response");
+ }
+
+ // Check the SubjectConfirmation, at least one SubjectConfirmation must be valid
+ $anySubjectConfirmation = false;
+ $subjectConfirmationNodes = $this->_queryAssertion('/saml:Subject/saml:SubjectConfirmation');
+ foreach ($subjectConfirmationNodes as $scn) {
+ if ($scn->hasAttribute('Method') && $scn->getAttribute('Method') != OneLogin_Saml2_Constants::CM_BEARER) {
+ continue;
+ }
+ $subjectConfirmationDataNodes = $scn->getElementsByTagName('SubjectConfirmationData');
+ if ($subjectConfirmationDataNodes->length == 0) {
+ continue;
+ } else {
+ $scnData = $subjectConfirmationDataNodes->item(0);
+ if ($scnData->hasAttribute('InResponseTo')) {
+ $inResponseTo = $scnData->getAttribute('InResponseTo');
+ if ($responseInResponseTo != $inResponseTo) {
+ continue;
+ }
+ }
+ if ($scnData->hasAttribute('Recipient')) {
+ $recipient = $scnData->getAttribute('Recipient');
+ if (!empty($recipient) && strpos($recipient, $currentURL) === false) {
+ continue;
+ }
+ }
+ if ($scnData->hasAttribute('NotOnOrAfter')) {
+ $noa = OneLogin_Saml2_Utils::parseSAML2Time($scnData->getAttribute('NotOnOrAfter'));
+ if ($noa <= time()) {
+ continue;
+ }
+ }
+ if ($scnData->hasAttribute('NotBefore')) {
+ $nb = OneLogin_Saml2_Utils::parseSAML2Time($scnData->getAttribute('NotBefore'));
+ if ($nb > time()) {
+ continue;
+ }
+ }
+ $anySubjectConfirmation = true;
+ break;
+ }
+ }
+
+ if (!$anySubjectConfirmation) {
+ throw new Exception("A valid SubjectConfirmation was not found on this Response");
+ }
+
+ if ($security['wantAssertionsSigned'] && !in_array('Assertion', $signedElements)) {
+ throw new Exception("The Assertion of the Response is not signed and the SP requires it");
+ }
+
+ if ($security['wantMessagesSigned'] && !in_array('Response', $signedElements)) {
+ throw new Exception("The Message of the Response is not signed and the SP requires it");
+ }
+ }
+
+ if (!empty($signedElements)) {
+ $cert = $idpData['x509cert'];
+ $fingerprint = $idpData['certFingerprint'];
+ $fingerprintalg = $idpData['certFingerprintAlgorithm'];
+
+ # If find a Signature on the Response, validates it checking the original response
+ if (in_array('Response', $signedElements)) {
+ $documentToValidate = $this->document;
+ } else {
+ # Otherwise validates the assertion (decrypted assertion if was encrypted)
+ $documentToValidate = $this->decryptedDocument;
+ if ($this->encrypted) {
+ $documentToValidate = $this->decryptedDocument;
+ $encryptedIDNodes = OneLogin_Saml2_Utils::query($this->decryptedDocument, '/samlp:Response/saml:Assertion/saml:Subject/saml:EncryptedID');
+ if ($encryptedIDNodes->length > 0) {
+ throw new Exception('Unsigned SAML Response that contains a signed and encrypted Assertion with encrypted nameId is not supported.');
+ }
+ } else {
+ $documentToValidate = $this->document;
+ }
+ }
+
+ if (!OneLogin_Saml2_Utils::validateSign($documentToValidate, $cert, $fingerprint, $fingerprintalg)) {
+ throw new Exception('Signature validation failed. SAML Response rejected');
+ }
+ } else {
+ throw new Exception('No Signature found. SAML Response rejected');
+ }
+ return true;
+ } catch (Exception $e) {
+ $this->_error = $e->getMessage();
+ $debug = $this->_settings->isDebugActive();
+ if ($debug) {
+ echo $this->_error;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the Status is success
+ *
+ * @throws $statusExceptionMsg If status is not success
+ */
+ public function checkStatus()
+ {
+ $status = OneLogin_Saml2_Utils::getStatus($this->document);
+
+ if (isset($status['code']) && $status['code'] !== OneLogin_Saml2_Constants::STATUS_SUCCESS) {
+ $explodedCode = explode(':', $status['code']);
+ $printableCode = array_pop($explodedCode);
+
+ $statusExceptionMsg = 'The status code of the Response was not Success, was '.$printableCode;
+ if (!empty($status['msg'])) {
+ $statusExceptionMsg .= ' -> '.$status['msg'];
+ }
+
+ throw new Exception($statusExceptionMsg);
+ }
+ }
+
+ /**
+ * Gets the audiences.
+ *
+ * @return array @audience The valid audiences of the response
+ */
+ public function getAudiences()
+ {
+ $audiences = array();
+
+ $entries = $this->_queryAssertion('/saml:Conditions/saml:AudienceRestriction/saml:Audience');
+ foreach ($entries as $entry) {
+ $value = trim($entry->textContent);
+ if (!empty($value)) {
+ $audiences[] = $value;
+ }
+ }
+
+ return array_unique($audiences);
+ }
+
+ /**
+ * Gets the Issuers (from Response and Assertion).
+ *
+ * @return array @issuers The issuers of the assertion/response
+ */
+ public function getIssuers()
+ {
+ $issuers = array();
+
+ $responseIssuer = $this->_query('/samlp:Response/saml:Issuer');
+ if ($responseIssuer->length == 1) {
+ $issuers[] = $responseIssuer->item(0)->textContent;
+ }
+
+ $assertionIssuer = $this->_queryAssertion('/saml:Issuer');
+ if ($assertionIssuer->length == 1) {
+ $issuers[] = $assertionIssuer->item(0)->textContent;
+ }
+
+ return array_unique($issuers);
+ }
+
+ /**
+ * Gets the NameID Data provided by the SAML response from the IdP.
+ *
+ * @return array Name ID Data (Value, Format, NameQualifier, SPNameQualifier)
+ */
+ public function getNameIdData()
+ {
+ $encryptedIdDataEntries = $this->_queryAssertion('/saml:Subject/saml:EncryptedID/xenc:EncryptedData');
+
+ if ($encryptedIdDataEntries->length == 1) {
+ $encryptedData = $encryptedIdDataEntries->item(0);
+
+ $key = $this->_settings->getSPkey();
+ $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'private'));
+ $seckey->loadKey($key);
+
+ $nameId = OneLogin_Saml2_Utils::decryptElement($encryptedData, $seckey);
+
+ } else {
+ $entries = $this->_queryAssertion('/saml:Subject/saml:NameID');
+ if ($entries->length == 1) {
+ $nameId = $entries->item(0);
+ }
+ }
+
+ $nameIdData = array();
+
+ if (!isset($nameId)) {
+ $security = $this->_settings->getSecurityData();
+ if ($security['wantNameId']) {
+ throw new Exception("Not NameID found in the assertion of the Response");
+ }
+ } else {
+ $nameIdData['Value'] = $nameId->nodeValue;
+ foreach (array('Format', 'SPNameQualifier', 'NameQualifier') as $attr) {
+ if ($nameId->hasAttribute($attr)) {
+ $nameIdData[$attr] = $nameId->getAttribute($attr);
+ }
+ }
+ }
+
+ return $nameIdData;
+ }
+
+ /**
+ * Gets the NameID provided by the SAML response from the IdP.
+ *
+ * @return string Name ID Value
+ */
+ public function getNameId()
+ {
+ $nameIdvalue = null;
+ $nameIdData = $this->getNameIdData();
+ if (!empty($nameIdData) && isset($nameIdData['Value'])) {
+ $nameIdvalue = $nameIdData['Value'];
+ }
+ return $nameIdvalue;
+ }
+
+ /**
+ * Gets the SessionNotOnOrAfter from the AuthnStatement.
+ * Could be used to set the local session expiration
+ *
+ * @return int|null The SessionNotOnOrAfter value
+ */
+ public function getSessionNotOnOrAfter()
+ {
+ $notOnOrAfter = null;
+ $entries = $this->_queryAssertion('/saml:AuthnStatement[@SessionNotOnOrAfter]');
+ if ($entries->length !== 0) {
+ $notOnOrAfter = OneLogin_Saml2_Utils::parseSAML2Time($entries->item(0)->getAttribute('SessionNotOnOrAfter'));
+ }
+ return $notOnOrAfter;
+ }
+
+ /**
+ * Gets the SessionIndex from the AuthnStatement.
+ * Could be used to be stored in the local session in order
+ * to be used in a future Logout Request that the SP could
+ * send to the SP, to set what specific session must be deleted
+ *
+ * @return string|null The SessionIndex value
+ */
+
+ public function getSessionIndex()
+ {
+ $sessionIndex = null;
+ $entries = $this->_queryAssertion('/saml:AuthnStatement[@SessionIndex]');
+ if ($entries->length !== 0) {
+ $sessionIndex = $entries->item(0)->getAttribute('SessionIndex');
+ }
+ return $sessionIndex;
+ }
+
+ /**
+ * Gets the Attributes from the AttributeStatement element.
+ *
+ * @return array The attributes of the SAML Assertion
+ */
+ public function getAttributes()
+ {
+ $attributes = array();
+
+ /* EncryptedAttributes not supported
+
+ $encriptedAttributes = $this->_queryAssertion('/saml:AttributeStatement/saml:EncryptedAttribute');
+
+ if ($encriptedAttributes->length > 0) {
+ foreach ($encriptedAttributes as $encriptedAttribute) {
+ $key = $this->_settings->getSPkey();
+ $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'private'));
+ $seckey->loadKey($key);
+ $attribute = OneLogin_Saml2_Utils::decryptElement($encriptedAttribute->firstChild(), $seckey);
+ }
+ }
+ */
+
+ $entries = $this->_queryAssertion('/saml:AttributeStatement/saml:Attribute');
+
+ /** @var $entry DOMNode */
+ foreach ($entries as $entry) {
+ $attributeName = $entry->attributes->getNamedItem('Name')->nodeValue;
+
+ $attributeValues = array();
+ foreach ($entry->childNodes as $childNode) {
+ $tagName = ($childNode->prefix ? $childNode->prefix.':' : '') . 'AttributeValue';
+ if ($childNode->nodeType == XML_ELEMENT_NODE && $childNode->tagName === $tagName) {
+ $attributeValues[] = $childNode->nodeValue;
+ }
+ }
+
+ $attributes[$attributeName] = $attributeValues;
+ }
+ return $attributes;
+ }
+
+ /**
+ * Verifies that the document only contains a single Assertion (encrypted or not).
+ *
+ * @return bool TRUE if the document passes.
+ */
+ public function validateNumAssertions()
+ {
+ $encryptedAssertionNodes = $this->document->getElementsByTagName('EncryptedAssertion');
+ $assertionNodes = $this->document->getElementsByTagName('Assertion');
+ return ($assertionNodes->length + $encryptedAssertionNodes->length == 1);
+ }
+
+ /**
+ * Verifies the signature nodes:
+ * - Checks that are Response or Assertion
+ * - Check that IDs and reference URI are unique and consistent.
+ *
+ * @return array Signed element tags
+ */
+ public function processSignedElements()
+ {
+ $signedElements = array();
+ $verifiedSeis = array();
+ $verifiedIds = array();
+
+ if ($this->encrypted) {
+ $signNodes = $this->decryptedDocument->getElementsByTagName('Signature');
+ } else {
+ $signNodes = $this->document->getElementsByTagName('Signature');
+ }
+ foreach ($signNodes as $signNode) {
+ $signedElement = $signNode->parentNode->localName;
+
+ if ($signedElement != 'Response' && $signedElement != 'Assertion') {
+ throw new Exception('Invalid Signature Element '.$signedElement.' SAML Response rejected');
+ }
+
+ # Check that reference URI matches the parent ID and no duplicate References or IDs
+ $idValue = $signNode->parentNode->getAttribute('ID');
+ if (empty($idValue)) {
+ throw new Exception('Signed Element must contain an ID. SAML Response rejected');
+ }
+
+ if (in_array($idValue, $verifiedIds)) {
+ throw new Exception('Duplicated ID. SAML Response rejected');
+ }
+ $verifiedIds[] = $idValue;
+
+ $ref = $signNode->getElementsByTagName('Reference');
+ if (!empty($ref)) {
+ $ref = $ref->item(0);
+ $sei = $ref->getAttribute('URI');
+ if (!empty($sei)) {
+ $sei = substr($sei, 1);
+
+ if ($sei != $idValue) {
+ throw new Exception('Found an invalid Signed Element. SAML Response rejected');
+ }
+
+ if (in_array($sei, $verifiedSeis)) {
+ throw new Exception('Duplicated Reference URI. SAML Response rejected');
+ }
+ $verifiedSeis[] = $sei;
+ }
+ }
+ $signedElements[] = $signedElement;
+ }
+
+ if (!empty($signedElements)) {
+ // Check SignedElements
+ if (!$this->validateSignedElements($signedElements)) {
+ throw new Exception('Found an unexpected Signature Element. SAML Response rejected');
+ }
+ }
+ return $signedElements;
+ }
+
+ /**
+ * Verifies that the document is still valid according Conditions Element.
+ *
+ * @return bool
+ */
+ public function validateTimestamps()
+ {
+ if ($this->encrypted) {
+ $document = $this->decryptedDocument;
+ } else {
+ $document = $this->document;
+ }
+
+ $timestampNodes = $document->getElementsByTagName('Conditions');
+ for ($i = 0; $i < $timestampNodes->length; $i++) {
+ $nbAttribute = $timestampNodes->item($i)->attributes->getNamedItem("NotBefore");
+ $naAttribute = $timestampNodes->item($i)->attributes->getNamedItem("NotOnOrAfter");
+ if ($nbAttribute && OneLogin_SAML2_Utils::parseSAML2Time($nbAttribute->textContent) > time() + OneLogin_Saml2_Constants::ALLOWED_CLOCK_DRIFT) {
+ return false;
+ }
+ if ($naAttribute && OneLogin_SAML2_Utils::parseSAML2Time($naAttribute->textContent) + OneLogin_Saml2_Constants::ALLOWED_CLOCK_DRIFT <= time()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Verifies that the document has the expected signed nodes.
+ *
+ * @return bool
+ */
+ public function validateSignedElements($signedElements)
+ {
+ if (count($signedElements) > 2) {
+ return false;
+ }
+ $ocurrence = array_count_values($signedElements);
+ if ((in_array('Response', $signedElements) && $ocurrence['Response'] > 1) ||
+ (in_array('Assertion', $signedElements) && $ocurrence['Assertion'] > 1) ||
+ !in_array('Response', $signedElements) && !in_array('Assertion', $signedElements)
+ ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Extracts a node from the DOMDocument (Assertion).
+ *
+ * @param string $assertionXpath Xpath Expresion
+ *
+ * @return DOMNodeList The queried node
+ *
+ * @throws Exception
+ */
+ protected function _queryAssertion($assertionXpath)
+ {
+ if ($this->encrypted) {
+ $xpath = new DOMXPath($this->decryptedDocument);
+ } else {
+ $xpath = new DOMXPath($this->document);
+ }
+
+ $xpath->registerNamespace('samlp', OneLogin_Saml2_Constants::NS_SAMLP);
+ $xpath->registerNamespace('saml', OneLogin_Saml2_Constants::NS_SAML);
+ $xpath->registerNamespace('ds', OneLogin_Saml2_Constants::NS_DS);
+ $xpath->registerNamespace('xenc', OneLogin_Saml2_Constants::NS_XENC);
+
+ $assertionNode = '/samlp:Response/saml:Assertion';
+ $signatureQuery = $assertionNode . '/ds:Signature/ds:SignedInfo/ds:Reference';
+ $assertionReferenceNode = $xpath->query($signatureQuery)->item(0);
+ if (!$assertionReferenceNode) {
+ // is the response signed as a whole?
+ $signatureQuery = '/samlp:Response/ds:Signature/ds:SignedInfo/ds:Reference';
+ $assertionReferenceNode = $xpath->query($signatureQuery)->item(0);
+ if ($assertionReferenceNode) {
+ $uri = $assertionReferenceNode->attributes->getNamedItem('URI')->nodeValue;
+ if (empty($uri)) {
+ $id = $assertionReferenceNode->parentNode->parentNode->parentNode->attributes->getNamedItem('ID')->nodeValue;
+ } else {
+ $id = substr($assertionReferenceNode->attributes->getNamedItem('URI')->nodeValue, 1);
+ }
+ $nameQuery = "/samlp:Response[@ID='$id']/saml:Assertion" . $assertionXpath;
+ } else {
+ $nameQuery = "/samlp:Response/saml:Assertion" . $assertionXpath;
+ }
+ } else {
+ $uri = $assertionReferenceNode->attributes->getNamedItem('URI')->nodeValue;
+ if (empty($uri)) {
+ $id = $assertionReferenceNode->parentNode->parentNode->parentNode->attributes->getNamedItem('ID')->nodeValue;
+ } else {
+ $id = substr($assertionReferenceNode->attributes->getNamedItem('URI')->nodeValue, 1);
+ }
+ $nameQuery = $assertionNode."[@ID='$id']" . $assertionXpath;
+ }
+
+ return $xpath->query($nameQuery);
+ }
+
+ /**
+ * Extracts nodes that match the query from the DOMDocument (Response Menssage)
+ *
+ * @param string $query Xpath Expresion
+ *
+ * @return DOMNodeList The queried nodes
+ */
+ private function _query($query)
+ {
+ return OneLogin_Saml2_Utils::query($this->document, $query);
+ }
+
+ /**
+ * Decrypts the Assertion (DOMDocument)
+ *
+ * @param DomNode $dom DomDocument
+ *
+ * @return DOMDocument Decrypted Assertion
+ *
+ * @throws Exception
+ */
+ protected function _decryptAssertion($dom)
+ {
+ $pem = $this->_settings->getSPkey();
+
+ if (empty($pem)) {
+ throw new Exception("No private key available, check settings");
+ }
+
+ $objenc = new XMLSecEnc();
+ $encData = $objenc->locateEncryptedData($dom);
+ if (!$encData) {
+ throw new Exception("Cannot locate encrypted assertion");
+ }
+
+ $objenc->setNode($encData);
+ $objenc->type = $encData->getAttribute("Type");
+ if (!$objKey = $objenc->locateKey()) {
+ throw new Exception("Unknown algorithm");
+ }
+
+ $key = null;
+ if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) {
+ if ($objKeyInfo->isEncrypted) {
+ $objencKey = $objKeyInfo->encryptedCtx;
+ $objKeyInfo->loadKey($pem, false, false);
+ $key = $objencKey->decryptKey($objKeyInfo);
+ } else {
+ // symmetric encryption key support
+ $objKeyInfo->loadKey($pem, false, false);
+ }
+ }
+
+ if (empty($objKey->key)) {
+ $objKey->loadKey($key);
+ }
+
+ $decrypted = $objenc->decryptNode($objKey, true);
+
+ if ($decrypted instanceof DOMDocument) {
+ return $decrypted;
+ } else {
+ $encryptedAssertion = $decrypted->parentNode;
+ $container = $encryptedAssertion->parentNode;
+
+ $container->replaceChild($decrypted, $encryptedAssertion);
+
+ return $decrypted->ownerDocument;
+ }
+ }
+
+ /* After execute a validation process, if fails this method returns the cause
+ *
+ * @return string Cause
+ */
+ public function getError()
+ {
+ return $this->_error;
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Settings.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Settings.php
new file mode 100644
index 00000000..a8bf8fcc
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Settings.php
@@ -0,0 +1,873 @@
+<?php
+
+/**
+ * Configuration of the OneLogin PHP Toolkit
+ *
+ */
+
+class OneLogin_Saml2_Settings
+{
+ /**
+ * List of paths.
+ *
+ * @var array
+ */
+ private $_paths = array();
+
+ /**
+ * Strict. If active, PHP Toolkit will reject unsigned or unencrypted messages
+ * if it expects them signed or encrypted. If not, the messages will be accepted
+ * and some security issues will be also relaxed.
+ *
+ * @var bool
+ */
+ private $_strict = false;
+
+ /**
+ * Activate debug mode
+ *
+ * @var bool
+ */
+ private $_debug = false;
+
+ /**
+ * SP data.
+ *
+ * @var array
+ */
+ private $_sp = array();
+
+ /**
+ * IdP data.
+ *
+ * @var array
+ */
+ private $_idp = array();
+
+ /**
+ * Security Info related to the SP.
+ *
+ * @var array
+ */
+ private $_security = array();
+
+ /**
+ * Setting contacts.
+ *
+ * @var array
+ */
+ private $_contacts = array();
+
+ /**
+ * Setting organization.
+ *
+ * @var array
+ */
+ private $_organization = array();
+
+ /**
+ * Setting errors.
+ *
+ * @var array
+ */
+ private $_errors = array();
+
+ /**
+ * Setting errors.
+ *
+ * @var array
+ */
+ private $_spValidationOnly = false;
+
+ /**
+ * Initializes the settings:
+ * - Sets the paths of the different folders
+ * - Loads settings info from settings file or array/object provided
+ *
+ * @param array|object|null $settings SAML Toolkit Settings
+ *
+ * @throws OneLogin_Saml2_Error If any settings parameter is invalid
+ */
+ public function __construct($settings = null, $spValidationOnly = false)
+ {
+ $this->_spValidationOnly = $spValidationOnly;
+ $this->_loadPaths();
+
+ if (!isset($settings)) {
+ if (!$this->_loadSettingsFromFile()) {
+ throw new OneLogin_Saml2_Error(
+ 'Invalid file settings: %s',
+ OneLogin_Saml2_Error::SETTINGS_INVALID,
+ array(implode(', ', $this->_errors))
+ );
+ }
+ $this->_addDefaultValues();
+ } else if (is_array($settings)) {
+ if (!$this->_loadSettingsFromArray($settings)) {
+ throw new OneLogin_Saml2_Error(
+ 'Invalid array settings: %s',
+ OneLogin_Saml2_Error::SETTINGS_INVALID,
+ array(implode(', ', $this->_errors))
+ );
+ }
+ } else {
+ if (!$this->_loadSettingsFromArray($settings->getValues())) {
+ throw new OneLogin_Saml2_Error(
+ 'Invalid array settings: %s',
+ OneLogin_Saml2_Error::SETTINGS_INVALID,
+ array(implode(', ', $this->_errors))
+ );
+ }
+ }
+
+ $this->formatIdPCert();
+ $this->formatSPCert();
+ $this->formatSPKey();
+ }
+
+ /**
+ * Sets the paths of the different folders
+ */
+ private function _loadPaths()
+ {
+ $basePath = dirname(dirname(dirname(__FILE__))).'/';
+ $this->_paths = array (
+ 'base' => $basePath,
+ 'config' => $basePath,
+ 'cert' => $basePath.'certs/',
+ 'lib' => $basePath.'lib/',
+ 'extlib' => $basePath.'extlib/'
+ );
+
+ if (defined('ONELOGIN_CUSTOMPATH')) {
+ $this->_paths['config'] = ONELOGIN_CUSTOMPATH;
+ $this->_paths['cert'] = ONELOGIN_CUSTOMPATH.'certs/';
+ }
+ }
+
+ /**
+ * Returns base path.
+ *
+ * @return string The base toolkit folder path
+ */
+ public function getBasePath()
+ {
+ return $this->_paths['base'];
+ }
+
+ /**
+ * Returns cert path.
+ *
+ * @return string The cert folder path
+ */
+ public function getCertPath()
+ {
+ return $this->_paths['cert'];
+ }
+
+ /**
+ * Returns config path.
+ *
+ * @return string The config folder path
+ */
+ public function getConfigPath()
+ {
+ return $this->_paths['config'];
+ }
+
+ /**
+ * Returns lib path.
+ *
+ * @return string The library folder path
+ */
+ public function getLibPath()
+ {
+ return $this->_paths['lib'];
+ }
+
+ /**
+ * Returns external lib path.
+ *
+ * @return string The external library folder path
+ */
+ public function getExtLibPath()
+ {
+ return $this->_paths['extlib'];
+ }
+
+ /**
+ * Returns schema path.
+ *
+ * @return string The external library folder path
+ */
+ public function getSchemasPath()
+ {
+ return $this->_paths['lib'].'schemas/';
+ }
+
+ /**
+ * Loads settings info from a settings Array
+ *
+ * @param array $settings SAML Toolkit Settings
+ *
+ * @return bool True if the settings info is valid
+ */
+ private function _loadSettingsFromArray($settings)
+ {
+ if (isset($settings['sp'])) {
+ $this->_sp = $settings['sp'];
+ }
+ if (isset($settings['idp'])) {
+ $this->_idp = $settings['idp'];
+ }
+
+ $errors = $this->checkSettings($settings);
+ if (empty($errors)) {
+ $this->_errors = array();
+
+ if (isset($settings['strict'])) {
+ $this->_strict = $settings['strict'];
+ }
+ if (isset($settings['debug'])) {
+ $this->_debug = $settings['debug'];
+ }
+
+ if (isset($settings['security'])) {
+ $this->_security = $settings['security'];
+ }
+
+ if (isset($settings['contactPerson'])) {
+ $this->_contacts = $settings['contactPerson'];
+ }
+
+ if (isset($settings['organization'])) {
+ $this->_organization = $settings['organization'];
+ }
+
+ $this->_addDefaultValues();
+ return true;
+ } else {
+ $this->_errors = $errors;
+ return false;
+ }
+ }
+
+ /**
+ * Loads settings info from the settings file
+ *
+ * @return bool True if the settings info is valid
+ * @throws OneLogin_Saml2_Error
+ */
+ private function _loadSettingsFromFile()
+ {
+ $filename = $this->getConfigPath().'settings.php';
+
+ if (!file_exists($filename)) {
+ throw new OneLogin_Saml2_Error(
+ 'Settings file not found: %s',
+ OneLogin_Saml2_Error::SETTINGS_FILE_NOT_FOUND,
+ array($filename)
+ );
+ }
+
+ include $filename;
+
+ // Add advance_settings if exists
+
+ $advancedFilename = $this->getConfigPath().'advanced_settings.php';
+
+ if (file_exists($advancedFilename)) {
+ include $advancedFilename;
+ $settings = array_merge($settings, $advancedSettings);
+ }
+
+
+ return $this->_loadSettingsFromArray($settings);
+ }
+
+ /**
+ * Add default values if the settings info is not complete
+ */
+ private function _addDefaultValues()
+ {
+ if (!isset($this->_sp['assertionConsumerService']['binding'])) {
+ $this->_sp['assertionConsumerService']['binding'] = OneLogin_Saml2_Constants::BINDING_HTTP_POST;
+ }
+ if (isset($this->_sp['singleLogoutService']) && !isset($this->_sp['singleLogoutService']['binding'])) {
+ $this->_sp['singleLogoutService']['binding'] = OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT;
+ }
+
+ // Related to nameID
+ if (!isset($this->_sp['NameIDFormat'])) {
+ $this->_sp['NameIDFormat'] = OneLogin_Saml2_Constants::NAMEID_UNSPECIFIED;
+ }
+ if (!isset($this->_security['nameIdEncrypted'])) {
+ $this->_security['nameIdEncrypted'] = false;
+ }
+ if (!isset($this->_security['requestedAuthnContext'])) {
+ $this->_security['requestedAuthnContext'] = true;
+ }
+
+ // sign provided
+ if (!isset($this->_security['authnRequestsSigned'])) {
+ $this->_security['authnRequestsSigned'] = false;
+ }
+ if (!isset($this->_security['logoutRequestSigned'])) {
+ $this->_security['logoutRequestSigned'] = false;
+ }
+ if (!isset($this->_security['logoutResponseSigned'])) {
+ $this->_security['logoutResponseSigned'] = false;
+ }
+ if (!isset($this->_security['signMetadata'])) {
+ $this->_security['signMetadata'] = false;
+ }
+
+ // sign expected
+ if (!isset($this->_security['wantMessagesSigned'])) {
+ $this->_security['wantMessagesSigned'] = false;
+ }
+ if (!isset($this->_security['wantAssertionsSigned'])) {
+ $this->_security['wantAssertionsSigned'] = false;
+ }
+
+ // NameID element expected
+ if (!isset($this->_security['wantNameId'])) {
+ $this->_security['wantNameId'] = true;
+ }
+
+ // encrypt expected
+ if (!isset($this->_security['wantAssertionsEncrypted'])) {
+ $this->_security['wantAssertionsEncrypted'] = false;
+ }
+ if (!isset($this->_security['wantNameIdEncrypted'])) {
+ $this->_security['wantNameIdEncrypted'] = false;
+ }
+
+ // XML validation
+ if (!isset($this->_security['wantXMLValidation'])) {
+ $this->_security['wantXMLValidation'] = true;
+ }
+
+ // Algorithm
+ if (!isset($this->_security['signatureAlgorithm'])) {
+ $this->_security['signatureAlgorithm'] = XMLSecurityKey::RSA_SHA1;
+ }
+
+ // Certificates / Private key /Fingerprint
+ if (!isset($this->_idp['x509cert'])) {
+ $this->_idp['x509cert'] = '';
+ }
+ if (!isset($this->_idp['certFingerprint'])) {
+ $this->_idp['certFingerprint'] = '';
+ }
+ if (!isset($this->_idp['certFingerprintAlgorithm'])) {
+ $this->_idp['certFingerprintAlgorithm'] = 'sha1';
+ }
+
+ if (!isset($this->_sp['x509cert'])) {
+ $this->_sp['x509cert'] = '';
+ }
+ if (!isset($this->_sp['privateKey'])) {
+ $this->_sp['privateKey'] = '';
+ }
+ }
+
+ /**
+ * Checks the settings info.
+ *
+ * @param array $settings Array with settings data
+ *
+ * @return array $errors Errors found on the settings data
+ */
+ public function checkSettings($settings)
+ {
+ assert('is_array($settings)');
+
+ if (!is_array($settings) || empty($settings)) {
+ $errors = array('invalid_syntax');
+ } else {
+ $errors = array();
+ if (!$this->_spValidationOnly) {
+ $idpErrors = $this->checkIdPSettings($settings);
+ $errors = array_merge($idpErrors, $errors);
+ }
+ $spErrors = $this->checkSPSettings($settings);
+ $errors = array_merge($spErrors, $errors);
+ }
+
+ return $errors;
+ }
+
+ /**
+ * Checks the IdP settings info.
+ *
+ * @param array $settings Array with settings data
+ *
+ * @return array $errors Errors found on the IdP settings data
+ */
+ public function checkIdPSettings($settings)
+ {
+ assert('is_array($settings)');
+
+ if (!is_array($settings) || empty($settings)) {
+ return array('invalid_syntax');
+ }
+
+ $errors = array();
+
+ if (!isset($settings['idp']) || empty($settings['idp'])) {
+ $errors[] = 'idp_not_found';
+ } else {
+ $idp = $settings['idp'];
+ if (!isset($idp['entityId']) || empty($idp['entityId'])) {
+ $errors[] = 'idp_entityId_not_found';
+ }
+
+ if (!isset($idp['singleSignOnService'])
+ || !isset($idp['singleSignOnService']['url'])
+ || empty($idp['singleSignOnService']['url'])
+ ) {
+ $errors[] = 'idp_sso_not_found';
+ } else if (!filter_var($idp['singleSignOnService']['url'], FILTER_VALIDATE_URL)) {
+ $errors[] = 'idp_sso_url_invalid';
+ }
+
+ if (isset($idp['singleLogoutService'])
+ && isset($idp['singleLogoutService']['url'])
+ && !empty($idp['singleLogoutService']['url'])
+ && !filter_var($idp['singleLogoutService']['url'], FILTER_VALIDATE_URL)
+ ) {
+ $errors[] = 'idp_slo_url_invalid';
+ }
+
+ if (isset($settings['security'])) {
+ $security = $settings['security'];
+
+ $existsX509 = isset($idp['x509cert']) && !empty($idp['x509cert']);
+ $existsFingerprint = isset($idp['certFingerprint']) && !empty($idp['certFingerprint']);
+ if (((isset($security['wantAssertionsSigned']) && $security['wantAssertionsSigned'] == true)
+ || (isset($security['wantMessagesSigned']) && $security['wantMessagesSigned'] == true))
+ && !($existsX509 || $existsFingerprint)
+ ) {
+ $errors[] = 'idp_cert_or_fingerprint_not_found_and_required';
+ }
+ if ((isset($security['nameIdEncrypted']) && $security['nameIdEncrypted'] == true)
+ && !($existsX509)
+ ) {
+ $errors[] = 'idp_cert_not_found_and_required';
+ }
+ }
+ }
+
+ return $errors;
+ }
+
+ /**
+ * Checks the SP settings info.
+ *
+ * @param array $settings Array with settings data
+ *
+ * @return array $errors Errors found on the SP settings data
+ */
+ public function checkSPSettings($settings)
+ {
+ assert('is_array($settings)');
+
+ if (!is_array($settings) || empty($settings)) {
+ return array('invalid_syntax');
+ }
+
+ $errors = array();
+
+ if (!isset($settings['sp']) || empty($settings['sp'])) {
+ $errors[] = 'sp_not_found';
+ } else {
+ $sp = $settings['sp'];
+ $security = array();
+ if (isset($settings['security'])) {
+ $security = $settings['security'];
+ }
+
+ if (!isset($sp['entityId']) || empty($sp['entityId'])) {
+ $errors[] = 'sp_entityId_not_found';
+ }
+
+ if (!isset($sp['assertionConsumerService'])
+ || !isset($sp['assertionConsumerService']['url'])
+ || empty($sp['assertionConsumerService']['url'])
+ ) {
+ $errors[] = 'sp_acs_not_found';
+ } else if (!filter_var($sp['assertionConsumerService']['url'], FILTER_VALIDATE_URL)) {
+ $errors[] = 'sp_acs_url_invalid';
+ }
+
+ if (isset($sp['singleLogoutService'])
+ && isset($sp['singleLogoutService']['url'])
+ && !filter_var($sp['singleLogoutService']['url'], FILTER_VALIDATE_URL)
+ ) {
+ $errors[] = 'sp_sls_url_invalid';
+ }
+
+ if (isset($security['signMetadata']) && is_array($security['signMetadata'])) {
+ if (!isset($security['signMetadata']['keyFileName'])
+ || !isset($security['signMetadata']['certFileName'])
+ ) {
+ $errors[] = 'sp_signMetadata_invalid';
+ }
+ }
+
+ if (((isset($security['authnRequestsSigned']) && $security['authnRequestsSigned'] == true)
+ || (isset($security['logoutRequestSigned']) && $security['logoutRequestSigned'] == true)
+ || (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned'] == true)
+ || (isset($security['wantAssertionsEncrypted']) && $security['wantAssertionsEncrypted'] == true)
+ || (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted'] == true))
+ && !$this->checkSPCerts()
+ ) {
+ $errors[] = 'sp_certs_not_found_and_required';
+ }
+ }
+
+ if (isset($settings['contactPerson'])) {
+ $types = array_keys($settings['contactPerson']);
+ $validTypes = array('technical', 'support', 'administrative', 'billing', 'other');
+ foreach ($types as $type) {
+ if (!in_array($type, $validTypes)) {
+ $errors[] = 'contact_type_invalid';
+ break;
+ }
+ }
+
+ foreach ($settings['contactPerson'] as $type => $contact) {
+ if (!isset($contact['givenName']) || empty($contact['givenName'])
+ || !isset($contact['emailAddress']) || empty($contact['emailAddress'])
+ ) {
+ $errors[] = 'contact_not_enought_data';
+ break;
+ }
+ }
+ }
+
+ if (isset($settings['organization'])) {
+ foreach ($settings['organization'] as $organization) {
+ if (!isset($organization['name']) || empty($organization['name'])
+ || !isset($organization['displayname']) || empty($organization['displayname'])
+ || !isset($organization['url']) || empty($organization['url'])
+ ) {
+ $errors[] = 'organization_not_enought_data';
+ break;
+ }
+ }
+ }
+
+ return $errors;
+ }
+
+ /**
+ * Checks if the x509 certs of the SP exists and are valid.
+ *
+ * @return bool
+ */
+ public function checkSPCerts()
+ {
+ $key = $this->getSPkey();
+ $cert = $this->getSPcert();
+ return (!empty($key) && !empty($cert));
+ }
+
+ /**
+ * Returns the x509 private key of the SP.
+ *
+ * @return string SP private key
+ */
+ public function getSPkey()
+ {
+ $key = null;
+ if (isset($this->_sp['privateKey']) && !empty($this->_sp['privateKey'])) {
+ $key = $this->_sp['privateKey'];
+ } else {
+ $keyFile = $this->_paths['cert'].'sp.key';
+
+ if (file_exists($keyFile)) {
+ $key = file_get_contents($keyFile);
+ }
+ }
+ return $key;
+ }
+
+ /**
+ * Returns the x509 public cert of the SP.
+ *
+ * @return string SP public cert
+ */
+ public function getSPcert()
+ {
+ $cert = null;
+
+ if (isset($this->_sp['x509cert']) && !empty($this->_sp['x509cert'])) {
+ $cert = $this->_sp['x509cert'];
+ } else {
+ $certFile = $this->_paths['cert'].'sp.crt';
+
+ if (file_exists($certFile)) {
+ $cert = file_get_contents($certFile);
+ }
+ }
+ return $cert;
+ }
+
+ /**
+ * Gets the IdP data.
+ *
+ * @return array IdP info
+ */
+ public function getIdPData()
+ {
+ return $this->_idp;
+ }
+
+ /**
+ * Gets the SP data.
+ *
+ * @return array SP info
+ */
+ public function getSPData()
+ {
+ return $this->_sp;
+ }
+
+ /**
+ * Gets security data.
+ *
+ * @return array SP info
+ */
+ public function getSecurityData()
+ {
+ return $this->_security;
+ }
+
+ /**
+ * Gets contact data.
+ *
+ * @return array SP info
+ */
+ public function getContacts()
+ {
+ return $this->_contacts;
+ }
+
+ /**
+ * Gets organization data.
+ *
+ * @return array SP info
+ */
+ public function getOrganization()
+ {
+ return $this->_organization;
+ }
+
+ /**
+ * Gets the SP metadata. The XML representation.
+ *
+ * @return string SP metadata (xml)
+ * @throws Exception
+ * @throws OneLogin_Saml2_Error
+ */
+ public function getSPMetadata()
+ {
+ $metadata = OneLogin_Saml2_Metadata::builder($this->_sp, $this->_security['authnRequestsSigned'], $this->_security['wantAssertionsSigned'], null, null, $this->getContacts(), $this->getOrganization());
+
+ $cert = $this->getSPcert();
+
+ if (!empty($cert)) {
+ $metadata = OneLogin_Saml2_Metadata::addX509KeyDescriptors(
+ $metadata,
+ $cert,
+ $this->_security['wantNameIdEncrypted'] || $this->_security['wantAssertionsEncrypted']
+ );
+ }
+
+ //Sign Metadata
+ if (isset($this->_security['signMetadata']) && $this->_security['signMetadata'] !== false) {
+ if ($this->_security['signMetadata'] === true) {
+ $keyMetadata = $this->getSPkey();
+ $certMetadata = $cert;
+
+ if (!$keyMetadata) {
+ throw new OneLogin_Saml2_Error(
+ 'Private key not found.',
+ OneLogin_Saml2_Error::PRIVATE_KEY_FILE_NOT_FOUND
+ );
+ }
+
+ if (!$certMetadata) {
+ throw new OneLogin_Saml2_Error(
+ 'Public cert file not found.',
+ OneLogin_Saml2_Error::PUBLIC_CERT_FILE_NOT_FOUND
+ );
+ }
+ } else {
+ if (!isset($this->_security['signMetadata']['keyFileName'])
+ || !isset($this->_security['signMetadata']['certFileName'])
+ ) {
+ throw new OneLogin_Saml2_Error(
+ 'Invalid Setting: signMetadata value of the sp is not valid',
+ OneLogin_Saml2_Error::SETTINGS_INVALID_SYNTAX
+ );
+ }
+ $keyFileName = $this->_security['signMetadata']['keyFileName'];
+ $certFileName = $this->_security['signMetadata']['certFileName'];
+
+ $keyMetadataFile = $this->_paths['cert'].$keyFileName;
+ $certMetadataFile = $this->_paths['cert'].$certFileName;
+
+
+ if (!file_exists($keyMetadataFile)) {
+ throw new OneLogin_Saml2_Error(
+ 'Private key file not found: %s',
+ OneLogin_Saml2_Error::PRIVATE_KEY_FILE_NOT_FOUND,
+ array($keyMetadataFile)
+ );
+ }
+
+ if (!file_exists($certMetadataFile)) {
+ throw new OneLogin_Saml2_Error(
+ 'Public cert file not found: %s',
+ OneLogin_Saml2_Error::PUBLIC_CERT_FILE_NOT_FOUND,
+ array($certMetadataFile)
+ );
+ }
+ $keyMetadata = file_get_contents($keyMetadataFile);
+ $certMetadata = file_get_contents($certMetadataFile);
+ }
+
+ $signatureAlgorithm = $this->_security['signatureAlgorithm'];
+ $metadata = OneLogin_Saml2_Metadata::signMetadata($metadata, $keyMetadata, $certMetadata, $signatureAlgorithm);
+ }
+ return $metadata;
+ }
+
+ /**
+ * Validates an XML SP Metadata.
+ *
+ * @param string $xml Metadata's XML that will be validate
+ *
+ * @return Array The list of found errors
+ */
+ public function validateMetadata($xml)
+ {
+ assert('is_string($xml)');
+
+ $errors = array();
+ $res = OneLogin_Saml2_Utils::validateXML($xml, 'saml-schema-metadata-2.0.xsd', $this->_debug);
+ if (!$res instanceof DOMDocument) {
+ $errors[] = $res;
+ } else {
+ $dom = $res;
+ $element = $dom->documentElement;
+ if ($element->tagName !== 'md:EntityDescriptor') {
+ $errors[] = 'noEntityDescriptor_xml';
+ } else {
+ $validUntil = $cacheDuration = $expireTime = null;
+
+ if ($element->hasAttribute('validUntil')) {
+ $validUntil = OneLogin_Saml2_Utils::parseSAML2Time($element->getAttribute('validUntil'));
+ }
+ if ($element->hasAttribute('cacheDuration')) {
+ $cacheDuration = $element->getAttribute('cacheDuration');
+ }
+
+ $expireTime = OneLogin_Saml2_Utils::getExpireTime($cacheDuration, $validUntil);
+ if (isset($expireTime) && time() > $expireTime) {
+ $errors[] = 'expired_xml';
+ }
+ }
+ }
+
+ // TODO: Support Metadata Sign Validation
+
+ return $errors;
+ }
+
+ /**
+ * Formats the IdP cert.
+ */
+ public function formatIdPCert()
+ {
+ if (isset($this->_idp['x509cert'])) {
+ $this->_idp['x509cert'] = OneLogin_Saml2_Utils::formatCert($this->_idp['x509cert']);
+ }
+ }
+
+ /**
+ * Formats the SP cert.
+ */
+ public function formatSPCert()
+ {
+ if (isset($this->_sp['x509cert'])) {
+ $this->_sp['x509cert'] = OneLogin_Saml2_Utils::formatCert($this->_sp['x509cert']);
+ }
+ }
+
+ /**
+ * Formats the SP private key.
+ */
+ public function formatSPKey()
+ {
+ if (isset($this->_sp['privateKey'])) {
+ $this->_sp['privateKey'] = OneLogin_Saml2_Utils::formatPrivateKey($this->_sp['privateKey']);
+ }
+ }
+
+ /**
+ * Returns an array with the errors, the array is empty when the settings is ok.
+ *
+ * @return array Errors
+ */
+ public function getErrors()
+ {
+ return $this->_errors;
+ }
+
+ /**
+ * Activates or deactivates the strict mode.
+ *
+ * @param bool $value Strict parameter
+ */
+ public function setStrict($value)
+ {
+ assert('is_bool($value)');
+
+ $this->_strict = $value;
+ }
+
+ /**
+ * Returns if the 'strict' mode is active.
+ *
+ * @return bool Strict parameter
+ */
+ public function isStrict()
+ {
+ return $this->_strict;
+ }
+
+ /**
+ * Returns if the debug is active.
+ *
+ * @return bool Debug parameter
+ */
+ public function isDebugActive()
+ {
+ return $this->_debug;
+ }
+
+ /**
+ * Sets the IdP certificate.
+ *
+ * @param string $value IdP certificate
+ */
+ public function setIdPCert($cert)
+ {
+ $this->_idp['x509cert'] = $cert;
+ $this->formatIdPCert();
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Utils.php b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Utils.php
new file mode 100644
index 00000000..2d6a4421
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/Utils.php
@@ -0,0 +1,1077 @@
+<?php
+
+/**
+ * Utils of OneLogin PHP Toolkit
+ *
+ * Defines several often used methods
+ */
+
+class OneLogin_Saml2_Utils
+{
+ /**
+ * Translates any string. Accepts args
+ *
+ * @param string $msg Message to be translated
+ * @param array|null $args Arguments
+ *
+ * @return string $translatedMsg Translated text
+ */
+ public static function t($msg, $args = array())
+ {
+ assert('is_string($msg)');
+ if (extension_loaded('gettext')) {
+ bindtextdomain("phptoolkit", dirname(dirname(dirname(__FILE__))).'/locale');
+ textdomain('phptoolkit');
+
+ $translatedMsg = gettext($msg);
+ } else {
+ $translatedMsg = $msg;
+ }
+ if (!empty($args)) {
+ $params = array_merge(array($translatedMsg), $args);
+ $translatedMsg = call_user_func_array('sprintf', $params);
+ }
+ return $translatedMsg;
+ }
+
+ /**
+ * This function load an XML string in a save way.
+ * Prevent XEE/XXE Attacks
+ *
+ * @param DOMDocument $dom The document where load the xml.
+ * @param string $xml The XML string to be loaded.
+ *
+ * @throws Exception
+ *
+ * @return DOMDocument $dom The result of load the XML at the DomDocument
+ */
+ public static function loadXML($dom, $xml)
+ {
+ assert('$dom instanceof DOMDocument');
+ assert('is_string($xml)');
+
+ if (strpos($xml, '<!ENTITY') !== false) {
+ throw new Exception('Detected use of ENTITY in XML, disabled to prevent XXE/XEE attacks');
+ }
+
+ $oldEntityLoader = libxml_disable_entity_loader(true);
+ $res = $dom->loadXML($xml);
+ libxml_disable_entity_loader($oldEntityLoader);
+
+ if (!$res) {
+ return false;
+ } else {
+ return $dom;
+ }
+ }
+
+ /**
+ * This function attempts to validate an XML string against the specified schema.
+ *
+ * It will parse the string into a DOM document and validate this document against the schema.
+ *
+ * @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
+ *
+ * @return string|DOMDocument $dom string that explains the problem or the DOMDocument
+ */
+ public static function validateXML($xml, $schema, $debug = false)
+ {
+ assert('is_string($xml) || $xml instanceof DOMDocument');
+ assert('is_string($schema)');
+
+ libxml_clear_errors();
+ libxml_use_internal_errors(true);
+
+ if ($xml instanceof DOMDocument) {
+ $dom = $xml;
+ } else {
+ $dom = new DOMDocument;
+ $dom = self::loadXML($dom, $xml);
+ if (!$dom) {
+ return 'unloaded_xml';
+ }
+ }
+
+ $schemaFile = dirname(__FILE__).'/schemas/' . $schema;
+ $oldEntityLoader = libxml_disable_entity_loader(false);
+ $res = $dom->schemaValidate($schemaFile);
+ libxml_disable_entity_loader($oldEntityLoader);
+ if (!$res) {
+
+ $xmlErrors = libxml_get_errors();
+ syslog(LOG_INFO, 'Error validating the metadata: '.var_export($xmlErrors, true));
+
+ if ($debug) {
+ foreach ($xmlErrors as $error) {
+ echo $error->message."\n";
+ }
+ }
+
+ return 'invalid_xml';
+ }
+
+
+ return $dom;
+ }
+
+ /**
+ * Returns a x509 cert (adding header & footer if required).
+ *
+ * @param string $cert A x509 unformated cert
+ * @param bool $heads True if we want to include head and footer
+ *
+ * @return string $x509 Formated cert
+ */
+
+ public static function formatCert($cert, $heads = true)
+ {
+ $x509cert = str_replace(array("\x0D", "\r", "\n"), "", $cert);
+ if (!empty($x509cert)) {
+ $x509cert = str_replace('-----BEGIN CERTIFICATE-----', "", $x509cert);
+ $x509cert = str_replace('-----END CERTIFICATE-----', "", $x509cert);
+ $x509cert = str_replace(' ', '', $x509cert);
+
+ if ($heads) {
+ $x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n";
+ }
+
+ }
+ return $x509cert;
+ }
+
+ /**
+ * Returns a private key (adding header & footer if required).
+ *
+ * @param string $key A private key
+ * @param bool $heads True if we want to include head and footer
+ *
+ * @return string $rsaKey Formated private key
+ */
+
+ public static function formatPrivateKey($key, $heads = true)
+ {
+ $key = str_replace(array("\x0D", "\r", "\n"), "", $key);
+ if (!empty($key)) {
+
+ if (strpos($key, '-----BEGIN PRIVATE KEY-----') !== false) {
+ $key = OneLogin_Saml2_Utils::get_string_between($key, '-----BEGIN PRIVATE KEY-----', '-----END PRIVATE KEY-----');
+ $key = str_replace(' ', '', $key);
+
+ if ($heads) {
+ $key = "-----BEGIN PRIVATE KEY-----\n".chunk_split($key, 64, "\n")."-----END PRIVATE KEY-----\n";
+ }
+ } else if (strpos($key, '-----BEGIN RSA PRIVATE KEY-----') !== false) {
+ $key = OneLogin_Saml2_Utils::get_string_between($key, '-----BEGIN RSA PRIVATE KEY-----', '-----END RSA PRIVATE KEY-----');
+ $key = str_replace(' ', '', $key);
+
+ if ($heads) {
+ $key = "-----BEGIN RSA PRIVATE KEY-----\n".chunk_split($key, 64, "\n")."-----END RSA PRIVATE KEY-----\n";
+ }
+ } else {
+ $key = str_replace(' ', '', $key);
+
+ if ($heads) {
+ $key = "-----BEGIN RSA PRIVATE KEY-----\n".chunk_split($key, 64, "\n")."-----END RSA PRIVATE KEY-----\n";
+ }
+ }
+ }
+ return $key;
+ }
+
+ /**
+ * Extracts a substring between 2 marks
+ *
+ * @param string $str The target string
+ * @param string $start The initial mark
+ * @param string $end The end mark
+ *
+ * @return string A substring or an empty string if is not able to find the marks
+ * or if there is no string between the marks
+ */
+ public static function get_string_between($str, $start, $end)
+ {
+ $str = ' ' . $str;
+ $ini = strpos($str, $start);
+
+ if ($ini == 0) {
+ return '';
+ }
+
+ $ini += strlen($start);
+ $len = strpos($str, $end, $ini) - $ini;
+ return substr($str, $ini, $len);
+ }
+
+ /**
+ * Executes a redirection to the provided url (or return the target url).
+ *
+ * @param string $url The target url
+ * @param array $parameters Extra parameters to be passed as part of the url
+ * @param bool $stay True if we want to stay (returns the url string) False to redirect
+ *
+ * @return string|null $url
+ *
+ * @throws OneLogin_Saml2_Error
+ */
+ public static function redirect($url, $parameters = array(), $stay = false)
+ {
+ assert('is_string($url)');
+ assert('is_array($parameters)');
+
+ if (substr($url, 0, 1) === '/') {
+ $url = self::getSelfURLhost() . $url;
+ }
+
+ /* Verify that the URL is to a http or https site. */
+ if (!preg_match('@^https?://@i', $url)) {
+ throw new OneLogin_Saml2_Error(
+ 'Redirect to invalid URL: ' . $url,
+ OneLogin_Saml2_Error::REDIRECT_INVALID_URL
+ );
+ }
+
+
+ /* Add encoded parameters */
+ if (strpos($url, '?') === false) {
+ $paramPrefix = '?';
+ } else {
+ $paramPrefix = '&';
+ }
+
+ foreach ($parameters as $name => $value) {
+
+ if ($value === null) {
+ $param = urlencode($name);
+ } else if (is_array($value)) {
+ $param = "";
+ foreach ($value as $val) {
+ $param .= urlencode($name) . "[]=" . urlencode($val). '&';
+ }
+ if (!empty($param)) {
+ $param = substr($param, 0, -1);
+ }
+ } else {
+ $param = urlencode($name) . '=' . urlencode($value);
+ }
+
+ if (!empty($param)) {
+ $url .= $paramPrefix . $param;
+ $paramPrefix = '&';
+ }
+ }
+
+ if ($stay) {
+ return $url;
+ }
+
+ header('Pragma: no-cache');
+ header('Cache-Control: no-cache, must-revalidate');
+ header('Location: ' . $url);
+ exit();
+ }
+
+ /**
+ * Returns the protocol + the current host + the port (if different than
+ * common ports).
+ *
+ * @return string $url
+ */
+ public static function getSelfURLhost()
+ {
+ $currenthost = self::getSelfHost();
+
+ $port = '';
+
+ if (self::isHTTPS()) {
+ $protocol = 'https';
+ } else {
+ $protocol = 'http';
+ }
+
+ if (isset($_SERVER["HTTP_X_FORWARDED_PORT"])) {
+ $portnumber = $_SERVER["HTTP_X_FORWARDED_PORT"];
+ } else if (isset($_SERVER["SERVER_PORT"])) {
+ $portnumber = $_SERVER["SERVER_PORT"];
+ }
+
+ if (isset($portnumber) && ($portnumber != '80') && ($portnumber != '443')) {
+ $port = ':' . $portnumber;
+ }
+
+ return $protocol."://" . $currenthost . $port;
+ }
+
+ /**
+ * Returns the current host.
+ *
+ * @return string $currentHost The current host
+ */
+ public static function getSelfHost()
+ {
+
+ if (array_key_exists('HTTP_HOST', $_SERVER)) {
+ $currentHost = $_SERVER['HTTP_HOST'];
+ } elseif (array_key_exists('SERVER_NAME', $_SERVER)) {
+ $currentHost = $_SERVER['SERVER_NAME'];
+ } else {
+ if (function_exists('gethostname')) {
+ $currentHost = gethostname();
+ } else {
+ $currentHost = php_uname("n");
+ }
+ }
+
+ if (strstr($currentHost, ":")) {
+ $currentHostData = explode(":", $currentHost);
+ $possiblePort = array_pop($currentHostData);
+ if (is_numeric($possiblePort)) {
+ $currentHost = implode(':', $currentHostData);
+ }
+ }
+ return $currentHost;
+ }
+
+ /**
+ * Checks if https or http.
+ *
+ * @return bool $isHttps False if https is not active
+ */
+ public static function isHTTPS()
+ {
+ $isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
+ || (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)
+ || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https');
+ return $isHttps;
+ }
+
+ /**
+ * Returns the URL of the current host + current view.
+ *
+ * @return string
+ */
+ public static function getSelfURLNoQuery()
+ {
+
+ $selfURLhost = self::getSelfURLhost();
+ $selfURLNoQuery = $selfURLhost . $_SERVER['SCRIPT_NAME'];
+ if (isset($_SERVER['PATH_INFO'])) {
+ $selfURLNoQuery .= $_SERVER['PATH_INFO'];
+ }
+ return $selfURLNoQuery;
+ }
+
+ /**
+ * Returns the routed URL of the current host + current view.
+ *
+ * @return string
+ */
+ public static function getSelfRoutedURLNoQuery()
+ {
+
+ $selfURLhost = self::getSelfURLhost();
+ $route = '';
+ if (!empty($_SERVER['REQUEST_URI'])) {
+ $route = $_SERVER['REQUEST_URI'];
+ if (!empty($_SERVER['QUERY_STRING'])) {
+ $route = str_replace($_SERVER['QUERY_STRING'], '', $route);
+ if (substr($route, -1) == '?') {
+ $route = substr($route, 0, -1);
+ }
+ }
+ }
+
+ $selfRoutedURLNoQuery = $selfURLhost . $route;
+ return $selfRoutedURLNoQuery;
+ }
+
+ /**
+ * Returns the URL of the current host + current view + query.
+ *
+ * @return string
+ */
+ public static function getSelfURL()
+ {
+ $selfURLhost = self::getSelfURLhost();
+
+ $requestURI = '';
+ if (!empty($_SERVER['REQUEST_URI'])) {
+ $requestURI = $_SERVER['REQUEST_URI'];
+ if ($requestURI[0] !== '/') {
+ if (preg_match('#^https?://[^/]*(/.*)#i', $requestURI, $matches)) {
+ $requestURI = $matches[1];
+ }
+ }
+ }
+ return $selfURLhost . $requestURI;
+ }
+
+ /**
+ * Extract a query param - as it was sent - from $_SERVER[QUERY_STRING]
+ *
+ * @param string $name The param to-be extracted
+ *
+ * @return string
+ */
+ public static function extractOriginalQueryParam ($name)
+ {
+ $index = strpos($_SERVER['QUERY_STRING'], $name.'=');
+ $substring = substr($_SERVER['QUERY_STRING'], $index + strlen($name) + 1);
+ $end = strpos($substring, '&');
+ return $end ? substr($substring, 0, strpos($substring, '&')) : $substring;
+ }
+
+ /**
+ * Generates an unique string (used for example as ID for assertions).
+ *
+ * @return string A unique string
+ */
+ public static function generateUniqueID()
+ {
+ return 'ONELOGIN_' . sha1(uniqid(mt_rand(), true));
+ }
+
+ /**
+ * Converts a UNIX timestamp to SAML2 timestamp on the form
+ * yyyy-mm-ddThh:mm:ss(\.s+)?Z.
+ *
+ * @param string $time The time we should convert (DateTime).
+ *
+ * @return string $timestamp SAML2 timestamp.
+ */
+ public static function parseTime2SAML($time)
+ {
+ $defaultTimezone = date_default_timezone_get();
+ date_default_timezone_set('UTC');
+ $timestamp = strftime("%Y-%m-%dT%H:%M:%SZ", $time);
+ date_default_timezone_set($defaultTimezone);
+ return $timestamp;
+ }
+
+ /**
+ * Converts a SAML2 timestamp on the form yyyy-mm-ddThh:mm:ss(\.s+)?Z
+ * to a UNIX timestamp. The sub-second part is ignored.
+ *
+ * @param string $time The time we should convert (SAML Timestamp).
+ *
+ * @return int $timestamp Converted to a unix timestamp.
+ *
+ * @throws Exception
+ */
+ public static function parseSAML2Time($time)
+ {
+ $matches = array();
+
+ /* We use a very strict regex to parse the timestamp. */
+ $exp1 = '/^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)';
+ $exp2 = 'T(\\d\\d):(\\d\\d):(\\d\\d)(?:\\.\\d+)?Z$/D';
+ if (preg_match($exp1 . $exp2, $time, $matches) == 0) {
+ throw new Exception(
+ 'Invalid SAML2 timestamp passed to' .
+ ' parseSAML2Time: ' . $time
+ );
+ }
+
+ /* Extract the different components of the time from the
+ * matches in the regex. intval will ignore leading zeroes
+ * in the string.
+ */
+ $year = intval($matches[1]);
+ $month = intval($matches[2]);
+ $day = intval($matches[3]);
+ $hour = intval($matches[4]);
+ $minute = intval($matches[5]);
+ $second = intval($matches[6]);
+
+ /* We use gmmktime because the timestamp will always be given
+ * in UTC.
+ */
+ $ts = gmmktime($hour, $minute, $second, $month, $day, $year);
+
+ return $ts;
+ }
+
+
+ /**
+ * Interprets a ISO8601 duration value relative to a given timestamp.
+ *
+ * @param string $duration The duration, as a string.
+ * @param int|null $timestamp The unix timestamp we should apply the
+ * duration to. Optional, default to the
+ * current time.
+ *
+ * @return int|null The new timestamp, after the duration is applied.
+ *
+ * @throws Exception
+ */
+ public static function parseDuration($duration, $timestamp = null)
+ {
+ assert('is_string($duration)');
+ assert('is_null($timestamp) || is_int($timestamp)');
+
+ /* Parse the duration. We use a very strict pattern. */
+ $durationRegEx = '#^(-?)P(?:(?:(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?)|(?:(\\d+)W))$#D';
+ if (!preg_match($durationRegEx, $duration, $matches)) {
+ throw new Exception('Invalid ISO 8601 duration: ' . $duration);
+ }
+
+ $durYears = (empty($matches[2]) ? 0 : (int)$matches[2]);
+ $durMonths = (empty($matches[3]) ? 0 : (int)$matches[3]);
+ $durDays = (empty($matches[4]) ? 0 : (int)$matches[4]);
+ $durHours = (empty($matches[5]) ? 0 : (int)$matches[5]);
+ $durMinutes = (empty($matches[6]) ? 0 : (int)$matches[6]);
+ $durSeconds = (empty($matches[7]) ? 0 : (int)$matches[7]);
+ $durWeeks = (empty($matches[8]) ? 0 : (int)$matches[8]);
+
+ if (!empty($matches[1])) {
+ /* Negative */
+ $durYears = -$durYears;
+ $durMonths = -$durMonths;
+ $durDays = -$durDays;
+ $durHours = -$durHours;
+ $durMinutes = -$durMinutes;
+ $durSeconds = -$durSeconds;
+ $durWeeks = -$durWeeks;
+ }
+
+ if ($timestamp === null) {
+ $timestamp = time();
+ }
+
+ if ($durYears !== 0 || $durMonths !== 0) {
+ /* Special handling of months and years, since they aren't a specific interval, but
+ * instead depend on the current time.
+ */
+
+ /* We need the year and month from the timestamp. Unfortunately, PHP doesn't have the
+ * gmtime function. Instead we use the gmdate function, and split the result.
+ */
+ $yearmonth = explode(':', gmdate('Y:n', $timestamp));
+ $year = (int)($yearmonth[0]);
+ $month = (int)($yearmonth[1]);
+
+ /* Remove the year and month from the timestamp. */
+ $timestamp -= gmmktime(0, 0, 0, $month, 1, $year);
+
+ /* Add years and months, and normalize the numbers afterwards. */
+ $year += $durYears;
+ $month += $durMonths;
+ while ($month > 12) {
+ $year += 1;
+ $month -= 12;
+ }
+ while ($month < 1) {
+ $year -= 1;
+ $month += 12;
+ }
+
+ /* Add year and month back into timestamp. */
+ $timestamp += gmmktime(0, 0, 0, $month, 1, $year);
+ }
+
+ /* Add the other elements. */
+ $timestamp += $durWeeks * 7 * 24 * 60 * 60;
+ $timestamp += $durDays * 24 * 60 * 60;
+ $timestamp += $durHours * 60 * 60;
+ $timestamp += $durMinutes * 60;
+ $timestamp += $durSeconds;
+
+ return $timestamp;
+ }
+
+ /**
+ * Compares 2 dates and returns the earliest.
+ *
+ * @param string $cacheDuration The duration, as a string.
+ * @param string $validUntil The valid until date, as a string or as a timestamp
+ *
+ * @return int $expireTime The expiration time.
+ */
+ public static function getExpireTime($cacheDuration = null, $validUntil = null)
+ {
+ $expireTime = null;
+
+ if ($cacheDuration !== null) {
+ $expireTime = self::parseDuration($cacheDuration, time());
+ }
+
+ if ($validUntil !== null) {
+ if (is_int($validUntil)) {
+ $validUntilTime = $validUntil;
+ } else {
+ $validUntilTime = self::parseSAML2Time($validUntil);
+ }
+ if ($expireTime === null || $expireTime > $validUntilTime) {
+ $expireTime = $validUntilTime;
+ }
+ }
+
+ return $expireTime;
+ }
+
+
+ /**
+ * Extracts nodes from the DOMDocument.
+ *
+ * @param DOMDocument $dom The DOMDocument
+ * @param string $query Xpath Expresion
+ * @param DomElement $context Context Node (DomElement)
+ *
+ * @return DOMNodeList The queried nodes
+ */
+ public static function query($dom, $query, $context = null)
+ {
+ $xpath = new DOMXPath($dom);
+ $xpath->registerNamespace('samlp', OneLogin_Saml2_Constants::NS_SAMLP);
+ $xpath->registerNamespace('saml', OneLogin_Saml2_Constants::NS_SAML);
+ $xpath->registerNamespace('ds', OneLogin_Saml2_Constants::NS_DS);
+ $xpath->registerNamespace('xenc', OneLogin_Saml2_Constants::NS_XENC);
+
+ if (isset($context)) {
+ $res = $xpath->query($query, $context);
+ } else {
+ $res = $xpath->query($query);
+ }
+ return $res;
+ }
+
+ /**
+ * Checks if the session is started or not.
+ *
+ * @return bool true if the sessíon is started
+ */
+ public static function isSessionStarted()
+ {
+ if (version_compare(phpversion(), '5.4.0', '>=')) {
+ return session_status() === PHP_SESSION_ACTIVE ? true : false;
+ } else {
+ return session_id() === '' ? false : true;
+ }
+ }
+
+ /**
+ * Deletes the local session.
+ */
+ public static function deleteLocalSession()
+ {
+
+ if (OneLogin_Saml2_Utils::isSessionStarted()) {
+ session_destroy();
+ }
+
+ unset($_SESSION);
+ }
+
+ /**
+ * Calculates the fingerprint of a x509cert.
+ *
+ * @param string $x509cert x509 cert
+ *
+ * @return null|string Formated fingerprint
+ */
+ public static function calculateX509Fingerprint($x509cert, $alg='sha1')
+ {
+ assert('is_string($x509cert)');
+
+ $lines = explode("\n", $x509cert);
+
+ $data = '';
+
+ foreach ($lines as $line) {
+ /* Remove '\r' from end of line if present. */
+ $line = rtrim($line);
+ if ($line === '-----BEGIN CERTIFICATE-----') {
+ /* Delete junk from before the certificate. */
+ $data = '';
+ } elseif ($line === '-----END CERTIFICATE-----') {
+ /* Ignore data after the certificate. */
+ break;
+ } elseif ($line === '-----BEGIN PUBLIC KEY-----' || $line === '-----BEGIN RSA PRIVATE KEY-----') {
+ /* This isn't an X509 certificate. */
+ return null;
+ } else {
+ /* Append the current line to the certificate data. */
+ $data .= $line;
+ }
+ }
+ $decodedData = base64_decode($data);
+
+ switch ($alg) {
+ case 'sha512':
+ case 'sha384':
+ case 'sha256':
+ $fingerprint = hash($alg, $decodedData, FALSE);
+ break;
+ case 'sha1':
+ default:
+ $fingerprint = strtolower(sha1($decodedData));
+ break;
+ }
+ return $fingerprint;
+ }
+
+ /**
+ * Formates a fingerprint.
+ *
+ * @param string $fingerprint fingerprint
+ *
+ * @return string Formated fingerprint
+ */
+ public static function formatFingerPrint($fingerprint)
+ {
+ $formatedFingerprint = str_replace(':', '', $fingerprint);
+ $formatedFingerprint = strtolower($formatedFingerprint);
+ return $formatedFingerprint;
+ }
+
+ /**
+ * Generates a nameID.
+ *
+ * @param string $value fingerprint
+ * @param string $spnq SP Name Qualifier
+ * @param string $format SP Format
+ * @param string|null $cert IdP Public cert to encrypt the nameID
+ *
+ * @return string $nameIDElement DOMElement | XMLSec nameID
+ */
+ public static function generateNameId($value, $spnq, $format, $cert = null)
+ {
+
+ $doc = new DOMDocument();
+
+ $nameId = $doc->createElement('saml:NameID');
+ if (isset($spnq)) {
+ $nameId->setAttribute('SPNameQualifier', $spnq);
+ }
+ $nameId->setAttribute('Format', $format);
+ $nameId->appendChild($doc->createTextNode($value));
+
+ $doc->appendChild($nameId);
+
+ if (!empty($cert)) {
+ $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'public'));
+ $seckey->loadKey($cert);
+
+ $enc = new XMLSecEnc();
+ $enc->setNode($nameId);
+ $enc->type = XMLSecEnc::Element;
+
+ $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
+ $symmetricKey->generateSessionKey();
+ $enc->encryptKey($seckey, $symmetricKey);
+
+ $encryptedData = $enc->encryptNode($symmetricKey);
+
+ $newdoc = new DOMDocument();
+
+ $encryptedID = $newdoc->createElement('saml:EncryptedID');
+
+ $newdoc->appendChild($encryptedID);
+
+ $encryptedID->appendChild($encryptedID->ownerDocument->importNode($encryptedData, true));
+
+ return $newdoc->saveXML($encryptedID);
+ } else {
+ return $doc->saveXML($nameId);
+ }
+ }
+
+
+ /**
+ * Gets Status from a Response.
+ *
+ * @param DOMDocument $dom The Response as XML
+ *
+ * @return array $status The Status, an array with the code and a message.
+ *
+ * @throws Exception
+ */
+ public static function getStatus($dom)
+ {
+ $status = array();
+
+ $statusEntry = self::query($dom, '/samlp:Response/samlp:Status');
+ if ($statusEntry->length == 0) {
+ throw new Exception('Missing Status on response');
+ }
+
+ $codeEntry = self::query($dom, '/samlp:Response/samlp:Status/samlp:StatusCode', $statusEntry->item(0));
+ if ($codeEntry->length == 0) {
+ throw new Exception('Missing Status Code on response');
+ }
+ $code = $codeEntry->item(0)->getAttribute('Value');
+ $status['code'] = $code;
+
+ $messageEntry = self::query($dom, '/samlp:Response/samlp:Status/samlp:StatusMessage', $statusEntry->item(0));
+ if ($messageEntry->length == 0) {
+ $subCodeEntry = self::query($dom, '/samlp:Response/samlp:Status/samlp:StatusCode/samlp:StatusCode', $statusEntry->item(0));
+ if ($subCodeEntry->length > 0) {
+ $status['msg'] = $subCodeEntry->item(0)->getAttribute('Value');
+ } else {
+ $status['msg'] = '';
+ }
+ } else {
+ $msg = $messageEntry->item(0)->textContent;
+ $status['msg'] = $msg;
+ }
+
+ return $status;
+ }
+
+ /**
+ * Decrypts an encrypted element.
+ *
+ * @param DOMElement $encryptedData The encrypted data.
+ * @param XMLSecurityKey $inputKey The decryption key.
+ *
+ * @return DOMElement The decrypted element.
+ *
+ * @throws Exception
+ */
+ public static function decryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey)
+ {
+
+ $enc = new XMLSecEnc();
+
+ $enc->setNode($encryptedData);
+ $enc->type = $encryptedData->getAttribute("Type");
+
+ $symmetricKey = $enc->locateKey($encryptedData);
+ if (!$symmetricKey) {
+ throw new Exception('Could not locate key algorithm in encrypted data.');
+ }
+
+ $symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey);
+ if (!$symmetricKeyInfo) {
+ throw new Exception('Could not locate <dsig:KeyInfo> for the encrypted key.');
+ }
+
+ $inputKeyAlgo = $inputKey->getAlgorithm();
+ if ($symmetricKeyInfo->isEncrypted) {
+ $symKeyInfoAlgo = $symmetricKeyInfo->getAlgorithm();
+
+ if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) {
+ $inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P;
+ }
+
+ if ($inputKeyAlgo !== $symKeyInfoAlgo) {
+ throw new Exception(
+ 'Algorithm mismatch between input key and key used to encrypt ' .
+ ' the symmetric key for the message. Key was: ' .
+ var_export($inputKeyAlgo, true) . '; message was: ' .
+ var_export($symKeyInfoAlgo, true)
+ );
+ }
+
+ $encKey = $symmetricKeyInfo->encryptedCtx;
+ $symmetricKeyInfo->key = $inputKey->key;
+ $keySize = $symmetricKey->getSymmetricKeySize();
+ if ($keySize === null) {
+ // To protect against "key oracle" attacks
+ throw new Exception('Unknown key size for encryption algorithm: ' . var_export($symmetricKey->type, true));
+ }
+
+ $key = $encKey->decryptKey($symmetricKeyInfo);
+ if (strlen($key) != $keySize) {
+ $encryptedKey = $encKey->getCipherValue();
+ $pkey = openssl_pkey_get_details($symmetricKeyInfo->key);
+ $pkey = sha1(serialize($pkey), true);
+ $key = sha1($encryptedKey . $pkey, true);
+
+ /* Make sure that the key has the correct length. */
+ if (strlen($key) > $keySize) {
+ $key = substr($key, 0, $keySize);
+ } elseif (strlen($key) < $keySize) {
+ $key = str_pad($key, $keySize);
+ }
+ }
+ $symmetricKey->loadkey($key);
+ } else {
+ $symKeyAlgo = $symmetricKey->getAlgorithm();
+ if ($inputKeyAlgo !== $symKeyAlgo) {
+ throw new Exception(
+ 'Algorithm mismatch between input key and key in message. ' .
+ 'Key was: ' . var_export($inputKeyAlgo, true) . '; message was: ' .
+ var_export($symKeyAlgo, true)
+ );
+ }
+ $symmetricKey = $inputKey;
+ }
+
+ $decrypted = $enc->decryptNode($symmetricKey, false);
+
+ $xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'.$decrypted.'</root>';
+ $newDoc = new DOMDocument();
+ $newDoc->preserveWhiteSpace = false;
+ $newDoc->formatOutput = true;
+ $newDoc = self::loadXML($newDoc, $xml);
+ if (!$newDoc) {
+ throw new Exception('Failed to parse decrypted XML.');
+ }
+
+ $decryptedElement = $newDoc->firstChild->firstChild;
+ if ($decryptedElement === null) {
+ throw new Exception('Missing encrypted element.');
+ }
+
+ return $decryptedElement;
+ }
+
+ /**
+ * Converts a XMLSecurityKey to the correct algorithm.
+ *
+ * @param XMLSecurityKey $key The key.
+ * @param string $algorithm The desired algorithm.
+ * @param string $type Public or private key, defaults to public.
+ *
+ * @return XMLSecurityKey The new key.
+ *
+ * @throws Exception
+ */
+ public static function castKey(XMLSecurityKey $key, $algorithm, $type = 'public')
+ {
+ assert('is_string($algorithm)');
+ assert('$type === "public" || $type === "private"');
+ // do nothing if algorithm is already the type of the key
+ if ($key->type === $algorithm) {
+ return $key;
+ }
+ $keyInfo = openssl_pkey_get_details($key->key);
+ if ($keyInfo === false) {
+ throw new Exception('Unable to get key details from XMLSecurityKey.');
+ }
+ if (!isset($keyInfo['key'])) {
+ throw new Exception('Missing key in public key details.');
+ }
+ $newKey = new XMLSecurityKey($algorithm, array('type'=>$type));
+ $newKey->loadKey($keyInfo['key']);
+ return $newKey;
+ }
+
+ /**
+ * Adds signature key and senders certificate to an element (Message or Assertion).
+ *
+ * @param string|DomDocument $xml The element we should sign
+ * @param string $key The private key
+ * @param string $cert The public
+ * @param string $signAlgorithm Signature algorithm method
+ *
+ * @return string
+ *
+ * @throws Exception
+ */
+ public static function addSign($xml, $key, $cert, $signAlgorithm = XMLSecurityKey::RSA_SHA1)
+ {
+ if ($xml instanceof DOMDocument) {
+ $dom = $xml;
+ } else {
+ $dom = new DOMDocument();
+ $dom = self::loadXML($dom, $xml);
+ if (!$dom) {
+ throw new Exception('Error parsing xml string');
+ }
+ }
+
+ /* Load the private key. */
+ $objKey = new XMLSecurityKey($signAlgorithm, array('type' => 'private'));
+ $objKey->loadKey($key, false);
+
+ /* Get the EntityDescriptor node we should sign. */
+ $rootNode = $dom->firstChild;
+
+ /* Sign the metadata with our private key. */
+ $objXMLSecDSig = new XMLSecurityDSig();
+ $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
+
+ $objXMLSecDSig->addReferenceList(
+ array($rootNode),
+ XMLSecurityDSig::SHA1,
+ array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N),
+ array('id_name' => 'ID')
+ );
+
+ $objXMLSecDSig->sign($objKey);
+
+ /* Add the certificate to the signature. */
+ $objXMLSecDSig->add509Cert($cert, true);
+
+ $insertBefore = $rootNode->firstChild;
+ $messageTypes = array('AuthnRequest', 'Response', 'LogoutRequest','LogoutResponse');
+ if (in_array($rootNode->localName, $messageTypes)) {
+ $issuerNodes = self::query($dom, '/'.$rootNode->tagName.'/saml:Issuer');
+ if ($issuerNodes->length == 1) {
+ $insertBefore = $issuerNodes->item(0)->nextSibling;
+ }
+ }
+
+ /* Add the signature. */
+ $objXMLSecDSig->insertSignature($rootNode, $insertBefore);
+
+ /* Return the DOM tree as a string. */
+ $signedxml = $dom->saveXML();
+
+ return $signedxml;
+ }
+
+ /**
+ * Validates a signature (Message or Assertion).
+ *
+ * @param string|DomNode $xml The element we should validate
+ * @param string|null $cert The pubic cert
+ * @param string|null $fingerprint The fingerprint of the public cert
+ * @param string|null $fingerprintalg The algorithm used to get the fingerprint
+ *
+ * @return bool
+ *
+ * @throws Exception
+ */
+ public static function validateSign($xml, $cert = null, $fingerprint = null, $fingerprintalg = 'sha1')
+ {
+ if ($xml instanceof DOMDocument) {
+ $dom = clone $xml;
+ } else if ($xml instanceof DOMElement) {
+ $dom = clone $xml->ownerDocument;
+ } else {
+ $dom = new DOMDocument();
+ $dom = self::loadXML($dom, $xml);
+ }
+
+ $objXMLSecDSig = new XMLSecurityDSig();
+ $objXMLSecDSig->idKeys = array('ID');
+
+ $objDSig = $objXMLSecDSig->locateSignature($dom);
+ if (!$objDSig) {
+ throw new Exception('Cannot locate Signature Node');
+ }
+
+ $objKey = $objXMLSecDSig->locateKey();
+ if (!$objKey) {
+ throw new Exception('We have no idea about the key');
+ }
+
+ $objXMLSecDSig->canonicalizeSignedInfo();
+
+ try {
+ $retVal = $objXMLSecDSig->validateReference();
+ } catch (Exception $e) {
+ throw $e;
+ }
+
+ XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);
+
+ if (!empty($cert)) {
+ $objKey->loadKey($cert, false, true);
+ return ($objXMLSecDSig->verify($objKey) === 1);
+ } else {
+ $domCert = $objKey->getX509Certificate();
+ $domCertFingerprint = OneLogin_Saml2_Utils::calculateX509Fingerprint($domCert, $fingerprintalg);
+ if (OneLogin_Saml2_Utils::formatFingerPrint($fingerprint) !== $domCertFingerprint) {
+ return false;
+ } else {
+ $objKey->loadKey($domCert, false, true);
+ return ($objXMLSecDSig->verify($objKey) === 1);
+ }
+ }
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-assertion-2.0.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-assertion-2.0.xsd
new file mode 100644
index 00000000..2b2f7b80
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-assertion-2.0.xsd
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<schema
+ targetNamespace="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
+ elementFormDefault="unqualified"
+ attributeFormDefault="unqualified"
+ blockDefault="substitution"
+ version="2.0">
+ <import namespace="http://www.w3.org/2000/09/xmldsig#"
+ schemaLocation="xmldsig-core-schema.xsd"/>
+ <import namespace="http://www.w3.org/2001/04/xmlenc#"
+ schemaLocation="xenc-schema.xsd"/>
+ <annotation>
+ <documentation>
+ Document identifier: saml-schema-assertion-2.0
+ Location: http://docs.oasis-open.org/security/saml/v2.0/
+ Revision history:
+ V1.0 (November, 2002):
+ Initial Standard Schema.
+ V1.1 (September, 2003):
+ Updates within the same V1.0 namespace.
+ V2.0 (March, 2005):
+ New assertion schema for SAML V2.0 namespace.
+ </documentation>
+ </annotation>
+ <attributeGroup name="IDNameQualifiers">
+ <attribute name="NameQualifier" type="string" use="optional"/>
+ <attribute name="SPNameQualifier" type="string" use="optional"/>
+ </attributeGroup>
+ <element name="BaseID" type="saml:BaseIDAbstractType"/>
+ <complexType name="BaseIDAbstractType" abstract="true">
+ <attributeGroup ref="saml:IDNameQualifiers"/>
+ </complexType>
+ <element name="NameID" type="saml:NameIDType"/>
+ <complexType name="NameIDType">
+ <simpleContent>
+ <extension base="string">
+ <attributeGroup ref="saml:IDNameQualifiers"/>
+ <attribute name="Format" type="anyURI" use="optional"/>
+ <attribute name="SPProvidedID" type="string" use="optional"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+ <complexType name="EncryptedElementType">
+ <sequence>
+ <element ref="xenc:EncryptedData"/>
+ <element ref="xenc:EncryptedKey" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+ <element name="EncryptedID" type="saml:EncryptedElementType"/>
+ <element name="Issuer" type="saml:NameIDType"/>
+ <element name="AssertionIDRef" type="NCName"/>
+ <element name="AssertionURIRef" type="anyURI"/>
+ <element name="Assertion" type="saml:AssertionType"/>
+ <complexType name="AssertionType">
+ <sequence>
+ <element ref="saml:Issuer"/>
+ <element ref="ds:Signature" minOccurs="0"/>
+ <element ref="saml:Subject" minOccurs="0"/>
+ <element ref="saml:Conditions" minOccurs="0"/>
+ <element ref="saml:Advice" minOccurs="0"/>
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="saml:Statement"/>
+ <element ref="saml:AuthnStatement"/>
+ <element ref="saml:AuthzDecisionStatement"/>
+ <element ref="saml:AttributeStatement"/>
+ </choice>
+ </sequence>
+ <attribute name="Version" type="string" use="required"/>
+ <attribute name="ID" type="ID" use="required"/>
+ <attribute name="IssueInstant" type="dateTime" use="required"/>
+ </complexType>
+ <element name="Subject" type="saml:SubjectType"/>
+ <complexType name="SubjectType">
+ <choice>
+ <sequence>
+ <choice>
+ <element ref="saml:BaseID"/>
+ <element ref="saml:NameID"/>
+ <element ref="saml:EncryptedID"/>
+ </choice>
+ <element ref="saml:SubjectConfirmation" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <element ref="saml:SubjectConfirmation" maxOccurs="unbounded"/>
+ </choice>
+ </complexType>
+ <element name="SubjectConfirmation" type="saml:SubjectConfirmationType"/>
+ <complexType name="SubjectConfirmationType">
+ <sequence>
+ <choice minOccurs="0">
+ <element ref="saml:BaseID"/>
+ <element ref="saml:NameID"/>
+ <element ref="saml:EncryptedID"/>
+ </choice>
+ <element ref="saml:SubjectConfirmationData" minOccurs="0"/>
+ </sequence>
+ <attribute name="Method" type="anyURI" use="required"/>
+ </complexType>
+ <element name="SubjectConfirmationData" type="saml:SubjectConfirmationDataType"/>
+ <complexType name="SubjectConfirmationDataType" mixed="true">
+ <complexContent>
+ <restriction base="anyType">
+ <sequence>
+ <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="NotBefore" type="dateTime" use="optional"/>
+ <attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
+ <attribute name="Recipient" type="anyURI" use="optional"/>
+ <attribute name="InResponseTo" type="NCName" use="optional"/>
+ <attribute name="Address" type="string" use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </restriction>
+ </complexContent>
+ </complexType>
+ <complexType name="KeyInfoConfirmationDataType" mixed="false">
+ <complexContent>
+ <restriction base="saml:SubjectConfirmationDataType">
+ <sequence>
+ <element ref="ds:KeyInfo" maxOccurs="unbounded"/>
+ </sequence>
+ </restriction>
+ </complexContent>
+ </complexType>
+ <element name="Conditions" type="saml:ConditionsType"/>
+ <complexType name="ConditionsType">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="saml:Condition"/>
+ <element ref="saml:AudienceRestriction"/>
+ <element ref="saml:OneTimeUse"/>
+ <element ref="saml:ProxyRestriction"/>
+ </choice>
+ <attribute name="NotBefore" type="dateTime" use="optional"/>
+ <attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
+ </complexType>
+ <element name="Condition" type="saml:ConditionAbstractType"/>
+ <complexType name="ConditionAbstractType" abstract="true"/>
+ <element name="AudienceRestriction" type="saml:AudienceRestrictionType"/>
+ <complexType name="AudienceRestrictionType">
+ <complexContent>
+ <extension base="saml:ConditionAbstractType">
+ <sequence>
+ <element ref="saml:Audience" maxOccurs="unbounded"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="Audience" type="anyURI"/>
+ <element name="OneTimeUse" type="saml:OneTimeUseType" />
+ <complexType name="OneTimeUseType">
+ <complexContent>
+ <extension base="saml:ConditionAbstractType"/>
+ </complexContent>
+ </complexType>
+ <element name="ProxyRestriction" type="saml:ProxyRestrictionType"/>
+ <complexType name="ProxyRestrictionType">
+ <complexContent>
+ <extension base="saml:ConditionAbstractType">
+ <sequence>
+ <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Count" type="nonNegativeInteger" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="Advice" type="saml:AdviceType"/>
+ <complexType name="AdviceType">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="saml:AssertionIDRef"/>
+ <element ref="saml:AssertionURIRef"/>
+ <element ref="saml:Assertion"/>
+ <element ref="saml:EncryptedAssertion"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </complexType>
+ <element name="EncryptedAssertion" type="saml:EncryptedElementType"/>
+ <element name="Statement" type="saml:StatementAbstractType"/>
+ <complexType name="StatementAbstractType" abstract="true"/>
+ <element name="AuthnStatement" type="saml:AuthnStatementType"/>
+ <complexType name="AuthnStatementType">
+ <complexContent>
+ <extension base="saml:StatementAbstractType">
+ <sequence>
+ <element ref="saml:SubjectLocality" minOccurs="0"/>
+ <element ref="saml:AuthnContext"/>
+ </sequence>
+ <attribute name="AuthnInstant" type="dateTime" use="required"/>
+ <attribute name="SessionIndex" type="string" use="optional"/>
+ <attribute name="SessionNotOnOrAfter" type="dateTime" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="SubjectLocality" type="saml:SubjectLocalityType"/>
+ <complexType name="SubjectLocalityType">
+ <attribute name="Address" type="string" use="optional"/>
+ <attribute name="DNSName" type="string" use="optional"/>
+ </complexType>
+ <element name="AuthnContext" type="saml:AuthnContextType"/>
+ <complexType name="AuthnContextType">
+ <sequence>
+ <choice>
+ <sequence>
+ <element ref="saml:AuthnContextClassRef"/>
+ <choice minOccurs="0">
+ <element ref="saml:AuthnContextDecl"/>
+ <element ref="saml:AuthnContextDeclRef"/>
+ </choice>
+ </sequence>
+ <choice>
+ <element ref="saml:AuthnContextDecl"/>
+ <element ref="saml:AuthnContextDeclRef"/>
+ </choice>
+ </choice>
+ <element ref="saml:AuthenticatingAuthority" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+ <element name="AuthnContextClassRef" type="anyURI"/>
+ <element name="AuthnContextDeclRef" type="anyURI"/>
+ <element name="AuthnContextDecl" type="anyType"/>
+ <element name="AuthenticatingAuthority" type="anyURI"/>
+ <element name="AuthzDecisionStatement" type="saml:AuthzDecisionStatementType"/>
+ <complexType name="AuthzDecisionStatementType">
+ <complexContent>
+ <extension base="saml:StatementAbstractType">
+ <sequence>
+ <element ref="saml:Action" maxOccurs="unbounded"/>
+ <element ref="saml:Evidence" minOccurs="0"/>
+ </sequence>
+ <attribute name="Resource" type="anyURI" use="required"/>
+ <attribute name="Decision" type="saml:DecisionType" use="required"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <simpleType name="DecisionType">
+ <restriction base="string">
+ <enumeration value="Permit"/>
+ <enumeration value="Deny"/>
+ <enumeration value="Indeterminate"/>
+ </restriction>
+ </simpleType>
+ <element name="Action" type="saml:ActionType"/>
+ <complexType name="ActionType">
+ <simpleContent>
+ <extension base="string">
+ <attribute name="Namespace" type="anyURI" use="required"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+ <element name="Evidence" type="saml:EvidenceType"/>
+ <complexType name="EvidenceType">
+ <choice maxOccurs="unbounded">
+ <element ref="saml:AssertionIDRef"/>
+ <element ref="saml:AssertionURIRef"/>
+ <element ref="saml:Assertion"/>
+ <element ref="saml:EncryptedAssertion"/>
+ </choice>
+ </complexType>
+ <element name="AttributeStatement" type="saml:AttributeStatementType"/>
+ <complexType name="AttributeStatementType">
+ <complexContent>
+ <extension base="saml:StatementAbstractType">
+ <choice maxOccurs="unbounded">
+ <element ref="saml:Attribute"/>
+ <element ref="saml:EncryptedAttribute"/>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="Attribute" type="saml:AttributeType"/>
+ <complexType name="AttributeType">
+ <sequence>
+ <element ref="saml:AttributeValue" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Name" type="string" use="required"/>
+ <attribute name="NameFormat" type="anyURI" use="optional"/>
+ <attribute name="FriendlyName" type="string" use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+ <element name="AttributeValue" type="anyType" nillable="true"/>
+ <element name="EncryptedAttribute" type="saml:EncryptedElementType"/>
+</schema>
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-authn-context-2.0.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-authn-context-2.0.xsd
new file mode 100644
index 00000000..e4754faf
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-authn-context-2.0.xsd
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema
+ targetNamespace="urn:oasis:names:tc:SAML:2.0:ac"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns="urn:oasis:names:tc:SAML:2.0:ac"
+ blockDefault="substitution"
+ version="2.0">
+
+ <xs:annotation>
+ <xs:documentation>
+ Document identifier: saml-schema-authn-context-2.0
+ Location: http://docs.oasis-open.org/security/saml/v2.0/
+ Revision history:
+ V2.0 (March, 2005):
+ New core authentication context schema for SAML V2.0.
+ This is just an include of all types from the schema
+ referred to in the include statement below.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:include schemaLocation="saml-schema-authn-context-types-2.0.xsd"/>
+
+</xs:schema> \ No newline at end of file
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-authn-context-types-2.0.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-authn-context-types-2.0.xsd
new file mode 100644
index 00000000..8513959a
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-authn-context-types-2.0.xsd
@@ -0,0 +1,821 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified"
+ version="2.0">
+
+ <xs:annotation>
+ <xs:documentation>
+ Document identifier: saml-schema-authn-context-types-2.0
+ Location: http://docs.oasis-open.org/security/saml/v2.0/
+ Revision history:
+ V2.0 (March, 2005):
+ New core authentication context schema types for SAML V2.0.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:element name="AuthenticationContextDeclaration" type="AuthnContextDeclarationBaseType">
+ <xs:annotation>
+ <xs:documentation>
+ A particular assertion on an identity
+ provider's part with respect to the authentication
+ context associated with an authentication assertion.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="Identification" type="IdentificationType">
+ <xs:annotation>
+ <xs:documentation>
+ Refers to those characteristics that describe the
+ processes and mechanisms
+ the Authentication Authority uses to initially create
+ an association between a Principal
+ and the identity (or name) by which the Principal will
+ be known
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="PhysicalVerification">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that identification has been
+ performed in a physical
+ face-to-face meeting with the principal and not in an
+ online manner.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="credentialLevel">
+ <xs:simpleType>
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="primary"/>
+ <xs:enumeration value="secondary"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="WrittenConsent" type="ExtensionOnlyType"/>
+
+ <xs:element name="TechnicalProtection" type="TechnicalProtectionBaseType">
+ <xs:annotation>
+ <xs:documentation>
+ Refers to those characterstics that describe how the
+ 'secret' (the knowledge or possession
+ of which allows the Principal to authenticate to the
+ Authentication Authority) is kept secure
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="SecretKeyProtection" type="SecretKeyProtectionType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates the types and strengths of
+ facilities
+ of a UA used to protect a shared secret key from
+ unauthorized access and/or use.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="PrivateKeyProtection" type="PrivateKeyProtectionType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates the types and strengths of
+ facilities
+ of a UA used to protect a private key from
+ unauthorized access and/or use.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="KeyActivation" type="KeyActivationType">
+ <xs:annotation>
+ <xs:documentation>The actions that must be performed
+ before the private key can be used. </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="KeySharing" type="KeySharingType">
+ <xs:annotation>
+ <xs:documentation>Whether or not the private key is shared
+ with the certificate authority.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="KeyStorage" type="KeyStorageType">
+ <xs:annotation>
+ <xs:documentation>
+ In which medium is the key stored.
+ memory - the key is stored in memory.
+ smartcard - the key is stored in a smartcard.
+ token - the key is stored in a hardware token.
+ MobileDevice - the key is stored in a mobile device.
+ MobileAuthCard - the key is stored in a mobile
+ authentication card.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="SubscriberLineNumber" type="ExtensionOnlyType"/>
+ <xs:element name="UserSuffix" type="ExtensionOnlyType"/>
+
+ <xs:element name="Password" type="PasswordType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that a password (or passphrase)
+ has been used to
+ authenticate the Principal to a remote system.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="ActivationPin" type="ActivationPinType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that a Pin (Personal
+ Identification Number) has been used to authenticate the Principal to
+ some local system in order to activate a key.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="Token" type="TokenType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that a hardware or software
+ token is used
+ as a method of identifying the Principal.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="TimeSyncToken" type="TimeSyncTokenType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that a time synchronization
+ token is used to identify the Principal. hardware -
+ the time synchonization
+ token has been implemented in hardware. software - the
+ time synchronization
+ token has been implemented in software. SeedLength -
+ the length, in bits, of the
+ random seed used in the time synchronization token.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="Smartcard" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that a smartcard is used to
+ identity the Principal.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="Length" type="LengthType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates the minimum and/or maximum
+ ASCII length of the password which is enforced (by the UA or the
+ IdP). In other words, this is the minimum and/or maximum number of
+ ASCII characters required to represent a valid password.
+ min - the minimum number of ASCII characters required
+ in a valid password, as enforced by the UA or the IdP.
+ max - the maximum number of ASCII characters required
+ in a valid password, as enforced by the UA or the IdP.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="ActivationLimit" type="ActivationLimitType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates the length of time for which an
+ PIN-based authentication is valid.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="Generation">
+ <xs:annotation>
+ <xs:documentation>
+ Indicates whether the password was chosen by the
+ Principal or auto-supplied by the Authentication Authority.
+ principalchosen - the Principal is allowed to choose
+ the value of the password. This is true even if
+ the initial password is chosen at random by the UA or
+ the IdP and the Principal is then free to change
+ the password.
+ automatic - the password is chosen by the UA or the
+ IdP to be cryptographically strong in some sense,
+ or to satisfy certain password rules, and that the
+ Principal is not free to change it or to choose a new password.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:complexType>
+ <xs:attribute name="mechanism" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="principalchosen"/>
+ <xs:enumeration value="automatic"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="AuthnMethod" type="AuthnMethodBaseType">
+ <xs:annotation>
+ <xs:documentation>
+ Refers to those characteristics that define the
+ mechanisms by which the Principal authenticates to the Authentication
+ Authority.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="PrincipalAuthenticationMechanism" type="PrincipalAuthenticationMechanismType">
+ <xs:annotation>
+ <xs:documentation>
+ The method that a Principal employs to perform
+ authentication to local system components.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="Authenticator" type="AuthenticatorBaseType">
+ <xs:annotation>
+ <xs:documentation>
+ The method applied to validate a principal's
+ authentication across a network
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="ComplexAuthenticator" type="ComplexAuthenticatorType">
+ <xs:annotation>
+ <xs:documentation>
+ Supports Authenticators with nested combinations of
+ additional complexity.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="PreviousSession" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ Indicates that the Principal has been strongly
+ authenticated in a previous session during which the IdP has set a
+ cookie in the UA. During the present session the Principal has only
+ been authenticated by the UA returning the cookie to the IdP.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="ResumeSession" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ Rather like PreviousSession but using stronger
+ security. A secret that was established in a previous session with
+ the Authentication Authority has been cached by the local system and
+ is now re-used (e.g. a Master Secret is used to derive new session
+ keys in TLS, SSL, WTLS).
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="ZeroKnowledge" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Principal has been
+ authenticated by a zero knowledge technique as specified in ISO/IEC
+ 9798-5.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="SharedSecretChallengeResponse" type="SharedSecretChallengeResponseType"/>
+
+ <xs:complexType name="SharedSecretChallengeResponseType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Principal has been
+ authenticated by a challenge-response protocol utilizing shared secret
+ keys and symmetric cryptography.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="method" type="xs:anyURI" use="optional"/>
+ </xs:complexType>
+
+ <xs:element name="DigSig" type="PublicKeyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Principal has been
+ authenticated by a mechanism which involves the Principal computing a
+ digital signature over at least challenge data provided by the IdP.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="AsymmetricDecryption" type="PublicKeyType">
+ <xs:annotation>
+ <xs:documentation>
+ The local system has a private key but it is used
+ in decryption mode, rather than signature mode. For example, the
+ Authentication Authority generates a secret and encrypts it using the
+ local system's public key: the local system then proves it has
+ decrypted the secret.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="AsymmetricKeyAgreement" type="PublicKeyType">
+ <xs:annotation>
+ <xs:documentation>
+ The local system has a private key and uses it for
+ shared secret key agreement with the Authentication Authority (e.g.
+ via Diffie Helman).
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:complexType name="PublicKeyType">
+ <xs:sequence>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="keyValidation" use="optional"/>
+ </xs:complexType>
+
+ <xs:element name="IPAddress" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Principal has been
+ authenticated through connection from a particular IP address.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="SharedSecretDynamicPlaintext" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ The local system and Authentication Authority
+ share a secret key. The local system uses this to encrypt a
+ randomised string to pass to the Authentication Authority.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="AuthenticatorTransportProtocol" type="AuthenticatorTransportProtocolType">
+ <xs:annotation>
+ <xs:documentation>
+ The protocol across which Authenticator information is
+ transferred to an Authentication Authority verifier.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="HTTP" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Authenticator has been
+ transmitted using bare HTTP utilizing no additional security
+ protocols.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="IPSec" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Authenticator has been
+ transmitted using a transport mechanism protected by an IPSEC session.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="WTLS" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Authenticator has been
+ transmitted using a transport mechanism protected by a WTLS session.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="MobileNetworkNoEncryption" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Authenticator has been
+ transmitted solely across a mobile network using no additional
+ security mechanism.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="MobileNetworkRadioEncryption" type="ExtensionOnlyType"/>
+ <xs:element name="MobileNetworkEndToEndEncryption" type="ExtensionOnlyType"/>
+
+ <xs:element name="SSL" type="ExtensionOnlyType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Authenticator has been
+ transmitted using a transport mechnanism protected by an SSL or TLS
+ session.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="PSTN" type="ExtensionOnlyType"/>
+ <xs:element name="ISDN" type="ExtensionOnlyType"/>
+ <xs:element name="ADSL" type="ExtensionOnlyType"/>
+
+ <xs:element name="OperationalProtection" type="OperationalProtectionType">
+ <xs:annotation>
+ <xs:documentation>
+ Refers to those characteristics that describe
+ procedural security controls employed by the Authentication Authority.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="SecurityAudit" type="SecurityAuditType"/>
+ <xs:element name="SwitchAudit" type="ExtensionOnlyType"/>
+ <xs:element name="DeactivationCallCenter" type="ExtensionOnlyType"/>
+
+ <xs:element name="GoverningAgreements" type="GoverningAgreementsType">
+ <xs:annotation>
+ <xs:documentation>
+ Provides a mechanism for linking to external (likely
+ human readable) documents in which additional business agreements,
+ (e.g. liability constraints, obligations, etc) can be placed.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="GoverningAgreementRef" type="GoverningAgreementRefType"/>
+
+ <xs:simpleType name="nymType">
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="anonymity"/>
+ <xs:enumeration value="verinymity"/>
+ <xs:enumeration value="pseudonymity"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="AuthnContextDeclarationBaseType">
+ <xs:sequence>
+ <xs:element ref="Identification" minOccurs="0"/>
+ <xs:element ref="TechnicalProtection" minOccurs="0"/>
+ <xs:element ref="OperationalProtection" minOccurs="0"/>
+ <xs:element ref="AuthnMethod" minOccurs="0"/>
+ <xs:element ref="GoverningAgreements" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="ID" type="xs:ID" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="IdentificationType">
+ <xs:sequence>
+ <xs:element ref="PhysicalVerification" minOccurs="0"/>
+ <xs:element ref="WrittenConsent" minOccurs="0"/>
+ <xs:element ref="GoverningAgreements" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="nym" type="nymType">
+ <xs:annotation>
+ <xs:documentation>
+ This attribute indicates whether or not the
+ Identification mechanisms allow the actions of the Principal to be
+ linked to an actual end user.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="TechnicalProtectionBaseType">
+ <xs:sequence>
+ <xs:choice minOccurs="0">
+ <xs:element ref="PrivateKeyProtection"/>
+ <xs:element ref="SecretKeyProtection"/>
+ </xs:choice>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="OperationalProtectionType">
+ <xs:sequence>
+ <xs:element ref="SecurityAudit" minOccurs="0"/>
+ <xs:element ref="DeactivationCallCenter" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="AuthnMethodBaseType">
+ <xs:sequence>
+ <xs:element ref="PrincipalAuthenticationMechanism" minOccurs="0"/>
+ <xs:element ref="Authenticator" minOccurs="0"/>
+ <xs:element ref="AuthenticatorTransportProtocol" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="GoverningAgreementsType">
+ <xs:sequence>
+ <xs:element ref="GoverningAgreementRef" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="GoverningAgreementRefType">
+ <xs:attribute name="governingAgreementRef" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="PrincipalAuthenticationMechanismType">
+ <xs:sequence>
+ <xs:element ref="Password" minOccurs="0"/>
+ <xs:element ref="RestrictedPassword" minOccurs="0"/>
+ <xs:element ref="Token" minOccurs="0"/>
+ <xs:element ref="Smartcard" minOccurs="0"/>
+ <xs:element ref="ActivationPin" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="preauth" type="xs:integer" use="optional"/>
+ </xs:complexType>
+
+ <xs:group name="AuthenticatorChoiceGroup">
+ <xs:choice>
+ <xs:element ref="PreviousSession"/>
+ <xs:element ref="ResumeSession"/>
+ <xs:element ref="DigSig"/>
+ <xs:element ref="Password"/>
+ <xs:element ref="RestrictedPassword"/>
+ <xs:element ref="ZeroKnowledge"/>
+ <xs:element ref="SharedSecretChallengeResponse"/>
+ <xs:element ref="SharedSecretDynamicPlaintext"/>
+ <xs:element ref="IPAddress"/>
+ <xs:element ref="AsymmetricDecryption"/>
+ <xs:element ref="AsymmetricKeyAgreement"/>
+ <xs:element ref="SubscriberLineNumber"/>
+ <xs:element ref="UserSuffix"/>
+ <xs:element ref="ComplexAuthenticator"/>
+ </xs:choice>
+ </xs:group>
+
+ <xs:group name="AuthenticatorSequenceGroup">
+ <xs:sequence>
+ <xs:element ref="PreviousSession" minOccurs="0"/>
+ <xs:element ref="ResumeSession" minOccurs="0"/>
+ <xs:element ref="DigSig" minOccurs="0"/>
+ <xs:element ref="Password" minOccurs="0"/>
+ <xs:element ref="RestrictedPassword" minOccurs="0"/>
+ <xs:element ref="ZeroKnowledge" minOccurs="0"/>
+ <xs:element ref="SharedSecretChallengeResponse" minOccurs="0"/>
+ <xs:element ref="SharedSecretDynamicPlaintext" minOccurs="0"/>
+ <xs:element ref="IPAddress" minOccurs="0"/>
+ <xs:element ref="AsymmetricDecryption" minOccurs="0"/>
+ <xs:element ref="AsymmetricKeyAgreement" minOccurs="0"/>
+ <xs:element ref="SubscriberLineNumber" minOccurs="0"/>
+ <xs:element ref="UserSuffix" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:group>
+
+ <xs:complexType name="AuthenticatorBaseType">
+ <xs:sequence>
+ <xs:group ref="AuthenticatorChoiceGroup"/>
+ <xs:group ref="AuthenticatorSequenceGroup"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="ComplexAuthenticatorType">
+ <xs:sequence>
+ <xs:group ref="AuthenticatorChoiceGroup"/>
+ <xs:group ref="AuthenticatorSequenceGroup"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="AuthenticatorTransportProtocolType">
+ <xs:sequence>
+ <xs:choice minOccurs="0">
+ <xs:element ref="HTTP"/>
+ <xs:element ref="SSL"/>
+ <xs:element ref="MobileNetworkNoEncryption"/>
+ <xs:element ref="MobileNetworkRadioEncryption"/>
+ <xs:element ref="MobileNetworkEndToEndEncryption"/>
+ <xs:element ref="WTLS"/>
+ <xs:element ref="IPSec"/>
+ <xs:element ref="PSTN"/>
+ <xs:element ref="ISDN"/>
+ <xs:element ref="ADSL"/>
+ </xs:choice>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="KeyActivationType">
+ <xs:sequence>
+ <xs:element ref="ActivationPin" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="KeySharingType">
+ <xs:attribute name="sharing" type="xs:boolean" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="PrivateKeyProtectionType">
+ <xs:sequence>
+ <xs:element ref="KeyActivation" minOccurs="0"/>
+ <xs:element ref="KeyStorage" minOccurs="0"/>
+ <xs:element ref="KeySharing" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="PasswordType">
+ <xs:sequence>
+ <xs:element ref="Length" minOccurs="0"/>
+ <xs:element ref="Alphabet" minOccurs="0"/>
+ <xs:element ref="Generation" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="ExternalVerification" type="xs:anyURI" use="optional"/>
+ </xs:complexType>
+
+ <xs:element name="RestrictedPassword" type="RestrictedPasswordType"/>
+
+ <xs:complexType name="RestrictedPasswordType">
+ <xs:complexContent>
+ <xs:restriction base="PasswordType">
+ <xs:sequence>
+ <xs:element name="Length" type="RestrictedLengthType" minOccurs="1"/>
+ <xs:element ref="Generation" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="ExternalVerification" type="xs:anyURI" use="optional"/>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:complexType name="RestrictedLengthType">
+ <xs:complexContent>
+ <xs:restriction base="LengthType">
+ <xs:attribute name="min" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:integer">
+ <xs:minInclusive value="3"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="max" type="xs:integer" use="optional"/>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:complexType name="ActivationPinType">
+ <xs:sequence>
+ <xs:element ref="Length" minOccurs="0"/>
+ <xs:element ref="Alphabet" minOccurs="0"/>
+ <xs:element ref="Generation" minOccurs="0"/>
+ <xs:element ref="ActivationLimit" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:element name="Alphabet" type="AlphabetType"/>
+ <xs:complexType name="AlphabetType">
+ <xs:attribute name="requiredChars" type="xs:string" use="required"/>
+ <xs:attribute name="excludedChars" type="xs:string" use="optional"/>
+ <xs:attribute name="case" type="xs:string" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="TokenType">
+ <xs:sequence>
+ <xs:element ref="TimeSyncToken"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:simpleType name="DeviceTypeType">
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="hardware"/>
+ <xs:enumeration value="software"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="booleanType">
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="true"/>
+ <xs:enumeration value="false"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="TimeSyncTokenType">
+ <xs:attribute name="DeviceType" type="DeviceTypeType" use="required"/>
+ <xs:attribute name="SeedLength" type="xs:integer" use="required"/>
+ <xs:attribute name="DeviceInHand" type="booleanType" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="ActivationLimitType">
+ <xs:choice>
+ <xs:element ref="ActivationLimitDuration"/>
+ <xs:element ref="ActivationLimitUsages"/>
+ <xs:element ref="ActivationLimitSession"/>
+ </xs:choice>
+ </xs:complexType>
+
+ <xs:element name="ActivationLimitDuration" type="ActivationLimitDurationType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Key Activation Limit is
+ defined as a specific duration of time.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="ActivationLimitUsages" type="ActivationLimitUsagesType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Key Activation Limit is
+ defined as a number of usages.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:element name="ActivationLimitSession" type="ActivationLimitSessionType">
+ <xs:annotation>
+ <xs:documentation>
+ This element indicates that the Key Activation Limit is
+ the session.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:complexType name="ActivationLimitDurationType">
+ <xs:attribute name="duration" type="xs:duration" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="ActivationLimitUsagesType">
+ <xs:attribute name="number" type="xs:integer" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="ActivationLimitSessionType"/>
+
+ <xs:complexType name="LengthType">
+ <xs:attribute name="min" type="xs:integer" use="required"/>
+ <xs:attribute name="max" type="xs:integer" use="optional"/>
+ </xs:complexType>
+
+ <xs:simpleType name="mediumType">
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="memory"/>
+ <xs:enumeration value="smartcard"/>
+ <xs:enumeration value="token"/>
+ <xs:enumeration value="MobileDevice"/>
+ <xs:enumeration value="MobileAuthCard"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="KeyStorageType">
+ <xs:attribute name="medium" type="mediumType" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="SecretKeyProtectionType">
+ <xs:sequence>
+ <xs:element ref="KeyActivation" minOccurs="0"/>
+ <xs:element ref="KeyStorage" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="SecurityAuditType">
+ <xs:sequence>
+ <xs:element ref="SwitchAudit" minOccurs="0"/>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="ExtensionOnlyType">
+ <xs:sequence>
+ <xs:element ref="Extension" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:element name="Extension" type="ExtensionType"/>
+
+ <xs:complexType name="ExtensionType">
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+</xs:schema>
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-metadata-2.0.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-metadata-2.0.xsd
new file mode 100644
index 00000000..86e58f9b
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-metadata-2.0.xsd
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema
+ targetNamespace="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="unqualified"
+ attributeFormDefault="unqualified"
+ blockDefault="substitution"
+ version="2.0">
+ <import namespace="http://www.w3.org/2000/09/xmldsig#"
+ schemaLocation="xmldsig-core-schema.xsd"/>
+ <import namespace="http://www.w3.org/2001/04/xmlenc#"
+ schemaLocation="xenc-schema.xsd"/>
+ <import namespace="urn:oasis:names:tc:SAML:2.0:assertion"
+ schemaLocation="saml-schema-assertion-2.0.xsd"/>
+ <import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="xml.xsd"/>
+ <annotation>
+ <documentation>
+ Document identifier: saml-schema-metadata-2.0
+ Location: http://docs.oasis-open.org/security/saml/v2.0/
+ Revision history:
+ V2.0 (March, 2005):
+ Schema for SAML metadata, first published in SAML 2.0.
+ </documentation>
+ </annotation>
+
+ <simpleType name="entityIDType">
+ <restriction base="anyURI">
+ <maxLength value="1024"/>
+ </restriction>
+ </simpleType>
+ <complexType name="localizedNameType">
+ <simpleContent>
+ <extension base="string">
+ <attribute ref="xml:lang" use="required"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+ <complexType name="localizedURIType">
+ <simpleContent>
+ <extension base="anyURI">
+ <attribute ref="xml:lang" use="required"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+
+ <element name="Extensions" type="md:ExtensionsType"/>
+ <complexType final="#all" name="ExtensionsType">
+ <sequence>
+ <any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="EndpointType">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Binding" type="anyURI" use="required"/>
+ <attribute name="Location" type="anyURI" use="required"/>
+ <attribute name="ResponseLocation" type="anyURI" use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <complexType name="IndexedEndpointType">
+ <complexContent>
+ <extension base="md:EndpointType">
+ <attribute name="index" type="unsignedShort" use="required"/>
+ <attribute name="isDefault" type="boolean" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <element name="EntitiesDescriptor" type="md:EntitiesDescriptorType"/>
+ <complexType name="EntitiesDescriptorType">
+ <sequence>
+ <element ref="ds:Signature" minOccurs="0"/>
+ <element ref="md:Extensions" minOccurs="0"/>
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element ref="md:EntityDescriptor"/>
+ <element ref="md:EntitiesDescriptor"/>
+ </choice>
+ </sequence>
+ <attribute name="validUntil" type="dateTime" use="optional"/>
+ <attribute name="cacheDuration" type="duration" use="optional"/>
+ <attribute name="ID" type="ID" use="optional"/>
+ <attribute name="Name" type="string" use="optional"/>
+ </complexType>
+
+ <element name="EntityDescriptor" type="md:EntityDescriptorType"/>
+ <complexType name="EntityDescriptorType">
+ <sequence>
+ <element ref="ds:Signature" minOccurs="0"/>
+ <element ref="md:Extensions" minOccurs="0"/>
+ <choice>
+ <choice maxOccurs="unbounded">
+ <element ref="md:RoleDescriptor"/>
+ <element ref="md:IDPSSODescriptor"/>
+ <element ref="md:SPSSODescriptor"/>
+ <element ref="md:AuthnAuthorityDescriptor"/>
+ <element ref="md:AttributeAuthorityDescriptor"/>
+ <element ref="md:PDPDescriptor"/>
+ </choice>
+ <element ref="md:AffiliationDescriptor"/>
+ </choice>
+ <element ref="md:Organization" minOccurs="0"/>
+ <element ref="md:ContactPerson" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:AdditionalMetadataLocation" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="entityID" type="md:entityIDType" use="required"/>
+ <attribute name="validUntil" type="dateTime" use="optional"/>
+ <attribute name="cacheDuration" type="duration" use="optional"/>
+ <attribute name="ID" type="ID" use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <element name="Organization" type="md:OrganizationType"/>
+ <complexType name="OrganizationType">
+ <sequence>
+ <element ref="md:Extensions" minOccurs="0"/>
+ <element ref="md:OrganizationName" maxOccurs="unbounded"/>
+ <element ref="md:OrganizationDisplayName" maxOccurs="unbounded"/>
+ <element ref="md:OrganizationURL" maxOccurs="unbounded"/>
+ </sequence>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+ <element name="OrganizationName" type="md:localizedNameType"/>
+ <element name="OrganizationDisplayName" type="md:localizedNameType"/>
+ <element name="OrganizationURL" type="md:localizedURIType"/>
+ <element name="ContactPerson" type="md:ContactType"/>
+ <complexType name="ContactType">
+ <sequence>
+ <element ref="md:Extensions" minOccurs="0"/>
+ <element ref="md:Company" minOccurs="0"/>
+ <element ref="md:GivenName" minOccurs="0"/>
+ <element ref="md:SurName" minOccurs="0"/>
+ <element ref="md:EmailAddress" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:TelephoneNumber" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="contactType" type="md:ContactTypeType" use="required"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+ <element name="Company" type="string"/>
+ <element name="GivenName" type="string"/>
+ <element name="SurName" type="string"/>
+ <element name="EmailAddress" type="anyURI"/>
+ <element name="TelephoneNumber" type="string"/>
+ <simpleType name="ContactTypeType">
+ <restriction base="string">
+ <enumeration value="technical"/>
+ <enumeration value="support"/>
+ <enumeration value="administrative"/>
+ <enumeration value="billing"/>
+ <enumeration value="other"/>
+ </restriction>
+ </simpleType>
+
+ <element name="AdditionalMetadataLocation" type="md:AdditionalMetadataLocationType"/>
+ <complexType name="AdditionalMetadataLocationType">
+ <simpleContent>
+ <extension base="anyURI">
+ <attribute name="namespace" type="anyURI" use="required"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+
+ <element name="RoleDescriptor" type="md:RoleDescriptorType"/>
+ <complexType name="RoleDescriptorType" abstract="true">
+ <sequence>
+ <element ref="ds:Signature" minOccurs="0"/>
+ <element ref="md:Extensions" minOccurs="0"/>
+ <element ref="md:KeyDescriptor" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:Organization" minOccurs="0"/>
+ <element ref="md:ContactPerson" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="ID" type="ID" use="optional"/>
+ <attribute name="validUntil" type="dateTime" use="optional"/>
+ <attribute name="cacheDuration" type="duration" use="optional"/>
+ <attribute name="protocolSupportEnumeration" type="md:anyURIListType" use="required"/>
+ <attribute name="errorURL" type="anyURI" use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+ <simpleType name="anyURIListType">
+ <list itemType="anyURI"/>
+ </simpleType>
+
+ <element name="KeyDescriptor" type="md:KeyDescriptorType"/>
+ <complexType name="KeyDescriptorType">
+ <sequence>
+ <element ref="ds:KeyInfo"/>
+ <element ref="md:EncryptionMethod" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="use" type="md:KeyTypes" use="optional"/>
+ </complexType>
+ <simpleType name="KeyTypes">
+ <restriction base="string">
+ <enumeration value="encryption"/>
+ <enumeration value="signing"/>
+ </restriction>
+ </simpleType>
+ <element name="EncryptionMethod" type="xenc:EncryptionMethodType"/>
+
+ <complexType name="SSODescriptorType" abstract="true">
+ <complexContent>
+ <extension base="md:RoleDescriptorType">
+ <sequence>
+ <element ref="md:ArtifactResolutionService" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:SingleLogoutService" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:ManageNameIDService" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="ArtifactResolutionService" type="md:IndexedEndpointType"/>
+ <element name="SingleLogoutService" type="md:EndpointType"/>
+ <element name="ManageNameIDService" type="md:EndpointType"/>
+ <element name="NameIDFormat" type="anyURI"/>
+
+ <element name="IDPSSODescriptor" type="md:IDPSSODescriptorType"/>
+ <complexType name="IDPSSODescriptorType">
+ <complexContent>
+ <extension base="md:SSODescriptorType">
+ <sequence>
+ <element ref="md:SingleSignOnService" maxOccurs="unbounded"/>
+ <element ref="md:NameIDMappingService" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:AttributeProfile" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="saml:Attribute" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="WantAuthnRequestsSigned" type="boolean" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="SingleSignOnService" type="md:EndpointType"/>
+ <element name="NameIDMappingService" type="md:EndpointType"/>
+ <element name="AssertionIDRequestService" type="md:EndpointType"/>
+ <element name="AttributeProfile" type="anyURI"/>
+
+ <element name="SPSSODescriptor" type="md:SPSSODescriptorType"/>
+ <complexType name="SPSSODescriptorType">
+ <complexContent>
+ <extension base="md:SSODescriptorType">
+ <sequence>
+ <element ref="md:AssertionConsumerService" maxOccurs="unbounded"/>
+ <element ref="md:AttributeConsumingService" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="AuthnRequestsSigned" type="boolean" use="optional"/>
+ <attribute name="WantAssertionsSigned" type="boolean" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="AssertionConsumerService" type="md:IndexedEndpointType"/>
+ <element name="AttributeConsumingService" type="md:AttributeConsumingServiceType"/>
+ <complexType name="AttributeConsumingServiceType">
+ <sequence>
+ <element ref="md:ServiceName" maxOccurs="unbounded"/>
+ <element ref="md:ServiceDescription" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:RequestedAttribute" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="index" type="unsignedShort" use="required"/>
+ <attribute name="isDefault" type="boolean" use="optional"/>
+ </complexType>
+ <element name="ServiceName" type="md:localizedNameType"/>
+ <element name="ServiceDescription" type="md:localizedNameType"/>
+ <element name="RequestedAttribute" type="md:RequestedAttributeType"/>
+ <complexType name="RequestedAttributeType">
+ <complexContent>
+ <extension base="saml:AttributeType">
+ <attribute name="isRequired" type="boolean" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <element name="AuthnAuthorityDescriptor" type="md:AuthnAuthorityDescriptorType"/>
+ <complexType name="AuthnAuthorityDescriptorType">
+ <complexContent>
+ <extension base="md:RoleDescriptorType">
+ <sequence>
+ <element ref="md:AuthnQueryService" maxOccurs="unbounded"/>
+ <element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="AuthnQueryService" type="md:EndpointType"/>
+
+ <element name="PDPDescriptor" type="md:PDPDescriptorType"/>
+ <complexType name="PDPDescriptorType">
+ <complexContent>
+ <extension base="md:RoleDescriptorType">
+ <sequence>
+ <element ref="md:AuthzService" maxOccurs="unbounded"/>
+ <element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="AuthzService" type="md:EndpointType"/>
+
+ <element name="AttributeAuthorityDescriptor" type="md:AttributeAuthorityDescriptorType"/>
+ <complexType name="AttributeAuthorityDescriptorType">
+ <complexContent>
+ <extension base="md:RoleDescriptorType">
+ <sequence>
+ <element ref="md:AttributeService" maxOccurs="unbounded"/>
+ <element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="md:AttributeProfile" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="saml:Attribute" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="AttributeService" type="md:EndpointType"/>
+
+ <element name="AffiliationDescriptor" type="md:AffiliationDescriptorType"/>
+ <complexType name="AffiliationDescriptorType">
+ <sequence>
+ <element ref="ds:Signature" minOccurs="0"/>
+ <element ref="md:Extensions" minOccurs="0"/>
+ <element ref="md:AffiliateMember" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="affiliationOwnerID" type="md:entityIDType" use="required"/>
+ <attribute name="validUntil" type="dateTime" use="optional"/>
+ <attribute name="cacheDuration" type="duration" use="optional"/>
+ <attribute name="ID" type="ID" use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+ <element name="AffiliateMember" type="md:entityIDType"/>
+</schema>
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-protocol-2.0.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-protocol-2.0.xsd
new file mode 100644
index 00000000..7fa6f489
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/saml-schema-protocol-2.0.xsd
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema
+ targetNamespace="urn:oasis:names:tc:SAML:2.0:protocol"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ elementFormDefault="unqualified"
+ attributeFormDefault="unqualified"
+ blockDefault="substitution"
+ version="2.0">
+ <import namespace="urn:oasis:names:tc:SAML:2.0:assertion"
+ schemaLocation="saml-schema-assertion-2.0.xsd"/>
+ <import namespace="http://www.w3.org/2000/09/xmldsig#"
+ schemaLocation="xmldsig-core-schema.xsd"/>
+ <annotation>
+ <documentation>
+ Document identifier: saml-schema-protocol-2.0
+ Location: http://docs.oasis-open.org/security/saml/v2.0/
+ Revision history:
+ V1.0 (November, 2002):
+ Initial Standard Schema.
+ V1.1 (September, 2003):
+ Updates within the same V1.0 namespace.
+ V2.0 (March, 2005):
+ New protocol schema based in a SAML V2.0 namespace.
+ </documentation>
+ </annotation>
+ <complexType name="RequestAbstractType" abstract="true">
+ <sequence>
+ <element ref="saml:Issuer" minOccurs="0"/>
+ <element ref="ds:Signature" minOccurs="0"/>
+ <element ref="samlp:Extensions" minOccurs="0"/>
+ </sequence>
+ <attribute name="ID" type="ID" use="required"/>
+ <attribute name="Version" type="string" use="required"/>
+ <attribute name="IssueInstant" type="dateTime" use="required"/>
+ <attribute name="Destination" type="anyURI" use="optional"/>
+ <attribute name="Consent" type="anyURI" use="optional"/>
+ </complexType>
+ <element name="Extensions" type="samlp:ExtensionsType"/>
+ <complexType name="ExtensionsType">
+ <sequence>
+ <any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+ <complexType name="StatusResponseType">
+ <sequence>
+ <element ref="saml:Issuer" minOccurs="0"/>
+ <element ref="ds:Signature" minOccurs="0"/>
+ <element ref="samlp:Extensions" minOccurs="0"/>
+ <element ref="samlp:Status"/>
+ </sequence>
+ <attribute name="ID" type="ID" use="required"/>
+ <attribute name="InResponseTo" type="NCName" use="optional"/>
+ <attribute name="Version" type="string" use="required"/>
+ <attribute name="IssueInstant" type="dateTime" use="required"/>
+ <attribute name="Destination" type="anyURI" use="optional"/>
+ <attribute name="Consent" type="anyURI" use="optional"/>
+ </complexType>
+ <element name="Status" type="samlp:StatusType"/>
+ <complexType name="StatusType">
+ <sequence>
+ <element ref="samlp:StatusCode"/>
+ <element ref="samlp:StatusMessage" minOccurs="0"/>
+ <element ref="samlp:StatusDetail" minOccurs="0"/>
+ </sequence>
+ </complexType>
+ <element name="StatusCode" type="samlp:StatusCodeType"/>
+ <complexType name="StatusCodeType">
+ <sequence>
+ <element ref="samlp:StatusCode" minOccurs="0"/>
+ </sequence>
+ <attribute name="Value" type="anyURI" use="required"/>
+ </complexType>
+ <element name="StatusMessage" type="string"/>
+ <element name="StatusDetail" type="samlp:StatusDetailType"/>
+ <complexType name="StatusDetailType">
+ <sequence>
+ <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+ <element name="AssertionIDRequest" type="samlp:AssertionIDRequestType"/>
+ <complexType name="AssertionIDRequestType">
+ <complexContent>
+ <extension base="samlp:RequestAbstractType">
+ <sequence>
+ <element ref="saml:AssertionIDRef" maxOccurs="unbounded"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="SubjectQuery" type="samlp:SubjectQueryAbstractType"/>
+ <complexType name="SubjectQueryAbstractType" abstract="true">
+ <complexContent>
+ <extension base="samlp:RequestAbstractType">
+ <sequence>
+ <element ref="saml:Subject"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="AuthnQuery" type="samlp:AuthnQueryType"/>
+ <complexType name="AuthnQueryType">
+ <complexContent>
+ <extension base="samlp:SubjectQueryAbstractType">
+ <sequence>
+ <element ref="samlp:RequestedAuthnContext" minOccurs="0"/>
+ </sequence>
+ <attribute name="SessionIndex" type="string" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="RequestedAuthnContext" type="samlp:RequestedAuthnContextType"/>
+ <complexType name="RequestedAuthnContextType">
+ <choice>
+ <element ref="saml:AuthnContextClassRef" maxOccurs="unbounded"/>
+ <element ref="saml:AuthnContextDeclRef" maxOccurs="unbounded"/>
+ </choice>
+ <attribute name="Comparison" type="samlp:AuthnContextComparisonType" use="optional"/>
+ </complexType>
+ <simpleType name="AuthnContextComparisonType">
+ <restriction base="string">
+ <enumeration value="exact"/>
+ <enumeration value="minimum"/>
+ <enumeration value="maximum"/>
+ <enumeration value="better"/>
+ </restriction>
+ </simpleType>
+ <element name="AttributeQuery" type="samlp:AttributeQueryType"/>
+ <complexType name="AttributeQueryType">
+ <complexContent>
+ <extension base="samlp:SubjectQueryAbstractType">
+ <sequence>
+ <element ref="saml:Attribute" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="AuthzDecisionQuery" type="samlp:AuthzDecisionQueryType"/>
+ <complexType name="AuthzDecisionQueryType">
+ <complexContent>
+ <extension base="samlp:SubjectQueryAbstractType">
+ <sequence>
+ <element ref="saml:Action" maxOccurs="unbounded"/>
+ <element ref="saml:Evidence" minOccurs="0"/>
+ </sequence>
+ <attribute name="Resource" type="anyURI" use="required"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="AuthnRequest" type="samlp:AuthnRequestType"/>
+ <complexType name="AuthnRequestType">
+ <complexContent>
+ <extension base="samlp:RequestAbstractType">
+ <sequence>
+ <element ref="saml:Subject" minOccurs="0"/>
+ <element ref="samlp:NameIDPolicy" minOccurs="0"/>
+ <element ref="saml:Conditions" minOccurs="0"/>
+ <element ref="samlp:RequestedAuthnContext" minOccurs="0"/>
+ <element ref="samlp:Scoping" minOccurs="0"/>
+ </sequence>
+ <attribute name="ForceAuthn" type="boolean" use="optional"/>
+ <attribute name="IsPassive" type="boolean" use="optional"/>
+ <attribute name="ProtocolBinding" type="anyURI" use="optional"/>
+ <attribute name="AssertionConsumerServiceIndex" type="unsignedShort" use="optional"/>
+ <attribute name="AssertionConsumerServiceURL" type="anyURI" use="optional"/>
+ <attribute name="AttributeConsumingServiceIndex" type="unsignedShort" use="optional"/>
+ <attribute name="ProviderName" type="string" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="NameIDPolicy" type="samlp:NameIDPolicyType"/>
+ <complexType name="NameIDPolicyType">
+ <attribute name="Format" type="anyURI" use="optional"/>
+ <attribute name="SPNameQualifier" type="string" use="optional"/>
+ <attribute name="AllowCreate" type="boolean" use="optional"/>
+ </complexType>
+ <element name="Scoping" type="samlp:ScopingType"/>
+ <complexType name="ScopingType">
+ <sequence>
+ <element ref="samlp:IDPList" minOccurs="0"/>
+ <element ref="samlp:RequesterID" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="ProxyCount" type="nonNegativeInteger" use="optional"/>
+ </complexType>
+ <element name="RequesterID" type="anyURI"/>
+ <element name="IDPList" type="samlp:IDPListType"/>
+ <complexType name="IDPListType">
+ <sequence>
+ <element ref="samlp:IDPEntry" maxOccurs="unbounded"/>
+ <element ref="samlp:GetComplete" minOccurs="0"/>
+ </sequence>
+ </complexType>
+ <element name="IDPEntry" type="samlp:IDPEntryType"/>
+ <complexType name="IDPEntryType">
+ <attribute name="ProviderID" type="anyURI" use="required"/>
+ <attribute name="Name" type="string" use="optional"/>
+ <attribute name="Loc" type="anyURI" use="optional"/>
+ </complexType>
+ <element name="GetComplete" type="anyURI"/>
+ <element name="Response" type="samlp:ResponseType"/>
+ <complexType name="ResponseType">
+ <complexContent>
+ <extension base="samlp:StatusResponseType">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="saml:Assertion"/>
+ <element ref="saml:EncryptedAssertion"/>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="ArtifactResolve" type="samlp:ArtifactResolveType"/>
+ <complexType name="ArtifactResolveType">
+ <complexContent>
+ <extension base="samlp:RequestAbstractType">
+ <sequence>
+ <element ref="samlp:Artifact"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="Artifact" type="string"/>
+ <element name="ArtifactResponse" type="samlp:ArtifactResponseType"/>
+ <complexType name="ArtifactResponseType">
+ <complexContent>
+ <extension base="samlp:StatusResponseType">
+ <sequence>
+ <any namespace="##any" processContents="lax" minOccurs="0"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="ManageNameIDRequest" type="samlp:ManageNameIDRequestType"/>
+ <complexType name="ManageNameIDRequestType">
+ <complexContent>
+ <extension base="samlp:RequestAbstractType">
+ <sequence>
+ <choice>
+ <element ref="saml:NameID"/>
+ <element ref="saml:EncryptedID"/>
+ </choice>
+ <choice>
+ <element ref="samlp:NewID"/>
+ <element ref="samlp:NewEncryptedID"/>
+ <element ref="samlp:Terminate"/>
+ </choice>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="NewID" type="string"/>
+ <element name="NewEncryptedID" type="saml:EncryptedElementType"/>
+ <element name="Terminate" type="samlp:TerminateType"/>
+ <complexType name="TerminateType"/>
+ <element name="ManageNameIDResponse" type="samlp:StatusResponseType"/>
+ <element name="LogoutRequest" type="samlp:LogoutRequestType"/>
+ <complexType name="LogoutRequestType">
+ <complexContent>
+ <extension base="samlp:RequestAbstractType">
+ <sequence>
+ <choice>
+ <element ref="saml:BaseID"/>
+ <element ref="saml:NameID"/>
+ <element ref="saml:EncryptedID"/>
+ </choice>
+ <element ref="samlp:SessionIndex" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Reason" type="string" use="optional"/>
+ <attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="SessionIndex" type="string"/>
+ <element name="LogoutResponse" type="samlp:StatusResponseType"/>
+ <element name="NameIDMappingRequest" type="samlp:NameIDMappingRequestType"/>
+ <complexType name="NameIDMappingRequestType">
+ <complexContent>
+ <extension base="samlp:RequestAbstractType">
+ <sequence>
+ <choice>
+ <element ref="saml:BaseID"/>
+ <element ref="saml:NameID"/>
+ <element ref="saml:EncryptedID"/>
+ </choice>
+ <element ref="samlp:NameIDPolicy"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+ <element name="NameIDMappingResponse" type="samlp:NameIDMappingResponseType"/>
+ <complexType name="NameIDMappingResponseType">
+ <complexContent>
+ <extension base="samlp:StatusResponseType">
+ <choice>
+ <element ref="saml:NameID"/>
+ <element ref="saml:EncryptedID"/>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+</schema>
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-metadata-attr.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-metadata-attr.xsd
new file mode 100644
index 00000000..f23e462a
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-metadata-attr.xsd
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema
+ targetNamespace="urn:oasis:names:tc:SAML:metadata:attribute"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute"
+ elementFormDefault="unqualified"
+ attributeFormDefault="unqualified"
+ blockDefault="substitution"
+ version="2.0">
+
+ <annotation>
+ <documentation>
+ Document title: SAML V2.0 Metadata Extention for Entity Attributes Schema
+ Document identifier: sstc-metadata-attr.xsd
+ Location: http://www.oasis-open.org/committees/documents.php?wg_abbrev=security
+ Revision history:
+ V1.0 (November 2008):
+ Initial version.
+ </documentation>
+ </annotation>
+
+ <import namespace="urn:oasis:names:tc:SAML:2.0:assertion"
+ schemaLocation="saml-schema-assertion-2.0.xsd"/>
+
+ <element name="EntityAttributes" type="mdattr:EntityAttributesType"/>
+ <complexType name="EntityAttributesType">
+ <choice maxOccurs="unbounded">
+ <element ref="saml:Attribute"/>
+ <element ref="saml:Assertion"/>
+ </choice>
+ </complexType>
+
+</schema>
+
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-attribute-ext.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-attribute-ext.xsd
new file mode 100644
index 00000000..ad309c14
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-attribute-ext.xsd
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema
+ targetNamespace="urn:oasis:names:tc:SAML:attribute:ext"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="unqualified"
+ attributeFormDefault="unqualified"
+ blockDefault="substitution"
+ version="2.0">
+
+ <annotation>
+ <documentation>
+ Document title: SAML V2.0 Attribute Extension Schema
+ Document identifier: sstc-saml-attribute-ext.xsd
+ Location: http://www.oasis-open.org/committees/documents.php?wg_abbrev=security
+ Revision history:
+ V1.0 (October 2008):
+ Initial version.
+ </documentation>
+ </annotation>
+
+ <attribute name="OriginalIssuer" type="anyURI"/>
+ <attribute name="LastModified" type="dateTime"/>
+
+</schema>
+
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-metadata-algsupport-v1.0.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-metadata-algsupport-v1.0.xsd
new file mode 100644
index 00000000..3236ffcd
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-metadata-algsupport-v1.0.xsd
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema
+ targetNamespace="urn:oasis:names:tc:SAML:metadata:algsupport"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
+ elementFormDefault="unqualified"
+ attributeFormDefault="unqualified"
+ blockDefault="substitution"
+ version="1.0">
+
+ <annotation>
+ <documentation>
+ Document title: Metadata Extension Schema for SAML V2.0 Metadata Profile for Algorithm Support Version 1.0
+ Document identifier: sstc-saml-metadata-algsupport.xsd
+ Location: http://docs.oasis-open.org/security/saml/Post2.0/
+ Revision history:
+ V1.0 (June 2010):
+ Initial version.
+ </documentation>
+ </annotation>
+
+ <element name="DigestMethod" type="alg:DigestMethodType"/>
+ <complexType name="DigestMethodType">
+ <sequence>
+ <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ </complexType>
+
+ <element name="SigningMethod" type="alg:SigningMethodType"/>
+ <complexType name="SigningMethodType">
+ <sequence>
+ <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ <attribute name="MinKeySize" type="positiveInteger"/>
+ <attribute name="MaxKeySize" type="positiveInteger"/>
+ </complexType>
+
+</schema>
+
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-metadata-ui-v1.0.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-metadata-ui-v1.0.xsd
new file mode 100644
index 00000000..de0b754a
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/sstc-saml-metadata-ui-v1.0.xsd
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema
+ targetNamespace="urn:oasis:names:tc:SAML:metadata:ui"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui"
+ elementFormDefault="unqualified"
+ attributeFormDefault="unqualified"
+ blockDefault="substitution"
+ version="1.0">
+
+ <annotation>
+ <documentation>
+ Document title: Metadata Extension Schema for SAML V2.0 Metadata Extensions for Login and Discovery User Interface Version 1.0
+ Document identifier: sstc-saml-metadata-ui-v1.0.xsd
+ Location: http://docs.oasis-open.org/security/saml/Post2.0/
+ Revision history:
+ 16 November 2010:
+ Added Keywords element/type.
+ 01 November 2010
+ Changed filename.
+ September 2010:
+ Initial version.
+ </documentation>
+ </annotation>
+
+ <import namespace="urn:oasis:names:tc:SAML:2.0:metadata"
+ schemaLocation="saml-schema-metadata-2.0.xsd"/>
+ <import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="xml.xsd"/>
+
+ <element name="UIInfo" type="mdui:UIInfoType" />
+ <complexType name="UIInfoType">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="mdui:DisplayName"/>
+ <element ref="mdui:Description"/>
+ <element ref="mdui:Keywords"/>
+ <element ref="mdui:Logo"/>
+ <element ref="mdui:InformationURL"/>
+ <element ref="mdui:PrivacyStatementURL"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </complexType>
+
+ <element name="DisplayName" type="md:localizedNameType"/>
+ <element name="Description" type="md:localizedNameType"/>
+ <element name="InformationURL" type="md:localizedURIType"/>
+ <element name="PrivacyStatementURL" type="md:localizedURIType"/>
+
+ <element name="Keywords" type="mdui:KeywordsType"/>
+ <complexType name="KeywordsType">
+ <simpleContent>
+ <extension base="mdui:listOfStrings">
+ <attribute ref="xml:lang" use="required"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+
+ <simpleType name="listOfStrings">
+ <list itemType="string"/>
+ </simpleType>
+
+ <element name="Logo" type="mdui:LogoType"/>
+ <complexType name="LogoType">
+ <simpleContent>
+ <extension base="anyURI">
+ <attribute name="height" type="positiveInteger" use="required"/>
+ <attribute name="width" type="positiveInteger" use="required"/>
+ <attribute ref="xml:lang"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+
+ <element name="DiscoHints" type="mdui:DiscoHintsType"/>
+ <complexType name="DiscoHintsType">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="mdui:IPHint"/>
+ <element ref="mdui:DomainHint"/>
+ <element ref="mdui:GeolocationHint"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </complexType>
+
+ <element name="IPHint" type="string"/>
+ <element name="DomainHint" type="string"/>
+ <element name="GeolocationHint" type="anyURI"/>
+
+</schema>
+
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xenc-schema.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xenc-schema.xsd
new file mode 100644
index 00000000..d6d79103
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xenc-schema.xsd
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<schema xmlns='http://www.w3.org/2001/XMLSchema' version='1.0'
+ xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'
+ xmlns:ds='http://www.w3.org/2000/09/xmldsig#'
+ targetNamespace='http://www.w3.org/2001/04/xmlenc#'
+ elementFormDefault='qualified'>
+
+ <import namespace='http://www.w3.org/2000/09/xmldsig#'
+ schemaLocation='xmldsig-core-schema.xsd'/>
+
+ <complexType name='EncryptedType' abstract='true'>
+ <sequence>
+ <element name='EncryptionMethod' type='xenc:EncryptionMethodType'
+ minOccurs='0'/>
+ <element ref='ds:KeyInfo' minOccurs='0'/>
+ <element ref='xenc:CipherData'/>
+ <element ref='xenc:EncryptionProperties' minOccurs='0'/>
+ </sequence>
+ <attribute name='Id' type='ID' use='optional'/>
+ <attribute name='Type' type='anyURI' use='optional'/>
+ <attribute name='MimeType' type='string' use='optional'/>
+ <attribute name='Encoding' type='anyURI' use='optional'/>
+ </complexType>
+
+ <complexType name='EncryptionMethodType' mixed='true'>
+ <sequence>
+ <element name='KeySize' minOccurs='0' type='xenc:KeySizeType'/>
+ <element name='OAEPparams' minOccurs='0' type='base64Binary'/>
+ <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
+ </sequence>
+ <attribute name='Algorithm' type='anyURI' use='required'/>
+ </complexType>
+
+ <simpleType name='KeySizeType'>
+ <restriction base="integer"/>
+ </simpleType>
+
+ <element name='CipherData' type='xenc:CipherDataType'/>
+ <complexType name='CipherDataType'>
+ <choice>
+ <element name='CipherValue' type='base64Binary'/>
+ <element ref='xenc:CipherReference'/>
+ </choice>
+ </complexType>
+
+ <element name='CipherReference' type='xenc:CipherReferenceType'/>
+ <complexType name='CipherReferenceType'>
+ <choice>
+ <element name='Transforms' type='xenc:TransformsType' minOccurs='0'/>
+ </choice>
+ <attribute name='URI' type='anyURI' use='required'/>
+ </complexType>
+
+ <complexType name='TransformsType'>
+ <sequence>
+ <element ref='ds:Transform' maxOccurs='unbounded'/>
+ </sequence>
+ </complexType>
+
+
+ <element name='EncryptedData' type='xenc:EncryptedDataType'/>
+ <complexType name='EncryptedDataType'>
+ <complexContent>
+ <extension base='xenc:EncryptedType'>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Children of ds:KeyInfo -->
+
+ <element name='EncryptedKey' type='xenc:EncryptedKeyType'/>
+ <complexType name='EncryptedKeyType'>
+ <complexContent>
+ <extension base='xenc:EncryptedType'>
+ <sequence>
+ <element ref='xenc:ReferenceList' minOccurs='0'/>
+ <element name='CarriedKeyName' type='string' minOccurs='0'/>
+ </sequence>
+ <attribute name='Recipient' type='string'
+ use='optional'/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <element name="AgreementMethod" type="xenc:AgreementMethodType"/>
+ <complexType name="AgreementMethodType" mixed="true">
+ <sequence>
+ <element name="KA-Nonce" minOccurs="0" type="base64Binary"/>
+ <!-- <element ref="ds:DigestMethod" minOccurs="0"/> -->
+ <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
+ <element name="OriginatorKeyInfo" minOccurs="0" type="ds:KeyInfoType"/>
+ <element name="RecipientKeyInfo" minOccurs="0" type="ds:KeyInfoType"/>
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ </complexType>
+
+ <!-- End Children of ds:KeyInfo -->
+
+ <element name='ReferenceList'>
+ <complexType>
+ <choice minOccurs='1' maxOccurs='unbounded'>
+ <element name='DataReference' type='xenc:ReferenceType'/>
+ <element name='KeyReference' type='xenc:ReferenceType'/>
+ </choice>
+ </complexType>
+ </element>
+
+ <complexType name='ReferenceType'>
+ <sequence>
+ <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
+ </sequence>
+ <attribute name='URI' type='anyURI' use='required'/>
+ </complexType>
+
+
+ <element name='EncryptionProperties' type='xenc:EncryptionPropertiesType'/>
+ <complexType name='EncryptionPropertiesType'>
+ <sequence>
+ <element ref='xenc:EncryptionProperty' maxOccurs='unbounded'/>
+ </sequence>
+ <attribute name='Id' type='ID' use='optional'/>
+ </complexType>
+
+ <element name='EncryptionProperty' type='xenc:EncryptionPropertyType'/>
+ <complexType name='EncryptionPropertyType' mixed='true'>
+ <choice maxOccurs='unbounded'>
+ <any namespace='##other' processContents='lax'/>
+ </choice>
+ <attribute name='Target' type='anyURI' use='optional'/>
+ <attribute name='Id' type='ID' use='optional'/>
+ <anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/>
+ </complexType>
+
+</schema>
+
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xml.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xml.xsd
new file mode 100644
index 00000000..aea7d0db
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xml.xsd
@@ -0,0 +1,287 @@
+<?xml version='1.0'?>
+<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
+<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns ="http://www.w3.org/1999/xhtml"
+ xml:lang="en">
+
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+ <h1>About the XML namespace</h1>
+
+ <div class="bodytext">
+ <p>
+ This schema document describes the XML namespace, in a form
+ suitable for import by other schema documents.
+ </p>
+ <p>
+ See <a href="http://www.w3.org/XML/1998/namespace.html">
+ http://www.w3.org/XML/1998/namespace.html</a> and
+ <a href="http://www.w3.org/TR/REC-xml">
+ http://www.w3.org/TR/REC-xml</a> for information
+ about this namespace.
+ </p>
+ <p>
+ Note that local names in this namespace are intended to be
+ defined only by the World Wide Web Consortium or its subgroups.
+ The names currently defined in this namespace are listed below.
+ They should not be used with conflicting semantics by any Working
+ Group, specification, or document instance.
+ </p>
+ <p>
+ See further below in this document for more information about <a
+ href="#usage">how to refer to this schema document from your own
+ XSD schema documents</a> and about <a href="#nsversioning">the
+ namespace-versioning policy governing this schema document</a>.
+ </p>
+ </div>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:attribute name="lang">
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>lang (as an attribute name)</h3>
+ <p>
+ denotes an attribute whose value
+ is a language code for the natural language of the content of
+ any element; its value is inherited. This name is reserved
+ by virtue of its definition in the XML specification.</p>
+
+ </div>
+ <div>
+ <h4>Notes</h4>
+ <p>
+ Attempting to install the relevant ISO 2- and 3-letter
+ codes as the enumerated possible values is probably never
+ going to be a realistic possibility.
+ </p>
+ <p>
+ See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
+ http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
+ and the IANA language subtag registry at
+ <a href="http://www.iana.org/assignments/language-subtag-registry">
+ http://www.iana.org/assignments/language-subtag-registry</a>
+ for further information.
+ </p>
+ <p>
+ The union allows for the 'un-declaration' of xml:lang with
+ the empty string.
+ </p>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:union memberTypes="xs:language">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value=""/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="space">
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>space (as an attribute name)</h3>
+ <p>
+ denotes an attribute whose
+ value is a keyword indicating what whitespace processing
+ discipline is intended for the content of the element; its
+ value is inherited. This name is reserved by virtue of its
+ definition in the XML specification.</p>
+
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:NCName">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>base (as an attribute name)</h3>
+ <p>
+ denotes an attribute whose value
+ provides a URI to be used as the base for interpreting any
+ relative URIs in the scope of the element on which it
+ appears; its value is inherited. This name is reserved
+ by virtue of its definition in the XML Base specification.</p>
+
+ <p>
+ See <a
+ href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
+ for information about this attribute.
+ </p>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="id" type="xs:ID">
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>id (as an attribute name)</h3>
+ <p>
+ denotes an attribute whose value
+ should be interpreted as if declared to be of type ID.
+ This name is reserved by virtue of its definition in the
+ xml:id specification.</p>
+
+ <p>
+ See <a
+ href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
+ for information about this attribute.
+ </p>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attributeGroup name="specialAttrs">
+ <xs:attribute ref="xml:base"/>
+ <xs:attribute ref="xml:lang"/>
+ <xs:attribute ref="xml:space"/>
+ <xs:attribute ref="xml:id"/>
+ </xs:attributeGroup>
+
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>Father (in any context at all)</h3>
+
+ <div class="bodytext">
+ <p>
+ denotes Jon Bosak, the chair of
+ the original XML Working Group. This name is reserved by
+ the following decision of the W3C XML Plenary and
+ XML Coordination groups:
+ </p>
+ <blockquote>
+ <p>
+ In appreciation for his vision, leadership and
+ dedication the W3C XML Plenary on this 10th day of
+ February, 2000, reserves for Jon Bosak in perpetuity
+ the XML name "xml:Father".
+ </p>
+ </blockquote>
+ </div>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>
+ <div xml:id="usage" id="usage">
+ <h2><a name="usage">About this schema document</a></h2>
+
+ <div class="bodytext">
+ <p>
+ This schema defines attributes and an attribute group suitable
+ for use by schemas wishing to allow <code>xml:base</code>,
+ <code>xml:lang</code>, <code>xml:space</code> or
+ <code>xml:id</code> attributes on elements they define.
+ </p>
+ <p>
+ To enable this, such a schema must import this schema for
+ the XML namespace, e.g. as follows:
+ </p>
+ <pre>
+ &lt;schema . . .>
+ . . .
+ &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+ </pre>
+ <p>
+ or
+ </p>
+ <pre>
+ &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+ </pre>
+ <p>
+ Subsequently, qualified reference to any of the attributes or the
+ group defined below will have the desired effect, e.g.
+ </p>
+ <pre>
+ &lt;type . . .>
+ . . .
+ &lt;attributeGroup ref="xml:specialAttrs"/>
+ </pre>
+ <p>
+ will define a type which will schema-validate an instance element
+ with any of those attributes.
+ </p>
+ </div>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>
+ <div id="nsversioning" xml:id="nsversioning">
+ <h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
+ <div class="bodytext">
+ <p>
+ In keeping with the XML Schema WG's standard versioning
+ policy, this schema document will persist at
+ <a href="http://www.w3.org/2009/01/xml.xsd">
+ http://www.w3.org/2009/01/xml.xsd</a>.
+ </p>
+ <p>
+ At the date of issue it can also be found at
+ <a href="http://www.w3.org/2001/xml.xsd">
+ http://www.w3.org/2001/xml.xsd</a>.
+ </p>
+ <p>
+ The schema document at that URI may however change in the future,
+ in order to remain compatible with the latest version of XML
+ Schema itself, or with the XML namespace itself. In other words,
+ if the XML Schema or XML namespaces change, the version of this
+ document at <a href="http://www.w3.org/2001/xml.xsd">
+ http://www.w3.org/2001/xml.xsd
+ </a>
+ will change accordingly; the version at
+ <a href="http://www.w3.org/2009/01/xml.xsd">
+ http://www.w3.org/2009/01/xml.xsd
+ </a>
+ will not change.
+ </p>
+ <p>
+ Previous dated (and unchanging) versions of this schema
+ document are at:
+ </p>
+ <ul>
+ <li><a href="http://www.w3.org/2009/01/xml.xsd">
+ http://www.w3.org/2009/01/xml.xsd</a></li>
+ <li><a href="http://www.w3.org/2007/08/xml.xsd">
+ http://www.w3.org/2007/08/xml.xsd</a></li>
+ <li><a href="http://www.w3.org/2004/10/xml.xsd">
+ http://www.w3.org/2004/10/xml.xsd</a></li>
+ <li><a href="http://www.w3.org/2001/03/xml.xsd">
+ http://www.w3.org/2001/03/xml.xsd</a></li>
+ </ul>
+ </div>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+
+</xs:schema>
+
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xmldsig-core-schema.xsd b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xmldsig-core-schema.xsd
new file mode 100644
index 00000000..dd5254bb
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/schemas/xmldsig-core-schema.xsd
@@ -0,0 +1,309 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Schema for XML Signatures
+ http://www.w3.org/2000/09/xmldsig#
+ $Revision: 1.1 $ on $Date: 2002/02/08 20:32:26 $ by $Author: reagle $
+
+ Copyright 2001 The Internet Society and W3C (Massachusetts Institute
+ of Technology, Institut National de Recherche en Informatique et en
+ Automatique, Keio University). All Rights Reserved.
+ http://www.w3.org/Consortium/Legal/
+
+ This document is governed by the W3C Software License [1] as described
+ in the FAQ [2].
+
+ [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
+ [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
+-->
+
+
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ targetNamespace="http://www.w3.org/2000/09/xmldsig#"
+ version="0.1" elementFormDefault="qualified">
+
+<!-- Basic Types Defined for Signatures -->
+
+<simpleType name="CryptoBinary">
+ <restriction base="base64Binary">
+ </restriction>
+</simpleType>
+
+<!-- Start Signature -->
+
+<element name="Signature" type="ds:SignatureType"/>
+<complexType name="SignatureType">
+ <sequence>
+ <element ref="ds:SignedInfo"/>
+ <element ref="ds:SignatureValue"/>
+ <element ref="ds:KeyInfo" minOccurs="0"/>
+ <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+ <element name="SignatureValue" type="ds:SignatureValueType"/>
+ <complexType name="SignatureValueType">
+ <simpleContent>
+ <extension base="base64Binary">
+ <attribute name="Id" type="ID" use="optional"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+
+<!-- Start SignedInfo -->
+
+<element name="SignedInfo" type="ds:SignedInfoType"/>
+<complexType name="SignedInfoType">
+ <sequence>
+ <element ref="ds:CanonicalizationMethod"/>
+ <element ref="ds:SignatureMethod"/>
+ <element ref="ds:Reference" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+ <element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/>
+ <complexType name="CanonicalizationMethodType" mixed="true">
+ <sequence>
+ <any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
+ <!-- (0,unbounded) elements from (1,1) namespace -->
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ </complexType>
+
+ <element name="SignatureMethod" type="ds:SignatureMethodType"/>
+ <complexType name="SignatureMethodType" mixed="true">
+ <sequence>
+ <element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
+ <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
+ <!-- (0,unbounded) elements from (1,1) external namespace -->
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ </complexType>
+
+<!-- Start Reference -->
+
+<element name="Reference" type="ds:ReferenceType"/>
+<complexType name="ReferenceType">
+ <sequence>
+ <element ref="ds:Transforms" minOccurs="0"/>
+ <element ref="ds:DigestMethod"/>
+ <element ref="ds:DigestValue"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+ <attribute name="URI" type="anyURI" use="optional"/>
+ <attribute name="Type" type="anyURI" use="optional"/>
+</complexType>
+
+ <element name="Transforms" type="ds:TransformsType"/>
+ <complexType name="TransformsType">
+ <sequence>
+ <element ref="ds:Transform" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <element name="Transform" type="ds:TransformType"/>
+ <complexType name="TransformType" mixed="true">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <any namespace="##other" processContents="lax"/>
+ <!-- (1,1) elements from (0,unbounded) namespaces -->
+ <element name="XPath" type="string"/>
+ </choice>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ </complexType>
+
+<!-- End Reference -->
+
+<element name="DigestMethod" type="ds:DigestMethodType"/>
+<complexType name="DigestMethodType" mixed="true">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+</complexType>
+
+<element name="DigestValue" type="ds:DigestValueType"/>
+<simpleType name="DigestValueType">
+ <restriction base="base64Binary"/>
+</simpleType>
+
+<!-- End SignedInfo -->
+
+<!-- Start KeyInfo -->
+
+<element name="KeyInfo" type="ds:KeyInfoType"/>
+<complexType name="KeyInfoType" mixed="true">
+ <choice maxOccurs="unbounded">
+ <element ref="ds:KeyName"/>
+ <element ref="ds:KeyValue"/>
+ <element ref="ds:RetrievalMethod"/>
+ <element ref="ds:X509Data"/>
+ <element ref="ds:PGPData"/>
+ <element ref="ds:SPKIData"/>
+ <element ref="ds:MgmtData"/>
+ <any processContents="lax" namespace="##other"/>
+ <!-- (1,1) elements from (0,unbounded) namespaces -->
+ </choice>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+ <element name="KeyName" type="string"/>
+ <element name="MgmtData" type="string"/>
+
+ <element name="KeyValue" type="ds:KeyValueType"/>
+ <complexType name="KeyValueType" mixed="true">
+ <choice>
+ <element ref="ds:DSAKeyValue"/>
+ <element ref="ds:RSAKeyValue"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </complexType>
+
+ <element name="RetrievalMethod" type="ds:RetrievalMethodType"/>
+ <complexType name="RetrievalMethodType">
+ <sequence>
+ <element ref="ds:Transforms" minOccurs="0"/>
+ </sequence>
+ <attribute name="URI" type="anyURI"/>
+ <attribute name="Type" type="anyURI" use="optional"/>
+ </complexType>
+
+<!-- Start X509Data -->
+
+<element name="X509Data" type="ds:X509DataType"/>
+<complexType name="X509DataType">
+ <sequence maxOccurs="unbounded">
+ <choice>
+ <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
+ <element name="X509SKI" type="base64Binary"/>
+ <element name="X509SubjectName" type="string"/>
+ <element name="X509Certificate" type="base64Binary"/>
+ <element name="X509CRL" type="base64Binary"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </sequence>
+</complexType>
+
+<complexType name="X509IssuerSerialType">
+ <sequence>
+ <element name="X509IssuerName" type="string"/>
+ <element name="X509SerialNumber" type="integer"/>
+ </sequence>
+</complexType>
+
+<!-- End X509Data -->
+
+<!-- Begin PGPData -->
+
+<element name="PGPData" type="ds:PGPDataType"/>
+<complexType name="PGPDataType">
+ <choice>
+ <sequence>
+ <element name="PGPKeyID" type="base64Binary"/>
+ <element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <sequence>
+ <element name="PGPKeyPacket" type="base64Binary"/>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ </choice>
+</complexType>
+
+<!-- End PGPData -->
+
+<!-- Begin SPKIData -->
+
+<element name="SPKIData" type="ds:SPKIDataType"/>
+<complexType name="SPKIDataType">
+ <sequence maxOccurs="unbounded">
+ <element name="SPKISexp" type="base64Binary"/>
+ <any namespace="##other" processContents="lax" minOccurs="0"/>
+ </sequence>
+</complexType>
+
+<!-- End SPKIData -->
+
+<!-- End KeyInfo -->
+
+<!-- Start Object (Manifest, SignatureProperty) -->
+
+<element name="Object" type="ds:ObjectType"/>
+<complexType name="ObjectType" mixed="true">
+ <sequence minOccurs="0" maxOccurs="unbounded">
+ <any namespace="##any" processContents="lax"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+ <attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
+ <attribute name="Encoding" type="anyURI" use="optional"/>
+</complexType>
+
+<element name="Manifest" type="ds:ManifestType"/>
+<complexType name="ManifestType">
+ <sequence>
+ <element ref="ds:Reference" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+<element name="SignatureProperties" type="ds:SignaturePropertiesType"/>
+<complexType name="SignaturePropertiesType">
+ <sequence>
+ <element ref="ds:SignatureProperty" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+ <element name="SignatureProperty" type="ds:SignaturePropertyType"/>
+ <complexType name="SignaturePropertyType" mixed="true">
+ <choice maxOccurs="unbounded">
+ <any namespace="##other" processContents="lax"/>
+ <!-- (1,1) elements from (1,unbounded) namespaces -->
+ </choice>
+ <attribute name="Target" type="anyURI" use="required"/>
+ <attribute name="Id" type="ID" use="optional"/>
+ </complexType>
+
+<!-- End Object (Manifest, SignatureProperty) -->
+
+<!-- Start Algorithm Parameters -->
+
+<simpleType name="HMACOutputLengthType">
+ <restriction base="integer"/>
+</simpleType>
+
+<!-- Start KeyValue Element-types -->
+
+<element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
+<complexType name="DSAKeyValueType">
+ <sequence>
+ <sequence minOccurs="0">
+ <element name="P" type="ds:CryptoBinary"/>
+ <element name="Q" type="ds:CryptoBinary"/>
+ </sequence>
+ <element name="G" type="ds:CryptoBinary" minOccurs="0"/>
+ <element name="Y" type="ds:CryptoBinary"/>
+ <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
+ <sequence minOccurs="0">
+ <element name="Seed" type="ds:CryptoBinary"/>
+ <element name="PgenCounter" type="ds:CryptoBinary"/>
+ </sequence>
+ </sequence>
+</complexType>
+
+<element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
+<complexType name="RSAKeyValueType">
+ <sequence>
+ <element name="Modulus" type="ds:CryptoBinary"/>
+ <element name="Exponent" type="ds:CryptoBinary"/>
+ </sequence>
+</complexType>
+
+<!-- End KeyValue Element-types -->
+
+<!-- End Signature -->
+
+</schema>
diff --git a/3rdparty/vendor/onelogin/php-saml/lib/Saml2/version.json b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/version.json
new file mode 100644
index 00000000..74955596
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/lib/Saml2/version.json
@@ -0,0 +1,6 @@
+{
+ "php-saml": {
+ "version": "2.9.0",
+ "released": "27/06/2016"
+ }
+}
diff --git a/3rdparty/vendor/onelogin/php-saml/locale/en_US/LC_MESSAGES/phptoolkit.mo b/3rdparty/vendor/onelogin/php-saml/locale/en_US/LC_MESSAGES/phptoolkit.mo
new file mode 100644
index 00000000..4898ddb5
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/locale/en_US/LC_MESSAGES/phptoolkit.mo
Binary files differ
diff --git a/3rdparty/vendor/onelogin/php-saml/locale/en_US/LC_MESSAGES/phptoolkit.po b/3rdparty/vendor/onelogin/php-saml/locale/en_US/LC_MESSAGES/phptoolkit.po
new file mode 100644
index 00000000..c8e9ef97
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/locale/en_US/LC_MESSAGES/phptoolkit.po
@@ -0,0 +1,26 @@
+msgid ""
+msgstr ""
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "test"
+msgstr "test"
+
+msgid "test2: %s"
+msgstr "test2: %s"
+
+#: index.php:15 endpoints/acs.php:35
+msgid "User attributes:"
+msgstr ""
+
+#: index.php:16 endpoints/acs.php:36
+msgid "Name"
+msgstr ""
+
+#: index.php:16 endpoints/acs.php:36
+msgid "Values"
+msgstr ""
+
+#: index.php:26 endpoints/acs.php:46
+msgid "Attributes not found"
+msgstr ""
diff --git a/3rdparty/vendor/onelogin/php-saml/locale/es_ES/LC_MESSAGES/phptoolkit.mo b/3rdparty/vendor/onelogin/php-saml/locale/es_ES/LC_MESSAGES/phptoolkit.mo
new file mode 100644
index 00000000..9f277740
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/locale/es_ES/LC_MESSAGES/phptoolkit.mo
Binary files differ
diff --git a/3rdparty/vendor/onelogin/php-saml/locale/es_ES/LC_MESSAGES/phptoolkit.po b/3rdparty/vendor/onelogin/php-saml/locale/es_ES/LC_MESSAGES/phptoolkit.po
new file mode 100644
index 00000000..a989377d
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/locale/es_ES/LC_MESSAGES/phptoolkit.po
@@ -0,0 +1,27 @@
+msgid ""
+msgstr ""
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "test"
+msgstr "prueba"
+
+msgid "test2: %s"
+msgstr "prueba2: %s"
+
+#: index.php:15 endpoints/acs.php:35
+msgid "User attributes:"
+msgstr "Atributos del usuario:"
+
+#: index.php:16 endpoints/acs.php:36
+msgid "Name"
+msgstr "Nombre"
+
+#: index.php:16 endpoints/acs.php:36
+msgid "Values"
+msgstr "Valores"
+
+#: index.php:26 endpoints/acs.php:46
+msgid "Attributes not found"
+msgstr "Atributos no encontrados"
+
diff --git a/3rdparty/vendor/onelogin/php-saml/phpdoc.xml b/3rdparty/vendor/onelogin/php-saml/phpdoc.xml
new file mode 100644
index 00000000..e9f38d82
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/phpdoc.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<phpdoc>
+ <title>OneLogin's SAML PHP Toolkit</title>
+ <parser>
+ <default-package-name>OneLogin_SAML_Toolkit</default-package-name>
+ <target>docs/Saml3</target>
+ </parser>
+ <extensions>
+ <extension>php</extension>
+ </extensions>
+ <transformer>
+ <target>docs/Saml3</target>
+ </transformer>
+ <transformations>
+ <template name="onelogin" />
+<!-- <template name="clean" /> -->
+ </transformations>
+ <files>
+ <directory>lib/Saml2/*</directory>
+ <ignore>lib/Saml/*</ignore>
+ <ignore>tests/*</ignore>
+ <ignore>demo1/*</ignore>
+ <ignore>demo2/*</ignore>
+ <ignore>demo-old/*</ignore>
+ <ignore>endpoints/*</ignore>
+ <ignore>extlib/*</ignore>
+ <ignore>locale/*</ignore>
+ <ignore>docs/*</ignore>
+ <ignore>vendor/*</ignore>
+ <ignore>compatibility.php</ignore>
+ <ignore>_toolkit_loader.php</ignore>
+ <ignore>settings.php</ignore>
+ <ignore>settings_example.php</ignore>
+ <ignore>advanced_settings.php</ignore>
+ <ignore>advanced_settings_example</ignore>
+ </files>
+</phpdoc>
diff --git a/3rdparty/vendor/onelogin/php-saml/settings_example.php b/3rdparty/vendor/onelogin/php-saml/settings_example.php
new file mode 100644
index 00000000..0fa28121
--- /dev/null
+++ b/3rdparty/vendor/onelogin/php-saml/settings_example.php
@@ -0,0 +1,84 @@
+<?php
+
+$settings = array (
+ // If 'strict' is True, then the PHP Toolkit will reject unsigned
+ // or unencrypted messages if it expects them signed or encrypted
+ // Also will reject the messages if not strictly follow the SAML
+ // standard: Destination, NameId, Conditions ... are validated too.
+ 'strict' => false,
+
+ // Enable debug mode (to print errors)
+ 'debug' => false,
+
+ // Service Provider Data that we are deploying
+ 'sp' => array (
+ // Identifier of the SP entity (must be a URI)
+ 'entityId' => '',
+ // Specifies info about where and how the <AuthnResponse> message MUST be
+ // returned to the requester, in this case our SP.
+ 'assertionConsumerService' => array (
+ // URL Location where the <Response> from the IdP will be returned
+ 'url' => '',
+ // SAML protocol binding to be used when returning the <Response>
+ // message. Onelogin Toolkit supports for this endpoint the
+ // HTTP-Redirect binding only
+ 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+ ),
+ // Specifies info about where and how the <Logout Response> message MUST be
+ // returned to the requester, in this case our SP.
+ 'singleLogoutService' => array (
+ // URL Location where the <Response> from the IdP will be returned
+ 'url' => '',
+ // SAML protocol binding to be used when returning the <Response>
+ // message. Onelogin Toolkit supports for this endpoint the
+ // HTTP-Redirect binding only
+ 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+ ),
+ // Specifies constraints on the name identifier to be used to
+ // represent the requested subject.
+ // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported
+ 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
+
+ // Usually x509cert and privateKey of the SP are provided by files placed at
+ // the certs folder. But we can also provide them with the following parameters
+ 'x509cert' => '',
+ 'privateKey' => '',
+ ),
+
+ // Identity Provider Data that we want connect with our SP
+ 'idp' => array (
+ // Identifier of the IdP entity (must be a URI)
+ 'entityId' => '',
+ // SSO endpoint info of the IdP. (Authentication Request protocol)
+ 'singleSignOnService' => array (
+ // URL Target of the IdP where the SP will send the Authentication Request Message
+ 'url' => '',
+ // SAML protocol binding to be used when returning the <Response>
+ // message. Onelogin Toolkit supports for this endpoint the
+ // HTTP-POST 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' => '',
+ // SAML protocol binding to be used when returning the <Response>
+ // message. Onelogin Toolkit supports for this endpoint the
+ // HTTP-Redirect binding only
+ 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+ ),
+ // Public x509 certificate of the IdP
+ 'x509cert' => '',
+ /*
+ * Instead of use the whole x509cert you can use a fingerprint
+ * (openssl x509 -noout -fingerprint -in "idp.crt" to generate it,
+ * or add for example the -sha256 , -sha384 or -sha512 parameter)
+ *
+ * If a fingerprint is provided, then the certFingerprintAlgorithm is required in order to
+ * let the toolkit know which Algorithm was used. Possible values: sha1, sha256, sha384 or sha512
+ * 'sha1' is the default value.
+ */
+ // 'certFingerprint' => '',
+ // 'certFingerprintAlgorithm' => 'sha1',
+ ),
+);