From b4e0d90ccfc10896e9833179e2c6cb9b74c64d75 Mon Sep 17 00:00:00 2001
From: nicolas <nicolas.lebozec@xelians.fr>
Date: Tue, 3 Jan 2023 18:06:30 +0100
Subject: [PATCH] FEAT #19887 TIME 3:00 CAS implementation

---
 composer.json                                 |    2 +-
 vendor/composer/InstalledVersions.php         |  352 ++
 vendor/composer/installed.php                 |  416 ++
 vendor/composer/platform_check.php            |   26 +
 vendor/jasig/phpcas/.codecov.yml              |   17 +
 vendor/jasig/phpcas/.gitattributes            |    7 +
 vendor/jasig/phpcas/.github/dependabot.yml    |    7 +
 .../jasig/phpcas/.github/workflows/test.yml   |   43 +
 vendor/jasig/phpcas/CAS.php                   |   32 +
 vendor/jasig/phpcas/LICENSE                   |  201 +
 vendor/jasig/phpcas/NOTICE                    |   81 +
 vendor/jasig/phpcas/README.md                 |   35 +
 vendor/jasig/phpcas/composer.json             |   55 +
 vendor/jasig/phpcas/phpunit.xml.dist          |   13 +
 vendor/jasig/phpcas/source/CAS.php            | 2065 ++++++++
 .../source/CAS/AuthenticationException.php    |  115 +
 vendor/jasig/phpcas/source/CAS/Autoload.php   |   95 +
 vendor/jasig/phpcas/source/CAS/Client.php     | 4377 +++++++++++++++++
 vendor/jasig/phpcas/source/CAS/CookieJar.php  |  385 ++
 vendor/jasig/phpcas/source/CAS/Exception.php  |   59 +
 .../CAS/GracefullTerminationException.php     |   86 +
 .../source/CAS/InvalidArgumentException.php   |   46 +
 .../phpcas/source/CAS/Languages/Catalan.php   |  114 +
 .../CAS/Languages/ChineseSimplified.php       |  114 +
 .../phpcas/source/CAS/Languages/English.php   |  114 +
 .../phpcas/source/CAS/Languages/French.php    |  116 +
 .../phpcas/source/CAS/Languages/Galego.php    |  117 +
 .../phpcas/source/CAS/Languages/German.php    |  116 +
 .../phpcas/source/CAS/Languages/Greek.php     |  115 +
 .../phpcas/source/CAS/Languages/Japanese.php  |  113 +
 .../CAS/Languages/LanguageInterface.php       |   96 +
 .../source/CAS/Languages/Portuguese.php       |  114 +
 .../phpcas/source/CAS/Languages/Spanish.php   |  117 +
 ...uenceBeforeAuthenticationCallException.php |   56 +
 .../OutOfSequenceBeforeClientException.php    |   58 +
 .../CAS/OutOfSequenceBeforeProxyException.php |   59 +
 .../source/CAS/OutOfSequenceException.php     |   49 +
 .../source/CAS/PGTStorage/AbstractStorage.php |  222 +
 .../jasig/phpcas/source/CAS/PGTStorage/Db.php |  440 ++
 .../phpcas/source/CAS/PGTStorage/File.php     |  261 +
 .../phpcas/source/CAS/ProxiedService.php      |   72 +
 .../source/CAS/ProxiedService/Abstract.php    |  149 +
 .../source/CAS/ProxiedService/Exception.php   |   46 +
 .../phpcas/source/CAS/ProxiedService/Http.php |   91 +
 .../CAS/ProxiedService/Http/Abstract.php      |  360 ++
 .../source/CAS/ProxiedService/Http/Get.php    |   85 +
 .../source/CAS/ProxiedService/Http/Post.php   |  152 +
 .../phpcas/source/CAS/ProxiedService/Imap.php |  281 ++
 .../source/CAS/ProxiedService/Testable.php    |   75 +
 vendor/jasig/phpcas/source/CAS/ProxyChain.php |  127 +
 .../source/CAS/ProxyChain/AllowedList.php     |  119 +
 .../phpcas/source/CAS/ProxyChain/Any.php      |   64 +
 .../source/CAS/ProxyChain/Interface.php       |   53 +
 .../phpcas/source/CAS/ProxyChain/Trusted.php  |   59 +
 .../source/CAS/ProxyTicketException.php       |   71 +
 .../source/CAS/Request/AbstractRequest.php    |  380 ++
 .../source/CAS/Request/CurlMultiRequest.php   |  147 +
 .../phpcas/source/CAS/Request/CurlRequest.php |  193 +
 .../phpcas/source/CAS/Request/Exception.php   |   45 +
 .../CAS/Request/MultiRequestInterface.php     |   83 +
 .../source/CAS/Request/RequestInterface.php   |  179 +
 .../phpcas/source/CAS/Session/PhpSession.php  |   45 +
 .../source/CAS/TypeMismatchException.php      |   70 +
 63 files changed, 13851 insertions(+), 1 deletion(-)
 create mode 100644 vendor/composer/InstalledVersions.php
 create mode 100644 vendor/composer/installed.php
 create mode 100644 vendor/composer/platform_check.php
 create mode 100644 vendor/jasig/phpcas/.codecov.yml
 create mode 100644 vendor/jasig/phpcas/.gitattributes
 create mode 100644 vendor/jasig/phpcas/.github/dependabot.yml
 create mode 100644 vendor/jasig/phpcas/.github/workflows/test.yml
 create mode 100644 vendor/jasig/phpcas/CAS.php
 create mode 100644 vendor/jasig/phpcas/LICENSE
 create mode 100644 vendor/jasig/phpcas/NOTICE
 create mode 100644 vendor/jasig/phpcas/README.md
 create mode 100644 vendor/jasig/phpcas/composer.json
 create mode 100644 vendor/jasig/phpcas/phpunit.xml.dist
 create mode 100644 vendor/jasig/phpcas/source/CAS.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/AuthenticationException.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Autoload.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Client.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/CookieJar.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Exception.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/GracefullTerminationException.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/InvalidArgumentException.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/Catalan.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/ChineseSimplified.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/English.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/French.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/Galego.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/German.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/Greek.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/Japanese.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/LanguageInterface.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/Portuguese.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Languages/Spanish.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeClientException.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/OutOfSequenceException.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/PGTStorage/AbstractStorage.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/PGTStorage/Db.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/PGTStorage/File.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService/Abstract.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService/Exception.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService/Http.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Abstract.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Get.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Post.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService/Imap.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxiedService/Testable.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxyChain.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxyChain/AllowedList.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxyChain/Any.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxyChain/Interface.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxyChain/Trusted.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/ProxyTicketException.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Request/AbstractRequest.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Request/CurlMultiRequest.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Request/CurlRequest.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Request/Exception.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Request/MultiRequestInterface.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Request/RequestInterface.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/Session/PhpSession.php
 create mode 100644 vendor/jasig/phpcas/source/CAS/TypeMismatchException.php

diff --git a/composer.json b/composer.json
index 6ccad4b22d..a234fe37d4 100755
--- a/composer.json
+++ b/composer.json
@@ -22,7 +22,7 @@
           "MaarchParapheur\\Tests\\": "test/unitTests/"
         }
       },
-  
+
     "require": {
         "slim/slim": "4.11.0",
         "respect/validation": "^2.2.3",
diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php
new file mode 100644
index 0000000000..c6b54af7ba
--- /dev/null
+++ b/vendor/composer/InstalledVersions.php
@@ -0,0 +1,352 @@
+<?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;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
+ */
+class InstalledVersions
+{
+    /**
+     * @var mixed[]|null
+     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
+     */
+    private static $installed;
+
+    /**
+     * @var bool|null
+     */
+    private static $canGetVendors;
+
+    /**
+     * @var array[]
+     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+     */
+    private static $installedByVendor = array();
+
+    /**
+     * Returns a list of all package names which are present, either by being installed, replaced or provided
+     *
+     * @return string[]
+     * @psalm-return list<string>
+     */
+    public static function getInstalledPackages()
+    {
+        $packages = array();
+        foreach (self::getInstalled() as $installed) {
+            $packages[] = array_keys($installed['versions']);
+        }
+
+        if (1 === \count($packages)) {
+            return $packages[0];
+        }
+
+        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+    }
+
+    /**
+     * Returns a list of all package names with a specific type e.g. 'library'
+     *
+     * @param  string   $type
+     * @return string[]
+     * @psalm-return list<string>
+     */
+    public static function getInstalledPackagesByType($type)
+    {
+        $packagesByType = array();
+
+        foreach (self::getInstalled() as $installed) {
+            foreach ($installed['versions'] as $name => $package) {
+                if (isset($package['type']) && $package['type'] === $type) {
+                    $packagesByType[] = $name;
+                }
+            }
+        }
+
+        return $packagesByType;
+    }
+
+    /**
+     * Checks whether the given package is installed
+     *
+     * This also returns true if the package name is provided or replaced by another package
+     *
+     * @param  string $packageName
+     * @param  bool   $includeDevRequirements
+     * @return bool
+     */
+    public static function isInstalled($packageName, $includeDevRequirements = true)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (isset($installed['versions'][$packageName])) {
+                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks whether the given package satisfies a version constraint
+     *
+     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+     *
+     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+     *
+     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
+     * @param  string        $packageName
+     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+     * @return bool
+     */
+    public static function satisfies(VersionParser $parser, $packageName, $constraint)
+    {
+        $constraint = $parser->parseConstraints($constraint);
+        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+        return $provided->matches($constraint);
+    }
+
+    /**
+     * Returns a version constraint representing all the range(s) which are installed for a given package
+     *
+     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+     * whether a given version of a package is installed, and not just whether it exists
+     *
+     * @param  string $packageName
+     * @return string Version constraint usable with composer/semver
+     */
+    public static function getVersionRanges($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            $ranges = array();
+            if (isset($installed['versions'][$packageName]['pretty_version'])) {
+                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+            }
+            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+            }
+            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+            }
+            if (array_key_exists('provided', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+            }
+
+            return implode(' || ', $ranges);
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+     */
+    public static function getVersion($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['version'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['version'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+     */
+    public static function getPrettyVersion($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['pretty_version'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+     */
+    public static function getReference($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['reference'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['reference'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+     */
+    public static function getInstallPath($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @return array
+     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
+     */
+    public static function getRootPackage()
+    {
+        $installed = self::getInstalled();
+
+        return $installed[0]['root'];
+    }
+
+    /**
+     * Returns the raw installed.php data for custom implementations
+     *
+     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+     * @return array[]
+     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
+     */
+    public static function getRawData()
+    {
+        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+        if (null === self::$installed) {
+            // only require the installed.php file if this file is loaded from its dumped location,
+            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+            if (substr(__DIR__, -8, 1) !== 'C') {
+                self::$installed = include __DIR__ . '/installed.php';
+            } else {
+                self::$installed = array();
+            }
+        }
+
+        return self::$installed;
+    }
+
+    /**
+     * Returns the raw data of all installed.php which are currently loaded for custom implementations
+     *
+     * @return array[]
+     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+     */
+    public static function getAllRawData()
+    {
+        return self::getInstalled();
+    }
+
+    /**
+     * Lets you reload the static array from another file
+     *
+     * This is only useful for complex integrations in which a project needs to use
+     * this class but then also needs to execute another project's autoloader in process,
+     * and wants to ensure both projects have access to their version of installed.php.
+     *
+     * A typical case would be PHPUnit, where it would need to make sure it reads all
+     * the data it needs from this class, then call reload() with
+     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+     * the project in which it runs can then also use this class safely, without
+     * interference between PHPUnit's dependencies and the project's dependencies.
+     *
+     * @param  array[] $data A vendor/composer/installed.php data set
+     * @return void
+     *
+     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
+     */
+    public static function reload($data)
+    {
+        self::$installed = $data;
+        self::$installedByVendor = array();
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+     */
+    private static function getInstalled()
+    {
+        if (null === self::$canGetVendors) {
+            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+        }
+
+        $installed = array();
+
+        if (self::$canGetVendors) {
+            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+                if (isset(self::$installedByVendor[$vendorDir])) {
+                    $installed[] = self::$installedByVendor[$vendorDir];
+                } elseif (is_file($vendorDir.'/composer/installed.php')) {
+                    $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
+                    if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+                        self::$installed = $installed[count($installed) - 1];
+                    }
+                }
+            }
+        }
+
+        if (null === self::$installed) {
+            // only require the installed.php file if this file is loaded from its dumped location,
+            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+            if (substr(__DIR__, -8, 1) !== 'C') {
+                self::$installed = require __DIR__ . '/installed.php';
+            } else {
+                self::$installed = array();
+            }
+        }
+        $installed[] = self::$installed;
+
+        return $installed;
+    }
+}
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
new file mode 100644
index 0000000000..eb814bdf4f
--- /dev/null
+++ b/vendor/composer/installed.php
@@ -0,0 +1,416 @@
+<?php return array(
+    'root' => array(
+        'name' => '__root__',
+        'pretty_version' => 'dev-develop',
+        'version' => 'dev-develop',
+        'reference' => 'ea1861a64fad1b68bf43e4a6a4656f2c60ecd661',
+        'type' => 'library',
+        'install_path' => __DIR__ . '/../../',
+        'aliases' => array(),
+        'dev' => true,
+    ),
+    'versions' => array(
+        '__root__' => array(
+            'pretty_version' => 'dev-develop',
+            'version' => 'dev-develop',
+            'reference' => 'ea1861a64fad1b68bf43e4a6a4656f2c60ecd661',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../../',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'doctrine/instantiator' => array(
+            'pretty_version' => '1.4.1',
+            'version' => '1.4.1.0',
+            'reference' => '10dcfce151b967d20fde1b34ae6640712c3891bc',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../doctrine/instantiator',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'firebase/php-jwt' => array(
+            'pretty_version' => 'v5.5.1',
+            'version' => '5.5.1.0',
+            'reference' => '83b609028194aa042ea33b5af2d41a7427de80e6',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../firebase/php-jwt',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'jasig/phpcas' => array(
+            'pretty_version' => '1.5.0',
+            'version' => '1.5.0.0',
+            'reference' => 'd6f5797fb568726f34c8e48741776d81e4a2646b',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../jasig/phpcas',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'myclabs/deep-copy' => array(
+            'pretty_version' => '1.11.0',
+            'version' => '1.11.0.0',
+            'reference' => '14daed4296fae74d9e3201d2c4925d1acb7aa614',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../myclabs/deep-copy',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'nikic/fast-route' => array(
+            'pretty_version' => 'v1.3.0',
+            'version' => '1.3.0.0',
+            'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../nikic/fast-route',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'nikic/php-parser' => array(
+            'pretty_version' => 'v4.15.2',
+            'version' => '4.15.2.0',
+            'reference' => 'f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../nikic/php-parser',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'phar-io/manifest' => array(
+            'pretty_version' => '2.0.3',
+            'version' => '2.0.3.0',
+            'reference' => '97803eca37d319dfa7826cc2437fc020857acb53',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phar-io/manifest',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'phar-io/version' => array(
+            'pretty_version' => '3.2.1',
+            'version' => '3.2.1.0',
+            'reference' => '4f7fd7836c6f332bb2933569e566a0d6c4cbed74',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phar-io/version',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'phpmailer/phpmailer' => array(
+            'pretty_version' => 'v6.7.1',
+            'version' => '6.7.1.0',
+            'reference' => '49cd7ea3d2563f028d7811f06864a53b1f15ff55',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phpmailer/phpmailer',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'phpunit/php-code-coverage' => array(
+            'pretty_version' => '9.2.22',
+            'version' => '9.2.22.0',
+            'reference' => 'e4bf60d2220b4baaa0572986b5d69870226b06df',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phpunit/php-code-coverage',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'phpunit/php-file-iterator' => array(
+            'pretty_version' => '3.0.6',
+            'version' => '3.0.6.0',
+            'reference' => 'cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phpunit/php-file-iterator',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'phpunit/php-invoker' => array(
+            'pretty_version' => '3.1.1',
+            'version' => '3.1.1.0',
+            'reference' => '5a10147d0aaf65b58940a0b72f71c9ac0423cc67',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phpunit/php-invoker',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'phpunit/php-text-template' => array(
+            'pretty_version' => '2.0.4',
+            'version' => '2.0.4.0',
+            'reference' => '5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phpunit/php-text-template',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'phpunit/php-timer' => array(
+            'pretty_version' => '5.0.3',
+            'version' => '5.0.3.0',
+            'reference' => '5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phpunit/php-timer',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'phpunit/phpunit' => array(
+            'pretty_version' => '9.5.27',
+            'version' => '9.5.27.0',
+            'reference' => 'a2bc7ffdca99f92d959b3f2270529334030bba38',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phpunit/phpunit',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'pimple/pimple' => array(
+            'pretty_version' => 'v3.5.0',
+            'version' => '3.5.0.0',
+            'reference' => 'a94b3a4db7fb774b3d78dad2315ddc07629e1bed',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../pimple/pimple',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/container' => array(
+            'pretty_version' => '1.1.2',
+            'version' => '1.1.2.0',
+            'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/container',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/http-message' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/http-message',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/http-message-implementation' => array(
+            'dev_requirement' => false,
+            'provided' => array(
+                0 => '1.0',
+            ),
+        ),
+        'psr/log' => array(
+            'pretty_version' => '1.1.4',
+            'version' => '1.1.4.0',
+            'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/log',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'respect/stringifier' => array(
+            'pretty_version' => '0.2.0',
+            'version' => '0.2.0.0',
+            'reference' => 'e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../respect/stringifier',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'respect/validation' => array(
+            'pretty_version' => '2.2.3',
+            'version' => '2.2.3.0',
+            'reference' => '4c21a7ffc9a4915673cb2c2843963919e664e627',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../respect/validation',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'sebastian/cli-parser' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => '442e7c7e687e42adc03470c7b668bc4b2402c0b2',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/cli-parser',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/code-unit' => array(
+            'pretty_version' => '1.0.8',
+            'version' => '1.0.8.0',
+            'reference' => '1fc9f64c0927627ef78ba436c9b17d967e68e120',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/code-unit',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/code-unit-reverse-lookup' => array(
+            'pretty_version' => '2.0.3',
+            'version' => '2.0.3.0',
+            'reference' => 'ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/comparator' => array(
+            'pretty_version' => '4.0.8',
+            'version' => '4.0.8.0',
+            'reference' => 'fa0f136dd2334583309d32b62544682ee972b51a',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/comparator',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/complexity' => array(
+            'pretty_version' => '2.0.2',
+            'version' => '2.0.2.0',
+            'reference' => '739b35e53379900cc9ac327b2147867b8b6efd88',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/complexity',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/diff' => array(
+            'pretty_version' => '4.0.4',
+            'version' => '4.0.4.0',
+            'reference' => '3461e3fccc7cfdfc2720be910d3bd73c69be590d',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/diff',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/environment' => array(
+            'pretty_version' => '5.1.4',
+            'version' => '5.1.4.0',
+            'reference' => '1b5dff7bb151a4db11d49d90e5408e4e938270f7',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/environment',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/exporter' => array(
+            'pretty_version' => '4.0.5',
+            'version' => '4.0.5.0',
+            'reference' => 'ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/exporter',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/global-state' => array(
+            'pretty_version' => '5.0.5',
+            'version' => '5.0.5.0',
+            'reference' => '0ca8db5a5fc9c8646244e629625ac486fa286bf2',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/global-state',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/lines-of-code' => array(
+            'pretty_version' => '1.0.3',
+            'version' => '1.0.3.0',
+            'reference' => 'c1c2e997aa3146983ed888ad08b15470a2e22ecc',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/lines-of-code',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/object-enumerator' => array(
+            'pretty_version' => '4.0.4',
+            'version' => '4.0.4.0',
+            'reference' => '5c9eeac41b290a3712d88851518825ad78f45c71',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/object-enumerator',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/object-reflector' => array(
+            'pretty_version' => '2.0.4',
+            'version' => '2.0.4.0',
+            'reference' => 'b4f479ebdbf63ac605d183ece17d8d7fe49c15c7',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/object-reflector',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/recursion-context' => array(
+            'pretty_version' => '4.0.4',
+            'version' => '4.0.4.0',
+            'reference' => 'cd9d8cf3c5804de4341c283ed787f099f5506172',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/recursion-context',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/resource-operations' => array(
+            'pretty_version' => '3.0.3',
+            'version' => '3.0.3.0',
+            'reference' => '0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/resource-operations',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/type' => array(
+            'pretty_version' => '3.2.0',
+            'version' => '3.2.0.0',
+            'reference' => 'fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/type',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'sebastian/version' => array(
+            'pretty_version' => '3.0.2',
+            'version' => '3.0.2.0',
+            'reference' => 'c6c1022351a901512170118436c764e473f6de8c',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sebastian/version',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'setasign/fpdi' => array(
+            'pretty_version' => 'v2.3.6',
+            'version' => '2.3.6.0',
+            'reference' => '6231e315f73e4f62d72b73f3d6d78ff0eed93c31',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../setasign/fpdi',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'setasign/fpdi-tcpdf' => array(
+            'pretty_version' => 'v2.3.0',
+            'version' => '2.3.0.0',
+            'reference' => 'f6711a95cba64db16e1a63e1b6195827a2150c93',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../setasign/fpdi-tcpdf',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'slim/slim' => array(
+            'pretty_version' => '3.12.4',
+            'version' => '3.12.4.0',
+            'reference' => 'ce3cb65a06325fc9fe3d0223f2ae23113a767304',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../slim/slim',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'symfony/polyfill-mbstring' => array(
+            'pretty_version' => 'v1.27.0',
+            'version' => '1.27.0.0',
+            'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'tecnickcom/tcpdf' => array(
+            'pretty_version' => '6.6.2',
+            'version' => '6.6.2.0',
+            'reference' => 'e3cffc9bcbc76e89e167e9eb0bbda0cab7518459',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../tecnickcom/tcpdf',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'theseer/tokenizer' => array(
+            'pretty_version' => '1.2.1',
+            'version' => '1.2.1.0',
+            'reference' => '34a41e998c2183e22995f158c581e7b5e755ab9e',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../theseer/tokenizer',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+    ),
+);
diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php
new file mode 100644
index 0000000000..580fa96095
--- /dev/null
+++ b/vendor/composer/platform_check.php
@@ -0,0 +1,26 @@
+<?php
+
+// platform_check.php @generated by Composer
+
+$issues = array();
+
+if (!(PHP_VERSION_ID >= 70400)) {
+    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+        } elseif (!headers_sent()) {
+            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+        }
+    }
+    trigger_error(
+        'Composer detected issues in your platform: ' . implode(' ', $issues),
+        E_USER_ERROR
+    );
+}
diff --git a/vendor/jasig/phpcas/.codecov.yml b/vendor/jasig/phpcas/.codecov.yml
new file mode 100644
index 0000000000..ddfdd0effb
--- /dev/null
+++ b/vendor/jasig/phpcas/.codecov.yml
@@ -0,0 +1,17 @@
+codecov:
+  strict_yaml_branch: master
+
+coverage:
+  round: up
+  precision: 2
+  status:
+    project:
+      default:
+        target: "70%"
+        informational: true
+    patch: # temporarily disabled
+      default:
+        target: "70%"
+        informational: true
+
+comment: false
diff --git a/vendor/jasig/phpcas/.gitattributes b/vendor/jasig/phpcas/.gitattributes
new file mode 100644
index 0000000000..3e28f4e425
--- /dev/null
+++ b/vendor/jasig/phpcas/.gitattributes
@@ -0,0 +1,7 @@
+/docs/ export-ignore
+/test/ export-ignore
+/utils/ export-ignore
+/.buildpath export-ignore
+/.gitignore export-ignore
+/.project export-ignore
+/.travis.yml export-ignore
diff --git a/vendor/jasig/phpcas/.github/dependabot.yml b/vendor/jasig/phpcas/.github/dependabot.yml
new file mode 100644
index 0000000000..c630ffa6b3
--- /dev/null
+++ b/vendor/jasig/phpcas/.github/dependabot.yml
@@ -0,0 +1,7 @@
+version: 2
+updates:
+- package-ecosystem: composer
+  directory: "/"
+  schedule:
+    interval: daily
+  open-pull-requests-limit: 10
diff --git a/vendor/jasig/phpcas/.github/workflows/test.yml b/vendor/jasig/phpcas/.github/workflows/test.yml
new file mode 100644
index 0000000000..081e334d61
--- /dev/null
+++ b/vendor/jasig/phpcas/.github/workflows/test.yml
@@ -0,0 +1,43 @@
+name: Test
+
+on:
+  - push
+  - pull_request
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+
+    strategy:
+      fail-fast: false
+      matrix:
+        php-version:
+          - php: '7.2'
+            phpunit: '8' 
+          - php: '7.3'
+            phpunit: latest
+          - php: '7.4'
+            phpunit: latest
+          - php: '8.0'
+            phpunit: latest
+          - php: '8.1'
+            phpunit: latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: php-actions/composer@v6
+        with:
+          php_version: "${{ matrix.php-version.php }}"
+      - name: Run PHPUnit
+        uses: php-actions/phpunit@v3
+        with:
+          version: "${{ matrix.php-version.phpunit }}"
+          php_version: "${{ matrix.php-version.php }}"
+          php_extensions: xdebug
+          args: --verbose --coverage-clover=coverage.xml
+          bootstrap: vendor/autoload.php
+        env:
+          XDEBUG_MODE: coverage
+      - name: Report coverage
+        uses: codecov/codecov-action@v1
+        with:
+          files: coverage.xml
diff --git a/vendor/jasig/phpcas/CAS.php b/vendor/jasig/phpcas/CAS.php
new file mode 100644
index 0000000000..6ddcf07bce
--- /dev/null
+++ b/vendor/jasig/phpcas/CAS.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+require_once __DIR__.'/source/CAS.php';
+
+trigger_error('Including CAS.php is deprecated. Install phpCAS using composer instead.', E_USER_DEPRECATED);
diff --git a/vendor/jasig/phpcas/LICENSE b/vendor/jasig/phpcas/LICENSE
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/vendor/jasig/phpcas/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/vendor/jasig/phpcas/NOTICE b/vendor/jasig/phpcas/NOTICE
new file mode 100644
index 0000000000..70d9ffcd4c
--- /dev/null
+++ b/vendor/jasig/phpcas/NOTICE
@@ -0,0 +1,81 @@
+Copyright 2007-2011, JA-SIG, Inc.
+This project includes software developed by Jasig.
+http://www.jasig.org/
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this software except in compliance with the License.
+You may obtain a copy of the License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+===========================================================================
+
+Copyright © 2003-2007, The ESUP-Portail consortium
+
+Requirements for sources originally licensed under the New BSD License:
+
+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 JA-SIG, Inc. nor the names of its 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.
+
+===========================================================================
+
+Copyright (c) 2009, Regents of the University of Nebraska
+All rights reserved.
+
+Requirements for CAS_Autloader originally licensed under the New BSD License:
+
+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 the University of Nebraska nor the names of its 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/vendor/jasig/phpcas/README.md b/vendor/jasig/phpcas/README.md
new file mode 100644
index 0000000000..d48128912e
--- /dev/null
+++ b/vendor/jasig/phpcas/README.md
@@ -0,0 +1,35 @@
+phpCAS
+=======
+
+phpCAS is an authentication library that allows PHP applications to easily authenticate
+users via a Central Authentication Service (CAS) server.
+
+Please see the wiki website for more information:
+
+https://apereo.github.io/phpCAS/
+
+Api documentation can be found here:
+
+https://apereo.github.io/phpCAS/api/
+
+
+[![Test](https://github.com/apereo/phpCAS/actions/workflows/test.yml/badge.svg)](https://github.com/apereo/phpCAS/actions/workflows/test.yml)
+
+LICENSE
+-------
+
+Copyright 2007-2020, Apereo Foundation.
+This project includes software developed by Apereo Foundation.
+http://www.apereo.org/
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this software except in compliance with the License.
+You may obtain a copy of the License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/jasig/phpcas/composer.json b/vendor/jasig/phpcas/composer.json
new file mode 100644
index 0000000000..89ab7b9f61
--- /dev/null
+++ b/vendor/jasig/phpcas/composer.json
@@ -0,0 +1,55 @@
+{
+	"name" : "apereo/phpcas",
+	"description" : "Provides a simple API for authenticating users against a CAS server",
+	"keywords" : [
+		"cas",
+		"jasig",
+		"apereo"
+	],
+	"homepage" : "https://wiki.jasig.org/display/CASC/phpCAS",
+	"type" : "library",
+	"license" : "Apache-2.0",
+	"authors" : [{
+			"name" : "Joachim Fritschi",
+			"homepage" : "https://github.com/jfritschi",
+			"email" : "jfritschi@freenet.de"
+		}, {
+			"name" : "Adam Franco",
+			"homepage" : "https://github.com/adamfranco"
+		}, {
+			"name" : "Henry Pan",
+			"homepage" : "https://github.com/phy25"
+		}
+	],
+	"require" : {
+		"php" : ">=7.1.0",
+		"ext-curl" : "*",
+		"ext-dom"  : "*",
+		"psr/log" : "^1.0 || ^2.0 || ^3.0"
+    },
+	"require-dev" : {
+		"monolog/monolog" : "^1.0.0 || ^2.0.0",
+		"phpunit/phpunit" : ">=7.5", 
+		"phpstan/phpstan" : "^1.5"
+	},
+	"autoload" : {
+		"classmap" : [
+			"source/"
+		]
+	},
+	"autoload-dev" : {
+		"files": ["source/CAS.php"],
+		"psr-4" : {
+			"PhpCas\\" : "test/CAS/"
+		}
+	},
+	"scripts" : {
+		"test" : "phpunit", 
+		"phpstan" : "phpstan"
+	},
+	"extra" : {
+		"branch-alias" : {
+			"dev-master" : "1.3.x-dev"
+		}
+	}
+}
diff --git a/vendor/jasig/phpcas/phpunit.xml.dist b/vendor/jasig/phpcas/phpunit.xml.dist
new file mode 100644
index 0000000000..f0431f153f
--- /dev/null
+++ b/vendor/jasig/phpcas/phpunit.xml.dist
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="source/CAS.php" convertNoticesToExceptions="false" colors="true" stderr="true" backupGlobals="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
+  <coverage includeUncoveredFiles="false">
+    <include>
+      <directory>source/</directory>
+    </include>
+  </coverage>
+  <testsuites>
+    <testsuite name="phpCAS Tests">
+      <directory>test/CAS/Tests/</directory>
+    </testsuite>
+  </testsuites>
+</phpunit>
diff --git a/vendor/jasig/phpcas/source/CAS.php b/vendor/jasig/phpcas/source/CAS.php
new file mode 100644
index 0000000000..c30e22d0ab
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS.php
@@ -0,0 +1,2065 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ *
+ * Interface class of the phpCAS library
+ * PHP Version 7
+ *
+ * @file     CAS/CAS.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
+ * @author   Brett Bieber <brett.bieber@gmail.com>
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ * @ingroup public
+ */
+
+use Psr\Log\LoggerInterface;
+
+//
+// hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI']
+// in IIS
+//
+if (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['QUERY_STRING'])) {
+    $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
+}
+
+
+// ########################################################################
+//  CONSTANTS
+// ########################################################################
+
+// ------------------------------------------------------------------------
+//  CAS VERSIONS
+// ------------------------------------------------------------------------
+
+/**
+ * phpCAS version. accessible for the user by phpCAS::getVersion().
+ */
+define('PHPCAS_VERSION', '1.5.0');
+
+/**
+ * @addtogroup public
+ * @{
+ */
+
+/**
+ * phpCAS supported protocols. accessible for the user by phpCAS::getSupportedProtocols().
+ */
+
+/**
+ * CAS version 1.0
+ */
+define("CAS_VERSION_1_0", '1.0');
+/*!
+ * CAS version 2.0
+*/
+define("CAS_VERSION_2_0", '2.0');
+/**
+ * CAS version 3.0
+ */
+define("CAS_VERSION_3_0", '3.0');
+
+// ------------------------------------------------------------------------
+//  SAML defines
+// ------------------------------------------------------------------------
+
+/**
+ * SAML protocol
+ */
+define("SAML_VERSION_1_1", 'S1');
+
+/**
+ * XML header for SAML POST
+ */
+define("SAML_XML_HEADER", '<?xml version="1.0" encoding="UTF-8"?>');
+
+/**
+ * SOAP envelope for SAML POST
+ */
+define("SAML_SOAP_ENV", '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/>');
+
+/**
+ * SOAP body for SAML POST
+ */
+define("SAML_SOAP_BODY", '<SOAP-ENV:Body>');
+
+/**
+ * SAMLP request
+ */
+define("SAMLP_REQUEST", '<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"  MajorVersion="1" MinorVersion="1" RequestID="_192.168.16.51.1024506224022" IssueInstant="2002-06-19T17:03:44.022Z">');
+define("SAMLP_REQUEST_CLOSE", '</samlp:Request>');
+
+/**
+ * SAMLP artifact tag (for the ticket)
+ */
+define("SAML_ASSERTION_ARTIFACT", '<samlp:AssertionArtifact>');
+
+/**
+ * SAMLP close
+ */
+define("SAML_ASSERTION_ARTIFACT_CLOSE", '</samlp:AssertionArtifact>');
+
+/**
+ * SOAP body close
+ */
+define("SAML_SOAP_BODY_CLOSE", '</SOAP-ENV:Body>');
+
+/**
+ * SOAP envelope close
+ */
+define("SAML_SOAP_ENV_CLOSE", '</SOAP-ENV:Envelope>');
+
+/**
+ * SAML Attributes
+ */
+define("SAML_ATTRIBUTES", 'SAMLATTRIBS');
+
+/** @} */
+/**
+ * @addtogroup publicPGTStorage
+ * @{
+ */
+// ------------------------------------------------------------------------
+//  FILE PGT STORAGE
+// ------------------------------------------------------------------------
+/**
+ * Default path used when storing PGT's to file
+ */
+define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH", session_save_path());
+/** @} */
+// ------------------------------------------------------------------------
+// SERVICE ACCESS ERRORS
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup publicServices
+ * @{
+ */
+
+/**
+ * phpCAS::service() error code on success
+ */
+define("PHPCAS_SERVICE_OK", 0);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the CAS server did not respond.
+ */
+define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE", 1);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the response of the CAS server was ill-formed.
+ */
+define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE", 2);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the CAS server did not want to.
+ */
+define("PHPCAS_SERVICE_PT_FAILURE", 3);
+/**
+ * phpCAS::service() error code when the service was not available.
+ */
+define("PHPCAS_SERVICE_NOT_AVAILABLE", 4);
+
+// ------------------------------------------------------------------------
+// SERVICE TYPES
+// ------------------------------------------------------------------------
+/**
+ * phpCAS::getProxiedService() type for HTTP GET
+ */
+define("PHPCAS_PROXIED_SERVICE_HTTP_GET", 'CAS_ProxiedService_Http_Get');
+/**
+ * phpCAS::getProxiedService() type for HTTP POST
+ */
+define("PHPCAS_PROXIED_SERVICE_HTTP_POST", 'CAS_ProxiedService_Http_Post');
+/**
+ * phpCAS::getProxiedService() type for IMAP
+ */
+define("PHPCAS_PROXIED_SERVICE_IMAP", 'CAS_ProxiedService_Imap');
+
+
+/** @} */
+// ------------------------------------------------------------------------
+//  LANGUAGES
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup publicLang
+ * @{
+ */
+
+define("PHPCAS_LANG_ENGLISH", 'CAS_Languages_English');
+define("PHPCAS_LANG_FRENCH", 'CAS_Languages_French');
+define("PHPCAS_LANG_GREEK", 'CAS_Languages_Greek');
+define("PHPCAS_LANG_GERMAN", 'CAS_Languages_German');
+define("PHPCAS_LANG_JAPANESE", 'CAS_Languages_Japanese');
+define("PHPCAS_LANG_SPANISH", 'CAS_Languages_Spanish');
+define("PHPCAS_LANG_CATALAN", 'CAS_Languages_Catalan');
+define("PHPCAS_LANG_CHINESE_SIMPLIFIED", 'CAS_Languages_ChineseSimplified');
+define("PHPCAS_LANG_GALEGO", 'CAS_Languages_Galego');
+define("PHPCAS_LANG_PORTUGUESE", 'CAS_Languages_Portuguese');
+
+/** @} */
+
+/**
+ * @addtogroup internalLang
+ * @{
+ */
+
+/**
+ * phpCAS default language (when phpCAS::setLang() is not used)
+ */
+define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH);
+
+/** @} */
+// ------------------------------------------------------------------------
+//  DEBUG
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup publicDebug
+ * @{
+ */
+
+/**
+ * The default directory for the debug file under Unix.
+ * @return  string directory for the debug file
+ */
+function gettmpdir() {
+if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
+if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
+if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
+return "/tmp";
+}
+define('DEFAULT_DEBUG_DIR', gettmpdir()."/");
+
+/** @} */
+
+// include the class autoloader
+require_once __DIR__ . '/CAS/Autoload.php';
+
+/**
+ * The phpCAS class is a simple container for the phpCAS library. It provides CAS
+ * authentication for web applications written in PHP.
+ *
+ * @ingroup public
+ * @class phpCAS
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
+ * @author   Brett Bieber <brett.bieber@gmail.com>
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class phpCAS
+{
+
+    /**
+     * This variable is used by the interface class phpCAS.
+     *
+     * @var CAS_Client
+     * @hideinitializer
+     */
+    private static $_PHPCAS_CLIENT;
+
+    /**
+     * @var array
+     * This variable is used to store where the initializer is called from
+     * (to print a comprehensive error in case of multiple calls).
+     *
+     * @hideinitializer
+     */
+    private static $_PHPCAS_INIT_CALL;
+
+    /**
+     * @var array
+     * This variable is used to store phpCAS debug mode.
+     *
+     * @hideinitializer
+     */
+    private static $_PHPCAS_DEBUG;
+
+    /**
+     * This variable is used to enable verbose mode
+     * This pevents debug info to be show to the user. Since it's a security
+     * feature the default is false
+     *
+     * @hideinitializer
+     */
+    private static $_PHPCAS_VERBOSE = false;
+
+
+    // ########################################################################
+    //  INITIALIZATION
+    // ########################################################################
+
+    /**
+     * @addtogroup publicInit
+     * @{
+     */
+
+    /**
+     * phpCAS client initializer.
+     *
+     * @param string                   $server_version  the version of the CAS server
+     * @param string                   $server_hostname the hostname of the CAS server
+     * @param int                      $server_port     the port the CAS server is running on
+     * @param string                   $server_uri      the URI the CAS server is responding on
+     * @param bool                     $changeSessionID Allow phpCAS to change the session_id
+     *                                                  (Single Sign Out/handleLogoutRequests
+     *                                                  is based on that change)
+     * @param \SessionHandlerInterface $sessionHandler  the session handler
+     *
+     * @return void a newly created CAS_Client object
+     * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
+     * called, only once, and before all other methods (except phpCAS::getVersion()
+     * and phpCAS::setDebug()).
+     */
+    public static function client($server_version, $server_hostname,
+        $server_port, $server_uri, $changeSessionID = true, \SessionHandlerInterface $sessionHandler = null
+    ) {
+        phpCAS :: traceBegin();
+        if (is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
+        }
+
+        // store where the initializer is called from
+        $dbg = debug_backtrace();
+        self::$_PHPCAS_INIT_CALL = array (
+            'done' => true,
+            'file' => $dbg[0]['file'],
+            'line' => $dbg[0]['line'],
+            'method' => __CLASS__ . '::' . __FUNCTION__
+        );
+
+        // initialize the object $_PHPCAS_CLIENT
+        try {
+            self::$_PHPCAS_CLIENT = new CAS_Client(
+                $server_version, false, $server_hostname, $server_port, $server_uri,
+                $changeSessionID, $sessionHandler
+            );
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * phpCAS proxy initializer.
+     *
+     * @param string                   $server_version  the version of the CAS server
+     * @param string                   $server_hostname the hostname of the CAS server
+     * @param string                   $server_port     the port the CAS server is running on
+     * @param string                   $server_uri      the URI the CAS server is responding on
+     * @param bool                     $changeSessionID Allow phpCAS to change the session_id
+     *                                                  (Single Sign Out/handleLogoutRequests
+     *                                                  is based on that change)
+     * @param \SessionHandlerInterface $sessionHandler  the session handler
+     *
+     * @return void a newly created CAS_Client object
+     * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
+     * called, only once, and before all other methods (except phpCAS::getVersion()
+     * and phpCAS::setDebug()).
+     */
+    public static function proxy($server_version, $server_hostname,
+        $server_port, $server_uri, $changeSessionID = true, \SessionHandlerInterface $sessionHandler = null
+    ) {
+        phpCAS :: traceBegin();
+        if (is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
+        }
+
+        // store where the initialzer is called from
+        $dbg = debug_backtrace();
+        self::$_PHPCAS_INIT_CALL = array (
+            'done' => true,
+            'file' => $dbg[0]['file'],
+            'line' => $dbg[0]['line'],
+            'method' => __CLASS__ . '::' . __FUNCTION__
+        );
+
+        // initialize the object $_PHPCAS_CLIENT
+        try {
+            self::$_PHPCAS_CLIENT = new CAS_Client(
+                $server_version, true, $server_hostname, $server_port, $server_uri,
+                $changeSessionID, $sessionHandler
+            );
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Answer whether or not the client or proxy has been initialized
+     *
+     * @return bool
+     */
+    public static function isInitialized ()
+    {
+        return (is_object(self::$_PHPCAS_CLIENT));
+    }
+
+    /** @} */
+    // ########################################################################
+    //  DEBUGGING
+    // ########################################################################
+
+    /**
+     * @addtogroup publicDebug
+     * @{
+     */
+
+    /**
+     * Set/unset PSR-3 logger
+     *
+     * @param LoggerInterface $logger the PSR-3 logger used for logging, or
+     * null to stop logging.
+     *
+     * @return void
+     */
+    public static function setLogger($logger = null)
+    {
+        if (empty(self::$_PHPCAS_DEBUG['unique_id'])) {
+            self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);
+        }
+        self::$_PHPCAS_DEBUG['logger'] = $logger;
+        self::$_PHPCAS_DEBUG['indent'] = 0;
+        phpCAS :: trace('START ('.date("Y-m-d H:i:s").') phpCAS-' . PHPCAS_VERSION . ' ******************');
+    }
+
+    /**
+     * Set/unset debug mode
+     *
+     * @param string $filename the name of the file used for logging, or false
+     * to stop debugging.
+     *
+     * @return void
+     *
+     * @deprecated
+     */
+    public static function setDebug($filename = '')
+    {
+        trigger_error('phpCAS::setDebug() is deprecated in favor of phpCAS::setLogger().', E_USER_DEPRECATED);
+
+        if ($filename != false && gettype($filename) != 'string') {
+            phpCAS :: error('type mismatched for parameter $dbg (should be false or the name of the log file)');
+        }
+        if ($filename === false) {
+            self::$_PHPCAS_DEBUG['filename'] = false;
+
+        } else {
+            if (empty ($filename)) {
+                if (preg_match('/^Win.*/', getenv('OS'))) {
+                    if (isset ($_ENV['TMP'])) {
+                        $debugDir = $_ENV['TMP'] . '/';
+                    } else {
+                        $debugDir = '';
+                    }
+                } else {
+                    $debugDir = DEFAULT_DEBUG_DIR;
+                }
+                $filename = $debugDir . 'phpCAS.log';
+            }
+
+            if (empty (self::$_PHPCAS_DEBUG['unique_id'])) {
+                self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);
+            }
+
+            self::$_PHPCAS_DEBUG['filename'] = $filename;
+            self::$_PHPCAS_DEBUG['indent'] = 0;
+
+            phpCAS :: trace('START ('.date("Y-m-d H:i:s").') phpCAS-' . PHPCAS_VERSION . ' ******************');
+        }
+    }
+
+    /**
+     * Enable verbose errors messages in the website output
+     * This is a security relevant since internal status info may leak an may
+     * help an attacker. Default is therefore false
+     *
+     * @param bool $verbose enable verbose output
+     *
+     * @return void
+     */
+    public static function setVerbose($verbose)
+    {
+        if ($verbose === true) {
+            self::$_PHPCAS_VERBOSE = true;
+        } else {
+            self::$_PHPCAS_VERBOSE = false;
+        }
+    }
+
+
+    /**
+     * Show is verbose mode is on
+     *
+     * @return bool verbose
+     */
+    public static function getVerbose()
+    {
+        return self::$_PHPCAS_VERBOSE;
+    }
+
+    /**
+     * Logs a string in debug mode.
+     *
+     * @param string $str the string to write
+     *
+     * @return void
+     * @private
+     */
+    public static function log($str)
+    {
+        $indent_str = ".";
+
+
+        if (isset(self::$_PHPCAS_DEBUG['logger']) || !empty(self::$_PHPCAS_DEBUG['filename'])) {
+            for ($i = 0; $i < self::$_PHPCAS_DEBUG['indent']; $i++) {
+
+                $indent_str .= '|    ';
+            }
+            // allow for multiline output with proper identing. Usefull for
+            // dumping cas answers etc.
+            $str2 = str_replace("\n", "\n" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str);
+            $str3 = self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2;
+            if (isset(self::$_PHPCAS_DEBUG['logger'])) {
+                self::$_PHPCAS_DEBUG['logger']->info($str3);
+            }
+            if (!empty(self::$_PHPCAS_DEBUG['filename'])) {
+                // Check if file exists and modifiy file permissions to be only
+                // readable by the webserver
+                if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {
+                    touch(self::$_PHPCAS_DEBUG['filename']);
+                    // Chmod will fail on windows
+                    @chmod(self::$_PHPCAS_DEBUG['filename'], 0600);
+                }
+                error_log($str3 . "\n", 3, self::$_PHPCAS_DEBUG['filename']);
+            }
+        }
+
+    }
+
+    /**
+     * This method is used by interface methods to print an error and where the
+     * function was originally called from.
+     *
+     * @param string $msg the message to print
+     *
+     * @return void
+     * @private
+     */
+    public static function error($msg)
+    {
+        phpCAS :: traceBegin();
+        $dbg = debug_backtrace();
+        $function = '?';
+        $file = '?';
+        $line = '?';
+        if (is_array($dbg)) {
+            for ($i = 1; $i < sizeof($dbg); $i++) {
+                if (is_array($dbg[$i]) && isset($dbg[$i]['class']) ) {
+                    if ($dbg[$i]['class'] == __CLASS__) {
+                        $function = $dbg[$i]['function'];
+                        $file = $dbg[$i]['file'];
+                        $line = $dbg[$i]['line'];
+                    }
+                }
+            }
+        }
+        if (self::$_PHPCAS_VERBOSE) {
+            echo "<br />\n<b>phpCAS error</b>: <font color=\"FF0000\"><b>" . __CLASS__ . "::" . $function . '(): ' . htmlentities($msg) . "</b></font> in <b>" . $file . "</b> on line <b>" . $line . "</b><br />\n";
+        }
+        phpCAS :: trace($msg . ' in ' . $file . 'on line ' . $line );
+        phpCAS :: traceEnd();
+
+        throw new CAS_GracefullTerminationException(__CLASS__ . "::" . $function . '(): ' . $msg);
+    }
+
+    /**
+     * This method is used to log something in debug mode.
+     *
+     * @param string $str string to log
+     *
+     * @return void
+     */
+    public static function trace($str)
+    {
+        $dbg = debug_backtrace();
+        phpCAS :: log($str . ' [' . basename($dbg[0]['file']) . ':' . $dbg[0]['line'] . ']');
+    }
+
+    /**
+     * This method is used to indicate the start of the execution of a function
+     * in debug mode.
+     *
+     * @return void
+     */
+    public static function traceBegin()
+    {
+        $dbg = debug_backtrace();
+        $str = '=> ';
+        if (!empty ($dbg[1]['class'])) {
+            $str .= $dbg[1]['class'] . '::';
+        }
+        $str .= $dbg[1]['function'] . '(';
+        if (is_array($dbg[1]['args'])) {
+            foreach ($dbg[1]['args'] as $index => $arg) {
+                if ($index != 0) {
+                    $str .= ', ';
+                }
+                if (is_object($arg)) {
+                    $str .= get_class($arg);
+                } else {
+                    $str .= str_replace(array("\r\n", "\n", "\r"), "", var_export($arg, true));
+                }
+            }
+        }
+        if (isset($dbg[1]['file'])) {
+            $file = basename($dbg[1]['file']);
+        } else {
+            $file = 'unknown_file';
+        }
+        if (isset($dbg[1]['line'])) {
+            $line = $dbg[1]['line'];
+        } else {
+            $line = 'unknown_line';
+        }
+        $str .= ') [' . $file . ':' . $line . ']';
+        phpCAS :: log($str);
+        if (!isset(self::$_PHPCAS_DEBUG['indent'])) {
+            self::$_PHPCAS_DEBUG['indent'] = 0;
+        } else {
+            self::$_PHPCAS_DEBUG['indent']++;
+        }
+    }
+
+    /**
+     * This method is used to indicate the end of the execution of a function in
+     * debug mode.
+     *
+     * @param mixed $res the result of the function
+     *
+     * @return void
+     */
+    public static function traceEnd($res = '')
+    {
+        if (empty(self::$_PHPCAS_DEBUG['indent'])) {
+            self::$_PHPCAS_DEBUG['indent'] = 0;
+        } else {
+            self::$_PHPCAS_DEBUG['indent']--;
+        }
+        $str = '';
+        if (is_object($res)) {
+            $str .= '<= ' . get_class($res);
+        } else {
+            $str .= '<= ' . str_replace(array("\r\n", "\n", "\r"), "", var_export($res, true));
+        }
+
+        phpCAS :: log($str);
+    }
+
+    /**
+     * This method is used to indicate the end of the execution of the program
+     *
+     * @return void
+     */
+    public static function traceExit()
+    {
+        phpCAS :: log('exit()');
+        while (self::$_PHPCAS_DEBUG['indent'] > 0) {
+            phpCAS :: log('-');
+            self::$_PHPCAS_DEBUG['indent']--;
+        }
+    }
+
+    /** @} */
+    // ########################################################################
+    //  INTERNATIONALIZATION
+    // ########################################################################
+    /**
+    * @addtogroup publicLang
+    * @{
+    */
+
+    /**
+     * This method is used to set the language used by phpCAS.
+     *
+     * @param string $lang string representing the language.
+     *
+     * @return void
+     *
+     * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH
+     * @note Can be called only once.
+     */
+    public static function setLang($lang)
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setLang($lang);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /** @} */
+    // ########################################################################
+    //  VERSION
+    // ########################################################################
+    /**
+    * @addtogroup public
+    * @{
+    */
+
+    /**
+     * This method returns the phpCAS version.
+     *
+     * @return string the phpCAS version.
+     */
+    public static function getVersion()
+    {
+        return PHPCAS_VERSION;
+    }
+
+    /**
+     * This method returns supported protocols.
+     *
+     * @return array an array of all supported protocols. Use internal protocol name as array key.
+     */
+    public static function getSupportedProtocols()
+    {
+        $supportedProtocols = array();
+        $supportedProtocols[CAS_VERSION_1_0] = 'CAS 1.0';
+        $supportedProtocols[CAS_VERSION_2_0] = 'CAS 2.0';
+        $supportedProtocols[CAS_VERSION_3_0] = 'CAS 3.0';
+        $supportedProtocols[SAML_VERSION_1_1] = 'SAML 1.1';
+
+        return $supportedProtocols;
+    }
+
+    /** @} */
+    // ########################################################################
+    //  HTML OUTPUT
+    // ########################################################################
+    /**
+    * @addtogroup publicOutput
+    * @{
+    */
+
+    /**
+     * This method sets the HTML header used for all outputs.
+     *
+     * @param string $header the HTML header.
+     *
+     * @return void
+     */
+    public static function setHTMLHeader($header)
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setHTMLHeader($header);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * This method sets the HTML footer used for all outputs.
+     *
+     * @param string $footer the HTML footer.
+     *
+     * @return void
+     */
+    public static function setHTMLFooter($footer)
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setHTMLFooter($footer);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /** @} */
+    // ########################################################################
+    //  PGT STORAGE
+    // ########################################################################
+    /**
+    * @addtogroup publicPGTStorage
+    * @{
+    */
+
+    /**
+     * This method can be used to set a custom PGT storage object.
+     *
+     * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that inherits from the
+     * CAS_PGTStorage_AbstractStorage class
+     *
+     * @return void
+     */
+    public static function setPGTStorage($storage)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateProxyExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setPGTStorage($storage);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to tell phpCAS to store the response of the
+     * CAS server to PGT requests in a database.
+     *
+     * @param string $dsn_or_pdo     a dsn string to use for creating a PDO
+     * object or a PDO object
+     * @param string $username       the username to use when connecting to the
+     * database
+     * @param string $password       the password to use when connecting to the
+     * database
+     * @param string $table          the table to use for storing and retrieving
+     * PGT's
+     * @param string $driver_options any driver options to use when connecting
+     * to the database
+     *
+     * @return void
+     */
+    public static function setPGTStorageDb($dsn_or_pdo, $username='',
+        $password='', $table='', $driver_options=null
+    ) {
+        phpCAS :: traceBegin();
+        phpCAS::_validateProxyExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to tell phpCAS to store the response of the
+     * CAS server to PGT requests onto the filesystem.
+     *
+     * @param string $path the path where the PGT's should be stored
+     *
+     * @return void
+     */
+    public static function setPGTStorageFile($path = '')
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateProxyExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setPGTStorageFile($path);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+        phpCAS :: traceEnd();
+    }
+    /** @} */
+    // ########################################################################
+    // ACCESS TO EXTERNAL SERVICES
+    // ########################################################################
+    /**
+    * @addtogroup publicServices
+    * @{
+    */
+
+    /**
+     * Answer a proxy-authenticated service handler.
+     *
+     * @param string $type The service type. One of
+     * PHPCAS_PROXIED_SERVICE_HTTP_GET; PHPCAS_PROXIED_SERVICE_HTTP_POST;
+     * PHPCAS_PROXIED_SERVICE_IMAP
+     *
+     * @return CAS_ProxiedService
+     * @throws InvalidArgumentException If the service type is unknown.
+     */
+    public static function getProxiedService ($type)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateProxyExists();
+
+        try {
+            $res = self::$_PHPCAS_CLIENT->getProxiedService($type);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+        return $res;
+    }
+
+    /**
+     * Initialize a proxied-service handler with the proxy-ticket it should use.
+     *
+     * @param CAS_ProxiedService $proxiedService Proxied Service Handler
+     *
+     * @return void
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *		The code of the Exception will be one of:
+     *			PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_FAILURE
+     */
+    public static function initializeProxiedService (CAS_ProxiedService $proxiedService)
+    {
+        phpCAS::_validateProxyExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * This method is used to access an HTTP[S] service.
+     *
+     * @param string $url       the service to access.
+     * @param int &$err_code an error code Possible values are
+     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
+     * PHPCAS_SERVICE_NOT_AVAILABLE.
+     * @param string &$output   the output of the service (also used to give an
+     * error message on failure).
+     *
+     * @return bool true on success, false otherwise (in this later case,
+     * $err_code gives the reason why it failed and $output contains an error
+     * message).
+     */
+    public static function serviceWeb($url, & $err_code, & $output)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateProxyExists();
+
+        try {
+            $res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * This method is used to access an IMAP/POP3/NNTP service.
+     *
+     * @param string $url       a string giving the URL of the service,
+     * including the mailing box for IMAP URLs, as accepted by imap_open().
+     * @param string $service   a string giving for CAS retrieve Proxy ticket
+     * @param string $flags     options given to imap_open().
+     * @param int &$err_code an error code Possible values are
+     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
+     * PHPCAS_SERVICE_NOT_AVAILABLE.
+     * @param string &$err_msg  an error message on failure
+     * @param string &$pt       the Proxy Ticket (PT) retrieved from the CAS
+     * server to access the URL on success, false on error).
+     *
+     * @return object|false IMAP stream on success, false otherwise (in this later
+     * case, $err_code gives the reason why it failed and $err_msg contains an
+     * error message).
+     */
+    public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateProxyExists();
+
+        try {
+            $res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd($res);
+        return $res;
+    }
+
+    /** @} */
+    // ########################################################################
+    //  AUTHENTICATION
+    // ########################################################################
+    /**
+    * @addtogroup publicAuth
+    * @{
+    */
+
+    /**
+     * Set the times authentication will be cached before really accessing the
+     * CAS server in gateway mode:
+     * - -1: check only once, and then never again (until you pree login)
+     * - 0: always check
+     * - n: check every "n" time
+     *
+     * @param int $n an integer.
+     *
+     * @return void
+     */
+    public static function setCacheTimesForAuthRecheck($n)
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+
+    /**
+     * Set a callback function to be run when receiving CAS attributes
+     *
+     * The callback function will be passed an $success_elements
+     * payload of the response (\DOMElement) as its first parameter.
+     *
+     * @param string $function       Callback function
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public static function setCasAttributeParserCallback($function, array $additionalArgs = array())
+    {
+        phpCAS::_validateClientExists();
+
+        self::$_PHPCAS_CLIENT->setCasAttributeParserCallback($function, $additionalArgs);
+    }
+
+    /**
+     * Set a callback function to be run when a user authenticates.
+     *
+     * The callback function will be passed a $logoutTicket as its first
+     * parameter, followed by any $additionalArgs you pass. The $logoutTicket
+     * parameter is an opaque string that can be used to map the session-id to
+     * logout request in order to support single-signout in applications that
+     * manage their own sessions (rather than letting phpCAS start the session).
+     *
+     * phpCAS::forceAuthentication() will always exit and forward client unless
+     * they are already authenticated. To perform an action at the moment the user
+     * logs in (such as registering an account, performing logging, etc), register
+     * a callback function here.
+     *
+     * @param callable $function       Callback function
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public static function setPostAuthenticateCallback ($function, array $additionalArgs = array())
+    {
+        phpCAS::_validateClientExists();
+
+        self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs);
+    }
+
+    /**
+     * Set a callback function to be run when a single-signout request is
+     * received. The callback function will be passed a $logoutTicket as its
+     * first parameter, followed by any $additionalArgs you pass. The
+     * $logoutTicket parameter is an opaque string that can be used to map a
+     * session-id to the logout request in order to support single-signout in
+     * applications that manage their own sessions (rather than letting phpCAS
+     * start and destroy the session).
+     *
+     * @param callable $function       Callback function
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public static function setSingleSignoutCallback ($function, array $additionalArgs = array())
+    {
+        phpCAS::_validateClientExists();
+
+        self::$_PHPCAS_CLIENT->setSingleSignoutCallback($function, $additionalArgs);
+    }
+
+    /**
+     * This method is called to check if the user is already authenticated
+     * locally or has a global cas session. A already existing cas session is
+     * determined by a cas gateway call.(cas login call without any interactive
+     * prompt)
+     *
+     * @return bool true when the user is authenticated, false when a previous
+     * gateway login failed or the function will not return if the user is
+     * redirected to the cas server for a gateway login attempt
+     */
+    public static function checkAuthentication()
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        $auth = self::$_PHPCAS_CLIENT->checkAuthentication();
+
+        // store where the authentication has been checked and the result
+        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
+
+        phpCAS :: traceEnd($auth);
+        return $auth;
+    }
+
+    /**
+     * This method is called to force authentication if the user was not already
+     * authenticated. If the user is not authenticated, halt by redirecting to
+     * the CAS server.
+     *
+     * @return bool Authentication
+     */
+    public static function forceAuthentication()
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+        $auth = self::$_PHPCAS_CLIENT->forceAuthentication();
+
+        // store where the authentication has been checked and the result
+        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
+
+        /*      if (!$auth) {
+         phpCAS :: trace('user is not authenticated, redirecting to the CAS server');
+        self::$_PHPCAS_CLIENT->forceAuthentication();
+        } else {
+        phpCAS :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\' is already authenticated)');
+        }*/
+
+        phpCAS :: traceEnd();
+        return $auth;
+    }
+
+    /**
+     * This method is called to renew the authentication.
+     *
+     * @return void
+     **/
+    public static function renewAuthentication()
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        $auth = self::$_PHPCAS_CLIENT->renewAuthentication();
+
+        // store where the authentication has been checked and the result
+        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
+
+        //self::$_PHPCAS_CLIENT->renewAuthentication();
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is called to check if the user is authenticated (previously or by
+     * tickets given in the URL).
+     *
+     * @return bool true when the user is authenticated.
+     */
+    public static function isAuthenticated()
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        // call the isAuthenticated method of the $_PHPCAS_CLIENT object
+        $auth = self::$_PHPCAS_CLIENT->isAuthenticated();
+
+        // store where the authentication has been checked and the result
+        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
+
+        phpCAS :: traceEnd($auth);
+        return $auth;
+    }
+
+    /**
+     * Checks whether authenticated based on $_SESSION. Useful to avoid
+     * server calls.
+     *
+     * @return bool true if authenticated, false otherwise.
+     * @since 0.4.22 by Brendan Arnold
+     */
+    public static function isSessionAuthenticated()
+    {
+        phpCAS::_validateClientExists();
+
+        return (self::$_PHPCAS_CLIENT->isSessionAuthenticated());
+    }
+
+    /**
+     * This method returns the CAS user's login name.
+     *
+     * @return string the login name of the authenticated user
+     * @warning should only be called after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     * */
+    public static function getUser()
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            return self::$_PHPCAS_CLIENT->getUser();
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * Answer attributes about the authenticated user.
+     *
+     * @warning should only be called after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     *
+     * @return array
+     */
+    public static function getAttributes()
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            return self::$_PHPCAS_CLIENT->getAttributes();
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * Answer true if there are attributes for the authenticated user.
+     *
+     * @warning should only be called after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     *
+     * @return bool
+     */
+    public static function hasAttributes()
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            return self::$_PHPCAS_CLIENT->hasAttributes();
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * Answer true if an attribute exists for the authenticated user.
+     *
+     * @param string $key attribute name
+     *
+     * @return bool
+     * @warning should only be called after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     */
+    public static function hasAttribute($key)
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            return self::$_PHPCAS_CLIENT->hasAttribute($key);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * Answer an attribute for the authenticated user.
+     *
+     * @param string $key attribute name
+     *
+     * @return mixed string for a single value or an array if multiple values exist.
+     * @warning should only be called after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     */
+    public static function getAttribute($key)
+    {
+        phpCAS::_validateClientExists();
+
+        try {
+            return self::$_PHPCAS_CLIENT->getAttribute($key);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * Handle logout requests.
+     *
+     * @param bool  $check_client    additional safety check
+     * @param array $allowed_clients array of allowed clients
+     *
+     * @return void
+     */
+    public static function handleLogoutRequests($check_client = true, $allowed_clients = array())
+    {
+        phpCAS::_validateClientExists();
+
+        return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients));
+    }
+
+    /**
+     * This method returns the URL to be used to login.
+     *
+     * @return string the login URL
+     */
+    public static function getServerLoginURL()
+    {
+        phpCAS::_validateClientExists();
+
+        return self::$_PHPCAS_CLIENT->getServerLoginURL();
+    }
+
+    /**
+     * Set the login URL of the CAS server.
+     *
+     * @param string $url the login URL
+     *
+     * @return void
+     * @since 0.4.21 by Wyman Chan
+     */
+    public static function setServerLoginURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setServerLoginURL($url);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the serviceValidate URL of the CAS server.
+     * Used for all CAS versions of URL validations.
+     * Examples:
+     * CAS 1.0 http://www.exemple.com/validate
+     * CAS 2.0 http://www.exemple.com/validateURL
+     * CAS 3.0 http://www.exemple.com/p3/serviceValidate
+     *
+     * @param string $url the serviceValidate URL
+     *
+     * @return void
+     */
+    public static function setServerServiceValidateURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the proxyValidate URL of the CAS server.
+     * Used for all CAS versions of proxy URL validations
+     * Examples:
+     * CAS 1.0 http://www.exemple.com/
+     * CAS 2.0 http://www.exemple.com/proxyValidate
+     * CAS 3.0 http://www.exemple.com/p3/proxyValidate
+     *
+     * @param string $url the proxyValidate URL
+     *
+     * @return void
+     */
+    public static function setServerProxyValidateURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the samlValidate URL of the CAS server.
+     *
+     * @param string $url the samlValidate URL
+     *
+     * @return void
+     */
+    public static function setServerSamlValidateURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method returns the URL to be used to logout.
+     *
+     * @return string the URL to use to log out
+     */
+    public static function getServerLogoutURL()
+    {
+        phpCAS::_validateClientExists();
+
+        return self::$_PHPCAS_CLIENT->getServerLogoutURL();
+    }
+
+    /**
+     * Set the logout URL of the CAS server.
+     *
+     * @param string $url the logout URL
+     *
+     * @return void
+     * @since 0.4.21 by Wyman Chan
+     */
+    public static function setServerLogoutURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setServerLogoutURL($url);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to logout from CAS.
+     *
+     * @param string $params an array that contains the optional url and
+     * service parameters that will be passed to the CAS server
+     *
+     * @return void
+     */
+    public static function logout($params = "")
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        $parsedParams = array ();
+        if ($params != "") {
+            if (is_string($params)) {
+                phpCAS :: error('method `phpCAS::logout($url)\' is now deprecated, use `phpCAS::logoutWithUrl($url)\' instead');
+            }
+            if (!is_array($params)) {
+                phpCAS :: error('type mismatched for parameter $params (should be `array\')');
+            }
+            foreach ($params as $key => $value) {
+                if ($key != "service" && $key != "url") {
+                    phpCAS :: error('only `url\' and `service\' parameters are allowed for method `phpCAS::logout($params)\'');
+                }
+                $parsedParams[$key] = $value;
+            }
+        }
+        self::$_PHPCAS_CLIENT->logout($parsedParams);
+        // never reached
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to logout from CAS. Halts by redirecting to the CAS
+     * server.
+     *
+     * @param string $service a URL that will be transmitted to the CAS server
+     *
+     * @return void
+     */
+    public static function logoutWithRedirectService($service)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        if (!is_string($service)) {
+            phpCAS :: error('type mismatched for parameter $service (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->logout(array ( "service" => $service ));
+        // never reached
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to logout from CAS. Halts by redirecting to the CAS
+     * server.
+     *
+     * @param string $url a URL that will be transmitted to the CAS server
+     *
+     * @return void
+     * @deprecated The url parameter has been removed from the CAS server as of
+     * version 3.3.5.1
+     */
+    public static function logoutWithUrl($url)
+    {
+        trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        if (!is_string($url)) {
+            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->logout(array ( "url" => $url ));
+        // never reached
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to logout from CAS. Halts by redirecting to the CAS
+     * server.
+     *
+     * @param string $service a URL that will be transmitted to the CAS server
+     * @param string $url     a URL that will be transmitted to the CAS server
+     *
+     * @return void
+     *
+     * @deprecated The url parameter has been removed from the CAS server as of
+     * version 3.3.5.1
+     */
+    public static function logoutWithRedirectServiceAndUrl($service, $url)
+    {
+        trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        if (!is_string($service)) {
+            phpCAS :: error('type mismatched for parameter $service (should be `string\')');
+        }
+        if (!is_string($url)) {
+            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->logout(
+            array (
+                "service" => $service,
+                "url" => $url
+            )
+        );
+        // never reached
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the fixed URL that will be used by the CAS server to transmit the
+     * PGT. When this method is not called, a phpCAS script uses its own URL
+     * for the callback.
+     *
+     * @param string $url the URL
+     *
+     * @return void
+     */
+    public static function setFixedCallbackURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateProxyExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setCallbackURL($url);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the fixed URL that will be set as the CAS service parameter. When this
+     * method is not called, a phpCAS script uses its own URL.
+     *
+     * @param string $url the URL
+     *
+     * @return void
+     */
+    public static function setFixedServiceURL($url)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateProxyExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setURL($url);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Get the URL that is set as the CAS service parameter.
+     *
+     * @return string Service Url
+     */
+    public static function getServiceURL()
+    {
+        phpCAS::_validateProxyExists();
+        return (self::$_PHPCAS_CLIENT->getURL());
+    }
+
+    /**
+     * Retrieve a Proxy Ticket from the CAS server.
+     *
+     * @param string $target_service Url string of service to proxy
+     * @param int &$err_code      error code
+     * @param string &$err_msg       error message
+     *
+     * @return string Proxy Ticket
+     */
+    public static function retrievePT($target_service, & $err_code, & $err_msg)
+    {
+        phpCAS::_validateProxyExists();
+
+        try {
+            return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+    }
+
+    /**
+     * Set the certificate of the CAS server CA and if the CN should be properly
+     * verified.
+     *
+     * @param string $cert        CA certificate file name
+     * @param bool   $validate_cn Validate CN in certificate (default true)
+     *
+     * @return void
+     */
+    public static function setCasServerCACert($cert, $validate_cn = true)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set no SSL validation for the CAS server.
+     *
+     * @return void
+     */
+    public static function setNoCasServerValidation()
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        phpCAS :: trace('You have configured no validation of the legitimacy of the cas server. This is not recommended for production use.');
+        self::$_PHPCAS_CLIENT->setNoCasServerValidation();
+        phpCAS :: traceEnd();
+    }
+
+
+    /**
+     * Disable the removal of a CAS-Ticket from the URL when authenticating
+     * DISABLING POSES A SECURITY RISK:
+     * We normally remove the ticket by an additional redirect as a security
+     * precaution to prevent a ticket in the HTTP_REFERRER or be carried over in
+     * the URL parameter
+     *
+     * @return void
+     */
+    public static function setNoClearTicketsFromUrl()
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl();
+        phpCAS :: traceEnd();
+    }
+
+    /** @} */
+
+    /**
+     * Change CURL options.
+     * CURL is used to connect through HTTPS to CAS server
+     *
+     * @param string $key   the option key
+     * @param string $value the value to set
+     *
+     * @return void
+     */
+    public static function setExtraCurlOption($key, $value)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        self::$_PHPCAS_CLIENT->setExtraCurlOption($key, $value);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set a salt/seed for the session-id hash to make it harder to guess.
+     *
+     * When $changeSessionID = true phpCAS will create a session-id that is derived
+     * from the service ticket. Doing so allows phpCAS to look-up and destroy the
+     * proper session on single-log-out requests. While the service tickets
+     * provided by the CAS server may include enough data to generate a strong
+     * hash, clients may provide an additional salt to ensure that session ids
+     * are not guessable if the session tickets do not have enough entropy.
+     *
+     * @param string $salt The salt to combine with the session ticket.
+     *
+     * @return void
+     */
+     public static function setSessionIdSalt($salt) {
+       phpCAS :: traceBegin();
+       phpCAS::_validateClientExists();
+       self::$_PHPCAS_CLIENT->setSessionIdSalt($salt);
+       phpCAS :: traceEnd();
+     }
+
+    /**
+     * If you want your service to be proxied you have to enable it (default
+     * disabled) and define an accepable list of proxies that are allowed to
+     * proxy your service.
+     *
+     * Add each allowed proxy definition object. For the normal CAS_ProxyChain
+     * class, the constructor takes an array of proxies to match. The list is in
+     * reverse just as seen from the service. Proxies have to be defined in reverse
+     * from the service to the user. If a user hits service A and gets proxied via
+     * B to service C the list of acceptable on C would be array(B,A). The definition
+     * of an individual proxy can be either a string or a regexp (preg_match is used)
+     * that will be matched against the proxy list supplied by the cas server
+     * when validating the proxy tickets. The strings are compared starting from
+     * the beginning and must fully match with the proxies in the list.
+     * Example:
+     * 		phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+     *				'https://app.example.com/'
+     *			)));
+     * 		phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+     *				'/^https:\/\/app[0-9]\.example\.com\/rest\//',
+     *				'http://client.example.com/'
+     *			)));
+     *
+     * For quick testing or in certain production screnarios you might want to
+     * allow allow any other valid service to proxy your service. To do so, add
+     * the "Any" chain:
+     *		phpCAS::allowProxyChain(new CAS_ProxyChain_Any);
+     * THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
+     * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
+     * ON THIS SERVICE.
+     *
+     * @param CAS_ProxyChain_Interface $proxy_chain A proxy-chain that will be
+     * matched against the proxies requesting access
+     *
+     * @return void
+     */
+    public static function allowProxyChain(CAS_ProxyChain_Interface $proxy_chain)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0
+            && self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_3_0
+        ) {
+            phpCAS :: error('this method can only be used with the cas 2.0/3.0 protocols');
+        }
+        self::$_PHPCAS_CLIENT->getAllowedProxyChains()->allowProxyChain($proxy_chain);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Answer an array of proxies that are sitting in front of this application.
+     * This method will only return a non-empty array if we have received and
+     * validated a Proxy Ticket.
+     *
+     * @return array
+     * @access public
+     * @since 6/25/09
+     */
+    public static function getProxies ()
+    {
+        phpCAS::_validateProxyExists();
+
+        return(self::$_PHPCAS_CLIENT->getProxies());
+    }
+
+    // ########################################################################
+    // PGTIOU/PGTID and logoutRequest rebroadcasting
+    // ########################################################################
+
+    /**
+     * Add a pgtIou/pgtId and logoutRequest rebroadcast node.
+     *
+     * @param string $rebroadcastNodeUrl The rebroadcast node URL. Can be
+     * hostname or IP.
+     *
+     * @return void
+     */
+    public static function addRebroadcastNode($rebroadcastNodeUrl)
+    {
+        phpCAS::traceBegin();
+        phpCAS::log('rebroadcastNodeUrl:'.$rebroadcastNodeUrl);
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method is used to add header parameters when rebroadcasting
+     * pgtIou/pgtId or logoutRequest.
+     *
+     * @param String $header Header to send when rebroadcasting.
+     *
+     * @return void
+     */
+    public static function addRebroadcastHeader($header)
+    {
+        phpCAS :: traceBegin();
+        phpCAS::_validateClientExists();
+
+        try {
+            self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);
+        } catch (Exception $e) {
+            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
+        }
+
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Checks if a client already exists
+     *
+     * @throws CAS_OutOfSequenceBeforeClientException
+     *
+     * @return void
+     */
+    private static function _validateClientExists()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            throw new CAS_OutOfSequenceBeforeClientException();
+        }
+    }
+
+    /**
+     * Checks of a proxy client aready exists
+     *
+     * @throws CAS_OutOfSequenceBeforeProxyException
+     *
+     * @return void
+     */
+    private static function _validateProxyExists()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            throw new CAS_OutOfSequenceBeforeProxyException();
+        }
+    }
+
+    /**
+     * @return CAS_Client
+     */
+    public static function getCasClient()
+    {
+        return self::$_PHPCAS_CLIENT;
+    }
+
+    /**
+     * For testing purposes, use this method to set the client to a test double
+     *
+     * @return void
+     */
+    public static function setCasClient(\CAS_Client $client)
+    {
+        self::$_PHPCAS_CLIENT = $client;
+    }
+}
+// ########################################################################
+// DOCUMENTATION
+// ########################################################################
+
+// ########################################################################
+//  MAIN PAGE
+
+/**
+ * @mainpage
+ *
+ * The following pages only show the source documentation.
+ *
+ */
+
+// ########################################################################
+//  MODULES DEFINITION
+
+/** @defgroup public User interface */
+
+/** @defgroup publicInit Initialization
+ *  @ingroup public */
+
+/** @defgroup publicAuth Authentication
+ *  @ingroup public */
+
+/** @defgroup publicServices Access to external services
+ *  @ingroup public */
+
+/** @defgroup publicConfig Configuration
+ *  @ingroup public */
+
+/** @defgroup publicLang Internationalization
+ *  @ingroup publicConfig */
+
+/** @defgroup publicOutput HTML output
+ *  @ingroup publicConfig */
+
+/** @defgroup publicPGTStorage PGT storage
+ *  @ingroup publicConfig */
+
+/** @defgroup publicDebug Debugging
+ *  @ingroup public */
+
+/** @defgroup internal Implementation */
+
+/** @defgroup internalAuthentication Authentication
+ *  @ingroup internal */
+
+/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets)
+ *  @ingroup internal */
+
+/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets)
+ *  @ingroup internal */
+
+/** @defgroup internalSAML CAS SAML features (SAML 1.1)
+ *  @ingroup internal */
+
+/** @defgroup internalPGTStorage PGT storage
+ *  @ingroup internalProxy */
+
+/** @defgroup internalPGTStorageDb PGT storage in a database
+ *  @ingroup internalPGTStorage */
+
+/** @defgroup internalPGTStorageFile PGT storage on the filesystem
+ *  @ingroup internalPGTStorage */
+
+/** @defgroup internalCallback Callback from the CAS server
+ *  @ingroup internalProxy */
+
+/** @defgroup internalProxyServices Proxy other services
+ *  @ingroup internalProxy */
+
+/** @defgroup internalService CAS client features (CAS 2.0, Proxied service)
+ *  @ingroup internal */
+
+/** @defgroup internalConfig Configuration
+ *  @ingroup internal */
+
+/** @defgroup internalBehave Internal behaviour of phpCAS
+ *  @ingroup internalConfig */
+
+/** @defgroup internalOutput HTML output
+ *  @ingroup internalConfig */
+
+/** @defgroup internalLang Internationalization
+ *  @ingroup internalConfig
+ *
+ * To add a new language:
+ * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php
+ * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php
+ * - 3. Make the translations
+ */
+
+/** @defgroup internalDebug Debugging
+ *  @ingroup internal */
+
+/** @defgroup internalMisc Miscellaneous
+ *  @ingroup internal */
+
+// ########################################################################
+//  EXAMPLES
+
+/**
+ * @example example_simple.php
+ */
+/**
+ * @example example_service.php
+ */
+/**
+ * @example example_service_that_proxies.php
+ */
+/**
+ * @example example_service_POST.php
+ */
+/**
+ * @example example_proxy_serviceWeb.php
+ */
+/**
+ * @example example_proxy_serviceWeb_chaining.php
+ */
+/**
+ * @example example_proxy_POST.php
+ */
+/**
+ * @example example_proxy_GET.php
+ */
+/**
+ * @example example_lang.php
+ */
+/**
+ * @example example_html.php
+ */
+/**
+ * @example example_pgt_storage_file.php
+ */
+/**
+ * @example example_pgt_storage_db.php
+ */
+/**
+ * @example example_gateway.php
+ */
+/**
+ * @example example_logout.php
+ */
+/**
+ * @example example_rebroadcast.php
+ */
+/**
+ * @example example_custom_urls.php
+ */
+/**
+ * @example example_advanced_saml11.php
+ */
diff --git a/vendor/jasig/phpcas/source/CAS/AuthenticationException.php b/vendor/jasig/phpcas/source/CAS/AuthenticationException.php
new file mode 100644
index 0000000000..803c88908b
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/AuthenticationException.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/AuthenticationException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines methods that allow proxy-authenticated service handlers
+ * to interact with phpCAS.
+ *
+ * Proxy service handlers must implement this interface as well as call
+ * phpCAS::initializeProxiedService($this) at some point in their implementation.
+ *
+ * While not required, proxy-authenticated service handlers are encouraged to
+ * implement the CAS_ProxiedService_Testable interface to facilitate unit testing.
+ *
+ * @class    CAS_AuthenticationException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class CAS_AuthenticationException
+extends RuntimeException
+implements CAS_Exception
+{
+
+    /**
+     * This method is used to print the HTML output when the user was not
+     * authenticated.
+     *
+     * @param CAS_Client $client       phpcas client
+     * @param string     $failure      the failure that occured
+     * @param string     $cas_url      the URL the CAS server was asked for
+     * @param bool       $no_response  the response from the CAS server (other
+     * parameters are ignored if TRUE)
+     * @param bool       $bad_response bad response from the CAS server ($err_code
+     * and $err_msg ignored if TRUE)
+     * @param string     $cas_response the response of the CAS server
+     * @param int        $err_code     the error code given by the CAS server
+     * @param string     $err_msg      the error message given by the CAS server
+     */
+    public function __construct($client,$failure,$cas_url,$no_response,
+        $bad_response=false,$cas_response='',$err_code=-1,$err_msg=''
+    ) {
+        $messages = array();
+        phpCAS::traceBegin();
+        $lang = $client->getLangObj();
+        $client->printHTMLHeader($lang->getAuthenticationFailed());
+
+        if (phpCAS::getVerbose()) {
+            printf(
+                $lang->getYouWereNotAuthenticated(),
+                htmlentities($client->getURL()),
+                $_SERVER['SERVER_ADMIN'] ?? ''
+            );
+        }
+
+        phpCAS::trace($messages[] = 'CAS URL: '.$cas_url);
+        phpCAS::trace($messages[] = 'Authentication failure: '.$failure);
+        if ( $no_response ) {
+            phpCAS::trace($messages[] = 'Reason: no response from the CAS server');
+        } else {
+            if ( $bad_response ) {
+                phpCAS::trace($messages[] = 'Reason: bad response from the CAS server');
+            } else {
+                switch ($client->getServerVersion()) {
+                case CAS_VERSION_1_0:
+                    phpCAS::trace($messages[] = 'Reason: CAS error');
+                    break;
+                case CAS_VERSION_2_0:
+                case CAS_VERSION_3_0:
+                    if ( $err_code === -1 ) {
+                        phpCAS::trace($messages[] = 'Reason: no CAS error');
+                    } else {
+                        phpCAS::trace($messages[] = 'Reason: ['.$err_code.'] CAS error: '.$err_msg);
+                    }
+                    break;
+                }
+            }
+            phpCAS::trace($messages[] = 'CAS response: '.$cas_response);
+        }
+        $client->printHTMLFooter();
+        phpCAS::traceExit();
+
+        parent::__construct(implode("\n", $messages));
+    }
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Autoload.php b/vendor/jasig/phpcas/source/CAS/Autoload.php
new file mode 100644
index 0000000000..29395d592d
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Autoload.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * Autoloader Class
+ *
+ *  PHP Version 7
+ *
+ * @file      CAS/Autoload.php
+ * @category  Authentication
+ * @package   SimpleCAS
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://code.google.com/p/simplecas/
+ **/
+
+/**
+ * Autoload a class
+ *
+ * @param string $class Classname to load
+ *
+ * @return bool
+ */
+function CAS_autoload($class)
+{
+    // Static to hold the Include Path to CAS
+    static $include_path;
+    // Check only for CAS classes
+    if (substr($class, 0, 4) !== 'CAS_' && substr($class, 0, 7) !== 'PhpCas\\') {
+        return false;
+    }
+
+    // Setup the include path if it's not already set from a previous call
+    if (empty($include_path)) {
+        $include_path = array(dirname(__DIR__));
+    }
+
+    // Declare local variable to store the expected full path to the file
+    foreach ($include_path as $path) {
+        $class_path = str_replace('_', DIRECTORY_SEPARATOR, $class);
+        // PhpCas namespace mapping
+        if (substr($class_path, 0, 7) === 'PhpCas\\') {
+            $class_path = 'CAS' . DIRECTORY_SEPARATOR . substr($class_path, 7);
+        }
+
+        $file_path = $path . DIRECTORY_SEPARATOR . $class_path . '.php';
+        $fp = @fopen($file_path, 'r', true);
+        if ($fp) {
+            fclose($fp);
+            include $file_path;
+            if (!class_exists($class, false) && !interface_exists($class, false)) {
+                die(
+                    new Exception(
+                        'Class ' . $class . ' was not present in ' .
+                        $file_path .
+                        ' [CAS_autoload]'
+                    )
+                );
+            }
+            return true;
+        }
+    }
+
+    $e = new Exception(
+        'Class ' . $class . ' could not be loaded from ' .
+        $file_path . ', file does not exist (Path="'
+        . implode(':', $include_path) .'") [CAS_autoload]'
+    );
+    $trace = $e->getTrace();
+    if (isset($trace[2]) && isset($trace[2]['function'])
+        && in_array($trace[2]['function'], array('class_exists', 'interface_exists', 'trait_exists'))
+    ) {
+        return false;
+    }
+    if (isset($trace[1]) && isset($trace[1]['function'])
+        && in_array($trace[1]['function'], array('class_exists', 'interface_exists', 'trait_exists'))
+    ) {
+        return false;
+    }
+    die ((string) $e);
+}
+
+// Set up autoload if not already configured by composer.
+if (!class_exists('CAS_Client'))
+{
+    trigger_error('phpCAS autoloader is deprecated. Install phpCAS using composer instead.', E_USER_DEPRECATED);
+    spl_autoload_register('CAS_autoload');
+    if (function_exists('__autoload')
+        && !in_array('__autoload', spl_autoload_functions())
+    ) {
+        // __autoload() was being used, but now would be ignored, add
+        // it to the autoload stack
+        spl_autoload_register('__autoload');
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Client.php b/vendor/jasig/phpcas/source/CAS/Client.php
new file mode 100644
index 0000000000..1a40f63e4f
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Client.php
@@ -0,0 +1,4377 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Client.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
+ * @author   Brett Bieber <brett.bieber@gmail.com>
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @author   Tobias Schiebeck <tobias.schiebeck@manchester.ac.uk>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * The CAS_Client class is a client interface that provides CAS authentication
+ * to PHP applications.
+ *
+ * @class    CAS_Client
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
+ * @author   Brett Bieber <brett.bieber@gmail.com>
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @author   Tobias Schiebeck <tobias.schiebeck@manchester.ac.uk>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ */
+
+class CAS_Client
+{
+
+    // ########################################################################
+    //  HTML OUTPUT
+    // ########################################################################
+    /**
+    * @addtogroup internalOutput
+    * @{
+    */
+
+    /**
+     * This method filters a string by replacing special tokens by appropriate values
+     * and prints it. The corresponding tokens are taken into account:
+     * - __CAS_VERSION__
+     * - __PHPCAS_VERSION__
+     * - __SERVER_BASE_URL__
+     *
+     * Used by CAS_Client::PrintHTMLHeader() and CAS_Client::printHTMLFooter().
+     *
+     * @param string $str the string to filter and output
+     *
+     * @return void
+     */
+    private function _htmlFilterOutput($str)
+    {
+        $str = str_replace('__CAS_VERSION__', $this->getServerVersion(), $str);
+        $str = str_replace('__PHPCAS_VERSION__', phpCAS::getVersion(), $str);
+        $str = str_replace('__SERVER_BASE_URL__', $this->_getServerBaseURL(), $str);
+        echo $str;
+    }
+
+    /**
+     * A string used to print the header of HTML pages. Written by
+     * CAS_Client::setHTMLHeader(), read by CAS_Client::printHTMLHeader().
+     *
+     * @hideinitializer
+     * @see CAS_Client::setHTMLHeader, CAS_Client::printHTMLHeader()
+     */
+    private $_output_header = '';
+
+    /**
+     * This method prints the header of the HTML output (after filtering). If
+     * CAS_Client::setHTMLHeader() was not used, a default header is output.
+     *
+     * @param string $title the title of the page
+     *
+     * @return void
+     * @see _htmlFilterOutput()
+     */
+    public function printHTMLHeader($title)
+    {
+        if (!phpCAS::getVerbose()) {
+            return;
+        }
+
+        $this->_htmlFilterOutput(
+            str_replace(
+                '__TITLE__', $title,
+                (empty($this->_output_header)
+                ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
+                : $this->_output_header)
+            )
+        );
+    }
+
+    /**
+     * A string used to print the footer of HTML pages. Written by
+     * CAS_Client::setHTMLFooter(), read by printHTMLFooter().
+     *
+     * @hideinitializer
+     * @see CAS_Client::setHTMLFooter, CAS_Client::printHTMLFooter()
+     */
+    private $_output_footer = '';
+
+    /**
+     * This method prints the footer of the HTML output (after filtering). If
+     * CAS_Client::setHTMLFooter() was not used, a default footer is output.
+     *
+     * @return void
+     * @see _htmlFilterOutput()
+     */
+    public function printHTMLFooter()
+    {
+        if (!phpCAS::getVerbose()) {
+            return;
+        }
+
+        $lang = $this->getLangObj();
+        $message = empty($this->_output_footer)
+            ? '<hr><address>phpCAS __PHPCAS_VERSION__ ' . $lang->getUsingServer() .
+              ' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>'
+            : $this->_output_footer;
+
+        $this->_htmlFilterOutput($message);
+    }
+
+    /**
+     * This method set the HTML header used for all outputs.
+     *
+     * @param string $header the HTML header.
+     *
+     * @return void
+     */
+    public function setHTMLHeader($header)
+    {
+        // Argument Validation
+        if (gettype($header) != 'string')
+            throw new CAS_TypeMismatchException($header, '$header', 'string');
+
+        $this->_output_header = $header;
+    }
+
+    /**
+     * This method set the HTML footer used for all outputs.
+     *
+     * @param string $footer the HTML footer.
+     *
+     * @return void
+     */
+    public function setHTMLFooter($footer)
+    {
+        // Argument Validation
+        if (gettype($footer) != 'string')
+            throw new CAS_TypeMismatchException($footer, '$footer', 'string');
+
+        $this->_output_footer = $footer;
+    }
+
+    /**
+     * Simple wrapper for printf function, that respects
+     * phpCAS verbosity setting.
+     *
+     * @param string $format
+     * @param string|int|float ...$values
+     *
+     * @see printf()
+     */
+    private function printf(string $format, ...$values): void
+    {
+        if (phpCAS::getVerbose()) {
+            printf($format, ...$values);
+        }
+    }
+
+    /** @} */
+
+
+    // ########################################################################
+    //  INTERNATIONALIZATION
+    // ########################################################################
+    /**
+    * @addtogroup internalLang
+    * @{
+    */
+    /**
+     * A string corresponding to the language used by phpCAS. Written by
+     * CAS_Client::setLang(), read by CAS_Client::getLang().
+
+     * @note debugging information is always in english (debug purposes only).
+     */
+    private $_lang = PHPCAS_LANG_DEFAULT;
+
+    /**
+     * This method is used to set the language used by phpCAS.
+     *
+     * @param string $lang representing the language.
+     *
+     * @return void
+     */
+    public function setLang($lang)
+    {
+        // Argument Validation
+        if (gettype($lang) != 'string')
+            throw new CAS_TypeMismatchException($lang, '$lang', 'string');
+
+        phpCAS::traceBegin();
+        $obj = new $lang();
+        if (!($obj instanceof CAS_Languages_LanguageInterface)) {
+            throw new CAS_InvalidArgumentException(
+                '$className must implement the CAS_Languages_LanguageInterface'
+            );
+        }
+        $this->_lang = $lang;
+        phpCAS::traceEnd();
+    }
+    /**
+     * Create the language
+     *
+     * @return CAS_Languages_LanguageInterface object implementing the class
+     */
+    public function getLangObj()
+    {
+        $classname = $this->_lang;
+        return new $classname();
+    }
+
+    /** @} */
+    // ########################################################################
+    //  CAS SERVER CONFIG
+    // ########################################################################
+    /**
+    * @addtogroup internalConfig
+    * @{
+    */
+
+    /**
+     * a record to store information about the CAS server.
+     * - $_server['version']: the version of the CAS server
+     * - $_server['hostname']: the hostname of the CAS server
+     * - $_server['port']: the port the CAS server is running on
+     * - $_server['uri']: the base URI the CAS server is responding on
+     * - $_server['base_url']: the base URL of the CAS server
+     * - $_server['login_url']: the login URL of the CAS server
+     * - $_server['service_validate_url']: the service validating URL of the
+     *   CAS server
+     * - $_server['proxy_url']: the proxy URL of the CAS server
+     * - $_server['proxy_validate_url']: the proxy validating URL of the CAS server
+     * - $_server['logout_url']: the logout URL of the CAS server
+     *
+     * $_server['version'], $_server['hostname'], $_server['port'] and
+     * $_server['uri'] are written by CAS_Client::CAS_Client(), read by
+     * CAS_Client::getServerVersion(), CAS_Client::_getServerHostname(),
+     * CAS_Client::_getServerPort() and CAS_Client::_getServerURI().
+     *
+     * The other fields are written and read by CAS_Client::_getServerBaseURL(),
+     * CAS_Client::getServerLoginURL(), CAS_Client::getServerServiceValidateURL(),
+     * CAS_Client::getServerProxyValidateURL() and CAS_Client::getServerLogoutURL().
+     *
+     * @hideinitializer
+     */
+    private $_server = array(
+        'version' => '',
+        'hostname' => 'none',
+        'port' => -1,
+        'uri' => 'none');
+
+    /**
+     * This method is used to retrieve the version of the CAS server.
+     *
+     * @return string the version of the CAS server.
+     */
+    public function getServerVersion()
+    {
+        return $this->_server['version'];
+    }
+
+    /**
+     * This method is used to retrieve the hostname of the CAS server.
+     *
+     * @return string the hostname of the CAS server.
+     */
+    private function _getServerHostname()
+    {
+        return $this->_server['hostname'];
+    }
+
+    /**
+     * This method is used to retrieve the port of the CAS server.
+     *
+     * @return int the port of the CAS server.
+     */
+    private function _getServerPort()
+    {
+        return $this->_server['port'];
+    }
+
+    /**
+     * This method is used to retrieve the URI of the CAS server.
+     *
+     * @return string a URI.
+     */
+    private function _getServerURI()
+    {
+        return $this->_server['uri'];
+    }
+
+    /**
+     * This method is used to retrieve the base URL of the CAS server.
+     *
+     * @return string a URL.
+     */
+    private function _getServerBaseURL()
+    {
+        // the URL is build only when needed
+        if ( empty($this->_server['base_url']) ) {
+            $this->_server['base_url'] = 'https://' . $this->_getServerHostname();
+            if ($this->_getServerPort()!=443) {
+                $this->_server['base_url'] .= ':'
+                .$this->_getServerPort();
+            }
+            $this->_server['base_url'] .= $this->_getServerURI();
+        }
+        return $this->_server['base_url'];
+    }
+
+    /**
+     * This method is used to retrieve the login URL of the CAS server.
+     *
+     * @param bool $gateway true to check authentication, false to force it
+     * @param bool $renew   true to force the authentication with the CAS server
+     *
+     * @return string a URL.
+     * @note It is recommended that CAS implementations ignore the "gateway"
+     * parameter if "renew" is set
+     */
+    public function getServerLoginURL($gateway=false,$renew=false)
+    {
+        phpCAS::traceBegin();
+        // the URL is build only when needed
+        if ( empty($this->_server['login_url']) ) {
+            $this->_server['login_url'] = $this->_buildQueryUrl($this->_getServerBaseURL().'login','service='.urlencode($this->getURL()));
+        }
+        $url = $this->_server['login_url'];
+        if ($renew) {
+            // It is recommended that when the "renew" parameter is set, its
+            // value be "true"
+            $url = $this->_buildQueryUrl($url, 'renew=true');
+        } elseif ($gateway) {
+            // It is recommended that when the "gateway" parameter is set, its
+            // value be "true"
+            $url = $this->_buildQueryUrl($url, 'gateway=true');
+        }
+        phpCAS::traceEnd($url);
+        return $url;
+    }
+
+    /**
+     * This method sets the login URL of the CAS server.
+     *
+     * @param string $url the login URL
+     *
+     * @return string login url
+     */
+    public function setServerLoginURL($url)
+    {
+        // Argument Validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        return $this->_server['login_url'] = $url;
+    }
+
+
+    /**
+     * This method sets the serviceValidate URL of the CAS server.
+     *
+     * @param string $url the serviceValidate URL
+     *
+     * @return string serviceValidate URL
+     */
+    public function setServerServiceValidateURL($url)
+    {
+        // Argument Validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        return $this->_server['service_validate_url'] = $url;
+    }
+
+
+    /**
+     * This method sets the proxyValidate URL of the CAS server.
+     *
+     * @param string $url the proxyValidate URL
+     *
+     * @return string proxyValidate URL
+     */
+    public function setServerProxyValidateURL($url)
+    {
+        // Argument Validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        return $this->_server['proxy_validate_url'] = $url;
+    }
+
+
+    /**
+     * This method sets the samlValidate URL of the CAS server.
+     *
+     * @param string $url the samlValidate URL
+     *
+     * @return string samlValidate URL
+     */
+    public function setServerSamlValidateURL($url)
+    {
+        // Argument Validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        return $this->_server['saml_validate_url'] = $url;
+    }
+
+
+    /**
+     * This method is used to retrieve the service validating URL of the CAS server.
+     *
+     * @return string serviceValidate URL.
+     */
+    public function getServerServiceValidateURL()
+    {
+        phpCAS::traceBegin();
+        // the URL is build only when needed
+        if ( empty($this->_server['service_validate_url']) ) {
+            switch ($this->getServerVersion()) {
+            case CAS_VERSION_1_0:
+                $this->_server['service_validate_url'] = $this->_getServerBaseURL()
+                .'validate';
+                break;
+            case CAS_VERSION_2_0:
+                $this->_server['service_validate_url'] = $this->_getServerBaseURL()
+                .'serviceValidate';
+                break;
+            case CAS_VERSION_3_0:
+                $this->_server['service_validate_url'] = $this->_getServerBaseURL()
+                .'p3/serviceValidate';
+                break;
+            }
+        }
+        $url = $this->_buildQueryUrl(
+            $this->_server['service_validate_url'],
+            'service='.urlencode($this->getURL())
+        );
+        phpCAS::traceEnd($url);
+        return $url;
+    }
+    /**
+     * This method is used to retrieve the SAML validating URL of the CAS server.
+     *
+     * @return string samlValidate URL.
+     */
+    public function getServerSamlValidateURL()
+    {
+        phpCAS::traceBegin();
+        // the URL is build only when needed
+        if ( empty($this->_server['saml_validate_url']) ) {
+            switch ($this->getServerVersion()) {
+            case SAML_VERSION_1_1:
+                $this->_server['saml_validate_url'] = $this->_getServerBaseURL().'samlValidate';
+                break;
+            }
+        }
+
+        $url = $this->_buildQueryUrl(
+            $this->_server['saml_validate_url'],
+            'TARGET='.urlencode($this->getURL())
+        );
+        phpCAS::traceEnd($url);
+        return $url;
+    }
+
+    /**
+     * This method is used to retrieve the proxy validating URL of the CAS server.
+     *
+     * @return string proxyValidate URL.
+     */
+    public function getServerProxyValidateURL()
+    {
+        phpCAS::traceBegin();
+        // the URL is build only when needed
+        if ( empty($this->_server['proxy_validate_url']) ) {
+            switch ($this->getServerVersion()) {
+            case CAS_VERSION_1_0:
+                $this->_server['proxy_validate_url'] = '';
+                break;
+            case CAS_VERSION_2_0:
+                $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'proxyValidate';
+                break;
+            case CAS_VERSION_3_0:
+                $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'p3/proxyValidate';
+                break;
+            }
+        }
+        $url = $this->_buildQueryUrl(
+            $this->_server['proxy_validate_url'],
+            'service='.urlencode($this->getURL())
+        );
+        phpCAS::traceEnd($url);
+        return $url;
+    }
+
+
+    /**
+     * This method is used to retrieve the proxy URL of the CAS server.
+     *
+     * @return  string proxy URL.
+     */
+    public function getServerProxyURL()
+    {
+        // the URL is build only when needed
+        if ( empty($this->_server['proxy_url']) ) {
+            switch ($this->getServerVersion()) {
+            case CAS_VERSION_1_0:
+                $this->_server['proxy_url'] = '';
+                break;
+            case CAS_VERSION_2_0:
+            case CAS_VERSION_3_0:
+                $this->_server['proxy_url'] = $this->_getServerBaseURL().'proxy';
+                break;
+            }
+        }
+        return $this->_server['proxy_url'];
+    }
+
+    /**
+     * This method is used to retrieve the logout URL of the CAS server.
+     *
+     * @return string logout URL.
+     */
+    public function getServerLogoutURL()
+    {
+        // the URL is build only when needed
+        if ( empty($this->_server['logout_url']) ) {
+            $this->_server['logout_url'] = $this->_getServerBaseURL().'logout';
+        }
+        return $this->_server['logout_url'];
+    }
+
+    /**
+     * This method sets the logout URL of the CAS server.
+     *
+     * @param string $url the logout URL
+     *
+     * @return string logout url
+     */
+    public function setServerLogoutURL($url)
+    {
+        // Argument Validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        return $this->_server['logout_url'] = $url;
+    }
+
+    /**
+     * An array to store extra curl options.
+     */
+    private $_curl_options = array();
+
+    /**
+     * This method is used to set additional user curl options.
+     *
+     * @param string $key   name of the curl option
+     * @param string $value value of the curl option
+     *
+     * @return void
+     */
+    public function setExtraCurlOption($key, $value)
+    {
+        $this->_curl_options[$key] = $value;
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  Change the internal behaviour of phpcas
+    // ########################################################################
+
+    /**
+     * @addtogroup internalBehave
+     * @{
+     */
+
+    /**
+     * The class to instantiate for making web requests in readUrl().
+     * The class specified must implement the CAS_Request_RequestInterface.
+     * By default CAS_Request_CurlRequest is used, but this may be overridden to
+     * supply alternate request mechanisms for testing.
+     */
+    private $_requestImplementation = 'CAS_Request_CurlRequest';
+
+    /**
+     * Override the default implementation used to make web requests in readUrl().
+     * This class must implement the CAS_Request_RequestInterface.
+     *
+     * @param string $className name of the RequestImplementation class
+     *
+     * @return void
+     */
+    public function setRequestImplementation ($className)
+    {
+        $obj = new $className;
+        if (!($obj instanceof CAS_Request_RequestInterface)) {
+            throw new CAS_InvalidArgumentException(
+                '$className must implement the CAS_Request_RequestInterface'
+            );
+        }
+        $this->_requestImplementation = $className;
+    }
+
+    /**
+     * @var boolean $_clearTicketsFromUrl; If true, phpCAS will clear session
+     * tickets from the URL after a successful authentication.
+     */
+    private $_clearTicketsFromUrl = true;
+
+    /**
+     * Configure the client to not send redirect headers and call exit() on
+     * authentication success. The normal redirect is used to remove the service
+     * ticket from the client's URL, but for running unit tests we need to
+     * continue without exiting.
+     *
+     * Needed for testing authentication
+     *
+     * @return void
+     */
+    public function setNoClearTicketsFromUrl ()
+    {
+        $this->_clearTicketsFromUrl = false;
+    }
+
+    /**
+     * @var callback $_attributeParserCallbackFunction;
+     */
+    private $_casAttributeParserCallbackFunction = null;
+
+    /**
+     * @var array $_attributeParserCallbackArgs;
+     */
+    private $_casAttributeParserCallbackArgs = array();
+
+    /**
+     * Set a callback function to be run when parsing CAS attributes
+     *
+     * The callback function will be passed a XMLNode as its first parameter,
+     * followed by any $additionalArgs you pass.
+     *
+     * @param string $function       callback function to call
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public function setCasAttributeParserCallback($function, array $additionalArgs = array())
+    {
+        $this->_casAttributeParserCallbackFunction = $function;
+        $this->_casAttributeParserCallbackArgs = $additionalArgs;
+    }
+
+    /** @var callable $_postAuthenticateCallbackFunction;
+     */
+    private $_postAuthenticateCallbackFunction = null;
+
+    /**
+     * @var array $_postAuthenticateCallbackArgs;
+     */
+    private $_postAuthenticateCallbackArgs = array();
+
+    /**
+     * Set a callback function to be run when a user authenticates.
+     *
+     * The callback function will be passed a $logoutTicket as its first parameter,
+     * followed by any $additionalArgs you pass. The $logoutTicket parameter is an
+     * opaque string that can be used to map a session-id to the logout request
+     * in order to support single-signout in applications that manage their own
+     * sessions (rather than letting phpCAS start the session).
+     *
+     * phpCAS::forceAuthentication() will always exit and forward client unless
+     * they are already authenticated. To perform an action at the moment the user
+     * logs in (such as registering an account, performing logging, etc), register
+     * a callback function here.
+     *
+     * @param callable $function       callback function to call
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public function setPostAuthenticateCallback ($function, array $additionalArgs = array())
+    {
+        $this->_postAuthenticateCallbackFunction = $function;
+        $this->_postAuthenticateCallbackArgs = $additionalArgs;
+    }
+
+    /**
+     * @var callable $_signoutCallbackFunction;
+     */
+    private $_signoutCallbackFunction = null;
+
+    /**
+     * @var array $_signoutCallbackArgs;
+     */
+    private $_signoutCallbackArgs = array();
+
+    /**
+     * Set a callback function to be run when a single-signout request is received.
+     *
+     * The callback function will be passed a $logoutTicket as its first parameter,
+     * followed by any $additionalArgs you pass. The $logoutTicket parameter is an
+     * opaque string that can be used to map a session-id to the logout request in
+     * order to support single-signout in applications that manage their own sessions
+     * (rather than letting phpCAS start and destroy the session).
+     *
+     * @param callable $function       callback function to call
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public function setSingleSignoutCallback ($function, array $additionalArgs = array())
+    {
+        $this->_signoutCallbackFunction = $function;
+        $this->_signoutCallbackArgs = $additionalArgs;
+    }
+
+    // ########################################################################
+    //  Methods for supplying code-flow feedback to integrators.
+    // ########################################################################
+
+    /**
+     * Ensure that this is actually a proxy object or fail with an exception
+     *
+     * @throws CAS_OutOfSequenceBeforeProxyException
+     *
+     * @return void
+     */
+    public function ensureIsProxy()
+    {
+        if (!$this->isProxy()) {
+            throw new CAS_OutOfSequenceBeforeProxyException();
+        }
+    }
+
+    /**
+     * Mark the caller of authentication. This will help client integraters determine
+     * problems with their code flow if they call a function such as getUser() before
+     * authentication has occurred.
+     *
+     * @param bool $auth True if authentication was successful, false otherwise.
+     *
+     * @return null
+     */
+    public function markAuthenticationCall ($auth)
+    {
+        // store where the authentication has been checked and the result
+        $dbg = debug_backtrace();
+        $this->_authentication_caller = array (
+            'file' => $dbg[1]['file'],
+            'line' => $dbg[1]['line'],
+            'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'],
+            'result' => (boolean)$auth
+        );
+    }
+    private $_authentication_caller;
+
+    /**
+     * Answer true if authentication has been checked.
+     *
+     * @return bool
+     */
+    public function wasAuthenticationCalled ()
+    {
+        return !empty($this->_authentication_caller);
+    }
+
+    /**
+     * Ensure that authentication was checked. Terminate with exception if no
+     * authentication was performed
+     *
+     * @throws CAS_OutOfSequenceBeforeAuthenticationCallException
+     *
+     * @return void
+     */
+    private function _ensureAuthenticationCalled()
+    {
+        if (!$this->wasAuthenticationCalled()) {
+            throw new CAS_OutOfSequenceBeforeAuthenticationCallException();
+        }
+    }
+
+    /**
+     * Answer the result of the authentication call.
+     *
+     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
+     * and markAuthenticationCall() didn't happen.
+     *
+     * @return bool
+     */
+    public function wasAuthenticationCallSuccessful ()
+    {
+        $this->_ensureAuthenticationCalled();
+        return $this->_authentication_caller['result'];
+    }
+
+
+    /**
+     * Ensure that authentication was checked. Terminate with exception if no
+     * authentication was performed
+     *
+     * @throws CAS_OutOfSequenceException
+     *
+     * @return void
+     */
+    public function ensureAuthenticationCallSuccessful()
+    {
+        $this->_ensureAuthenticationCalled();
+        if (!$this->_authentication_caller['result']) {
+            throw new CAS_OutOfSequenceException(
+                'authentication was checked (by '
+                . $this->getAuthenticationCallerMethod()
+                . '() at ' . $this->getAuthenticationCallerFile()
+                . ':' . $this->getAuthenticationCallerLine()
+                . ') but the method returned false'
+            );
+        }
+    }
+
+    /**
+     * Answer information about the authentication caller.
+     *
+     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
+     * and markAuthenticationCall() didn't happen.
+     *
+     * @return string the file that called authentication
+     */
+    public function getAuthenticationCallerFile ()
+    {
+        $this->_ensureAuthenticationCalled();
+        return $this->_authentication_caller['file'];
+    }
+
+    /**
+     * Answer information about the authentication caller.
+     *
+     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
+     * and markAuthenticationCall() didn't happen.
+     *
+     * @return int the line that called authentication
+     */
+    public function getAuthenticationCallerLine ()
+    {
+        $this->_ensureAuthenticationCalled();
+        return $this->_authentication_caller['line'];
+    }
+
+    /**
+     * Answer information about the authentication caller.
+     *
+     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
+     * and markAuthenticationCall() didn't happen.
+     *
+     * @return string the method that called authentication
+     */
+    public function getAuthenticationCallerMethod ()
+    {
+        $this->_ensureAuthenticationCalled();
+        return $this->_authentication_caller['method'];
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  CONSTRUCTOR
+    // ########################################################################
+    /**
+    * @addtogroup internalConfig
+    * @{
+    */
+
+    /**
+     * CAS_Client constructor.
+     *
+     * @param string                   $server_version  the version of the CAS server
+     * @param bool                     $proxy           true if the CAS client is a CAS proxy
+     * @param string                   $server_hostname the hostname of the CAS server
+     * @param int                      $server_port     the port the CAS server is running on
+     * @param string                   $server_uri      the URI the CAS server is responding on
+     * @param bool                     $changeSessionID Allow phpCAS to change the session_id
+     *                                                  (Single Sign Out/handleLogoutRequests
+     *                                                  is based on that change)
+     * @param \SessionHandlerInterface $sessionHandler  the session handler
+     *
+     * @return self a newly created CAS_Client object
+     */
+    public function __construct(
+        $server_version,
+        $proxy,
+        $server_hostname,
+        $server_port,
+        $server_uri,
+        $changeSessionID = true,
+        \SessionHandlerInterface $sessionHandler = null
+    ) {
+        // Argument validation
+        if (gettype($server_version) != 'string')
+            throw new CAS_TypeMismatchException($server_version, '$server_version', 'string');
+        if (gettype($proxy) != 'boolean')
+            throw new CAS_TypeMismatchException($proxy, '$proxy', 'boolean');
+        if (gettype($server_hostname) != 'string')
+            throw new CAS_TypeMismatchException($server_hostname, '$server_hostname', 'string');
+        if (gettype($server_port) != 'integer')
+            throw new CAS_TypeMismatchException($server_port, '$server_port', 'integer');
+        if (gettype($server_uri) != 'string')
+            throw new CAS_TypeMismatchException($server_uri, '$server_uri', 'string');
+        if (gettype($changeSessionID) != 'boolean')
+            throw new CAS_TypeMismatchException($changeSessionID, '$changeSessionID', 'boolean');
+
+        if (empty($sessionHandler)) {
+            $sessionHandler = new CAS_Session_PhpSession;
+        }
+
+        phpCAS::traceBegin();
+        // true : allow to change the session_id(), false session_id won't be
+        // changed and logout won't be handled because of that
+        $this->_setChangeSessionID($changeSessionID);
+
+        $this->setSessionHandler($sessionHandler);
+
+        if (!$this->_isLogoutRequest()) {
+            if (session_id() === "") {
+                // skip Session Handling for logout requests and if don't want it
+                session_start();
+                phpCAS :: trace("Starting a new session " . session_id());
+            }
+            // init phpCAS session array
+            if (!isset($_SESSION[static::PHPCAS_SESSION_PREFIX])
+                || !is_array($_SESSION[static::PHPCAS_SESSION_PREFIX])) {
+                $_SESSION[static::PHPCAS_SESSION_PREFIX] = array();
+            }
+        }
+
+        // Only for debug purposes
+        if ($this->isSessionAuthenticated()){
+            phpCAS :: trace("Session is authenticated as: " . $this->getSessionValue('user'));
+        } else {
+            phpCAS :: trace("Session is not authenticated");
+        }
+        // are we in proxy mode ?
+        $this->_proxy = $proxy;
+
+        // Make cookie handling available.
+        if ($this->isProxy()) {
+            if (!$this->hasSessionValue('service_cookies')) {
+                $this->setSessionValue('service_cookies', array());
+            }
+            // TODO remove explicit call to $_SESSION
+            $this->_serviceCookieJar = new CAS_CookieJar(
+                $_SESSION[static::PHPCAS_SESSION_PREFIX]['service_cookies']
+            );
+        }
+
+        // check version
+        $supportedProtocols = phpCAS::getSupportedProtocols();
+        if (isset($supportedProtocols[$server_version]) === false) {
+            phpCAS::error(
+                'this version of CAS (`'.$server_version
+                .'\') is not supported by phpCAS '.phpCAS::getVersion()
+            );
+        }
+
+        if ($server_version === CAS_VERSION_1_0 && $this->isProxy()) {
+            phpCAS::error(
+                'CAS proxies are not supported in CAS '.$server_version
+            );
+        }
+
+        $this->_server['version'] = $server_version;
+
+        // check hostname
+        if ( empty($server_hostname)
+            || !preg_match('/[\.\d\-a-z]*/', $server_hostname)
+        ) {
+            phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
+        }
+        $this->_server['hostname'] = $server_hostname;
+
+        // check port
+        if ( $server_port == 0
+            || !is_int($server_port)
+        ) {
+            phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
+        }
+        $this->_server['port'] = $server_port;
+
+        // check URI
+        if ( !preg_match('/[\.\d\-_a-z\/]*/', $server_uri) ) {
+            phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
+        }
+        // add leading and trailing `/' and remove doubles
+        if(strstr($server_uri, '?') === false) $server_uri .= '/';
+        $server_uri = preg_replace('/\/\//', '/', '/'.$server_uri);
+        $this->_server['uri'] = $server_uri;
+
+        // set to callback mode if PgtIou and PgtId CGI GET parameters are provided
+        if ( $this->isProxy() ) {
+            if(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId'])) {
+                $this->_setCallbackMode(true);
+                $this->_setCallbackModeUsingPost(false);
+            } elseif (!empty($_POST['pgtIou'])&&!empty($_POST['pgtId'])) {
+                $this->_setCallbackMode(true);
+                $this->_setCallbackModeUsingPost(true);
+            } else {
+                $this->_setCallbackMode(false);
+                $this->_setCallbackModeUsingPost(false);
+            }
+
+
+        }
+
+        if ( $this->_isCallbackMode() ) {
+            //callback mode: check that phpCAS is secured
+            if ( !$this->_isHttps() ) {
+                phpCAS::error(
+                    'CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server'
+                );
+            }
+        } else {
+            //normal mode: get ticket and remove it from CGI parameters for
+            // developers
+            $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : '');
+            if (preg_match('/^[SP]T-/', $ticket) ) {
+                phpCAS::trace('Ticket \''.$ticket.'\' found');
+                $this->setTicket($ticket);
+                unset($_GET['ticket']);
+            } else if ( !empty($ticket) ) {
+                //ill-formed ticket, halt
+                phpCAS::error(
+                    'ill-formed ticket found in the URL (ticket=`'
+                    .htmlentities($ticket).'\')'
+                );
+            }
+
+        }
+        phpCAS::traceEnd();
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                           Session Handling                         XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    /**
+     * @addtogroup internalConfig
+     * @{
+     */
+
+    /** The session prefix for phpCAS values */
+    const PHPCAS_SESSION_PREFIX = 'phpCAS';
+
+    /**
+     * @var bool A variable to whether phpcas will use its own session handling. Default = true
+     * @hideinitializer
+     */
+    private $_change_session_id = true;
+
+    /**
+     * @var SessionHandlerInterface
+     */
+    private $_sessionHandler;
+
+    /**
+     * Set a parameter whether to allow phpCAS to change session_id
+     *
+     * @param bool $allowed allow phpCAS to change session_id
+     *
+     * @return void
+     */
+    private function _setChangeSessionID($allowed)
+    {
+        $this->_change_session_id = $allowed;
+    }
+
+    /**
+     * Get whether phpCAS is allowed to change session_id
+     *
+     * @return bool
+     */
+    public function getChangeSessionID()
+    {
+        return $this->_change_session_id;
+    }
+
+    /**
+     * Set the session handler.
+     *
+     * @param \SessionHandlerInterface $sessionHandler
+     *
+     * @return bool
+     */
+    public function setSessionHandler(\SessionHandlerInterface $sessionHandler)
+    {
+        $this->_sessionHandler = $sessionHandler;
+        if (session_status() !== PHP_SESSION_ACTIVE) {
+            return session_set_save_handler($this->_sessionHandler, true);
+        }
+        return true;
+    }
+
+    /**
+     * Get a session value using the given key.
+     *
+     * @param string $key
+     * @param mixed  $default default value if the key is not set
+     *
+     * @return mixed
+     */
+    protected function getSessionValue($key, $default = null)
+    {
+        $this->validateSession($key);
+
+        if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {
+            return $_SESSION[static::PHPCAS_SESSION_PREFIX][$key];
+        }
+
+        return $default;
+    }
+
+    /**
+     * Determine whether a session value is set or not.
+     *
+     * To check if a session value is empty or not please use
+     * !!(getSessionValue($key)).
+     *
+     * @param string $key
+     *
+     * @return bool
+     */
+    protected function hasSessionValue($key)
+    {
+        $this->validateSession($key);
+
+        return isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);
+    }
+
+    /**
+     * Set a session value using the given key and value.
+     *
+     * @param string $key
+     * @param mixed $value
+     *
+     * @return string
+     */
+    protected function setSessionValue($key, $value)
+    {
+        $this->validateSession($key);
+
+        $_SESSION[static::PHPCAS_SESSION_PREFIX][$key] = $value;
+    }
+
+    /**
+     * Remove a session value with the given key.
+     *
+     * @param string $key
+     */
+    protected function removeSessionValue($key)
+    {
+        $this->validateSession($key);
+
+        if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {
+            unset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Remove all phpCAS session values.
+     */
+    protected function clearSessionValues()
+    {
+        unset($_SESSION[static::PHPCAS_SESSION_PREFIX]);
+    }
+
+    /**
+     * Ensure $key is a string for session utils input
+     *
+     * @param string $key
+     *
+     * @return bool
+     */
+    protected function validateSession($key)
+    {
+        if (!is_string($key)) {
+            throw new InvalidArgumentException('Session key must be a string.');
+        }
+
+        return true;
+    }
+
+    /**
+     * Renaming the session
+     *
+     * @param string $ticket name of the ticket
+     *
+     * @return void
+     */
+    protected function _renameSession($ticket)
+    {
+        phpCAS::traceBegin();
+        if ($this->getChangeSessionID()) {
+            if (!empty($this->_user)) {
+                $old_session = $_SESSION;
+                phpCAS :: trace("Killing session: ". session_id());
+                session_destroy();
+                // set up a new session, of name based on the ticket
+                $session_id = $this->_sessionIdForTicket($ticket);
+                phpCAS :: trace("Starting session: ". $session_id);
+                session_id($session_id);
+                session_start();
+                phpCAS :: trace("Restoring old session vars");
+                $_SESSION = $old_session;
+            } else {
+                phpCAS :: trace (
+                    'Session should only be renamed after successfull authentication'
+                );
+            }
+        } else {
+            phpCAS :: trace(
+                "Skipping session rename since phpCAS is not handling the session."
+            );
+        }
+        phpCAS::traceEnd();
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                           AUTHENTICATION                           XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    /**
+     * @addtogroup internalAuthentication
+     * @{
+     */
+
+    /**
+     * The Authenticated user. Written by CAS_Client::_setUser(), read by
+     * CAS_Client::getUser().
+     *
+     * @hideinitializer
+     */
+    private $_user = '';
+
+    /**
+     * This method sets the CAS user's login name.
+     *
+     * @param string $user the login name of the authenticated user.
+     *
+     * @return void
+     */
+    private function _setUser($user)
+    {
+        $this->_user = $user;
+    }
+
+    /**
+     * This method returns the CAS user's login name.
+     *
+     * @return string the login name of the authenticated user
+     *
+     * @warning should be called only after CAS_Client::forceAuthentication() or
+     * CAS_Client::isAuthenticated(), otherwise halt with an error.
+     */
+    public function getUser()
+    {
+        // Sequence validation
+        $this->ensureAuthenticationCallSuccessful();
+
+        return $this->_getUser();
+    }
+
+    /**
+     * This method returns the CAS user's login name.
+     *
+     * @return string the login name of the authenticated user
+     *
+     * @warning should be called only after CAS_Client::forceAuthentication() or
+     * CAS_Client::isAuthenticated(), otherwise halt with an error.
+     */
+    private function _getUser()
+    {
+        // This is likely a duplicate check that could be removed....
+        if ( empty($this->_user) ) {
+            phpCAS::error(
+                'this method should be used only after '.__CLASS__
+                .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
+            );
+        }
+        return $this->_user;
+    }
+
+    /**
+     * The Authenticated users attributes. Written by
+     * CAS_Client::setAttributes(), read by CAS_Client::getAttributes().
+     * @attention client applications should use phpCAS::getAttributes().
+     *
+     * @hideinitializer
+     */
+    private $_attributes = array();
+
+    /**
+     * Set an array of attributes
+     *
+     * @param array $attributes a key value array of attributes
+     *
+     * @return void
+     */
+    public function setAttributes($attributes)
+    {
+        $this->_attributes = $attributes;
+    }
+
+    /**
+     * Get an key values arry of attributes
+     *
+     * @return array of attributes
+     */
+    public function getAttributes()
+    {
+        // Sequence validation
+        $this->ensureAuthenticationCallSuccessful();
+        // This is likely a duplicate check that could be removed....
+        if ( empty($this->_user) ) {
+            // if no user is set, there shouldn't be any attributes also...
+            phpCAS::error(
+                'this method should be used only after '.__CLASS__
+                .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
+            );
+        }
+        return $this->_attributes;
+    }
+
+    /**
+     * Check whether attributes are available
+     *
+     * @return bool attributes available
+     */
+    public function hasAttributes()
+    {
+        // Sequence validation
+        $this->ensureAuthenticationCallSuccessful();
+
+        return !empty($this->_attributes);
+    }
+    /**
+     * Check whether a specific attribute with a name is available
+     *
+     * @param string $key name of attribute
+     *
+     * @return bool is attribute available
+     */
+    public function hasAttribute($key)
+    {
+        // Sequence validation
+        $this->ensureAuthenticationCallSuccessful();
+
+        return $this->_hasAttribute($key);
+    }
+
+    /**
+     * Check whether a specific attribute with a name is available
+     *
+     * @param string $key name of attribute
+     *
+     * @return bool is attribute available
+     */
+    private function _hasAttribute($key)
+    {
+        return (is_array($this->_attributes)
+            && array_key_exists($key, $this->_attributes));
+    }
+
+    /**
+     * Get a specific attribute by name
+     *
+     * @param string $key name of attribute
+     *
+     * @return string attribute values
+     */
+    public function getAttribute($key)
+    {
+        // Sequence validation
+        $this->ensureAuthenticationCallSuccessful();
+
+        if ($this->_hasAttribute($key)) {
+            return $this->_attributes[$key];
+        }
+    }
+
+    /**
+     * This method is called to renew the authentication of the user
+     * If the user is authenticated, renew the connection
+     * If not, redirect to CAS
+     *
+     * @return bool true when the user is authenticated; otherwise halt.
+     */
+    public function renewAuthentication()
+    {
+        phpCAS::traceBegin();
+        // Either way, the user is authenticated by CAS
+        $this->removeSessionValue('auth_checked');
+        if ( $this->isAuthenticated(true) ) {
+            phpCAS::trace('user already authenticated');
+            $res = true;
+        } else {
+            $this->redirectToCas(false, true);
+            // never reached
+            $res = false;
+        }
+        phpCAS::traceEnd();
+        return $res;
+    }
+
+    /**
+     * This method is called to be sure that the user is authenticated. When not
+     * authenticated, halt by redirecting to the CAS server; otherwise return true.
+     *
+     * @return bool true when the user is authenticated; otherwise halt.
+     */
+    public function forceAuthentication()
+    {
+        phpCAS::traceBegin();
+
+        if ( $this->isAuthenticated() ) {
+            // the user is authenticated, nothing to be done.
+            phpCAS::trace('no need to authenticate');
+            $res = true;
+        } else {
+            // the user is not authenticated, redirect to the CAS server
+            $this->removeSessionValue('auth_checked');
+            $this->redirectToCas(false/* no gateway */);
+            // never reached
+            $res = false;
+        }
+        phpCAS::traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * An integer that gives the number of times authentication will be cached
+     * before rechecked.
+     *
+     * @hideinitializer
+     */
+    private $_cache_times_for_auth_recheck = 0;
+
+    /**
+     * Set the number of times authentication will be cached before rechecked.
+     *
+     * @param int $n number of times to wait for a recheck
+     *
+     * @return void
+     */
+    public function setCacheTimesForAuthRecheck($n)
+    {
+        if (gettype($n) != 'integer')
+            throw new CAS_TypeMismatchException($n, '$n', 'string');
+
+        $this->_cache_times_for_auth_recheck = $n;
+    }
+
+    /**
+     * This method is called to check whether the user is authenticated or not.
+     *
+     * @return bool true when the user is authenticated, false when a previous
+     * gateway login failed or  the function will not return if the user is
+     * redirected to the cas server for a gateway login attempt
+     */
+    public function checkAuthentication()
+    {
+        phpCAS::traceBegin();
+        $res = false; // default
+        if ( $this->isAuthenticated() ) {
+            phpCAS::trace('user is authenticated');
+            /* The 'auth_checked' variable is removed just in case it's set. */
+            $this->removeSessionValue('auth_checked');
+            $res = true;
+        } else if ($this->getSessionValue('auth_checked')) {
+            // the previous request has redirected the client to the CAS server
+            // with gateway=true
+            $this->removeSessionValue('auth_checked');
+        } else {
+            // avoid a check against CAS on every request
+            // we need to write this back to session later
+            $unauth_count = $this->getSessionValue('unauth_count', -2);
+
+            if (($unauth_count != -2
+                && $this->_cache_times_for_auth_recheck == -1)
+                || ($unauth_count >= 0
+                && $unauth_count < $this->_cache_times_for_auth_recheck)
+            ) {
+                if ($this->_cache_times_for_auth_recheck != -1) {
+                    $unauth_count++;
+                    phpCAS::trace(
+                        'user is not authenticated (cached for '
+                        .$unauth_count.' times of '
+                        .$this->_cache_times_for_auth_recheck.')'
+                    );
+                } else {
+                    phpCAS::trace(
+                        'user is not authenticated (cached for until login pressed)'
+                    );
+                }
+                $this->setSessionValue('unauth_count', $unauth_count);
+            } else {
+                $this->setSessionValue('unauth_count', 0);
+                $this->setSessionValue('auth_checked', true);
+                phpCAS::trace('user is not authenticated (cache reset)');
+                $this->redirectToCas(true/* gateway */);
+                // never reached
+            }
+        }
+        phpCAS::traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * This method is called to check if the user is authenticated (previously or by
+     * tickets given in the URL).
+     *
+     * @param bool $renew true to force the authentication with the CAS server
+     *
+     * @return bool true when the user is authenticated. Also may redirect to the
+     * same URL without the ticket.
+     */
+    public function isAuthenticated($renew=false)
+    {
+        phpCAS::traceBegin();
+        $res = false;
+
+        if ( $this->_wasPreviouslyAuthenticated() ) {
+            if ($this->hasTicket()) {
+                // User has a additional ticket but was already authenticated
+                phpCAS::trace(
+                    'ticket was present and will be discarded, use renewAuthenticate()'
+                );
+                if ($this->_clearTicketsFromUrl) {
+                    phpCAS::trace("Prepare redirect to : ".$this->getURL());
+                    session_write_close();
+                    header('Location: '.$this->getURL());
+                    flush();
+                    phpCAS::traceExit();
+                    throw new CAS_GracefullTerminationException();
+                } else {
+                    phpCAS::trace(
+                        'Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.'
+                    );
+                    $res = true;
+                }
+            } else {
+                // the user has already (previously during the session) been
+                // authenticated, nothing to be done.
+                phpCAS::trace(
+                    'user was already authenticated, no need to look for tickets'
+                );
+                $res = true;
+            }
+
+            // Mark the auth-check as complete to allow post-authentication
+            // callbacks to make use of phpCAS::getUser() and similar methods
+            $this->markAuthenticationCall($res);
+        } else {
+            if ($this->hasTicket()) {
+                $validate_url = '';
+                $text_response = '';
+                $tree_response = '';
+
+                switch ($this->getServerVersion()) {
+                case CAS_VERSION_1_0:
+                    // if a Service Ticket was given, validate it
+                    phpCAS::trace(
+                        'CAS 1.0 ticket `'.$this->getTicket().'\' is present'
+                    );
+                    $this->validateCAS10(
+                        $validate_url, $text_response, $tree_response, $renew
+                    ); // if it fails, it halts
+                    phpCAS::trace(
+                        'CAS 1.0 ticket `'.$this->getTicket().'\' was validated'
+                    );
+                    $this->setSessionValue('user', $this->_getUser());
+                    $res = true;
+                    $logoutTicket = $this->getTicket();
+                    break;
+                case CAS_VERSION_2_0:
+                case CAS_VERSION_3_0:
+                    // if a Proxy Ticket was given, validate it
+                    phpCAS::trace(
+                        'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' is present'
+                    );
+                    $this->validateCAS20(
+                        $validate_url, $text_response, $tree_response, $renew
+                    ); // note: if it fails, it halts
+                    phpCAS::trace(
+                        'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' was validated'
+                    );
+                    if ( $this->isProxy() ) {
+                        $this->_validatePGT(
+                            $validate_url, $text_response, $tree_response
+                        ); // idem
+                        phpCAS::trace('PGT `'.$this->_getPGT().'\' was validated');
+                        $this->setSessionValue('pgt', $this->_getPGT());
+                    }
+                    $this->setSessionValue('user', $this->_getUser());
+                    if (!empty($this->_attributes)) {
+                        $this->setSessionValue('attributes', $this->_attributes);
+                    }
+                    $proxies = $this->getProxies();
+                    if (!empty($proxies)) {
+                        $this->setSessionValue('proxies', $this->getProxies());
+                    }
+                    $res = true;
+                    $logoutTicket = $this->getTicket();
+                    break;
+                case SAML_VERSION_1_1:
+                    // if we have a SAML ticket, validate it.
+                    phpCAS::trace(
+                        'SAML 1.1 ticket `'.$this->getTicket().'\' is present'
+                    );
+                    $this->validateSA(
+                        $validate_url, $text_response, $tree_response, $renew
+                    ); // if it fails, it halts
+                    phpCAS::trace(
+                        'SAML 1.1 ticket `'.$this->getTicket().'\' was validated'
+                    );
+                    $this->setSessionValue('user', $this->_getUser());
+                    $this->setSessionValue('attributes', $this->_attributes);
+                    $res = true;
+                    $logoutTicket = $this->getTicket();
+                    break;
+                default:
+                    phpCAS::trace('Protocol error');
+                    break;
+                }
+            } else {
+                // no ticket given, not authenticated
+                phpCAS::trace('no ticket found');
+            }
+
+            // Mark the auth-check as complete to allow post-authentication
+            // callbacks to make use of phpCAS::getUser() and similar methods
+            $this->markAuthenticationCall($res);
+
+            if ($res) {
+                // call the post-authenticate callback if registered.
+                if ($this->_postAuthenticateCallbackFunction) {
+                    $args = $this->_postAuthenticateCallbackArgs;
+                    array_unshift($args, $logoutTicket);
+                    call_user_func_array(
+                        $this->_postAuthenticateCallbackFunction, $args
+                    );
+                }
+
+                // if called with a ticket parameter, we need to redirect to the
+                // app without the ticket so that CAS-ification is transparent
+                // to the browser (for later POSTS) most of the checks and
+                // errors should have been made now, so we're safe for redirect
+                // without masking error messages. remove the ticket as a
+                // security precaution to prevent a ticket in the HTTP_REFERRER
+                if ($this->_clearTicketsFromUrl) {
+                    phpCAS::trace("Prepare redirect to : ".$this->getURL());
+                    session_write_close();
+                    header('Location: '.$this->getURL());
+                    flush();
+                    phpCAS::traceExit();
+                    throw new CAS_GracefullTerminationException();
+                }
+            }
+        }
+        phpCAS::traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * This method tells if the current session is authenticated.
+     *
+     * @return bool true if authenticated based soley on $_SESSION variable
+     */
+    public function isSessionAuthenticated ()
+    {
+        return !!$this->getSessionValue('user');
+    }
+
+    /**
+     * This method tells if the user has already been (previously) authenticated
+     * by looking into the session variables.
+     *
+     * @note This function switches to callback mode when needed.
+     *
+     * @return bool true when the user has already been authenticated; false otherwise.
+     */
+    private function _wasPreviouslyAuthenticated()
+    {
+        phpCAS::traceBegin();
+
+        if ( $this->_isCallbackMode() ) {
+            // Rebroadcast the pgtIou and pgtId to all nodes
+            if ($this->_rebroadcast&&!isset($_POST['rebroadcast'])) {
+                $this->_rebroadcast(self::PGTIOU);
+            }
+            $this->_callback();
+        }
+
+        $auth = false;
+
+        if ( $this->isProxy() ) {
+            // CAS proxy: username and PGT must be present
+            if ( $this->isSessionAuthenticated()
+                && $this->getSessionValue('pgt')
+            ) {
+                // authentication already done
+                $this->_setUser($this->getSessionValue('user'));
+                if ($this->hasSessionValue('attributes')) {
+                    $this->setAttributes($this->getSessionValue('attributes'));
+                }
+                $this->_setPGT($this->getSessionValue('pgt'));
+                phpCAS::trace(
+                    'user = `'.$this->getSessionValue('user').'\', PGT = `'
+                    .$this->getSessionValue('pgt').'\''
+                );
+
+                // Include the list of proxies
+                if ($this->hasSessionValue('proxies')) {
+                    $this->_setProxies($this->getSessionValue('proxies'));
+                    phpCAS::trace(
+                        'proxies = "'
+                        .implode('", "', $this->getSessionValue('proxies')).'"'
+                    );
+                }
+
+                $auth = true;
+            } elseif ( $this->isSessionAuthenticated()
+                && !$this->getSessionValue('pgt')
+            ) {
+                // these two variables should be empty or not empty at the same time
+                phpCAS::trace(
+                    'username found (`'.$this->getSessionValue('user')
+                    .'\') but PGT is empty'
+                );
+                // unset all tickets to enforce authentication
+                $this->clearSessionValues();
+                $this->setTicket('');
+            } elseif ( !$this->isSessionAuthenticated()
+                && $this->getSessionValue('pgt')
+            ) {
+                // these two variables should be empty or not empty at the same time
+                phpCAS::trace(
+                    'PGT found (`'.$this->getSessionValue('pgt')
+                    .'\') but username is empty'
+                );
+                // unset all tickets to enforce authentication
+                $this->clearSessionValues();
+                $this->setTicket('');
+            } else {
+                phpCAS::trace('neither user nor PGT found');
+            }
+        } else {
+            // `simple' CAS client (not a proxy): username must be present
+            if ( $this->isSessionAuthenticated() ) {
+                // authentication already done
+                $this->_setUser($this->getSessionValue('user'));
+                if ($this->hasSessionValue('attributes')) {
+                    $this->setAttributes($this->getSessionValue('attributes'));
+                }
+                phpCAS::trace('user = `'.$this->getSessionValue('user').'\'');
+
+                // Include the list of proxies
+                if ($this->hasSessionValue('proxies')) {
+                    $this->_setProxies($this->getSessionValue('proxies'));
+                    phpCAS::trace(
+                        'proxies = "'
+                        .implode('", "', $this->getSessionValue('proxies')).'"'
+                    );
+                }
+
+                $auth = true;
+            } else {
+                phpCAS::trace('no user found');
+            }
+        }
+
+        phpCAS::traceEnd($auth);
+        return $auth;
+    }
+
+    /**
+     * This method is used to redirect the client to the CAS server.
+     * It is used by CAS_Client::forceAuthentication() and
+     * CAS_Client::checkAuthentication().
+     *
+     * @param bool $gateway true to check authentication, false to force it
+     * @param bool $renew   true to force the authentication with the CAS server
+     *
+     * @return void
+     */
+    public function redirectToCas($gateway=false,$renew=false)
+    {
+        phpCAS::traceBegin();
+        $cas_url = $this->getServerLoginURL($gateway, $renew);
+        session_write_close();
+        if (php_sapi_name() === 'cli') {
+            @header('Location: '.$cas_url);
+        } else {
+            header('Location: '.$cas_url);
+        }
+        phpCAS::trace("Redirect to : ".$cas_url);
+        $lang = $this->getLangObj();
+        $this->printHTMLHeader($lang->getAuthenticationWanted());
+        $this->printf('<p>'. $lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
+        $this->printHTMLFooter();
+        phpCAS::traceExit();
+        throw new CAS_GracefullTerminationException();
+    }
+
+
+    /**
+     * This method is used to logout from CAS.
+     *
+     * @param array $params an array that contains the optional url and service
+     * parameters that will be passed to the CAS server
+     *
+     * @return void
+     */
+    public function logout($params)
+    {
+        phpCAS::traceBegin();
+        $cas_url = $this->getServerLogoutURL();
+        $paramSeparator = '?';
+        if (isset($params['url'])) {
+            $cas_url = $cas_url . $paramSeparator . "url="
+                . urlencode($params['url']);
+            $paramSeparator = '&';
+        }
+        if (isset($params['service'])) {
+            $cas_url = $cas_url . $paramSeparator . "service="
+                . urlencode($params['service']);
+        }
+        header('Location: '.$cas_url);
+        phpCAS::trace("Prepare redirect to : ".$cas_url);
+
+        phpCAS::trace("Destroying session : ".session_id());
+        session_unset();
+        session_destroy();
+        if (session_status() === PHP_SESSION_NONE) {
+            phpCAS::trace("Session terminated");
+        } else {
+            phpCAS::error("Session was not terminated");
+            phpCAS::trace("Session was not terminated");
+        }
+        $lang = $this->getLangObj();
+        $this->printHTMLHeader($lang->getLogout());
+        $this->printf('<p>'.$lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
+        $this->printHTMLFooter();
+        phpCAS::traceExit();
+        throw new CAS_GracefullTerminationException();
+    }
+
+    /**
+     * Check of the current request is a logout request
+     *
+     * @return bool is logout request.
+     */
+    private function _isLogoutRequest()
+    {
+        return !empty($_POST['logoutRequest']);
+    }
+
+    /**
+     * This method handles logout requests.
+     *
+     * @param bool $check_client    true to check the client bofore handling
+     * the request, false not to perform any access control. True by default.
+     * @param array $allowed_clients an array of host names allowed to send
+     * logout requests.
+     *
+     * @return void
+     */
+    public function handleLogoutRequests($check_client=true, $allowed_clients=array())
+    {
+        phpCAS::traceBegin();
+        if (!$this->_isLogoutRequest()) {
+            phpCAS::trace("Not a logout request");
+            phpCAS::traceEnd();
+            return;
+        }
+        if (!$this->getChangeSessionID()
+            && is_null($this->_signoutCallbackFunction)
+        ) {
+            phpCAS::trace(
+                "phpCAS can't handle logout requests if it is not allowed to change session_id."
+            );
+        }
+        phpCAS::trace("Logout requested");
+        $decoded_logout_rq = urldecode($_POST['logoutRequest']);
+        phpCAS::trace("SAML REQUEST: ".$decoded_logout_rq);
+        $allowed = false;
+        if ($check_client) {
+            if ($allowed_clients === array()) {
+                $allowed_clients = array( $this->_getServerHostname() );
+            }
+            $client_ip = $_SERVER['REMOTE_ADDR'];
+            $client = gethostbyaddr($client_ip);
+            phpCAS::trace("Client: ".$client."/".$client_ip);
+            foreach ($allowed_clients as $allowed_client) {
+                if (($client == $allowed_client)
+                    || ($client_ip == $allowed_client)
+                ) {
+                    phpCAS::trace(
+                        "Allowed client '".$allowed_client
+                        ."' matches, logout request is allowed"
+                    );
+                    $allowed = true;
+                    break;
+                } else {
+                    phpCAS::trace(
+                        "Allowed client '".$allowed_client."' does not match"
+                    );
+                }
+            }
+        } else {
+            phpCAS::trace("No access control set");
+            $allowed = true;
+        }
+        // If Logout command is permitted proceed with the logout
+        if ($allowed) {
+            phpCAS::trace("Logout command allowed");
+            // Rebroadcast the logout request
+            if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) {
+                $this->_rebroadcast(self::LOGOUT);
+            }
+            // Extract the ticket from the SAML Request
+            preg_match(
+                "|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|",
+                $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3
+            );
+            $wrappedSamlSessionIndex = preg_replace(
+                '|<samlp:SessionIndex>|', '', $tick[0][0]
+            );
+            $ticket2logout = preg_replace(
+                '|</samlp:SessionIndex>|', '', $wrappedSamlSessionIndex
+            );
+            phpCAS::trace("Ticket to logout: ".$ticket2logout);
+
+            // call the post-authenticate callback if registered.
+            if ($this->_signoutCallbackFunction) {
+                $args = $this->_signoutCallbackArgs;
+                array_unshift($args, $ticket2logout);
+                call_user_func_array($this->_signoutCallbackFunction, $args);
+            }
+
+            // If phpCAS is managing the session_id, destroy session thanks to
+            // session_id.
+            if ($this->getChangeSessionID()) {
+                $session_id = $this->_sessionIdForTicket($ticket2logout);
+                phpCAS::trace("Session id: ".$session_id);
+
+                // destroy a possible application session created before phpcas
+                if (session_id() !== "") {
+                    session_unset();
+                    session_destroy();
+                }
+                // fix session ID
+                session_id($session_id);
+                $_COOKIE[session_name()]=$session_id;
+                $_GET[session_name()]=$session_id;
+
+                // Overwrite session
+                session_start();
+                session_unset();
+                session_destroy();
+                phpCAS::trace("Session ". $session_id . " destroyed");
+            }
+        } else {
+            phpCAS::error("Unauthorized logout request from client '".$client."'");
+            phpCAS::trace("Unauthorized logout request from client '".$client."'");
+        }
+        flush();
+        phpCAS::traceExit();
+        throw new CAS_GracefullTerminationException();
+
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                  BASIC CLIENT FEATURES (CAS 1.0)                   XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    // ########################################################################
+    //  ST
+    // ########################################################################
+    /**
+    * @addtogroup internalBasic
+    * @{
+    */
+
+    /**
+     * The Ticket provided in the URL of the request if present
+     * (empty otherwise). Written by CAS_Client::CAS_Client(), read by
+     * CAS_Client::getTicket() and CAS_Client::_hasPGT().
+     *
+     * @hideinitializer
+     */
+    private $_ticket = '';
+
+    /**
+     * This method returns the Service Ticket provided in the URL of the request.
+     *
+     * @return string service ticket.
+     */
+    public  function getTicket()
+    {
+        return $this->_ticket;
+    }
+
+    /**
+     * This method stores the Service Ticket.
+     *
+     * @param string $st The Service Ticket.
+     *
+     * @return void
+     */
+    public function setTicket($st)
+    {
+        $this->_ticket = $st;
+    }
+
+    /**
+     * This method tells if a Service Ticket was stored.
+     *
+     * @return bool if a Service Ticket has been stored.
+     */
+    public function hasTicket()
+    {
+        return !empty($this->_ticket);
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  ST VALIDATION
+    // ########################################################################
+    /**
+    * @addtogroup internalBasic
+    * @{
+    */
+
+    /**
+     * @var  string the certificate of the CAS server CA.
+     *
+     * @hideinitializer
+     */
+    private $_cas_server_ca_cert = null;
+
+
+    /**
+
+     * validate CN of the CAS server certificate
+
+     *
+
+     * @hideinitializer
+
+     */
+
+    private $_cas_server_cn_validate = true;
+
+    /**
+     * Set to true not to validate the CAS server.
+     *
+     * @hideinitializer
+     */
+    private $_no_cas_server_validation = false;
+
+
+    /**
+     * Set the CA certificate of the CAS server.
+     *
+     * @param string $cert        the PEM certificate file name of the CA that emited
+     * the cert of the server
+     * @param bool   $validate_cn valiate CN of the CAS server certificate
+     *
+     * @return void
+     */
+    public function setCasServerCACert($cert, $validate_cn)
+    {
+    // Argument validation
+        if (gettype($cert) != 'string') {
+            throw new CAS_TypeMismatchException($cert, '$cert', 'string');
+        }
+        if (gettype($validate_cn) != 'boolean') {
+            throw new CAS_TypeMismatchException($validate_cn, '$validate_cn', 'boolean');
+        }
+        if (!file_exists($cert)) {
+            throw new CAS_InvalidArgumentException("Certificate file does not exist " . $this->_requestImplementation);
+        }
+        $this->_cas_server_ca_cert = $cert;
+        $this->_cas_server_cn_validate = $validate_cn;
+    }
+
+    /**
+     * Set no SSL validation for the CAS server.
+     *
+     * @return void
+     */
+    public function setNoCasServerValidation()
+    {
+        $this->_no_cas_server_validation = true;
+    }
+
+    /**
+     * This method is used to validate a CAS 1,0 ticket; halt on failure, and
+     * sets $validate_url, $text_reponse and $tree_response on success.
+     *
+     * @param string &$validate_url  reference to the the URL of the request to
+     * the CAS server.
+     * @param string &$text_response reference to the response of the CAS
+     * server, as is (XML text).
+     * @param string &$tree_response reference to the response of the CAS
+     * server, as a DOM XML tree.
+     * @param bool   $renew          true to force the authentication with the CAS server
+     *
+     * @return bool true when successfull and issue a CAS_AuthenticationException
+     * and false on an error
+     * @throws  CAS_AuthenticationException
+     */
+    public function validateCAS10(&$validate_url,&$text_response,&$tree_response,$renew=false)
+    {
+        phpCAS::traceBegin();
+        // build the URL to validate the ticket
+        $validate_url = $this->getServerServiceValidateURL()
+            .'&ticket='.urlencode($this->getTicket());
+
+        if ( $renew ) {
+            // pass the renew
+            $validate_url .= '&renew=true';
+        }
+
+        $headers = '';
+        $err_msg = '';
+        // open and read the URL
+        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
+            phpCAS::trace(
+                'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
+            );
+            throw new CAS_AuthenticationException(
+                $this, 'CAS 1.0 ticket not validated', $validate_url,
+                true/*$no_response*/
+            );
+        }
+
+        if (preg_match('/^no\n/', $text_response)) {
+            phpCAS::trace('Ticket has not been validated');
+            throw new CAS_AuthenticationException(
+                $this, 'ST not validated', $validate_url, false/*$no_response*/,
+                false/*$bad_response*/, $text_response
+            );
+        } else if (!preg_match('/^yes\n/', $text_response)) {
+            phpCAS::trace('ill-formed response');
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/, $text_response
+            );
+        }
+        // ticket has been validated, extract the user name
+        $arr = preg_split('/\n/', $text_response);
+        $this->_setUser(trim($arr[1]));
+
+        $this->_renameSession($this->getTicket());
+
+        // at this step, ticket has been validated and $this->_user has been set,
+        phpCAS::traceEnd(true);
+        return true;
+    }
+
+    /** @} */
+
+
+    // ########################################################################
+    //  SAML VALIDATION
+    // ########################################################################
+    /**
+    * @addtogroup internalSAML
+    * @{
+    */
+
+    /**
+     * This method is used to validate a SAML TICKET; halt on failure, and sets
+     * $validate_url, $text_reponse and $tree_response on success. These
+     * parameters are used later by CAS_Client::_validatePGT() for CAS proxies.
+     *
+     * @param string &$validate_url  reference to the the URL of the request to
+     * the CAS server.
+     * @param string &$text_response reference to the response of the CAS
+     * server, as is (XML text).
+     * @param string &$tree_response reference to the response of the CAS
+     * server, as a DOM XML tree.
+     * @param bool   $renew          true to force the authentication with the CAS server
+     *
+     * @return bool true when successfull and issue a CAS_AuthenticationException
+     * and false on an error
+     *
+     * @throws  CAS_AuthenticationException
+     */
+    public function validateSA(&$validate_url,&$text_response,&$tree_response,$renew=false)
+    {
+        phpCAS::traceBegin();
+        $result = false;
+        // build the URL to validate the ticket
+        $validate_url = $this->getServerSamlValidateURL();
+
+        if ( $renew ) {
+            // pass the renew
+            $validate_url .= '&renew=true';
+        }
+
+        $headers = '';
+        $err_msg = '';
+        // open and read the URL
+        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
+            phpCAS::trace(
+                'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
+            );
+            throw new CAS_AuthenticationException(
+                $this, 'SA not validated', $validate_url, true/*$no_response*/
+            );
+        }
+
+        phpCAS::trace('server version: '.$this->getServerVersion());
+
+        // analyze the result depending on the version
+        switch ($this->getServerVersion()) {
+        case SAML_VERSION_1_1:
+            // create new DOMDocument Object
+            $dom = new DOMDocument();
+            // Fix possible whitspace problems
+            $dom->preserveWhiteSpace = false;
+            // read the response of the CAS server into a DOM object
+            if (!($dom->loadXML($text_response))) {
+                phpCAS::trace('dom->loadXML() failed');
+                throw new CAS_AuthenticationException(
+                    $this, 'SA not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/,
+                    $text_response
+                );
+            }
+            // read the root node of the XML tree
+            if (!($tree_response = $dom->documentElement)) {
+                phpCAS::trace('documentElement() failed');
+                throw new CAS_AuthenticationException(
+                    $this, 'SA not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/,
+                    $text_response
+                );
+            } else if ( $tree_response->localName != 'Envelope' ) {
+                // insure that tag name is 'Envelope'
+                phpCAS::trace(
+                    'bad XML root node (should be `Envelope\' instead of `'
+                    .$tree_response->localName.'\''
+                );
+                throw new CAS_AuthenticationException(
+                    $this, 'SA not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/,
+                    $text_response
+                );
+            } else if ($tree_response->getElementsByTagName("NameIdentifier")->length != 0) {
+                // check for the NameIdentifier tag in the SAML response
+                $success_elements = $tree_response->getElementsByTagName("NameIdentifier");
+                phpCAS::trace('NameIdentifier found');
+                $user = trim($success_elements->item(0)->nodeValue);
+                phpCAS::trace('user = `'.$user.'`');
+                $this->_setUser($user);
+                $this->_setSessionAttributes($text_response);
+                $result = true;
+            } else {
+                phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
+                throw new CAS_AuthenticationException(
+                    $this, 'SA not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/,
+                    $text_response
+                );
+            }
+        }
+        if ($result) {
+            $this->_renameSession($this->getTicket());
+        }
+        // at this step, ST has been validated and $this->_user has been set,
+        phpCAS::traceEnd($result);
+        return $result;
+    }
+
+    /**
+     * This method will parse the DOM and pull out the attributes from the SAML
+     * payload and put them into an array, then put the array into the session.
+     *
+     * @param string $text_response the SAML payload.
+     *
+     * @return bool true when successfull and false if no attributes a found
+     */
+    private function _setSessionAttributes($text_response)
+    {
+        phpCAS::traceBegin();
+
+        $result = false;
+
+        $attr_array = array();
+
+        // create new DOMDocument Object
+        $dom = new DOMDocument();
+        // Fix possible whitspace problems
+        $dom->preserveWhiteSpace = false;
+        if (($dom->loadXML($text_response))) {
+            $xPath = new DOMXPath($dom);
+            $xPath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
+            $xPath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
+            $nodelist = $xPath->query("//saml:Attribute");
+
+            if ($nodelist) {
+                foreach ($nodelist as $node) {
+                    $xres = $xPath->query("saml:AttributeValue", $node);
+                    $name = $node->getAttribute("AttributeName");
+                    $value_array = array();
+                    foreach ($xres as $node2) {
+                        $value_array[] = $node2->nodeValue;
+                    }
+                    $attr_array[$name] = $value_array;
+                }
+                // UGent addition...
+                foreach ($attr_array as $attr_key => $attr_value) {
+                    if (count($attr_value) > 1) {
+                        $this->_attributes[$attr_key] = $attr_value;
+                        phpCAS::trace("* " . $attr_key . "=" . print_r($attr_value, true));
+                    } else {
+                        $this->_attributes[$attr_key] = $attr_value[0];
+                        phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
+                    }
+                }
+                $result = true;
+            } else {
+                phpCAS::trace("SAML Attributes are empty");
+                $result = false;
+            }
+        }
+        phpCAS::traceEnd($result);
+        return $result;
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                     PROXY FEATURES (CAS 2.0)                       XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    // ########################################################################
+    //  PROXYING
+    // ########################################################################
+    /**
+    * @addtogroup internalProxy
+    * @{
+    */
+
+    /**
+     * @var  bool is the client a proxy
+     * A boolean telling if the client is a CAS proxy or not. Written by
+     * CAS_Client::CAS_Client(), read by CAS_Client::isProxy().
+     */
+    private $_proxy;
+
+    /**
+     * @var  CAS_CookieJar Handler for managing service cookies.
+     */
+    private $_serviceCookieJar;
+
+    /**
+     * Tells if a CAS client is a CAS proxy or not
+     *
+     * @return bool true when the CAS client is a CAS proxy, false otherwise
+     */
+    public function isProxy()
+    {
+        return $this->_proxy;
+    }
+
+
+    /** @} */
+    // ########################################################################
+    //  PGT
+    // ########################################################################
+    /**
+    * @addtogroup internalProxy
+    * @{
+    */
+
+    /**
+     * the Proxy Grnting Ticket given by the CAS server (empty otherwise).
+     * Written by CAS_Client::_setPGT(), read by CAS_Client::_getPGT() and
+     * CAS_Client::_hasPGT().
+     *
+     * @hideinitializer
+     */
+    private $_pgt = '';
+
+    /**
+     * This method returns the Proxy Granting Ticket given by the CAS server.
+     *
+     * @return string the Proxy Granting Ticket.
+     */
+    private function _getPGT()
+    {
+        return $this->_pgt;
+    }
+
+    /**
+     * This method stores the Proxy Granting Ticket.
+     *
+     * @param string $pgt The Proxy Granting Ticket.
+     *
+     * @return void
+     */
+    private function _setPGT($pgt)
+    {
+        $this->_pgt = $pgt;
+    }
+
+    /**
+     * This method tells if a Proxy Granting Ticket was stored.
+     *
+     * @return bool true if a Proxy Granting Ticket has been stored.
+     */
+    private function _hasPGT()
+    {
+        return !empty($this->_pgt);
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  CALLBACK MODE
+    // ########################################################################
+    /**
+    * @addtogroup internalCallback
+    * @{
+    */
+    /**
+     * each PHP script using phpCAS in proxy mode is its own callback to get the
+     * PGT back from the CAS server. callback_mode is detected by the constructor
+     * thanks to the GET parameters.
+     */
+
+    /**
+     * @var bool a boolean to know if the CAS client is running in callback mode. Written by
+     * CAS_Client::setCallBackMode(), read by CAS_Client::_isCallbackMode().
+     *
+     * @hideinitializer
+     */
+    private $_callback_mode = false;
+
+    /**
+     * This method sets/unsets callback mode.
+     *
+     * @param bool $callback_mode true to set callback mode, false otherwise.
+     *
+     * @return void
+     */
+    private function _setCallbackMode($callback_mode)
+    {
+        $this->_callback_mode = $callback_mode;
+    }
+
+    /**
+     * This method returns true when the CAS client is running in callback mode,
+     * false otherwise.
+     *
+     * @return bool A boolean.
+     */
+    private function _isCallbackMode()
+    {
+        return $this->_callback_mode;
+    }
+
+    /**
+     * @var bool a boolean to know if the CAS client is using POST parameters when in callback mode.
+     * Written by CAS_Client::_setCallbackModeUsingPost(), read by CAS_Client::_isCallbackModeUsingPost().
+     *
+     * @hideinitializer
+     */
+    private $_callback_mode_using_post = false;
+
+    /**
+     * This method sets/unsets usage of POST parameters in callback mode (default/false is GET parameters)
+     *
+     * @param bool $callback_mode_using_post true to use POST, false to use GET (default).
+     *
+     * @return void
+     */
+    private function _setCallbackModeUsingPost($callback_mode_using_post)
+    {
+        $this->_callback_mode_using_post = $callback_mode_using_post;
+    }
+
+    /**
+     * This method returns true when the callback mode is using POST, false otherwise.
+     *
+     * @return bool A boolean.
+     */
+    private function _isCallbackModeUsingPost()
+    {
+        return $this->_callback_mode_using_post;
+    }
+
+    /**
+     * the URL that should be used for the PGT callback (in fact the URL of the
+     * current request without any CGI parameter). Written and read by
+     * CAS_Client::_getCallbackURL().
+     *
+     * @hideinitializer
+     */
+    private $_callback_url = '';
+
+    /**
+     * This method returns the URL that should be used for the PGT callback (in
+     * fact the URL of the current request without any CGI parameter, except if
+     * phpCAS::setFixedCallbackURL() was used).
+     *
+     * @return string The callback URL
+     */
+    private function _getCallbackURL()
+    {
+        // the URL is built when needed only
+        if ( empty($this->_callback_url) ) {
+            // remove the ticket if present in the URL
+            $final_uri = 'https://';
+            $final_uri .= $this->_getClientUrl();
+            $request_uri = $_SERVER['REQUEST_URI'];
+            $request_uri = preg_replace('/\?.*$/', '', $request_uri);
+            $final_uri .= $request_uri;
+            $this->_callback_url = $final_uri;
+        }
+        return $this->_callback_url;
+    }
+
+    /**
+     * This method sets the callback url.
+     *
+     * @param string $url url to set callback
+     *
+     * @return string the callback url
+     */
+    public function setCallbackURL($url)
+    {
+        // Sequence validation
+        $this->ensureIsProxy();
+        // Argument Validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        return $this->_callback_url = $url;
+    }
+
+    /**
+     * This method is called by CAS_Client::CAS_Client() when running in callback
+     * mode. It stores the PGT and its PGT Iou, prints its output and halts.
+     *
+     * @return void
+     */
+    private function _callback()
+    {
+        phpCAS::traceBegin();
+        if ($this->_isCallbackModeUsingPost()) {
+            $pgtId = $_POST['pgtId'];
+            $pgtIou = $_POST['pgtIou'];
+        } else {
+            $pgtId = $_GET['pgtId'];
+            $pgtIou = $_GET['pgtIou'];
+        }
+        if (preg_match('/^PGTIOU-[\.\-\w]+$/', $pgtIou)) {
+            if (preg_match('/^[PT]GT-[\.\-\w]+$/', $pgtId)) {
+                phpCAS::trace('Storing PGT `'.$pgtId.'\' (id=`'.$pgtIou.'\')');
+                $this->_storePGT($pgtId, $pgtIou);
+                if ($this->isXmlResponse()) {
+                    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n";
+                    echo '<proxySuccess xmlns="http://www.yale.edu/tp/cas" />';
+                    phpCAS::traceExit("XML response sent");
+                } else {
+                    $this->printHTMLHeader('phpCAS callback');
+                    echo '<p>Storing PGT `'.$pgtId.'\' (id=`'.$pgtIou.'\').</p>';
+                    $this->printHTMLFooter();
+                    phpCAS::traceExit("HTML response sent");
+                }
+                phpCAS::traceExit("Successfull Callback");
+            } else {
+                phpCAS::error('PGT format invalid' . $pgtId);
+                phpCAS::traceExit('PGT format invalid' . $pgtId);
+            }
+        } else {
+            phpCAS::error('PGTiou format invalid' . $pgtIou);
+            phpCAS::traceExit('PGTiou format invalid' . $pgtIou);
+        }
+
+        // Flush the buffer to prevent from sending anything other then a 200
+        // Success Status back to the CAS Server. The Exception would normally
+        // report as a 500 error.
+        flush();
+        throw new CAS_GracefullTerminationException();
+    }
+
+    /**
+     * Check if application/xml or text/xml is pressent in HTTP_ACCEPT header values
+     * when return value is complex and contains attached q parameters.
+     * Example:  HTTP_ACCEPT = text/html,application/xhtml+xml,application/xml;q=0.9
+     * @return bool
+     */
+    private function isXmlResponse()
+    {
+        if (!array_key_exists('HTTP_ACCEPT', $_SERVER)) {
+            return false;
+        }
+        if (strpos($_SERVER['HTTP_ACCEPT'], 'application/xml') === false && strpos($_SERVER['HTTP_ACCEPT'], 'text/xml') === false) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  PGT STORAGE
+    // ########################################################################
+    /**
+    * @addtogroup internalPGTStorage
+    * @{
+    */
+
+    /**
+     * @var  CAS_PGTStorage_AbstractStorage
+     * an instance of a class inheriting of PGTStorage, used to deal with PGT
+     * storage. Created by CAS_Client::setPGTStorageFile(), used
+     * by CAS_Client::setPGTStorageFile() and CAS_Client::_initPGTStorage().
+     *
+     * @hideinitializer
+     */
+    private $_pgt_storage = null;
+
+    /**
+     * This method is used to initialize the storage of PGT's.
+     * Halts on error.
+     *
+     * @return void
+     */
+    private function _initPGTStorage()
+    {
+        // if no SetPGTStorageXxx() has been used, default to file
+        if ( !is_object($this->_pgt_storage) ) {
+            $this->setPGTStorageFile();
+        }
+
+        // initializes the storage
+        $this->_pgt_storage->init();
+    }
+
+    /**
+     * This method stores a PGT. Halts on error.
+     *
+     * @param string $pgt     the PGT to store
+     * @param string $pgt_iou its corresponding Iou
+     *
+     * @return void
+     */
+    private function _storePGT($pgt,$pgt_iou)
+    {
+        // ensure that storage is initialized
+        $this->_initPGTStorage();
+        // writes the PGT
+        $this->_pgt_storage->write($pgt, $pgt_iou);
+    }
+
+    /**
+     * This method reads a PGT from its Iou and deletes the corresponding
+     * storage entry.
+     *
+     * @param string $pgt_iou the PGT Iou
+     *
+     * @return string mul The PGT corresponding to the Iou, false when not found.
+     */
+    private function _loadPGT($pgt_iou)
+    {
+        // ensure that storage is initialized
+        $this->_initPGTStorage();
+        // read the PGT
+        return $this->_pgt_storage->read($pgt_iou);
+    }
+
+    /**
+     * This method can be used to set a custom PGT storage object.
+     *
+     * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that
+     * inherits from the CAS_PGTStorage_AbstractStorage class
+     *
+     * @return void
+     */
+    public function setPGTStorage($storage)
+    {
+        // Sequence validation
+        $this->ensureIsProxy();
+
+        // check that the storage has not already been set
+        if ( is_object($this->_pgt_storage) ) {
+            phpCAS::error('PGT storage already defined');
+        }
+
+        // check to make sure a valid storage object was specified
+        if ( !($storage instanceof CAS_PGTStorage_AbstractStorage) )
+            throw new CAS_TypeMismatchException($storage, '$storage', 'CAS_PGTStorage_AbstractStorage object');
+
+        // store the PGTStorage object
+        $this->_pgt_storage = $storage;
+    }
+
+    /**
+     * This method is used to tell phpCAS to store the response of the
+     * CAS server to PGT requests in a database.
+     *
+     * @param string|PDO $dsn_or_pdo     a dsn string to use for creating a PDO
+     * object or a PDO object
+     * @param string $username       the username to use when connecting to the
+     * database
+     * @param string $password       the password to use when connecting to the
+     * database
+     * @param string $table          the table to use for storing and retrieving
+     * PGTs
+     * @param string $driver_options any driver options to use when connecting
+     * to the database
+     *
+     * @return void
+     */
+    public function setPGTStorageDb(
+        $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null
+    ) {
+        // Sequence validation
+        $this->ensureIsProxy();
+
+        // Argument validation
+        if (!(is_object($dsn_or_pdo) && $dsn_or_pdo instanceof PDO) && !is_string($dsn_or_pdo))
+            throw new CAS_TypeMismatchException($dsn_or_pdo, '$dsn_or_pdo', 'string or PDO object');
+        if (gettype($username) != 'string')
+            throw new CAS_TypeMismatchException($username, '$username', 'string');
+        if (gettype($password) != 'string')
+            throw new CAS_TypeMismatchException($password, '$password', 'string');
+        if (gettype($table) != 'string')
+            throw new CAS_TypeMismatchException($table, '$password', 'string');
+
+        // create the storage object
+        $this->setPGTStorage(
+            new CAS_PGTStorage_Db(
+                $this, $dsn_or_pdo, $username, $password, $table, $driver_options
+            )
+        );
+    }
+
+    /**
+     * This method is used to tell phpCAS to store the response of the
+     * CAS server to PGT requests onto the filesystem.
+     *
+     * @param string $path the path where the PGT's should be stored
+     *
+     * @return void
+     */
+    public function setPGTStorageFile($path='')
+    {
+        // Sequence validation
+        $this->ensureIsProxy();
+
+        // Argument validation
+        if (gettype($path) != 'string')
+            throw new CAS_TypeMismatchException($path, '$path', 'string');
+
+        // create the storage object
+        $this->setPGTStorage(new CAS_PGTStorage_File($this, $path));
+    }
+
+
+    // ########################################################################
+    //  PGT VALIDATION
+    // ########################################################################
+    /**
+    * This method is used to validate a PGT; halt on failure.
+    *
+    * @param string &$validate_url the URL of the request to the CAS server.
+    * @param string $text_response the response of the CAS server, as is
+    *                              (XML text); result of
+    *                              CAS_Client::validateCAS10() or
+    *                              CAS_Client::validateCAS20().
+    * @param DOMElement $tree_response the response of the CAS server, as a DOM XML
+    * tree; result of CAS_Client::validateCAS10() or CAS_Client::validateCAS20().
+    *
+    * @return bool true when successfull and issue a CAS_AuthenticationException
+    * and false on an error
+    *
+    * @throws CAS_AuthenticationException
+    */
+    private function _validatePGT(&$validate_url,$text_response,$tree_response)
+    {
+        phpCAS::traceBegin();
+        if ( $tree_response->getElementsByTagName("proxyGrantingTicket")->length == 0) {
+            phpCAS::trace('<proxyGrantingTicket> not found');
+            // authentication succeded, but no PGT Iou was transmitted
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket validated but no PGT Iou transmitted',
+                $validate_url, false/*$no_response*/, false/*$bad_response*/,
+                $text_response
+            );
+        } else {
+            // PGT Iou transmitted, extract it
+            $pgt_iou = trim(
+                $tree_response->getElementsByTagName("proxyGrantingTicket")->item(0)->nodeValue
+            );
+            if (preg_match('/^PGTIOU-[\.\-\w]+$/', $pgt_iou)) {
+                $pgt = $this->_loadPGT($pgt_iou);
+                if ( $pgt == false ) {
+                    phpCAS::trace('could not load PGT');
+                    throw new CAS_AuthenticationException(
+                        $this,
+                        'PGT Iou was transmitted but PGT could not be retrieved',
+                        $validate_url, false/*$no_response*/,
+                        false/*$bad_response*/, $text_response
+                    );
+                }
+                $this->_setPGT($pgt);
+            } else {
+                phpCAS::trace('PGTiou format error');
+                throw new CAS_AuthenticationException(
+                    $this, 'PGT Iou was transmitted but has wrong format',
+                    $validate_url, false/*$no_response*/, false/*$bad_response*/,
+                    $text_response
+                );
+            }
+        }
+        phpCAS::traceEnd(true);
+        return true;
+    }
+
+    // ########################################################################
+    //  PGT VALIDATION
+    // ########################################################################
+
+    /**
+     * This method is used to retrieve PT's from the CAS server thanks to a PGT.
+     *
+     * @param string $target_service the service to ask for with the PT.
+     * @param int &$err_code      an error code (PHPCAS_SERVICE_OK on success).
+     * @param string &$err_msg       an error message (empty on success).
+     *
+     * @return string|false a Proxy Ticket, or false on error.
+     */
+    public function retrievePT($target_service,&$err_code,&$err_msg)
+    {
+        // Argument validation
+        if (gettype($target_service) != 'string')
+            throw new CAS_TypeMismatchException($target_service, '$target_service', 'string');
+
+        phpCAS::traceBegin();
+
+        // by default, $err_msg is set empty and $pt to true. On error, $pt is
+        // set to false and $err_msg to an error message. At the end, if $pt is false
+        // and $error_msg is still empty, it is set to 'invalid response' (the most
+        // commonly encountered error).
+        $err_msg = '';
+
+        // build the URL to retrieve the PT
+        $cas_url = $this->getServerProxyURL().'?targetService='
+            .urlencode($target_service).'&pgt='.$this->_getPGT();
+
+        $headers = '';
+        $cas_response = '';
+        // open and read the URL
+        if ( !$this->_readURL($cas_url, $headers, $cas_response, $err_msg) ) {
+            phpCAS::trace(
+                'could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')'
+            );
+            $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
+            $err_msg = 'could not retrieve PT (no response from the CAS server)';
+            phpCAS::traceEnd(false);
+            return false;
+        }
+
+        $bad_response = false;
+
+        // create new DOMDocument object
+        $dom = new DOMDocument();
+        // Fix possible whitspace problems
+        $dom->preserveWhiteSpace = false;
+        // read the response of the CAS server into a DOM object
+        if ( !($dom->loadXML($cas_response))) {
+            phpCAS::trace('dom->loadXML() failed');
+            // read failed
+            $bad_response = true;
+        }
+
+        if ( !$bad_response ) {
+            // read the root node of the XML tree
+            if ( !($root = $dom->documentElement) ) {
+                phpCAS::trace('documentElement failed');
+                // read failed
+                $bad_response = true;
+            }
+        }
+
+        if ( !$bad_response ) {
+            // insure that tag name is 'serviceResponse'
+            if ( $root->localName != 'serviceResponse' ) {
+                phpCAS::trace('localName failed');
+                // bad root node
+                $bad_response = true;
+            }
+        }
+
+        if ( !$bad_response ) {
+            // look for a proxySuccess tag
+            if ( $root->getElementsByTagName("proxySuccess")->length != 0) {
+                $proxy_success_list = $root->getElementsByTagName("proxySuccess");
+
+                // authentication succeded, look for a proxyTicket tag
+                if ( $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->length != 0) {
+                    $err_code = PHPCAS_SERVICE_OK;
+                    $err_msg = '';
+                    $pt = trim(
+                        $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->item(0)->nodeValue
+                    );
+                    phpCAS::trace('original PT: '.trim($pt));
+                    phpCAS::traceEnd($pt);
+                    return $pt;
+                } else {
+                    phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
+                }
+            } else if ($root->getElementsByTagName("proxyFailure")->length != 0) {
+                // look for a proxyFailure tag
+                $proxy_failure_list = $root->getElementsByTagName("proxyFailure");
+
+                // authentication failed, extract the error
+                $err_code = PHPCAS_SERVICE_PT_FAILURE;
+                $err_msg = 'PT retrieving failed (code=`'
+                .$proxy_failure_list->item(0)->getAttribute('code')
+                .'\', message=`'
+                .trim($proxy_failure_list->item(0)->nodeValue)
+                .'\')';
+                phpCAS::traceEnd(false);
+                return false;
+            } else {
+                phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
+            }
+        }
+
+        // at this step, we are sure that the response of the CAS server was
+        // illformed
+        $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
+        $err_msg = 'Invalid response from the CAS server (response=`'
+            .$cas_response.'\')';
+
+        phpCAS::traceEnd(false);
+        return false;
+    }
+
+    /** @} */
+
+    // ########################################################################
+    // READ CAS SERVER ANSWERS
+    // ########################################################################
+
+    /**
+     * @addtogroup internalMisc
+     * @{
+     */
+
+    /**
+     * This method is used to acces a remote URL.
+     *
+     * @param string $url      the URL to access.
+     * @param string &$headers an array containing the HTTP header lines of the
+     * response (an empty array on failure).
+     * @param string &$body    the body of the response, as a string (empty on
+     * failure).
+     * @param string &$err_msg an error message, filled on failure.
+     *
+     * @return bool true on success, false otherwise (in this later case, $err_msg
+     * contains an error message).
+     */
+    private function _readURL($url, &$headers, &$body, &$err_msg)
+    {
+        phpCAS::traceBegin();
+        $className = $this->_requestImplementation;
+        $request = new $className();
+
+        if (count($this->_curl_options)) {
+            $request->setCurlOptions($this->_curl_options);
+        }
+
+        $request->setUrl($url);
+
+        if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) {
+            phpCAS::error(
+                'one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.'
+            );
+        }
+        if ($this->_cas_server_ca_cert != '') {
+            $request->setSslCaCert(
+                $this->_cas_server_ca_cert, $this->_cas_server_cn_validate
+            );
+        }
+
+        // add extra stuff if SAML
+        if ($this->getServerVersion() == SAML_VERSION_1_1) {
+            $request->addHeader("soapaction: http://www.oasis-open.org/committees/security");
+            $request->addHeader("cache-control: no-cache");
+            $request->addHeader("pragma: no-cache");
+            $request->addHeader("accept: text/xml");
+            $request->addHeader("connection: keep-alive");
+            $request->addHeader("content-type: text/xml");
+            $request->makePost();
+            $request->setPostBody($this->_buildSAMLPayload());
+        }
+
+        if ($request->send()) {
+            $headers = $request->getResponseHeaders();
+            $body = $request->getResponseBody();
+            $err_msg = '';
+            phpCAS::traceEnd(true);
+            return true;
+        } else {
+            $headers = '';
+            $body = '';
+            $err_msg = $request->getErrorMessage();
+            phpCAS::traceEnd(false);
+            return false;
+        }
+    }
+
+    /**
+     * This method is used to build the SAML POST body sent to /samlValidate URL.
+     *
+     * @return string the SOAP-encased SAMLP artifact (the ticket).
+     */
+    private function _buildSAMLPayload()
+    {
+        phpCAS::traceBegin();
+
+        //get the ticket
+        $sa = urlencode($this->getTicket());
+
+        $body = SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST
+            .SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE
+            .SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
+
+        phpCAS::traceEnd($body);
+        return ($body);
+    }
+
+    /** @} **/
+
+    // ########################################################################
+    // ACCESS TO EXTERNAL SERVICES
+    // ########################################################################
+
+    /**
+     * @addtogroup internalProxyServices
+     * @{
+     */
+
+
+    /**
+     * Answer a proxy-authenticated service handler.
+     *
+     * @param string $type The service type. One of:
+     * PHPCAS_PROXIED_SERVICE_HTTP_GET, PHPCAS_PROXIED_SERVICE_HTTP_POST,
+     * PHPCAS_PROXIED_SERVICE_IMAP
+     *
+     * @return CAS_ProxiedService
+     * @throws InvalidArgumentException If the service type is unknown.
+     */
+    public function getProxiedService ($type)
+    {
+        // Sequence validation
+        $this->ensureIsProxy();
+        $this->ensureAuthenticationCallSuccessful();
+
+        // Argument validation
+        if (gettype($type) != 'string')
+            throw new CAS_TypeMismatchException($type, '$type', 'string');
+
+        switch ($type) {
+        case PHPCAS_PROXIED_SERVICE_HTTP_GET:
+        case PHPCAS_PROXIED_SERVICE_HTTP_POST:
+            $requestClass = $this->_requestImplementation;
+            $request = new $requestClass();
+            if (count($this->_curl_options)) {
+                $request->setCurlOptions($this->_curl_options);
+            }
+            $proxiedService = new $type($request, $this->_serviceCookieJar);
+            if ($proxiedService instanceof CAS_ProxiedService_Testable) {
+                $proxiedService->setCasClient($this);
+            }
+            return $proxiedService;
+        case PHPCAS_PROXIED_SERVICE_IMAP;
+            $proxiedService = new CAS_ProxiedService_Imap($this->_getUser());
+            if ($proxiedService instanceof CAS_ProxiedService_Testable) {
+                $proxiedService->setCasClient($this);
+            }
+            return $proxiedService;
+        default:
+            throw new CAS_InvalidArgumentException(
+                "Unknown proxied-service type, $type."
+            );
+        }
+    }
+
+    /**
+     * Initialize a proxied-service handler with the proxy-ticket it should use.
+     *
+     * @param CAS_ProxiedService $proxiedService service handler
+     *
+     * @return void
+     *
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *		The code of the Exception will be one of:
+     *			PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_FAILURE
+     * @throws CAS_ProxiedService_Exception If there is a failure getting the
+     * url from the proxied service.
+     */
+    public function initializeProxiedService (CAS_ProxiedService $proxiedService)
+    {
+        // Sequence validation
+        $this->ensureIsProxy();
+        $this->ensureAuthenticationCallSuccessful();
+
+        $url = $proxiedService->getServiceUrl();
+        if (!is_string($url)) {
+            throw new CAS_ProxiedService_Exception(
+                "Proxied Service ".get_class($proxiedService)
+                ."->getServiceUrl() should have returned a string, returned a "
+                .gettype($url)." instead."
+            );
+        }
+        $pt = $this->retrievePT($url, $err_code, $err_msg);
+        if (!$pt) {
+            throw new CAS_ProxyTicketException($err_msg, $err_code);
+        }
+        $proxiedService->setProxyTicket($pt);
+    }
+
+    /**
+     * This method is used to access an HTTP[S] service.
+     *
+     * @param string $url       the service to access.
+     * @param int    &$err_code an error code Possible values are
+     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
+     * PHPCAS_SERVICE_NOT_AVAILABLE.
+     * @param string &$output   the output of the service (also used to give an error
+     * message on failure).
+     *
+     * @return bool true on success, false otherwise (in this later case, $err_code
+     * gives the reason why it failed and $output contains an error message).
+     */
+    public function serviceWeb($url,&$err_code,&$output)
+    {
+        // Sequence validation
+        $this->ensureIsProxy();
+        $this->ensureAuthenticationCallSuccessful();
+
+        // Argument validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        try {
+            $service = $this->getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
+            $service->setUrl($url);
+            $service->send();
+            $output = $service->getResponseBody();
+            $err_code = PHPCAS_SERVICE_OK;
+            return true;
+        } catch (CAS_ProxyTicketException $e) {
+            $err_code = $e->getCode();
+            $output = $e->getMessage();
+            return false;
+        } catch (CAS_ProxiedService_Exception $e) {
+            $lang = $this->getLangObj();
+            $output = sprintf(
+                $lang->getServiceUnavailable(), $url, $e->getMessage()
+            );
+            $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
+            return false;
+        }
+    }
+
+    /**
+     * This method is used to access an IMAP/POP3/NNTP service.
+     *
+     * @param string $url        a string giving the URL of the service, including
+     * the mailing box for IMAP URLs, as accepted by imap_open().
+     * @param string $serviceUrl a string giving for CAS retrieve Proxy ticket
+     * @param string $flags      options given to imap_open().
+     * @param int    &$err_code  an error code Possible values are
+     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
+     *  PHPCAS_SERVICE_NOT_AVAILABLE.
+     * @param string &$err_msg   an error message on failure
+     * @param string &$pt        the Proxy Ticket (PT) retrieved from the CAS
+     * server to access the URL on success, false on error).
+     *
+     * @return object|false an IMAP stream on success, false otherwise (in this later
+     *  case, $err_code gives the reason why it failed and $err_msg contains an
+     *  error message).
+     */
+    public function serviceMail($url,$serviceUrl,$flags,&$err_code,&$err_msg,&$pt)
+    {
+        // Sequence validation
+        $this->ensureIsProxy();
+        $this->ensureAuthenticationCallSuccessful();
+
+        // Argument validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+        if (gettype($serviceUrl) != 'string')
+            throw new CAS_TypeMismatchException($serviceUrl, '$serviceUrl', 'string');
+        if (gettype($flags) != 'integer')
+            throw new CAS_TypeMismatchException($flags, '$flags', 'string');
+
+        try {
+            $service = $this->getProxiedService(PHPCAS_PROXIED_SERVICE_IMAP);
+            $service->setServiceUrl($serviceUrl);
+            $service->setMailbox($url);
+            $service->setOptions($flags);
+
+            $stream = $service->open();
+            $err_code = PHPCAS_SERVICE_OK;
+            $pt = $service->getImapProxyTicket();
+            return $stream;
+        } catch (CAS_ProxyTicketException $e) {
+            $err_msg = $e->getMessage();
+            $err_code = $e->getCode();
+            $pt = false;
+            return false;
+        } catch (CAS_ProxiedService_Exception $e) {
+            $lang = $this->getLangObj();
+            $err_msg = sprintf(
+                $lang->getServiceUnavailable(),
+                $url,
+                $e->getMessage()
+            );
+            $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
+            $pt = false;
+            return false;
+        }
+    }
+
+    /** @} **/
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                  PROXIED CLIENT FEATURES (CAS 2.0)                 XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    // ########################################################################
+    //  PT
+    // ########################################################################
+    /**
+    * @addtogroup internalService
+    * @{
+    */
+
+    /**
+     * This array will store a list of proxies in front of this application. This
+     * property will only be populated if this script is being proxied rather than
+     * accessed directly.
+     *
+     * It is set in CAS_Client::validateCAS20() and can be read by
+     * CAS_Client::getProxies()
+     *
+     * @access private
+     */
+    private $_proxies = array();
+
+    /**
+     * Answer an array of proxies that are sitting in front of this application.
+     *
+     * This method will only return a non-empty array if we have received and
+     * validated a Proxy Ticket.
+     *
+     * @return array
+     * @access public
+     */
+    public function getProxies()
+    {
+        return $this->_proxies;
+    }
+
+    /**
+     * Set the Proxy array, probably from persistant storage.
+     *
+     * @param array $proxies An array of proxies
+     *
+     * @return void
+     * @access private
+     */
+    private function _setProxies($proxies)
+    {
+        $this->_proxies = $proxies;
+        if (!empty($proxies)) {
+            // For proxy-authenticated requests people are not viewing the URL
+            // directly since the client is another application making a
+            // web-service call.
+            // Because of this, stripping the ticket from the URL is unnecessary
+            // and causes another web-service request to be performed. Additionally,
+            // if session handling on either the client or the server malfunctions
+            // then the subsequent request will not complete successfully.
+            $this->setNoClearTicketsFromUrl();
+        }
+    }
+
+    /**
+     * A container of patterns to be allowed as proxies in front of the cas client.
+     *
+     * @var CAS_ProxyChain_AllowedList
+     */
+    private $_allowed_proxy_chains;
+
+    /**
+     * Answer the CAS_ProxyChain_AllowedList object for this client.
+     *
+     * @return CAS_ProxyChain_AllowedList
+     */
+    public function getAllowedProxyChains ()
+    {
+        if (empty($this->_allowed_proxy_chains)) {
+            $this->_allowed_proxy_chains = new CAS_ProxyChain_AllowedList();
+        }
+        return $this->_allowed_proxy_chains;
+    }
+
+    /** @} */
+    // ########################################################################
+    //  PT VALIDATION
+    // ########################################################################
+    /**
+    * @addtogroup internalProxied
+    * @{
+    */
+
+    /**
+     * This method is used to validate a cas 2.0 ST or PT; halt on failure
+     * Used for all CAS 2.0 validations
+     *
+     * @param string &$validate_url  the url of the reponse
+     * @param string &$text_response the text of the repsones
+     * @param DOMElement &$tree_response the domxml tree of the respones
+     * @param bool   $renew          true to force the authentication with the CAS server
+     *
+     * @return bool true when successfull and issue a CAS_AuthenticationException
+     * and false on an error
+     *
+     * @throws  CAS_AuthenticationException
+     */
+    public function validateCAS20(&$validate_url,&$text_response,&$tree_response, $renew=false)
+    {
+        phpCAS::traceBegin();
+        phpCAS::trace($text_response);
+        // build the URL to validate the ticket
+        if ($this->getAllowedProxyChains()->isProxyingAllowed()) {
+            $validate_url = $this->getServerProxyValidateURL().'&ticket='
+                .urlencode($this->getTicket());
+        } else {
+            $validate_url = $this->getServerServiceValidateURL().'&ticket='
+                .urlencode($this->getTicket());
+        }
+
+        if ( $this->isProxy() ) {
+            // pass the callback url for CAS proxies
+            $validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL());
+        }
+
+        if ( $renew ) {
+            // pass the renew
+            $validate_url .= '&renew=true';
+        }
+
+        // open and read the URL
+        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
+            phpCAS::trace(
+                'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
+            );
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                true/*$no_response*/
+            );
+        }
+
+        // create new DOMDocument object
+        $dom = new DOMDocument();
+        // Fix possible whitspace problems
+        $dom->preserveWhiteSpace = false;
+        // CAS servers should only return data in utf-8
+        $dom->encoding = "utf-8";
+        // read the response of the CAS server into a DOMDocument object
+        if ( !($dom->loadXML($text_response))) {
+            // read failed
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/, $text_response
+            );
+        } else if ( !($tree_response = $dom->documentElement) ) {
+            // read the root node of the XML tree
+            // read failed
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/, $text_response
+            );
+        } else if ($tree_response->localName != 'serviceResponse') {
+            // insure that tag name is 'serviceResponse'
+            // bad root node
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/, $text_response
+            );
+        } else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
+            // authentication failed, extract the error code and message and throw exception
+            $auth_fail_list = $tree_response
+                ->getElementsByTagName("authenticationFailure");
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, false/*$bad_response*/,
+                $text_response,
+                $auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
+                trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
+            );
+        } else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) {
+            // authentication succeded, extract the user name
+            $success_elements = $tree_response
+                ->getElementsByTagName("authenticationSuccess");
+            if ( $success_elements->item(0)->getElementsByTagName("user")->length == 0) {
+                // no user specified => error
+                throw new CAS_AuthenticationException(
+                    $this, 'Ticket not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/, $text_response
+                );
+            } else {
+                $this->_setUser(
+                    trim(
+                        $success_elements->item(0)->getElementsByTagName("user")->item(0)->nodeValue
+                    )
+                );
+                $this->_readExtraAttributesCas20($success_elements);
+                // Store the proxies we are sitting behind for authorization checking
+                $proxyList = array();
+                if ( sizeof($arr = $success_elements->item(0)->getElementsByTagName("proxy")) > 0) {
+                    foreach ($arr as $proxyElem) {
+                        phpCAS::trace("Found Proxy: ".$proxyElem->nodeValue);
+                        $proxyList[] = trim($proxyElem->nodeValue);
+                    }
+                    $this->_setProxies($proxyList);
+                    phpCAS::trace("Storing Proxy List");
+                }
+                // Check if the proxies in front of us are allowed
+                if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) {
+                    throw new CAS_AuthenticationException(
+                        $this, 'Proxy not allowed', $validate_url,
+                        false/*$no_response*/, true/*$bad_response*/,
+                        $text_response
+                    );
+                } else {
+                    $result = true;
+                }
+            }
+        } else {
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/,
+                $text_response
+            );
+        }
+
+        $this->_renameSession($this->getTicket());
+
+        // at this step, Ticket has been validated and $this->_user has been set,
+
+        phpCAS::traceEnd($result);
+        return $result;
+    }
+
+    /**
+     * This method recursively parses the attribute XML.
+     * It also collapses name-value pairs into a single
+     * array entry. It parses all common formats of
+     * attributes and well formed XML files.
+     *
+     * @param string $root       the DOM root element to be parsed
+     * @param string $namespace  namespace of the elements
+     *
+     * @return an array of the parsed XML elements
+     *
+     * Formats tested:
+     *
+     *  "Jasig Style" Attributes:
+     *
+     *      <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+     *          <cas:authenticationSuccess>
+     *              <cas:user>jsmith</cas:user>
+     *              <cas:attributes>
+     *                  <cas:attraStyle>RubyCAS</cas:attraStyle>
+     *                  <cas:surname>Smith</cas:surname>
+     *                  <cas:givenName>John</cas:givenName>
+     *                  <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
+     *                  <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>
+     *              </cas:attributes>
+     *              <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
+     *          </cas:authenticationSuccess>
+     *      </cas:serviceResponse>
+     *
+     *  "Jasig Style" Attributes (longer version):
+     *
+     *      <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+     *          <cas:authenticationSuccess>
+     *              <cas:user>jsmith</cas:user>
+     *              <cas:attributes>
+     *                  <cas:attribute>
+     *                      <cas:name>surname</cas:name>
+     *                      <cas:value>Smith</cas:value>
+     *                  </cas:attribute>
+     *                  <cas:attribute>
+     *                      <cas:name>givenName</cas:name>
+     *                      <cas:value>John</cas:value>
+     *                  </cas:attribute>
+     *                  <cas:attribute>
+     *                      <cas:name>memberOf</cas:name>
+     *                      <cas:value>['CN=Staff,OU=Groups,DC=example,DC=edu', 'CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu']</cas:value>
+     *                  </cas:attribute>
+     *              </cas:attributes>
+     *              <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
+     *          </cas:authenticationSuccess>
+     *      </cas:serviceResponse>
+     *
+     *  "RubyCAS Style" attributes
+     *
+     *      <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+     *          <cas:authenticationSuccess>
+     *              <cas:user>jsmith</cas:user>
+     *
+     *              <cas:attraStyle>RubyCAS</cas:attraStyle>
+     *              <cas:surname>Smith</cas:surname>
+     *              <cas:givenName>John</cas:givenName>
+     *              <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
+     *              <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>
+     *
+     *              <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
+     *          </cas:authenticationSuccess>
+     *      </cas:serviceResponse>
+     *
+     *  "Name-Value" attributes.
+     *
+     *  Attribute format from these mailing list thread:
+     *  http://jasig.275507.n4.nabble.com/CAS-attributes-and-how-they-appear-in-the-CAS-response-td264272.html
+     *  Note: This is a less widely used format, but in use by at least two institutions.
+     *
+     *      <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+     *          <cas:authenticationSuccess>
+     *              <cas:user>jsmith</cas:user>
+     *
+     *              <cas:attribute name='attraStyle' value='Name-Value' />
+     *              <cas:attribute name='surname' value='Smith' />
+     *              <cas:attribute name='givenName' value='John' />
+     *              <cas:attribute name='memberOf' value='CN=Staff,OU=Groups,DC=example,DC=edu' />
+     *              <cas:attribute name='memberOf' value='CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu' />
+     *
+     *              <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
+     *          </cas:authenticationSuccess>
+     *      </cas:serviceResponse>
+     *
+     * result:
+     *
+     *      Array (
+     *          [surname] => Smith
+     *          [givenName] => John
+     *          [memberOf] => Array (
+     *              [0] => CN=Staff, OU=Groups, DC=example, DC=edu
+     *              [1] => CN=Spanish Department, OU=Departments, OU=Groups, DC=example, DC=edu
+     *          )
+     *      )
+     */
+    private function _xml_to_array($root, $namespace = "cas")
+    {
+        $result = array();
+        if ($root->hasAttributes()) {
+            $attrs = $root->attributes;
+            $pair = array();
+            foreach ($attrs as $attr) {
+                if ($attr->name === "name") {
+                    $pair['name'] = $attr->value;
+                } elseif ($attr->name === "value") {
+                    $pair['value'] = $attr->value;
+                } else {
+                    $result[$attr->name] = $attr->value;
+                }
+                if (array_key_exists('name', $pair) && array_key_exists('value', $pair)) {
+                    $result[$pair['name']] = $pair['value'];
+                }
+            }
+        }
+        if ($root->hasChildNodes()) {
+            $children = $root->childNodes;
+            if ($children->length == 1) {
+                $child = $children->item(0);
+                if ($child->nodeType == XML_TEXT_NODE) {
+                    $result['_value'] = $child->nodeValue;
+                    return (count($result) == 1) ? $result['_value'] : $result;
+                }
+            }
+            $groups = array();
+            foreach ($children as $child) {
+                $child_nodeName = str_ireplace($namespace . ":", "", $child->nodeName);
+                if (in_array($child_nodeName, array("user", "proxies", "proxyGrantingTicket"))) {
+                    continue;
+                }
+                if (!isset($result[$child_nodeName])) {
+                    $res = $this->_xml_to_array($child, $namespace);
+                    if (!empty($res)) {
+                        $result[$child_nodeName] = $this->_xml_to_array($child, $namespace);
+                    }
+                } else {
+                    if (!isset($groups[$child_nodeName])) {
+                        $result[$child_nodeName] = array($result[$child_nodeName]);
+                        $groups[$child_nodeName] = 1;
+                    }
+                    $result[$child_nodeName][] = $this->_xml_to_array($child, $namespace);
+                }
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * This method parses a "JSON-like array" of strings
+     * into an array of strings
+     *
+     * @param string $json_value  the json-like string:
+     *      e.g.:
+     *          ['CN=Staff,OU=Groups,DC=example,DC=edu', 'CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu']
+     *
+     * @return array of strings Description
+     *      e.g.:
+     *          Array (
+     *              [0] => CN=Staff,OU=Groups,DC=example,DC=edu
+     *              [1] => CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu
+     *          )
+     */
+    private function _parse_json_like_array_value($json_value)
+    {
+        $parts = explode(",", trim($json_value, "[]"));
+        $out = array();
+        $quote = '';
+        foreach ($parts as $part) {
+            $part = trim($part);
+            if ($quote === '') {
+                $value = "";
+                if ($this->_startsWith($part, '\'')) {
+                    $quote = '\'';
+                } elseif ($this->_startsWith($part, '"')) {
+                    $quote = '"';
+                } else {
+                    $out[] = $part;
+                }
+                $part = ltrim($part, $quote);
+            }
+            if ($quote !== '') {
+                $value .= $part;
+                if ($this->_endsWith($part, $quote)) {
+                    $out[] = rtrim($value, $quote);
+                    $quote = '';
+                } else {
+                    $value .= ", ";
+                };
+            }
+        }
+        return $out;
+    }
+
+    /**
+     * This method recursively removes unneccessary hirarchy levels in array-trees.
+     * into an array of strings
+     *
+     * @param array $arr the array to flatten
+     *      e.g.:
+     *          Array (
+     *              [attributes] => Array (
+     *                  [attribute] => Array (
+     *                      [0] => Array (
+     *                          [name] => surname
+     *                          [value] => Smith
+     *                      )
+     *                      [1] => Array (
+     *                          [name] => givenName
+     *                          [value] => John
+     *                      )
+     *                      [2] => Array (
+     *                          [name] => memberOf
+     *                          [value] => ['CN=Staff,OU=Groups,DC=example,DC=edu', 'CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu']
+     *                      )
+     *                  )
+     *              )
+     *          )
+     *
+     * @return array the flattened array
+     *      e.g.:
+     *          Array (
+     *              [attribute] => Array (
+     *                  [surname] => Smith
+     *                  [givenName] => John
+     *                  [memberOf] => Array (
+     *                      [0] => CN=Staff, OU=Groups, DC=example, DC=edu
+     *                      [1] => CN=Spanish Department, OU=Departments, OU=Groups, DC=example, DC=edu
+     *                  )
+     *              )
+     *          )
+     */
+    private function _flatten_array($arr)
+    {
+        if (!is_array($arr)) {
+            if ($this->_startsWith($arr, '[') && $this->_endsWith($arr, ']')) {
+                return $this->_parse_json_like_array_value($arr);
+            } else {
+                return $arr;
+            }
+        }
+        $out = array();
+        foreach ($arr as $key => $val) {
+            if (!is_array($val)) {
+                $out[$key] = $val;
+            } else {
+                switch (count($val)) {
+                case 1 : {
+                        $key = key($val);
+                        if (array_key_exists($key, $out)) {
+                            $value = $out[$key];
+                            if (!is_array($value)) {
+                                $out[$key] = array();
+                                $out[$key][] = $value;
+                            }
+                            $out[$key][] = $this->_flatten_array($val[$key]);
+                        } else {
+                            $out[$key] = $this->_flatten_array($val[$key]);
+                        };
+                        break;
+                    };
+                case 2 : {
+                        if (array_key_exists("name", $val) && array_key_exists("value", $val)) {
+                            $key = $val['name'];
+                            if (array_key_exists($key, $out)) {
+                                $value = $out[$key];
+                                if (!is_array($value)) {
+                                    $out[$key] = array();
+                                    $out[$key][] = $value;
+                                }
+                                $out[$key][] = $this->_flatten_array($val['value']);
+                            } else {
+                                $out[$key] = $this->_flatten_array($val['value']);
+                            };
+                        } else {
+                            $out[$key] = $this->_flatten_array($val);
+                        }
+                        break;
+                    };
+                default: {
+                        $out[$key] = $this->_flatten_array($val);
+                    }
+                }
+            }
+        }
+        return $out;
+    }
+
+    /**
+     * This method will parse the DOM and pull out the attributes from the XML
+     * payload and put them into an array, then put the array into the session.
+     *
+     * @param DOMNodeList $success_elements payload of the response
+     *
+     * @return bool true when successfull, halt otherwise by calling
+     * CAS_Client::_authError().
+     */
+    private function _readExtraAttributesCas20($success_elements)
+    {
+        phpCAS::traceBegin();
+
+        $extra_attributes = array();
+        if ($this->_casAttributeParserCallbackFunction !== null
+            && is_callable($this->_casAttributeParserCallbackFunction)
+        ) {
+            array_unshift($this->_casAttributeParserCallbackArgs, $success_elements->item(0));
+            phpCAS :: trace("Calling attritubeParser callback");
+            $extra_attributes =  call_user_func_array(
+                $this->_casAttributeParserCallbackFunction,
+                $this->_casAttributeParserCallbackArgs
+            );
+        } else {
+            phpCAS :: trace("Parse extra attributes:    ");
+            $attributes = $this->_xml_to_array($success_elements->item(0));
+            phpCAS :: trace(print_r($attributes,true). "\nFLATTEN Array:    ");
+            $extra_attributes = $this->_flatten_array($attributes);
+            phpCAS :: trace(print_r($extra_attributes, true)."\nFILTER :    ");
+            if (array_key_exists("attribute", $extra_attributes)) {
+                $extra_attributes = $extra_attributes["attribute"];
+            } elseif (array_key_exists("attributes", $extra_attributes)) {
+                $extra_attributes = $extra_attributes["attributes"];
+            };
+            phpCAS :: trace(print_r($extra_attributes, true)."return");
+        }
+        $this->setAttributes($extra_attributes);
+        phpCAS::traceEnd();
+        return true;
+    }
+
+    /**
+     * Add an attribute value to an array of attributes.
+     *
+     * @param array  &$attributeArray reference to array
+     * @param string $name            name of attribute
+     * @param string $value           value of attribute
+     *
+     * @return void
+     */
+    private function _addAttributeToArray(array &$attributeArray, $name, $value)
+    {
+        // If multiple attributes exist, add as an array value
+        if (isset($attributeArray[$name])) {
+            // Initialize the array with the existing value
+            if (!is_array($attributeArray[$name])) {
+                $existingValue = $attributeArray[$name];
+                $attributeArray[$name] = array($existingValue);
+            }
+
+            $attributeArray[$name][] = trim($value);
+        } else {
+            $attributeArray[$name] = trim($value);
+        }
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                               MISC                                 XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    /**
+     * @addtogroup internalMisc
+     * @{
+     */
+
+    // ########################################################################
+    //  URL
+    // ########################################################################
+    /**
+    * the URL of the current request (without any ticket CGI parameter). Written
+    * and read by CAS_Client::getURL().
+    *
+    * @hideinitializer
+    */
+    private $_url = '';
+
+
+    /**
+     * This method sets the URL of the current request
+     *
+     * @param string $url url to set for service
+     *
+     * @return void
+     */
+    public function setURL($url)
+    {
+        // Argument Validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        $this->_url = $url;
+    }
+
+    /**
+     * This method returns the URL of the current request (without any ticket
+     * CGI parameter).
+     *
+     * @return string The URL
+     */
+    public function getURL()
+    {
+        phpCAS::traceBegin();
+        // the URL is built when needed only
+        if ( empty($this->_url) ) {
+            // remove the ticket if present in the URL
+            $final_uri = ($this->_isHttps()) ? 'https' : 'http';
+            $final_uri .= '://';
+
+            $final_uri .= $this->_getClientUrl();
+            $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);
+            $final_uri .= $request_uri[0];
+
+            if (isset($request_uri[1]) && $request_uri[1]) {
+                $query_string= $this->_removeParameterFromQueryString('ticket', $request_uri[1]);
+
+                // If the query string still has anything left,
+                // append it to the final URI
+                if ($query_string !== '') {
+                    $final_uri .= "?$query_string";
+                }
+            }
+
+            phpCAS::trace("Final URI: $final_uri");
+            $this->setURL($final_uri);
+        }
+        phpCAS::traceEnd($this->_url);
+        return $this->_url;
+    }
+
+    /**
+     * This method sets the base URL of the CAS server.
+     *
+     * @param string $url the base URL
+     *
+     * @return string base url
+     */
+    public function setBaseURL($url)
+    {
+        // Argument Validation
+        if (gettype($url) != 'string')
+            throw new CAS_TypeMismatchException($url, '$url', 'string');
+
+        return $this->_server['base_url'] = $url;
+    }
+
+
+    /**
+     * Try to figure out the phpCAS client URL with possible Proxys / Ports etc.
+     *
+     * @return string Server URL with domain:port
+     */
+    private function _getClientUrl()
+    {
+        if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
+            // explode the host list separated by comma and use the first host
+            $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
+            // see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default
+            return $hosts[0];
+        } else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
+            $server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];
+        } else {
+            if (empty($_SERVER['SERVER_NAME'])) {
+                $server_url = $_SERVER['HTTP_HOST'];
+            } else {
+                $server_url = $_SERVER['SERVER_NAME'];
+            }
+        }
+        if (!strpos($server_url, ':')) {
+            if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
+                $server_port = $_SERVER['SERVER_PORT'];
+            } else {
+                $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);
+                $server_port = $ports[0];
+            }
+
+            if ( ($this->_isHttps() && $server_port!=443)
+                || (!$this->_isHttps() && $server_port!=80)
+            ) {
+                $server_url .= ':';
+                $server_url .= $server_port;
+            }
+        }
+        return $server_url;
+    }
+
+    /**
+     * This method checks to see if the request is secured via HTTPS
+     *
+     * @return bool true if https, false otherwise
+     */
+    private function _isHttps()
+    {
+        if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
+            return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
+        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {
+            return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https');
+        } elseif ( isset($_SERVER['HTTPS'])
+            && !empty($_SERVER['HTTPS'])
+            && strcasecmp($_SERVER['HTTPS'], 'off') !== 0
+        ) {
+            return true;
+        }
+        return false;
+
+    }
+
+    /**
+     * Removes a parameter from a query string
+     *
+     * @param string $parameterName name of parameter
+     * @param string $queryString   query string
+     *
+     * @return string new query string
+     *
+     * @link http://stackoverflow.com/questions/1842681/regular-expression-to-remove-one-parameter-from-query-string
+     */
+    private function _removeParameterFromQueryString($parameterName, $queryString)
+    {
+        $parameterName	= preg_quote($parameterName);
+        return preg_replace(
+            "/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/",
+            '', $queryString
+        );
+    }
+
+    /**
+     * This method is used to append query parameters to an url. Since the url
+     * might already contain parameter it has to be detected and to build a proper
+     * URL
+     *
+     * @param string $url   base url to add the query params to
+     * @param string $query params in query form with & separated
+     *
+     * @return string url with query params
+     */
+    private function _buildQueryUrl($url, $query)
+    {
+        $url .= (strstr($url, '?') === false) ? '?' : '&';
+        $url .= $query;
+        return $url;
+    }
+
+    /**
+     * This method tests if a string starts with a given character.
+     *
+     * @param string $text  text to test
+     * @param string $char  character to test for
+     *
+     * @return bool          true if the $text starts with $char
+     */
+    private function _startsWith($text, $char)
+    {
+        return (strpos($text, $char) === 0);
+    }
+
+    /**
+     * This method tests if a string ends with a given character
+     *
+     * @param string $text  text to test
+     * @param string $char  character to test for
+     *
+     * @return bool         true if the $text ends with $char
+     */
+    private function _endsWith($text, $char)
+    {
+        return (strpos(strrev($text), $char) === 0);
+    }
+
+    /**
+     * Answer a valid session-id given a CAS ticket.
+     *
+     * The output must be deterministic to allow single-log-out when presented with
+     * the ticket to log-out.
+     *
+     *
+     * @param string $ticket name of the ticket
+     *
+     * @return string
+     */
+    private function _sessionIdForTicket($ticket)
+    {
+      // Hash the ticket to ensure that the value meets the PHP 7.1 requirement
+      // that session-ids have a length between 22 and 256 characters.
+      return hash('sha256', $this->_sessionIdSalt . $ticket);
+    }
+
+    /**
+     * Set a salt/seed for the session-id hash to make it harder to guess.
+     *
+     * @var string $_sessionIdSalt
+     */
+    private $_sessionIdSalt = '';
+
+    /**
+     * Set a salt/seed for the session-id hash to make it harder to guess.
+     *
+     * @param string $salt
+     *
+     * @return void
+     */
+    public function setSessionIdSalt($salt) {
+      $this->_sessionIdSalt = (string)$salt;
+    }
+
+    // ########################################################################
+    //  AUTHENTICATION ERROR HANDLING
+    // ########################################################################
+    /**
+    * This method is used to print the HTML output when the user was not
+    * authenticated.
+    *
+    * @param string $failure      the failure that occured
+    * @param string $cas_url      the URL the CAS server was asked for
+    * @param bool   $no_response  the response from the CAS server (other
+    * parameters are ignored if true)
+    * @param bool   $bad_response bad response from the CAS server ($err_code
+    * and $err_msg ignored if true)
+    * @param string $cas_response the response of the CAS server
+    * @param int    $err_code     the error code given by the CAS server
+    * @param string $err_msg      the error message given by the CAS server
+    *
+    * @return void
+    */
+    private function _authError(
+        $failure,
+        $cas_url,
+        $no_response=false,
+        $bad_response=false,
+        $cas_response='',
+        $err_code=-1,
+        $err_msg=''
+    ) {
+        phpCAS::traceBegin();
+        $lang = $this->getLangObj();
+        $this->printHTMLHeader($lang->getAuthenticationFailed());
+        $this->printf(
+            $lang->getYouWereNotAuthenticated(), htmlentities($this->getURL()),
+            isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''
+        );
+        phpCAS::trace('CAS URL: '.$cas_url);
+        phpCAS::trace('Authentication failure: '.$failure);
+        if ( $no_response ) {
+            phpCAS::trace('Reason: no response from the CAS server');
+        } else {
+            if ( $bad_response ) {
+                phpCAS::trace('Reason: bad response from the CAS server');
+            } else {
+                switch ($this->getServerVersion()) {
+                case CAS_VERSION_1_0:
+                    phpCAS::trace('Reason: CAS error');
+                    break;
+                case CAS_VERSION_2_0:
+                case CAS_VERSION_3_0:
+                    if ( $err_code === -1 ) {
+                        phpCAS::trace('Reason: no CAS error');
+                    } else {
+                        phpCAS::trace(
+                            'Reason: ['.$err_code.'] CAS error: '.$err_msg
+                        );
+                    }
+                    break;
+                }
+            }
+            phpCAS::trace('CAS response: '.$cas_response);
+        }
+        $this->printHTMLFooter();
+        phpCAS::traceExit();
+        throw new CAS_GracefullTerminationException();
+    }
+
+    // ########################################################################
+    //  PGTIOU/PGTID and logoutRequest rebroadcasting
+    // ########################################################################
+
+    /**
+     * Boolean of whether to rebroadcast pgtIou/pgtId and logoutRequest, and
+     * array of the nodes.
+     */
+    private $_rebroadcast = false;
+    private $_rebroadcast_nodes = array();
+
+    /**
+     * Constants used for determining rebroadcast node type.
+     */
+    const HOSTNAME = 0;
+    const IP = 1;
+
+    /**
+     * Determine the node type from the URL.
+     *
+     * @param String $nodeURL The node URL.
+     *
+     * @return int hostname
+     *
+     */
+    private function _getNodeType($nodeURL)
+    {
+        phpCAS::traceBegin();
+        if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $nodeURL)) {
+            phpCAS::traceEnd(self::IP);
+            return self::IP;
+        } else {
+            phpCAS::traceEnd(self::HOSTNAME);
+            return self::HOSTNAME;
+        }
+    }
+
+    /**
+     * Store the rebroadcast node for pgtIou/pgtId and logout requests.
+     *
+     * @param string $rebroadcastNodeUrl The rebroadcast node URL.
+     *
+     * @return void
+     */
+    public function addRebroadcastNode($rebroadcastNodeUrl)
+    {
+        // Argument validation
+        if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl))
+            throw new CAS_TypeMismatchException($rebroadcastNodeUrl, '$rebroadcastNodeUrl', 'url');
+
+        // Store the rebroadcast node and set flag
+        $this->_rebroadcast = true;
+        $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl;
+    }
+
+    /**
+     * An array to store extra rebroadcast curl options.
+     */
+    private $_rebroadcast_headers = array();
+
+    /**
+     * This method is used to add header parameters when rebroadcasting
+     * pgtIou/pgtId or logoutRequest.
+     *
+     * @param string $header Header to send when rebroadcasting.
+     *
+     * @return void
+     */
+    public function addRebroadcastHeader($header)
+    {
+        if (gettype($header) != 'string')
+            throw new CAS_TypeMismatchException($header, '$header', 'string');
+
+        $this->_rebroadcast_headers[] = $header;
+    }
+
+    /**
+     * Constants used for determining rebroadcast type (logout or pgtIou/pgtId).
+     */
+    const LOGOUT = 0;
+    const PGTIOU = 1;
+
+    /**
+     * This method rebroadcasts logout/pgtIou requests. Can be LOGOUT,PGTIOU
+     *
+     * @param int $type type of rebroadcasting.
+     *
+     * @return void
+     */
+    private function _rebroadcast($type)
+    {
+        phpCAS::traceBegin();
+
+        $rebroadcast_curl_options = array(
+        CURLOPT_FAILONERROR => 1,
+        CURLOPT_FOLLOWLOCATION => 1,
+        CURLOPT_RETURNTRANSFER => 1,
+        CURLOPT_CONNECTTIMEOUT => 1,
+        CURLOPT_TIMEOUT => 4);
+
+        // Try to determine the IP address of the server
+        if (!empty($_SERVER['SERVER_ADDR'])) {
+            $ip = $_SERVER['SERVER_ADDR'];
+        } else if (!empty($_SERVER['LOCAL_ADDR'])) {
+            // IIS 7
+            $ip = $_SERVER['LOCAL_ADDR'];
+        }
+        // Try to determine the DNS name of the server
+        if (!empty($ip)) {
+            $dns = gethostbyaddr($ip);
+        }
+        $multiClassName = 'CAS_Request_CurlMultiRequest';
+        $multiRequest = new $multiClassName();
+
+        for ($i = 0; $i < sizeof($this->_rebroadcast_nodes); $i++) {
+            if ((($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) === false))
+                || (($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) === false))
+            ) {
+                phpCAS::trace(
+                    'Rebroadcast target URL: '.$this->_rebroadcast_nodes[$i]
+                    .$_SERVER['REQUEST_URI']
+                );
+                $className = $this->_requestImplementation;
+                $request = new $className();
+
+                $url = $this->_rebroadcast_nodes[$i].$_SERVER['REQUEST_URI'];
+                $request->setUrl($url);
+
+                if (count($this->_rebroadcast_headers)) {
+                    $request->addHeaders($this->_rebroadcast_headers);
+                }
+
+                $request->makePost();
+                if ($type == self::LOGOUT) {
+                    // Logout request
+                    $request->setPostBody(
+                        'rebroadcast=false&logoutRequest='.$_POST['logoutRequest']
+                    );
+                } else if ($type == self::PGTIOU) {
+                    // pgtIou/pgtId rebroadcast
+                    $request->setPostBody('rebroadcast=false');
+                }
+
+                $request->setCurlOptions($rebroadcast_curl_options);
+
+                $multiRequest->addRequest($request);
+            } else {
+                phpCAS::trace(
+                    'Rebroadcast not sent to self: '
+                    .$this->_rebroadcast_nodes[$i].' == '.(!empty($ip)?$ip:'')
+                    .'/'.(!empty($dns)?$dns:'')
+                );
+            }
+        }
+        // We need at least 1 request
+        if ($multiRequest->getNumRequests() > 0) {
+            $multiRequest->send();
+        }
+        phpCAS::traceEnd();
+    }
+
+    /** @} */
+}
diff --git a/vendor/jasig/phpcas/source/CAS/CookieJar.php b/vendor/jasig/phpcas/source/CAS/CookieJar.php
new file mode 100644
index 0000000000..b2439373ad
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/CookieJar.php
@@ -0,0 +1,385 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/CookieJar.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class provides access to service cookies and handles parsing of response
+ * headers to pull out cookie values.
+ *
+ * @class    CAS_CookieJar
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_CookieJar
+{
+
+    private $_cookies;
+
+    /**
+     * Create a new cookie jar by passing it a reference to an array in which it
+     * should store cookies.
+     *
+     * @param array &$storageArray Array to store cookies
+     *
+     * @return void
+     */
+    public function __construct (array &$storageArray)
+    {
+        $this->_cookies =& $storageArray;
+    }
+
+    /**
+     * Store cookies for a web service request.
+     * Cookie storage is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt
+     *
+     * @param string $request_url      The URL that generated the response headers.
+     * @param array  $response_headers An array of the HTTP response header strings.
+     *
+     * @return void
+     *
+     * @access private
+     */
+    public function storeCookies ($request_url, $response_headers)
+    {
+        $urlParts = parse_url($request_url);
+        $defaultDomain = $urlParts['host'];
+
+        $cookies = $this->parseCookieHeaders($response_headers, $defaultDomain);
+
+        foreach ($cookies as $cookie) {
+            // Enforce the same-origin policy by verifying that the cookie
+            // would match the url that is setting it
+            if (!$this->cookieMatchesTarget($cookie, $urlParts)) {
+                continue;
+            }
+
+            // store the cookie
+            $this->storeCookie($cookie);
+
+            phpCAS::trace($cookie['name'].' -> '.$cookie['value']);
+        }
+    }
+
+    /**
+     * Retrieve cookies applicable for a web service request.
+     * Cookie applicability is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt
+     *
+     * @param string $request_url The url that the cookies will be for.
+     *
+     * @return array An array containing cookies. E.g. array('name' => 'val');
+     *
+     * @access private
+     */
+    public function getCookies ($request_url)
+    {
+        if (!count($this->_cookies)) {
+            return array();
+        }
+
+        // If our request URL can't be parsed, no cookies apply.
+        $target = parse_url($request_url);
+        if ($target === false) {
+            return array();
+        }
+
+        $this->expireCookies();
+
+        $matching_cookies = array();
+        foreach ($this->_cookies as $key => $cookie) {
+            if ($this->cookieMatchesTarget($cookie, $target)) {
+                $matching_cookies[$cookie['name']] = $cookie['value'];
+            }
+        }
+        return $matching_cookies;
+    }
+
+
+    /**
+     * Parse Cookies without PECL
+     * From the comments in http://php.net/manual/en/function.http-parse-cookie.php
+     *
+     * @param array  $header        array of header lines.
+     * @param string $defaultDomain The domain to use if none is specified in
+     * the cookie.
+     *
+     * @return array of cookies
+     */
+    protected function parseCookieHeaders( $header, $defaultDomain )
+    {
+        phpCAS::traceBegin();
+        $cookies = array();
+        foreach ( $header as $line ) {
+            if ( preg_match('/^Set-Cookie2?: /i', $line)) {
+                $cookies[] = $this->parseCookieHeader($line, $defaultDomain);
+            }
+        }
+
+        phpCAS::traceEnd($cookies);
+        return $cookies;
+    }
+
+    /**
+     * Parse a single cookie header line.
+     *
+     * Based on RFC2965 http://www.ietf.org/rfc/rfc2965.txt
+     *
+     * @param string $line          The header line.
+     * @param string $defaultDomain The domain to use if none is specified in
+     * the cookie.
+     *
+     * @return array
+     */
+    protected function parseCookieHeader ($line, $defaultDomain)
+    {
+        if (!$defaultDomain) {
+            throw new CAS_InvalidArgumentException(
+                '$defaultDomain was not provided.'
+            );
+        }
+
+        // Set our default values
+        $cookie = array(
+            'domain' => $defaultDomain,
+            'path' => '/',
+            'secure' => false,
+        );
+
+        $line = preg_replace('/^Set-Cookie2?: /i', '', trim($line));
+
+        // trim any trailing semicolons.
+        $line = trim($line, ';');
+
+        phpCAS::trace("Cookie Line: $line");
+
+        // This implementation makes the assumption that semicolons will not
+        // be present in quoted attribute values. While attribute values that
+        // contain semicolons are allowed by RFC2965, they are hopefully rare
+        // enough to ignore for our purposes. Most browsers make the same
+        // assumption.
+        $attributeStrings = explode(';', $line);
+
+        foreach ( $attributeStrings as $attributeString ) {
+            // split on the first equals sign and use the rest as value
+            $attributeParts = explode('=', $attributeString, 2);
+
+            $attributeName = trim($attributeParts[0]);
+            $attributeNameLC = strtolower($attributeName);
+
+            if (isset($attributeParts[1])) {
+                $attributeValue = trim($attributeParts[1]);
+                // Values may be quoted strings.
+                if (strpos($attributeValue, '"') === 0) {
+                    $attributeValue = trim($attributeValue, '"');
+                    // unescape any escaped quotes:
+                    $attributeValue = str_replace('\"', '"', $attributeValue);
+                }
+            } else {
+                $attributeValue = null;
+            }
+
+            switch ($attributeNameLC) {
+            case 'expires':
+                $cookie['expires'] = strtotime($attributeValue);
+                break;
+            case 'max-age':
+                $cookie['max-age'] = (int)$attributeValue;
+                // Set an expiry time based on the max-age
+                if ($cookie['max-age']) {
+                    $cookie['expires'] = time() + $cookie['max-age'];
+                } else {
+                    // If max-age is zero, then the cookie should be removed
+                    // imediately so set an expiry before now.
+                    $cookie['expires'] = time() - 1;
+                }
+                break;
+            case 'secure':
+                $cookie['secure'] = true;
+                break;
+            case 'domain':
+            case 'path':
+            case 'port':
+            case 'version':
+            case 'comment':
+            case 'commenturl':
+            case 'discard':
+            case 'httponly':
+            case 'samesite':
+                $cookie[$attributeNameLC] = $attributeValue;
+                break;
+            default:
+                $cookie['name'] = $attributeName;
+                $cookie['value'] = $attributeValue;
+            }
+        }
+
+        return $cookie;
+    }
+
+    /**
+     * Add, update, or remove a cookie.
+     *
+     * @param array $cookie A cookie array as created by parseCookieHeaders()
+     *
+     * @return void
+     *
+     * @access protected
+     */
+    protected function storeCookie ($cookie)
+    {
+        // Discard any old versions of this cookie.
+        $this->discardCookie($cookie);
+        $this->_cookies[] = $cookie;
+
+    }
+
+    /**
+     * Discard an existing cookie
+     *
+     * @param array $cookie An cookie
+     *
+     * @return void
+     *
+     * @access protected
+     */
+    protected function discardCookie ($cookie)
+    {
+        if (!isset($cookie['domain'])
+            || !isset($cookie['path'])
+            || !isset($cookie['path'])
+        ) {
+            throw new CAS_InvalidArgumentException('Invalid Cookie array passed.');
+        }
+
+        foreach ($this->_cookies as $key => $old_cookie) {
+            if ( $cookie['domain'] == $old_cookie['domain']
+                && $cookie['path'] == $old_cookie['path']
+                && $cookie['name'] == $old_cookie['name']
+            ) {
+                unset($this->_cookies[$key]);
+            }
+        }
+    }
+
+    /**
+     * Go through our stored cookies and remove any that are expired.
+     *
+     * @return void
+     *
+     * @access protected
+     */
+    protected function expireCookies ()
+    {
+        foreach ($this->_cookies as $key => $cookie) {
+            if (isset($cookie['expires']) && $cookie['expires'] < time()) {
+                unset($this->_cookies[$key]);
+            }
+        }
+    }
+
+    /**
+     * Answer true if cookie is applicable to a target.
+     *
+     * @param array $cookie An array of cookie attributes.
+     * @param array|false $target An array of URL attributes as generated by parse_url().
+     *
+     * @return bool
+     *
+     * @access private
+     */
+    protected function cookieMatchesTarget ($cookie, $target)
+    {
+        if (!is_array($target)) {
+            throw new CAS_InvalidArgumentException(
+                '$target must be an array of URL attributes as generated by parse_url().'
+            );
+        }
+        if (!isset($target['host'])) {
+            throw new CAS_InvalidArgumentException(
+                '$target must be an array of URL attributes as generated by parse_url().'
+            );
+        }
+
+        // Verify that the scheme matches
+        if ($cookie['secure'] && $target['scheme'] != 'https') {
+            return false;
+        }
+
+        // Verify that the host matches
+        // Match domain and mulit-host cookies
+        if (strpos($cookie['domain'], '.') === 0) {
+            // .host.domain.edu cookies are valid for host.domain.edu
+            if (substr($cookie['domain'], 1) == $target['host']) {
+                // continue with other checks
+            } else {
+                // non-exact host-name matches.
+                // check that the target host a.b.c.edu is within .b.c.edu
+                $pos = strripos($target['host'], $cookie['domain']);
+                if (!$pos) {
+                    return false;
+                }
+                // verify that the cookie domain is the last part of the host.
+                if ($pos + strlen($cookie['domain']) != strlen($target['host'])) {
+                    return false;
+                }
+                // verify that the host name does not contain interior dots as per
+                // RFC 2965 section 3.3.2  Rejecting Cookies
+                // http://www.ietf.org/rfc/rfc2965.txt
+                $hostname = substr($target['host'], 0, $pos);
+                if (strpos($hostname, '.') !== false) {
+                    return false;
+                }
+            }
+        } else {
+            // If the cookie host doesn't begin with '.',
+            // the host must case-insensitive match exactly
+            if (strcasecmp($target['host'], $cookie['domain']) !== 0) {
+                return false;
+            }
+        }
+
+        // Verify that the port matches
+        if (isset($cookie['ports'])
+            && !in_array($target['port'], $cookie['ports'])
+        ) {
+            return false;
+        }
+
+        // Verify that the path matches
+        if (strpos($target['path'], $cookie['path']) !== 0) {
+            return false;
+        }
+
+        return true;
+    }
+
+}
+
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Exception.php b/vendor/jasig/phpcas/source/CAS/Exception.php
new file mode 100644
index 0000000000..2ff7cd658d
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Exception.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Exception.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * A root exception interface for all exceptions in phpCAS.
+ *
+ * All exceptions thrown in phpCAS should implement this interface to allow them
+ * to be caught as a category by clients. Each phpCAS exception should extend
+ * an appropriate SPL exception class that best fits its type.
+ *
+ * For example, an InvalidArgumentException in phpCAS should be defined as
+ *
+ *		class CAS_InvalidArgumentException
+ *			extends InvalidArgumentException
+ *			implements CAS_Exception
+ *		{ }
+ *
+ * This definition allows the CAS_InvalidArgumentException to be caught as either
+ * an InvalidArgumentException or as a CAS_Exception.
+ *
+ * @class    CAS_Exception
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ */
+interface CAS_Exception
+{
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/GracefullTerminationException.php b/vendor/jasig/phpcas/source/CAS/GracefullTerminationException.php
new file mode 100644
index 0000000000..29aa638cd8
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/GracefullTerminationException.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/GracefullTerminationException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * An exception for terminatinating execution or to throw for unit testing
+ *
+ * @class     CAS_GracefullTerminationException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class CAS_GracefullTerminationException
+extends RuntimeException
+implements CAS_Exception
+{
+
+    /**
+     * Test if exceptions should be thrown or if we should just exit.
+     * In production usage we want to just exit cleanly when prompting the user
+     * for a redirect without filling the error logs with uncaught exceptions.
+     * In unit testing scenarios we cannot exit or we won't be able to continue
+     * with our tests.
+     *
+     * @param string $message Message Text
+     * @param int $code    Error code
+     *
+     * @return self
+     */
+    public function __construct ($message = 'Terminate Gracefully', $code = 0)
+    {
+        // Exit cleanly to avoid filling up the logs with uncaught exceptions.
+        if (self::$_exitWhenThrown) {
+            exit;
+        } else {
+            // Throw exceptions to allow unit testing to continue;
+            parent::__construct($message, $code);
+        }
+    }
+
+    private static $_exitWhenThrown = true;
+    /**
+    * Force phpcas to thow Exceptions instead of calling exit()
+    * Needed for unit testing. Generally shouldn't be used in production due to
+    * an increase in Apache error logging if CAS_GracefulTerminiationExceptions
+    * are not caught and handled.
+    *
+    * @return void
+    */
+    public static function throwInsteadOfExiting()
+    {
+        self::$_exitWhenThrown = false;
+    }
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/InvalidArgumentException.php b/vendor/jasig/phpcas/source/CAS/InvalidArgumentException.php
new file mode 100644
index 0000000000..99be2ac329
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/InvalidArgumentException.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/InvalidArgumentException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Exception that denotes invalid arguments were passed.
+ *
+ * @class    CAS_InvalidArgumentException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_InvalidArgumentException
+extends InvalidArgumentException
+implements CAS_Exception
+{
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/Catalan.php b/vendor/jasig/phpcas/source/CAS/Languages/Catalan.php
new file mode 100644
index 0000000000..1ead905fc9
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/Catalan.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/Catalan.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Catalan language class
+ *
+ * @class    CAS_Languages_Catalan
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_Catalan implements CAS_Languages_LanguageInterface
+{
+    /**
+    * Get the using server string
+    *
+    * @return string using server
+    */
+    public function getUsingServer()
+    {
+        return 'usant servidor';
+    }
+
+    /**
+    * Get authentication wanted string
+    *
+    * @return string authentication wanted
+    */
+    public function getAuthenticationWanted()
+    {
+        return 'Autentificació CAS necessària!';
+    }
+
+    /**
+    * Get logout string
+    *
+    * @return string logout
+    */
+    public function getLogout()
+    {
+        return 'Sortida de CAS necessària!';
+    }
+
+    /**
+    * Get the should have been redirected string
+    *
+    * @return string should habe been redirected
+    */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Ja hauria d\ haver estat redireccionat al servidor CAS. Feu click <a href="%s">aquí</a> per a continuar.';
+    }
+
+    /**
+    * Get authentication failed string
+    *
+    * @return string authentication failed
+    */
+    public function getAuthenticationFailed()
+    {
+        return 'Autentificació CAS fallida!';
+    }
+
+    /**
+    * Get the your were not authenticated string
+    *
+    * @return string not authenticated
+    */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>No estàs autentificat.</p><p>Pots tornar a intentar-ho fent click <a href="%s">aquí</a>.</p><p>Si el problema persisteix hauría de contactar amb l\'<a href="mailto:%s">administrador d\'aquest llocc</a>.</p>';
+    }
+
+    /**
+    * Get the service unavailable string
+    *
+    * @return string service unavailable
+    */
+    public function getServiceUnavailable()
+    {
+        return 'El servei `<b>%s</b>\' no està disponible (<b>%s</b>).';
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/ChineseSimplified.php b/vendor/jasig/phpcas/source/CAS/Languages/ChineseSimplified.php
new file mode 100644
index 0000000000..5e33cb650d
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/ChineseSimplified.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/ChineseSimplified.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>, Phy25 <caslang@phy25.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Chinese Simplified language class
+ *
+ * @class    CAS_Languages_ChineseSimplified
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>, Phy25 <caslang@phy25.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_ChineseSimplified implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return '连接的服务器';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return '请进行 CAS 认证!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return '请进行 CAS 登出!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return '你正被重定向到 CAS 服务器。<a href="%s">点击这里</a>继续。';
+    }
+
+    /**
+    * Get authentication failed string
+    *
+    * @return string authentication failed
+    */
+    public function getAuthenticationFailed()
+    {
+        return 'CAS 认证失败!';
+    }
+
+    /**
+    * Get the your were not authenticated string
+    *
+    * @return string not authenticated
+    */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>你没有成功登录。</p><p>你可以<a href="%s">点击这里重新登录</a>。</p><p>如果问题依然存在,请<a href="mailto:%s">联系本站管理员</a>。</p>';
+    }
+
+    /**
+    * Get the service unavailable string
+    *
+    * @return string service unavailable
+    */
+    public function getServiceUnavailable()
+    {
+        return '服务器 <b>%s</b> 不可用(<b>%s</b>)。';
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/English.php b/vendor/jasig/phpcas/source/CAS/Languages/English.php
new file mode 100644
index 0000000000..cb13bde93a
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/English.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/English.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * English language class
+ *
+ * @class    CAS_Languages_English
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_English implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'using server';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'CAS Authentication wanted!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'CAS logout wanted!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'You should already have been redirected to the CAS server. Click <a href="%s">here</a> to continue.';
+    }
+
+    /**
+    * Get authentication failed string
+    *
+    * @return string authentication failed
+    */
+    public function getAuthenticationFailed()
+    {
+        return 'CAS Authentication failed!';
+    }
+
+    /**
+    * Get the your were not authenticated string
+    *
+    * @return string not authenticated
+    */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>You were not authenticated.</p><p>You may submit your request again by clicking <a href="%s">here</a>.</p><p>If the problem persists, you may contact <a href="mailto:%s">the administrator of this site</a>.</p>';
+    }
+
+    /**
+    * Get the service unavailable string
+    *
+    * @return string service unavailable
+    */
+    public function getServiceUnavailable()
+    {
+        return 'The service `<b>%s</b>\' is not available (<b>%s</b>).';
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/French.php b/vendor/jasig/phpcas/source/CAS/Languages/French.php
new file mode 100644
index 0000000000..14f65aba24
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/French.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/French.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * French language class
+ *
+ * @class    CAS_Languages_French
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_French implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'utilisant le serveur';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'Authentication CAS nécessaire&nbsp;!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'Déconnexion demandée&nbsp;!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Vous auriez du etre redirigé(e) vers le serveur CAS. Cliquez <a href="%s">ici</a> pour continuer.';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'Authentification CAS infructueuse&nbsp;!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>Vous n\'avez pas été authentifié(e).</p><p>Vous pouvez soumettre votre requete à nouveau en cliquant <a href="%s">ici</a>.</p><p>Si le problème persiste, vous pouvez contacter <a href="mailto:%s">l\'administrateur de ce site</a>.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'Le service `<b>%s</b>\' est indisponible (<b>%s</b>)';
+    }
+}
+
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/Galego.php b/vendor/jasig/phpcas/source/CAS/Languages/Galego.php
new file mode 100644
index 0000000000..d5bf404557
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/Galego.php
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/Galego.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Enrique Huelva Rivero enrique.huelvarivero@plexus.es
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Galego language class
+ *
+ * @class    CAS_Languages_Galego
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Enrique Huelva Rivero enrique.huelvarivero@plexus.es
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_Galego implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'usando servidor';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'Autenticación CAS necesaria!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'Saída CAS necesaria!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Xa debería ser redireccionado ao servidor CAS. Faga click <a href="%s">aquí</a> para continuar';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'Autenticación CAS errada!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '
+        <p>Non estás autenticado</p><p>Podes volver tentalo facendo click <a href="%s">aquí</a>.</p><p>Se o problema persiste debería contactar con el <a href="mailto:%s">administrador deste sitio</a>.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'O servizo `<b>%s</b>\' non está dispoñible (<b>%s</b>).';
+    }
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/German.php b/vendor/jasig/phpcas/source/CAS/Languages/German.php
new file mode 100644
index 0000000000..b718b14521
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/German.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/German.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Henrik Genssen <hg@mediafactory.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * German language class
+ *
+ * @class    CAS_Languages_German
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Henrik Genssen <hg@mediafactory.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_German implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'via Server';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'CAS Authentifizierung erforderlich!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'CAS Abmeldung!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'eigentlich h&auml;ten Sie zum CAS Server weitergeleitet werden sollen. Dr&uuml;cken Sie <a href="%s">hier</a> um fortzufahren.';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'CAS Anmeldung fehlgeschlagen!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href="%s">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontaktieren Sie den <a href="mailto:%s">Administrator</a> dieser Seite.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'Der Dienst `<b>%s</b>\' ist nicht verf&uuml;gbar (<b>%s</b>).';
+    }
+}
+
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/Greek.php b/vendor/jasig/phpcas/source/CAS/Languages/Greek.php
new file mode 100644
index 0000000000..1cfb107e4a
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/Greek.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/Greek.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Vangelis Haniotakis <haniotak@ucnet.uoc.gr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Greek language class
+ *
+ * @class    CAS_Languages_Greek
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Vangelis Haniotakis <haniotak@ucnet.uoc.gr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_Greek implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'χρησιμοποιείται ο εξυπηρετητής';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'Απαιτείται η ταυτοποίηση CAS!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'Απαιτείται η αποσύνδεση από CAS!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Θα έπρεπε να είχατε ανακατευθυνθεί στον εξυπηρετητή CAS. Κάντε κλίκ <a href="%s">εδώ</a> για να συνεχίσετε.';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'Η ταυτοποίηση CAS απέτυχε!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>Δεν ταυτοποιηθήκατε.</p><p>Μπορείτε να ξαναπροσπαθήσετε, κάνοντας κλίκ <a href="%s">εδώ</a>.</p><p>Εαν το πρόβλημα επιμείνει, ελάτε σε επαφή με τον <a href="mailto:%s">διαχειριστή</a>.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'Η υπηρεσία `<b>%s</b>\' δεν είναι διαθέσιμη (<b>%s</b>).';
+    }
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/Japanese.php b/vendor/jasig/phpcas/source/CAS/Languages/Japanese.php
new file mode 100644
index 0000000000..568148458d
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/Japanese.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/Japanese.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   fnorif <fnorif@yahoo.co.jp>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Japanese language class. Now Encoding is UTF-8.
+ *
+ * @class    CAS_Languages_Japanese
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   fnorif <fnorif@yahoo.co.jp>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ **/
+class CAS_Languages_Japanese implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'サーバーを使っています。';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'CASによる認証を行います。';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'CASからログアウトします!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'CASサーバに行く必要があります。自動的に転送されない場合は <a href="%s">こちら</a> をクリックして続行します。';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'CASによる認証に失敗しました。';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>認証できませんでした。</p><p>もう一度リクエストを送信する場合は<a href="%s">こちら</a>をクリック。</p><p>問題が解決しない場合は <a href="mailto:%s">このサイトの管理者</a>に問い合わせてください。</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'サービス `<b>%s</b>\' は利用できません (<b>%s</b>)。';
+    }
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/LanguageInterface.php b/vendor/jasig/phpcas/source/CAS/Languages/LanguageInterface.php
new file mode 100644
index 0000000000..dfb0ac5144
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/LanguageInterface.php
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/LanguageInterface.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Language Interface class for all internationalization files
+ *
+ * @class    CAS_Languages_LanguageInterface
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+
+interface CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer();
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted();
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout();
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected();
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed();
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated();
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable();
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/Portuguese.php b/vendor/jasig/phpcas/source/CAS/Languages/Portuguese.php
new file mode 100644
index 0000000000..a927cad629
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/Portuguese.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/Portuguese.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Sherwin Harris <sherwin.harris@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://apereo.atlassian.net/wiki/spaces/CASC/pages/103252517/phpCAS
+ */
+
+/**
+ * Portuguese language class
+ *
+ * @class    CAS_Languages_Portuguese
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Sherwin Harris <sherwin.harris@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://apereo.atlassian.net/wiki/spaces/CASC/pages/103252517/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_Portuguese implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'Usando o servidor';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'A autenticação do servidor CAS desejado!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'Saida do servidor CAS desejado!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should have been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Você já deve ter sido redirecionado para o servidor CAS. Clique <a href="%s">aqui</a> para continuar';
+    }
+
+    /**
+    * Get authentication failed string
+    *
+    * @return string authentication failed
+    */
+    public function getAuthenticationFailed()
+    {
+        return 'A autenticação do servidor CAS falheu!';
+    }
+
+    /**
+    * Get the your were not authenticated string
+    *
+    * @return string not authenticated
+    */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>Você não foi autenticado.</p><p>Você pode enviar sua solicitação novamente clicando <a href="%s">aqui</a>. </p><p>Se o problema persistir, você pode entrar em contato com <a href="mailto:%s">o administrador deste site</a>.</p>';
+    }
+
+    /**
+    * Get the service unavailable string
+    *
+    * @return string service unavailable
+    */
+    public function getServiceUnavailable()
+    {
+        return 'O serviço `<b>%s</b>\' não está disponível (<b>%s</b>).';
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Languages/Spanish.php b/vendor/jasig/phpcas/source/CAS/Languages/Spanish.php
new file mode 100644
index 0000000000..c6ea50e747
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Languages/Spanish.php
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Language/Spanish.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Spanish language class
+ *
+ * @class    CAS_Languages_Spanish
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_Spanish implements CAS_Languages_LanguageInterface
+{
+
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'usando servidor';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return '¡Autentificación CAS necesaria!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return '¡Salida CAS necesaria!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Ya debería haber sido redireccionado al servidor CAS. Haga click <a href="%s">aquí</a> para continuar.';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return '¡Autentificación CAS fallida!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>No estás autentificado.</p><p>Puedes volver a intentarlo haciendo click <a href="%s">aquí</a>.</p><p>Si el problema persiste debería contactar con el <a href="mailto:%s">administrador de este sitio</a>.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'El servicio `<b>%s</b>\' no está disponible (<b>%s</b>).';
+    }
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php b/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php
new file mode 100644
index 0000000000..d4d7680de6
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/OutOfSequenceBeforeAuthenticationCallException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class defines Exceptions that should be thrown when the sequence of
+ * operations is invalid. In this case it should be thrown when an
+ * authentication call has not yet happened.
+ *
+ * @class    CAS_OutOfSequenceBeforeAuthenticationCallException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_OutOfSequenceBeforeAuthenticationCallException
+extends CAS_OutOfSequenceException
+implements CAS_Exception
+{
+    /**
+     * Return standard error meessage
+     *
+     * @return void
+     */
+    public function __construct ()
+    {
+        parent::__construct('An authentication call hasn\'t happened yet.');
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeClientException.php b/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeClientException.php
new file mode 100644
index 0000000000..6c2c39c587
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeClientException.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/OutOfSequenceBeforeClientException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class defines Exceptions that should be thrown when the sequence of
+ * operations is invalid. In this case it should be thrown when the client() or
+ *  proxy() call has not yet happened and no client or proxy object exists.
+ *
+ * @class    CAS_OutOfSequenceBeforeClientException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_OutOfSequenceBeforeClientException
+extends CAS_OutOfSequenceException
+implements CAS_Exception
+{
+    /**
+     * Return standard error message
+     *
+     * @return void
+     */
+    public function __construct ()
+    {
+        parent::__construct(
+            'this method cannot be called before phpCAS::client() or phpCAS::proxy()'
+        );
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php b/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php
new file mode 100644
index 0000000000..7991555218
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/OutOfSequenceBeforeProxyException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class defines Exceptions that should be thrown when the sequence of
+ * operations is invalid. In this case it should be thrown when the proxy() call
+ * has not yet happened and no proxy object exists.
+ *
+ * @class    CAS_OutOfSequenceBeforeProxyException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_OutOfSequenceBeforeProxyException
+extends CAS_OutOfSequenceException
+implements CAS_Exception
+{
+
+    /**
+     * Return standard error message
+     *
+     * @return void
+     */
+    public function __construct ()
+    {
+        parent::__construct(
+            'this method cannot be called before phpCAS::proxy()'
+        );
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/OutOfSequenceException.php b/vendor/jasig/phpcas/source/CAS/OutOfSequenceException.php
new file mode 100644
index 0000000000..d6f7d88fc1
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/OutOfSequenceException.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/OutOfSequenceException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class defines Exceptions that should be thrown when the sequence of
+ * operations is invalid. Examples are:
+ *		- Requesting the response before executing a request.
+ *		- Changing the URL of a request after executing the request.
+ *
+ * @class    CAS_OutOfSequenceException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_OutOfSequenceException
+extends BadMethodCallException
+implements CAS_Exception
+{
+
+}
diff --git a/vendor/jasig/phpcas/source/CAS/PGTStorage/AbstractStorage.php b/vendor/jasig/phpcas/source/CAS/PGTStorage/AbstractStorage.php
new file mode 100644
index 0000000000..a93568d60d
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/PGTStorage/AbstractStorage.php
@@ -0,0 +1,222 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/PGTStorage/AbstractStorage.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Basic class for PGT storage
+ * The CAS_PGTStorage_AbstractStorage class is a generic class for PGT storage.
+ * This class should not be instanciated itself but inherited by specific PGT
+ * storage classes.
+ *
+ * @class CAS_PGTStorage_AbstractStorage
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @ingroup internalPGTStorage
+ */
+
+abstract class CAS_PGTStorage_AbstractStorage
+{
+    /**
+     * @addtogroup internalPGTStorage
+     * @{
+     */
+
+    // ########################################################################
+    //  CONSTRUCTOR
+    // ########################################################################
+
+    /**
+     * The constructor of the class, should be called only by inherited classes.
+     *
+     * @param CAS_Client $cas_parent the CAS _client instance that creates the
+     * current object.
+     *
+     * @return void
+     *
+     * @protected
+     */
+    function __construct($cas_parent)
+    {
+        phpCAS::traceBegin();
+        if ( !$cas_parent->isProxy() ) {
+            phpCAS::error(
+                'defining PGT storage makes no sense when not using a CAS proxy'
+            );
+        }
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  DEBUGGING
+    // ########################################################################
+
+    /**
+     * This virtual method returns an informational string giving the type of storage
+     * used by the object (used for debugging purposes).
+     *
+     * @return string
+     *
+     * @public
+     */
+    function getStorageType()
+    {
+        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+    /**
+     * This virtual method returns an informational string giving informations on the
+     * parameters of the storage.(used for debugging purposes).
+     *
+     * @return string
+     *
+     * @public
+     */
+    function getStorageInfo()
+    {
+        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+    // ########################################################################
+    //  ERROR HANDLING
+    // ########################################################################
+
+    /**
+     * string used to store an error message. Written by
+     * PGTStorage::setErrorMessage(), read by PGTStorage::getErrorMessage().
+     *
+     * @hideinitializer
+     * @deprecated not used.
+     */
+    var $_error_message=false;
+
+    /**
+     * This method sets en error message, which can be read later by
+     * PGTStorage::getErrorMessage().
+     *
+     * @param string $error_message an error message
+     *
+     * @return void
+     *
+     * @deprecated not used.
+     */
+    function setErrorMessage($error_message)
+    {
+        $this->_error_message = $error_message;
+    }
+
+    /**
+     * This method returns an error message set by PGTStorage::setErrorMessage().
+     *
+     * @return string an error message when set by PGTStorage::setErrorMessage(), FALSE
+     * otherwise.
+     *
+     * @deprecated not used.
+     */
+    function getErrorMessage()
+    {
+        return $this->_error_message;
+    }
+
+    // ########################################################################
+    //  INITIALIZATION
+    // ########################################################################
+
+    /**
+     * a boolean telling if the storage has already been initialized. Written by
+     * PGTStorage::init(), read by PGTStorage::isInitialized().
+     *
+     * @hideinitializer
+     */
+    var $_initialized = false;
+
+    /**
+     * This method tells if the storage has already been intialized.
+     *
+     * @return bool
+     *
+     * @protected
+     */
+    function isInitialized()
+    {
+        return $this->_initialized;
+    }
+
+    /**
+     * This virtual method initializes the object.
+     *
+     * @return void
+     */
+    function init()
+    {
+        $this->_initialized = true;
+    }
+
+    // ########################################################################
+    //  PGT I/O
+    // ########################################################################
+
+    /**
+     * This virtual method stores a PGT and its corresponding PGT Iuo.
+     *
+     * @param string $pgt     the PGT
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return void
+     *
+     * @note Should never be called.
+     *
+     */
+    function write($pgt,$pgt_iou)
+    {
+        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+    /**
+     * This virtual method reads a PGT corresponding to a PGT Iou and deletes
+     * the corresponding storage entry.
+     *
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return string
+     *
+     * @note Should never be called.
+     */
+    function read($pgt_iou)
+    {
+        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+    /** @} */
+
+}
+
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/PGTStorage/Db.php b/vendor/jasig/phpcas/source/CAS/PGTStorage/Db.php
new file mode 100644
index 0000000000..2efe5a3e85
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/PGTStorage/Db.php
@@ -0,0 +1,440 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/PGTStorage/Db.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Daniel Frett <daniel.frett@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+define('CAS_PGT_STORAGE_DB_DEFAULT_TABLE', 'cas_pgts');
+
+/**
+ * Basic class for PGT database storage
+ * The CAS_PGTStorage_Db class is a class for PGT database storage.
+ *
+ * @class    CAS_PGTStorage_Db
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Daniel Frett <daniel.frett@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @ingroup internalPGTStorageDb
+ */
+
+class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
+{
+    /**
+     * @addtogroup internalCAS_PGTStorageDb
+     * @{
+     */
+
+    /**
+     * the PDO object to use for database interactions
+     */
+    private $_pdo;
+
+    /**
+     * This method returns the PDO object to use for database interactions.
+     *
+     * @return PDO object
+     */
+    private function _getPdo()
+    {
+        return $this->_pdo;
+    }
+
+    /**
+     * database connection options to use when creating a new PDO object
+     */
+    private $_dsn;
+    private $_username;
+    private $_password;
+    private $_driver_options;
+
+    /**
+     * @var string the table to use for storing/retrieving pgt's
+     */
+    private $_table;
+
+    /**
+     * This method returns the table to use when storing/retrieving PGT's
+     *
+     * @return string the name of the pgt storage table.
+     */
+    private function _getTable()
+    {
+        return $this->_table;
+    }
+
+    // ########################################################################
+    //  DEBUGGING
+    // ########################################################################
+
+    /**
+     * This method returns an informational string giving the type of storage
+     * used by the object (used for debugging purposes).
+     *
+     * @return string an informational string.
+     */
+    public function getStorageType()
+    {
+        return "db";
+    }
+
+    /**
+     * This method returns an informational string giving informations on the
+     * parameters of the storage.(used for debugging purposes).
+     *
+     * @return string an informational string.
+     * @public
+     */
+    public function getStorageInfo()
+    {
+        return 'table=`'.$this->_getTable().'\'';
+    }
+
+    // ########################################################################
+    //  CONSTRUCTOR
+    // ########################################################################
+
+    /**
+     * The class constructor.
+     *
+     * @param CAS_Client $cas_parent     the CAS_Client instance that creates
+     * the object.
+     * @param string     $dsn_or_pdo     a dsn string to use for creating a PDO
+     * object or a PDO object
+     * @param string     $username       the username to use when connecting to
+     * the database
+     * @param string     $password       the password to use when connecting to
+     * the database
+     * @param string     $table          the table to use for storing and
+     * retrieving PGT's
+     * @param string     $driver_options any driver options to use when
+     * connecting to the database
+     */
+    public function __construct(
+        $cas_parent, $dsn_or_pdo, $username='', $password='', $table='',
+        $driver_options=null
+    ) {
+        phpCAS::traceBegin();
+        // call the ancestor's constructor
+        parent::__construct($cas_parent);
+
+        // set default values
+        if ( empty($table) ) {
+            $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE;
+        }
+        if ( !is_array($driver_options) ) {
+            $driver_options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
+        }
+
+        // store the specified parameters
+        if ($dsn_or_pdo instanceof PDO) {
+            $this->_pdo = $dsn_or_pdo;
+        } else {
+            $this->_dsn = $dsn_or_pdo;
+            $this->_username = $username;
+            $this->_password = $password;
+            $this->_driver_options = $driver_options;
+        }
+
+        // store the table name
+        $this->_table = $table;
+
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  INITIALIZATION
+    // ########################################################################
+
+    /**
+     * This method is used to initialize the storage. Halts on error.
+     *
+     * @return void
+     */
+    public function init()
+    {
+        phpCAS::traceBegin();
+        // if the storage has already been initialized, return immediatly
+        if ($this->isInitialized()) {
+            return;
+        }
+
+        // initialize the base object
+        parent::init();
+
+        // create the PDO object if it doesn't exist already
+        if (!($this->_pdo instanceof PDO)) {
+            try {
+                $this->_pdo = new PDO(
+                    $this->_dsn, $this->_username, $this->_password,
+                    $this->_driver_options
+                );
+            }
+            catch(PDOException $e) {
+                phpCAS::error('Database connection error: ' . $e->getMessage());
+            }
+        }
+
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  PDO database interaction
+    // ########################################################################
+
+    /**
+     * attribute that stores the previous error mode for the PDO handle while
+     * processing a transaction
+     */
+    private $_errMode;
+
+    /**
+     * This method will enable the Exception error mode on the PDO object
+     *
+     * @return void
+     */
+    private function _setErrorMode()
+    {
+        // get PDO object and enable exception error mode
+        $pdo = $this->_getPdo();
+        $this->_errMode = $pdo->getAttribute(PDO::ATTR_ERRMODE);
+        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+    }
+
+    /**
+     * this method will reset the error mode on the PDO object
+     *
+     * @return void
+     */
+    private function _resetErrorMode()
+    {
+        // get PDO object and reset the error mode to what it was originally
+        $pdo = $this->_getPdo();
+        $pdo->setAttribute(PDO::ATTR_ERRMODE, $this->_errMode);
+    }
+
+    // ########################################################################
+    //  database queries
+    // ########################################################################
+    // these queries are potentially unsafe because the person using this library
+    // can set the table to use, but there is no reliable way to escape SQL
+    // fieldnames in PDO yet
+
+    /**
+     * This method returns the query used to create a pgt storage table
+     *
+     * @return string the create table SQL, no bind params in query
+     */
+    protected function createTableSql()
+    {
+        return 'CREATE TABLE ' . $this->_getTable()
+            . ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)';
+    }
+
+    /**
+     * This method returns the query used to store a pgt
+     *
+     * @return string the store PGT SQL, :pgt and :pgt_iou are the bind params contained
+     *         in the query
+     */
+    protected function storePgtSql()
+    {
+        return 'INSERT INTO ' . $this->_getTable()
+            . ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)';
+    }
+
+    /**
+     * This method returns the query used to retrieve a pgt. the first column
+     * of the first row should contain the pgt
+     *
+     * @return string the retrieve PGT SQL, :pgt_iou is the only bind param contained
+     *         in the query
+     */
+    protected function retrievePgtSql()
+    {
+        return 'SELECT pgt FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou';
+    }
+
+    /**
+     * This method returns the query used to delete a pgt.
+     *
+     * @return string the delete PGT SQL, :pgt_iou is the only bind param contained in
+     *         the query
+     */
+    protected function deletePgtSql()
+    {
+        return 'DELETE FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou';
+    }
+
+    // ########################################################################
+    //  PGT I/O
+    // ########################################################################
+
+    /**
+     * This method creates the database table used to store pgt's and pgtiou's
+     *
+     * @return void
+     */
+    public function createTable()
+    {
+        phpCAS::traceBegin();
+
+        // initialize this PGTStorage object if it hasn't been initialized yet
+        if ( !$this->isInitialized() ) {
+            $this->init();
+        }
+
+        // initialize the PDO object for this method
+        $pdo = $this->_getPdo();
+        $this->_setErrorMode();
+
+        try {
+            $pdo->beginTransaction();
+
+            $query = $pdo->query($this->createTableSQL());
+            $query->closeCursor();
+
+            $pdo->commit();
+        }
+        catch(PDOException $e) {
+            // attempt rolling back the transaction before throwing a phpCAS error
+            try {
+                $pdo->rollBack();
+            }
+            catch(PDOException $e) {
+            }
+            phpCAS::error('error creating PGT storage table: ' . $e->getMessage());
+        }
+
+        // reset the PDO object
+        $this->_resetErrorMode();
+
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method stores a PGT and its corresponding PGT Iou in the database.
+     * Echoes a warning on error.
+     *
+     * @param string $pgt     the PGT
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return void
+     */
+    public function write($pgt, $pgt_iou)
+    {
+        phpCAS::traceBegin();
+
+        // initialize the PDO object for this method
+        $pdo = $this->_getPdo();
+        $this->_setErrorMode();
+
+        try {
+            $pdo->beginTransaction();
+
+            $query = $pdo->prepare($this->storePgtSql());
+            $query->bindValue(':pgt', $pgt, PDO::PARAM_STR);
+            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);
+            $query->execute();
+            $query->closeCursor();
+
+            $pdo->commit();
+        }
+        catch(PDOException $e) {
+            // attempt rolling back the transaction before throwing a phpCAS error
+            try {
+                $pdo->rollBack();
+            }
+            catch(PDOException $e) {
+            }
+            phpCAS::error('error writing PGT to database: ' . $e->getMessage());
+        }
+
+        // reset the PDO object
+        $this->_resetErrorMode();
+
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method reads a PGT corresponding to a PGT Iou and deletes the
+     * corresponding db entry.
+     *
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return string|false the corresponding PGT, or FALSE on error
+     */
+    public function read($pgt_iou)
+    {
+        phpCAS::traceBegin();
+        $pgt = false;
+
+        // initialize the PDO object for this method
+        $pdo = $this->_getPdo();
+        $this->_setErrorMode();
+
+        try {
+            $pdo->beginTransaction();
+
+            // fetch the pgt for the specified pgt_iou
+            $query = $pdo->prepare($this->retrievePgtSql());
+            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);
+            $query->execute();
+            $pgt = $query->fetchColumn(0);
+            $query->closeCursor();
+
+            // delete the specified pgt_iou from the database
+            $query = $pdo->prepare($this->deletePgtSql());
+            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);
+            $query->execute();
+            $query->closeCursor();
+
+            $pdo->commit();
+        }
+        catch(PDOException $e) {
+            // attempt rolling back the transaction before throwing a phpCAS error
+            try {
+                $pdo->rollBack();
+            }
+            catch(PDOException $e) {
+            }
+            phpCAS::trace('error reading PGT from database: ' . $e->getMessage());
+        }
+
+        // reset the PDO object
+        $this->_resetErrorMode();
+
+        phpCAS::traceEnd();
+        return $pgt;
+    }
+
+    /** @} */
+
+}
+
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/PGTStorage/File.php b/vendor/jasig/phpcas/source/CAS/PGTStorage/File.php
new file mode 100644
index 0000000000..fbacd3b7d2
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/PGTStorage/File.php
@@ -0,0 +1,261 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/PGTStorage/AbstractStorage.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * The CAS_PGTStorage_File class is a class for PGT file storage. An instance of
+ * this class is returned by CAS_Client::SetPGTStorageFile().
+ *
+ * @class    CAS_PGTStorage_File
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ *
+ * @ingroup internalPGTStorageFile
+ */
+
+class CAS_PGTStorage_File extends CAS_PGTStorage_AbstractStorage
+{
+    /**
+     * @addtogroup internalPGTStorageFile
+     * @{
+     */
+
+    /**
+     * a string telling where PGT's should be stored on the filesystem. Written by
+     * PGTStorageFile::PGTStorageFile(), read by getPath().
+     *
+     * @private
+     */
+    var $_path;
+
+    /**
+     * This method returns the name of the directory where PGT's should be stored
+     * on the filesystem.
+     *
+     * @return string the name of a directory (with leading and trailing '/')
+     *
+     * @private
+     */
+    function getPath()
+    {
+        return $this->_path;
+    }
+
+    // ########################################################################
+    //  DEBUGGING
+    // ########################################################################
+
+    /**
+     * This method returns an informational string giving the type of storage
+     * used by the object (used for debugging purposes).
+     *
+     * @return string an informational string.
+     * @public
+     */
+    function getStorageType()
+    {
+        return "file";
+    }
+
+    /**
+     * This method returns an informational string giving informations on the
+     * parameters of the storage.(used for debugging purposes).
+     *
+     * @return string an informational string.
+     * @public
+     */
+    function getStorageInfo()
+    {
+        return 'path=`'.$this->getPath().'\'';
+    }
+
+    // ########################################################################
+    //  CONSTRUCTOR
+    // ########################################################################
+
+    /**
+     * The class constructor, called by CAS_Client::SetPGTStorageFile().
+     *
+     * @param CAS_Client $cas_parent the CAS_Client instance that creates the object.
+     * @param string     $path       the path where the PGT's should be stored
+     *
+     * @return void
+     *
+     * @public
+     */
+    function __construct($cas_parent,$path)
+    {
+        phpCAS::traceBegin();
+        // call the ancestor's constructor
+        parent::__construct($cas_parent);
+
+        if (empty($path)) {
+            $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH;
+        }
+        // check that the path is an absolute path
+        if (getenv("OS")=="Windows_NT" || strtoupper(substr(PHP_OS,0,3)) == 'WIN') {
+
+            if (!preg_match('`^[a-zA-Z]:`', $path)) {
+                phpCAS::error('an absolute path is needed for PGT storage to file');
+            }
+
+        } else {
+
+            if ( $path[0] != '/' ) {
+                phpCAS::error('an absolute path is needed for PGT storage to file');
+            }
+
+            // store the path (with a leading and trailing '/')
+            $path = preg_replace('|[/]*$|', '/', $path);
+            $path = preg_replace('|^[/]*|', '/', $path);
+        }
+
+        $this->_path = $path;
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  INITIALIZATION
+    // ########################################################################
+
+    /**
+     * This method is used to initialize the storage. Halts on error.
+     *
+     * @return void
+     * @public
+     */
+    function init()
+    {
+        phpCAS::traceBegin();
+        // if the storage has already been initialized, return immediatly
+        if ($this->isInitialized()) {
+            return;
+        }
+        // call the ancestor's method (mark as initialized)
+        parent::init();
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  PGT I/O
+    // ########################################################################
+
+    /**
+     * This method returns the filename corresponding to a PGT Iou.
+     *
+     * @param string $pgt_iou the PGT iou.
+     *
+     * @return string a filename
+     * @private
+     */
+    function getPGTIouFilename($pgt_iou)
+    {
+        phpCAS::traceBegin();
+        $filename = $this->getPath()."phpcas-".hash("sha256", $pgt_iou);
+//        $filename = $this->getPath().$pgt_iou.'.plain';
+        phpCAS::trace("Sha256 filename:" . $filename);
+        phpCAS::traceEnd();
+        return $filename;
+    }
+
+    /**
+     * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a
+     * warning on error.
+     *
+     * @param string $pgt     the PGT
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return void
+     *
+     * @public
+     */
+    function write($pgt,$pgt_iou)
+    {
+        phpCAS::traceBegin();
+        $fname = $this->getPGTIouFilename($pgt_iou);
+        if (!file_exists($fname)) {
+            touch($fname);
+            // Chmod will fail on windows
+            @chmod($fname, 0600);
+            if ($f=fopen($fname, "w")) {
+                if (fputs($f, $pgt) === false) {
+                    phpCAS::error('could not write PGT to `'.$fname.'\'');
+                }
+                phpCAS::trace('Successful write of PGT to `'.$fname.'\'');
+                fclose($f);
+            } else {
+                phpCAS::error('could not open `'.$fname.'\'');
+            }
+        } else {
+            phpCAS::error('File exists: `'.$fname.'\'');
+        }
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method reads a PGT corresponding to a PGT Iou and deletes the
+     * corresponding file.
+     *
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return string|false the corresponding PGT, or FALSE on error
+     *
+     * @public
+     */
+    function read($pgt_iou)
+    {
+        phpCAS::traceBegin();
+        $pgt = false;
+        $fname = $this->getPGTIouFilename($pgt_iou);
+        if (file_exists($fname)) {
+            if (!($f=fopen($fname, "r"))) {
+                phpCAS::error('could not open `'.$fname.'\'');
+            } else {
+                if (($pgt=fgets($f)) === false) {
+                    phpCAS::error('could not read PGT from `'.$fname.'\'');
+                }
+                phpCAS::trace('Successful read of PGT to `'.$fname.'\'');
+                fclose($f);
+            }
+            // delete the PGT file
+            @unlink($fname);
+        } else {
+            phpCAS::error('No such file `'.$fname.'\'');
+        }
+        phpCAS::traceEnd($pgt);
+        return $pgt;
+    }
+
+    /** @} */
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService.php b/vendor/jasig/phpcas/source/CAS/ProxiedService.php
new file mode 100644
index 0000000000..2673ee955f
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines methods that allow proxy-authenticated service handlers
+ * to interact with phpCAS.
+ *
+ * Proxy service handlers must implement this interface as well as call
+ * phpCAS::initializeProxiedService($this) at some point in their implementation.
+ *
+ * While not required, proxy-authenticated service handlers are encouraged to
+ * implement the CAS_ProxiedService_Testable interface to facilitate unit testing.
+ *
+ * @class    CAS_ProxiedService
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_ProxiedService
+{
+
+    /**
+     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.
+     *
+     * @return string
+     * @throws Exception If no service url is available.
+     */
+    public function getServiceUrl ();
+
+    /**
+     * Register a proxy ticket with the ProxiedService that it can use when
+     * making requests.
+     *
+     * @param string $proxyTicket Proxy ticket string
+     *
+     * @return void
+     * @throws InvalidArgumentException If the $proxyTicket is invalid.
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has
+     * already been initialized/set.
+     */
+    public function setProxyTicket ($proxyTicket);
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService/Abstract.php b/vendor/jasig/phpcas/source/CAS/ProxiedService/Abstract.php
new file mode 100644
index 0000000000..0801c723bd
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService/Abstract.php
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService/Abstract.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class implements common methods for ProxiedService implementations included
+ * with phpCAS.
+ *
+ * @class    CAS_ProxiedService_Abstract
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+abstract class CAS_ProxiedService_Abstract
+implements CAS_ProxiedService, CAS_ProxiedService_Testable
+{
+
+    /**
+     * The proxy ticket that can be used when making service requests.
+     * @var string $_proxyTicket;
+     */
+    private $_proxyTicket;
+
+    /**
+     * Register a proxy ticket with the Proxy that it can use when making requests.
+     *
+     * @param string $proxyTicket proxy ticket
+     *
+     * @return void
+     * @throws InvalidArgumentException If the $proxyTicket is invalid.
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has
+     *         already been initialized/set.
+     */
+    public function setProxyTicket ($proxyTicket)
+    {
+        if (empty($proxyTicket)) {
+            throw new CAS_InvalidArgumentException(
+                'Trying to initialize with an empty proxy ticket.'
+            );
+        }
+        if (!empty($this->_proxyTicket)) {
+            throw new CAS_OutOfSequenceException(
+                'Already initialized, cannot change the proxy ticket.'
+            );
+        }
+        $this->_proxyTicket = $proxyTicket;
+    }
+
+    /**
+     * Answer the proxy ticket to be used when making requests.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before a proxy ticket has
+     * already been initialized/set.
+     */
+    protected function getProxyTicket ()
+    {
+        if (empty($this->_proxyTicket)) {
+            throw new CAS_OutOfSequenceException(
+                'No proxy ticket yet. Call $this->initializeProxyTicket() to aquire the proxy ticket.'
+            );
+        }
+
+        return $this->_proxyTicket;
+    }
+
+    /**
+     * @var CAS_Client $_casClient;
+     */
+    private $_casClient;
+
+    /**
+     * Use a particular CAS_Client->initializeProxiedService() rather than the
+     * static phpCAS::initializeProxiedService().
+     *
+     * This method should not be called in standard operation, but is needed for unit
+     * testing.
+     *
+     * @param CAS_Client $casClient cas client
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has
+     * already been initialized/set.
+     */
+    public function setCasClient (CAS_Client $casClient)
+    {
+        if (!empty($this->_proxyTicket)) {
+            throw new CAS_OutOfSequenceException(
+                'Already initialized, cannot change the CAS_Client.'
+            );
+        }
+
+        $this->_casClient = $casClient;
+    }
+
+    /**
+     * Fetch our proxy ticket.
+     *
+     * Descendent classes should call this method once their service URL is available
+     * to initialize their proxy ticket.
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has
+     * already been initialized.
+     */
+    protected function initializeProxyTicket()
+    {
+        if (!empty($this->_proxyTicket)) {
+            throw new CAS_OutOfSequenceException(
+                'Already initialized, cannot initialize again.'
+            );
+        }
+        // Allow usage of a particular CAS_Client for unit testing.
+        if (empty($this->_casClient)) {
+            phpCAS::initializeProxiedService($this);
+        } else {
+            $this->_casClient->initializeProxiedService($this);
+        }
+    }
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService/Exception.php b/vendor/jasig/phpcas/source/CAS/ProxiedService/Exception.php
new file mode 100644
index 0000000000..0f87413dd9
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService/Exception.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService/Exception.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * An Exception for problems communicating with a proxied service.
+ *
+ * @class    CAS_ProxiedService_Exception
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxiedService_Exception
+extends Exception
+implements CAS_Exception
+{
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService/Http.php b/vendor/jasig/phpcas/source/CAS/ProxiedService/Http.php
new file mode 100644
index 0000000000..4240b061ae
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService/Http.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService/Http.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines methods that clients should use for configuring, sending,
+ * and receiving proxied HTTP requests.
+ *
+ * @class    CAS_ProxiedService_Http
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_ProxiedService_Http
+{
+
+    /*********************************************************
+     * Configure the Request
+    *********************************************************/
+
+    /**
+     * Set the URL of the Request
+     *
+     * @param string $url Url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setUrl ($url);
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ();
+
+    /*********************************************************
+     * 3. Access the response
+    *********************************************************/
+
+    /**
+     * Answer the headers of the response.
+     *
+     * @return array An array of header strings.
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseHeaders ();
+
+    /**
+     * Answer the body of response.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseBody ();
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Abstract.php b/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Abstract.php
new file mode 100644
index 0000000000..8d55edd502
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Abstract.php
@@ -0,0 +1,360 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService/Http/Abstract.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class implements common methods for ProxiedService implementations included
+ * with phpCAS.
+ *
+ * @class    CAS_ProxiedService_Http_Abstract
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+abstract class CAS_ProxiedService_Http_Abstract extends
+CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
+{
+    /**
+     * The HTTP request mechanism talking to the target service.
+     *
+     * @var CAS_Request_RequestInterface $requestHandler
+     */
+    protected $requestHandler;
+
+    /**
+     * The storage mechanism for cookies set by the target service.
+     *
+     * @var CAS_CookieJar $_cookieJar
+     */
+    private $_cookieJar;
+
+    /**
+     * Constructor.
+     *
+     * @param CAS_Request_RequestInterface $requestHandler request handler object
+     * @param CAS_CookieJar                $cookieJar      cookieJar object
+     *
+     * @return void
+     */
+    public function __construct(CAS_Request_RequestInterface $requestHandler,
+        CAS_CookieJar $cookieJar
+    ) {
+        $this->requestHandler = $requestHandler;
+        $this->_cookieJar = $cookieJar;
+    }
+
+    /**
+     * The target service url.
+     * @var string $_url;
+     */
+    private $_url;
+
+    /**
+     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.
+     *
+     * @return string
+     * @throws Exception If no service url is available.
+     */
+    public function getServiceUrl()
+    {
+        if (empty($this->_url)) {
+            throw new CAS_ProxiedService_Exception(
+                'No URL set via ' . get_class($this) . '->setUrl($url).'
+            );
+        }
+
+        return $this->_url;
+    }
+
+    /*********************************************************
+     * Configure the Request
+     *********************************************************/
+
+    /**
+     * Set the URL of the Request
+     *
+     * @param string $url url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setUrl($url)
+    {
+        if ($this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot set the URL, request already sent.'
+            );
+        }
+        if (!is_string($url)) {
+            throw new CAS_InvalidArgumentException('$url must be a string.');
+        }
+
+        $this->_url = $url;
+    }
+
+    /*********************************************************
+     * 2. Send the Request
+     *********************************************************/
+
+    /**
+     * Perform the request.
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *		The code of the Exception will be one of:
+     *			PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_FAILURE
+     * @throws CAS_ProxiedService_Exception If there is a failure sending the
+     * request to the target service.
+     */
+    public function send()
+    {
+        if ($this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot send, request already sent.'
+            );
+        }
+
+        phpCAS::traceBegin();
+
+        // Get our proxy ticket and append it to our URL.
+        $this->initializeProxyTicket();
+        $url = $this->getServiceUrl();
+        if (strstr($url, '?') === false) {
+            $url = $url . '?ticket=' . $this->getProxyTicket();
+        } else {
+            $url = $url . '&ticket=' . $this->getProxyTicket();
+        }
+
+        try {
+            $this->makeRequest($url);
+        } catch (Exception $e) {
+            phpCAS::traceEnd();
+            throw $e;
+        }
+    }
+
+    /**
+     * Indicator of the number of requests (including redirects performed.
+     *
+     * @var int $_numRequests;
+     */
+    private $_numRequests = 0;
+
+    /**
+     * The response headers.
+     *
+     * @var array $_responseHeaders;
+     */
+    private $_responseHeaders = array();
+
+    /**
+     * The response status code.
+     *
+     * @var int $_responseStatusCode;
+     */
+    private $_responseStatusCode = '';
+
+    /**
+     * The response headers.
+     *
+     * @var string $_responseBody;
+     */
+    private $_responseBody = '';
+
+    /**
+     * Build and perform a request, following redirects
+     *
+     * @param string $url url for the request
+     *
+     * @return void
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *		The code of the Exception will be one of:
+     *			PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_FAILURE
+     * @throws CAS_ProxiedService_Exception If there is a failure sending the
+     * request to the target service.
+     */
+    protected function makeRequest($url)
+    {
+        // Verify that we are not in a redirect loop
+        $this->_numRequests++;
+        if ($this->_numRequests > 4) {
+            $message = 'Exceeded the maximum number of redirects (3) in proxied service request.';
+            phpCAS::trace($message);
+            throw new CAS_ProxiedService_Exception($message);
+        }
+
+        // Create a new request.
+        $request = clone $this->requestHandler;
+        $request->setUrl($url);
+
+        // Add any cookies to the request.
+        $request->addCookies($this->_cookieJar->getCookies($url));
+
+        // Add any other parts of the request needed by concrete classes
+        $this->populateRequest($request);
+
+        // Perform the request.
+        phpCAS::trace('Performing proxied service request to \'' . $url . '\'');
+        if (!$request->send()) {
+            $message = 'Could not perform proxied service request to URL`'
+            . $url . '\'. ' . $request->getErrorMessage();
+            phpCAS::trace($message);
+            throw new CAS_ProxiedService_Exception($message);
+        }
+
+        // Store any cookies from the response;
+        $this->_cookieJar->storeCookies($url, $request->getResponseHeaders());
+
+        // Follow any redirects
+        if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders())
+        ) {
+            phpCAS::trace('Found redirect:' . $redirectUrl);
+            $this->makeRequest($redirectUrl);
+        } else {
+
+            $this->_responseHeaders = $request->getResponseHeaders();
+            $this->_responseBody = $request->getResponseBody();
+            $this->_responseStatusCode = $request->getResponseStatusCode();
+        }
+    }
+
+    /**
+     * Add any other parts of the request needed by concrete classes
+     *
+     * @param CAS_Request_RequestInterface $request request interface object
+     *
+     * @return void
+     */
+    abstract protected function populateRequest(
+        CAS_Request_RequestInterface $request
+    );
+
+    /**
+     * Answer a redirect URL if a redirect header is found, otherwise null.
+     *
+     * @param array $responseHeaders response header to extract a redirect from
+     *
+     * @return string|null
+     */
+    protected function getRedirectUrl(array $responseHeaders)
+    {
+        // Check for the redirect after authentication
+        foreach ($responseHeaders as $header) {
+            if ( preg_match('/^(Location:|URI:)\s*([^\s]+.*)$/', $header, $matches)
+            ) {
+                return trim(array_pop($matches));
+            }
+        }
+        return null;
+    }
+
+    /*********************************************************
+     * 3. Access the response
+     *********************************************************/
+
+    /**
+     * Answer true if our request has been sent yet.
+     *
+     * @return bool
+     */
+    protected function hasBeenSent()
+    {
+        return ($this->_numRequests > 0);
+    }
+
+    /**
+     * Answer the headers of the response.
+     *
+     * @return array An array of header strings.
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseHeaders()
+    {
+        if (!$this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot access response, request not sent yet.'
+            );
+        }
+
+        return $this->_responseHeaders;
+    }
+
+    /**
+     * Answer HTTP status code of the response
+     *
+     * @return int
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseStatusCode()
+    {
+        if (!$this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot access response, request not sent yet.'
+            );
+        }
+
+        return $this->_responseStatusCode;
+    }
+
+    /**
+     * Answer the body of response.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseBody()
+    {
+        if (!$this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot access response, request not sent yet.'
+            );
+        }
+
+        return $this->_responseBody;
+    }
+
+    /**
+     * Answer the cookies from the response. This may include cookies set during
+     * redirect responses.
+     *
+     * @return array An array containing cookies. E.g. array('name' => 'val');
+     */
+    public function getCookies()
+    {
+        return $this->_cookieJar->getCookies($this->getServiceUrl());
+    }
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Get.php b/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Get.php
new file mode 100644
index 0000000000..a459d55ae9
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Get.php
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService/Http/Get.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class is used to make proxied service requests via the HTTP GET method.
+ *
+ * Usage Example:
+ *
+ *	try {
+ *		$service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
+ *		$service->setUrl('http://www.example.com/path/');
+ *		$service->send();
+ *		if ($service->getResponseStatusCode() == 200)
+ *			return $service->getResponseBody();
+ *		else
+ *			// The service responded with an error code 404, 500, etc.
+ *			throw new Exception('The service responded with an error.');
+ *
+ * 	} catch (CAS_ProxyTicketException $e) {
+ *	    if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
+ *			return "Your login has timed out. You need to log in again.";
+ *		else
+ *			// Other proxy ticket errors are from bad request format
+ *          // (shouldn't happen) or CAS server failure (unlikely)
+ *          // so lets just stop if we hit those.
+ *			throw $e;
+ *	} catch (CAS_ProxiedService_Exception $e) {
+ *		// Something prevented the service request from being sent or received.
+ *		// We didn't even get a valid error response (404, 500, etc), so this
+ *		// might be caused by a network error or a DNS resolution failure.
+ *		// We could handle it in some way, but for now we will just stop.
+ *		throw $e;
+ *	}
+ *
+ * @class    CAS_ProxiedService_Http_Get
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxiedService_Http_Get
+extends CAS_ProxiedService_Http_Abstract
+{
+
+    /**
+     * Add any other parts of the request needed by concrete classes
+     *
+     * @param CAS_Request_RequestInterface $request request interface
+     *
+     * @return void
+     */
+    protected function populateRequest (CAS_Request_RequestInterface $request)
+    {
+        // do nothing, since the URL has already been sent and that is our
+        // only data.
+    }
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Post.php b/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Post.php
new file mode 100644
index 0000000000..344c439878
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Post.php
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService/Http/Post.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class is used to make proxied service requests via the HTTP POST method.
+ *
+ * Usage Example:
+ *
+ *	try {
+ * 		$service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST);
+ * 		$service->setUrl('http://www.example.com/path/');
+ *		$service->setContentType('text/xml');
+ *		$service->setBody('<?xml version="1.0"?'.'><methodCall><methodName>example.search</methodName></methodCall>');
+ * 		$service->send();
+ *		if ($service->getResponseStatusCode() == 200)
+ *			return $service->getResponseBody();
+ *		else
+ *			// The service responded with an error code 404, 500, etc.
+ *			throw new Exception('The service responded with an error.');
+ *
+ *	} catch (CAS_ProxyTicketException $e) {
+ *		if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
+ *			return "Your login has timed out. You need to log in again.";
+ *		else
+ *			// Other proxy ticket errors are from bad request format
+ *          // (shouldn't happen) or CAS server failure (unlikely) so lets just
+ *          // stop if we hit those.
+ *			throw $e;
+ *	} catch (CAS_ProxiedService_Exception $e) {
+ *		// Something prevented the service request from being sent or received.
+ *		// We didn't even get a valid error response (404, 500, etc), so this
+ *		// might be caused by a network error or a DNS resolution failure.
+ *		// We could handle it in some way, but for now we will just stop.
+ *		throw $e;
+ *	}
+ *
+ * @class    CAS_ProxiedService_Http_Post
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxiedService_Http_Post
+extends CAS_ProxiedService_Http_Abstract
+{
+
+    /**
+     * The content-type of this request
+     *
+     * @var string $_contentType
+     */
+    private $_contentType;
+
+    /**
+     * The body of the this request
+     *
+     * @var string $_body
+     */
+    private $_body;
+
+    /**
+     * Set the content type of this POST request.
+     *
+     * @param string $contentType content type
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setContentType ($contentType)
+    {
+        if ($this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot set the content type, request already sent.'
+            );
+        }
+
+        $this->_contentType = $contentType;
+    }
+
+    /**
+     * Set the body of this POST request.
+     *
+     * @param string $body body to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setBody ($body)
+    {
+        if ($this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot set the body, request already sent.'
+            );
+        }
+
+        $this->_body = $body;
+    }
+
+    /**
+     * Add any other parts of the request needed by concrete classes
+     *
+     * @param CAS_Request_RequestInterface $request request interface class
+     *
+     * @return void
+     */
+    protected function populateRequest (CAS_Request_RequestInterface $request)
+    {
+        if (empty($this->_contentType) && !empty($this->_body)) {
+            throw new CAS_ProxiedService_Exception(
+                "If you pass a POST body, you must specify a content type via "
+                .get_class($this).'->setContentType($contentType).'
+            );
+        }
+
+        $request->makePost();
+        if (!empty($this->_body)) {
+            $request->addHeader('Content-Type: '.$this->_contentType);
+            $request->addHeader('Content-Length: '.strlen($this->_body));
+            $request->setPostBody($this->_body);
+        }
+    }
+
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService/Imap.php b/vendor/jasig/phpcas/source/CAS/ProxiedService/Imap.php
new file mode 100644
index 0000000000..c4b47401dd
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService/Imap.php
@@ -0,0 +1,281 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService/Imap.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Provides access to a proxy-authenticated IMAP stream
+ *
+ * @class    CAS_ProxiedService_Imap
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxiedService_Imap
+extends CAS_ProxiedService_Abstract
+{
+
+    /**
+     * The username to send via imap_open.
+     *
+     * @var string $_username;
+     */
+    private $_username;
+
+    /**
+     * Constructor.
+     *
+     * @param string $username Username
+     *
+     * @return void
+     */
+    public function __construct ($username)
+    {
+        if (!is_string($username) || !strlen($username)) {
+            throw new CAS_InvalidArgumentException('Invalid username.');
+        }
+
+        $this->_username = $username;
+    }
+
+    /**
+     * The target service url.
+     * @var string $_url;
+     */
+    private $_url;
+
+    /**
+     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.
+     *
+     * @return string
+     * @throws Exception If no service url is available.
+     */
+    public function getServiceUrl ()
+    {
+        if (empty($this->_url)) {
+            throw new CAS_ProxiedService_Exception(
+                'No URL set via '.get_class($this).'->getServiceUrl($url).'
+            );
+        }
+
+        return $this->_url;
+    }
+
+    /*********************************************************
+     * Configure the Stream
+    *********************************************************/
+
+    /**
+     * Set the URL of the service to pass to CAS for proxy-ticket retrieval.
+     *
+     * @param string $url Url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the stream has been opened.
+     */
+    public function setServiceUrl ($url)
+    {
+        if ($this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot set the URL, stream already opened.'
+            );
+        }
+        if (!is_string($url) || !strlen($url)) {
+            throw new CAS_InvalidArgumentException('Invalid url.');
+        }
+
+        $this->_url = $url;
+    }
+
+    /**
+     * The mailbox to open. See the $mailbox parameter of imap_open().
+     *
+     * @var string $_mailbox
+     */
+    private $_mailbox;
+
+    /**
+     * Set the mailbox to open. See the $mailbox parameter of imap_open().
+     *
+     * @param string $mailbox Mailbox to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the stream has been opened.
+     */
+    public function setMailbox ($mailbox)
+    {
+        if ($this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot set the mailbox, stream already opened.'
+            );
+        }
+        if (!is_string($mailbox) || !strlen($mailbox)) {
+            throw new CAS_InvalidArgumentException('Invalid mailbox.');
+        }
+
+        $this->_mailbox = $mailbox;
+    }
+
+    /**
+     * A bit mask of options to pass to imap_open() as the $options parameter.
+     *
+     * @var int $_options
+     */
+    private $_options = null;
+
+    /**
+     * Set the options for opening the stream. See the $options parameter of
+     * imap_open().
+     *
+     * @param int $options Options for the stream
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the stream has been opened.
+     */
+    public function setOptions ($options)
+    {
+        if ($this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot set options, stream already opened.'
+            );
+        }
+        if (!is_int($options)) {
+            throw new CAS_InvalidArgumentException('Invalid options.');
+        }
+
+        $this->_options = $options;
+    }
+
+    /*********************************************************
+     * 2. Open the stream
+    *********************************************************/
+
+    /**
+     * Open the IMAP stream (similar to imap_open()).
+     *
+     * @return resource Returns an IMAP stream on success
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *		The code of the Exception will be one of:
+     *			PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *			PHPCAS_SERVICE_PT_FAILURE
+     * @throws CAS_ProxiedService_Exception If there is a failure sending the
+     *         request to the target service.
+     */
+    public function open ()
+    {
+        if ($this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException('Stream already opened.');
+        }
+        if (empty($this->_mailbox)) {
+            throw new CAS_ProxiedService_Exception(
+                'You must specify a mailbox via '.get_class($this)
+                .'->setMailbox($mailbox)'
+            );
+        }
+
+        phpCAS::traceBegin();
+
+        // Get our proxy ticket and append it to our URL.
+        $this->initializeProxyTicket();
+        phpCAS::trace('opening IMAP mailbox `'.$this->_mailbox.'\'...');
+        $this->_stream = @imap_open(
+            $this->_mailbox, $this->_username, $this->getProxyTicket(),
+            $this->_options
+        );
+        if ($this->_stream) {
+            phpCAS::trace('ok');
+        } else {
+            phpCAS::trace('could not open mailbox');
+            // @todo add localization integration.
+            $message = 'IMAP Error: '.$this->_url.' '. var_export(imap_errors(), true);
+            phpCAS::trace($message);
+            throw new CAS_ProxiedService_Exception($message);
+        }
+
+        phpCAS::traceEnd();
+        return $this->_stream;
+    }
+
+    /**
+     * Answer true if our request has been sent yet.
+     *
+     * @return bool
+     */
+    protected function hasBeenOpened ()
+    {
+        return !empty($this->_stream);
+    }
+
+    /*********************************************************
+     * 3. Access the result
+    *********************************************************/
+    /**
+     * The IMAP stream
+     *
+     * @var resource $_stream
+     */
+    private $_stream;
+
+    /**
+     * Answer the IMAP stream
+     *
+     * @return resource
+     * @throws CAS_OutOfSequenceException if stream is not opened yet
+     */
+    public function getStream ()
+    {
+        if (!$this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot access stream, not opened yet.'
+            );
+        }
+        return $this->_stream;
+    }
+
+    /**
+     * CAS_Client::serviceMail() needs to return the proxy ticket for some reason,
+     * so this method provides access to it.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the stream has been
+     * opened.
+     */
+    public function getImapProxyTicket ()
+    {
+        if (!$this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot access errors, stream not opened yet.'
+            );
+        }
+        return $this->getProxyTicket();
+    }
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxiedService/Testable.php b/vendor/jasig/phpcas/source/CAS/ProxiedService/Testable.php
new file mode 100644
index 0000000000..3ce44fd16c
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxiedService/Testable.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxiedService/Testabel.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines methods that allow proxy-authenticated service handlers
+ * to be tested in unit tests.
+ *
+ * Classes implementing this interface SHOULD store the CAS_Client passed and
+ * initialize themselves with that client rather than via the static phpCAS
+ * method. For example:
+ *
+ *		/ **
+ *		 * Fetch our proxy ticket.
+ *		 * /
+ *		protected function initializeProxyTicket() {
+ *			// Allow usage of a particular CAS_Client for unit testing.
+ *			if (is_null($this->casClient))
+ *				phpCAS::initializeProxiedService($this);
+ *			else
+ *				$this->casClient->initializeProxiedService($this);
+ *		}
+ *
+ * @class    CAS_ProxiedService_Testabel
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_ProxiedService_Testable
+{
+
+    /**
+     * Use a particular CAS_Client->initializeProxiedService() rather than the
+     * static phpCAS::initializeProxiedService().
+     *
+     * This method should not be called in standard operation, but is needed for unit
+     * testing.
+     *
+     * @param CAS_Client $casClient Cas client object
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has
+     *         already been initialized/set.
+     */
+    public function setCasClient (CAS_Client $casClient);
+
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxyChain.php b/vendor/jasig/phpcas/source/CAS/ProxyChain.php
new file mode 100644
index 0000000000..e200724cef
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxyChain.php
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxyChain.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * A normal proxy-chain definition that lists each level of the chain as either
+ * a string or regular expression.
+ *
+ * @class    CAS_ProxyChain
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class CAS_ProxyChain
+implements CAS_ProxyChain_Interface
+{
+
+    protected $chain = array();
+
+    /**
+     * A chain is an array of strings or regexp strings that will be matched
+     * against. Regexp will be matched with preg_match and strings will be
+     * matched from the beginning. A string must fully match the beginning of
+     * an proxy url. So you can define a full domain as acceptable or go further
+     * down.
+     * Proxies have to be defined in reverse from the service to the user. If a
+     * user hits service A get proxied via B to service C the list of acceptable
+     * proxies on C would be array(B,A);
+     *
+     * @param array $chain A chain of proxies
+     */
+    public function __construct(array $chain)
+    {
+        // Ensure that we have an indexed array
+        $this->chain = array_values($chain);
+    }
+
+    /**
+     * Match a list of proxies.
+     *
+     * @param array $list The list of proxies in front of this service.
+     *
+     * @return bool
+     */
+    public function matches(array $list)
+    {
+        $list = array_values($list);  // Ensure that we have an indexed array
+        if ($this->isSizeValid($list)) {
+            $mismatch = false;
+            foreach ($this->chain as $i => $search) {
+                $proxy_url = $list[$i];
+                if (preg_match('/^\/.*\/[ixASUXu]*$/s', $search)) {
+                    if (preg_match($search, $proxy_url)) {
+                        phpCAS::trace(
+                            "Found regexp " .  $search . " matching " . $proxy_url
+                        );
+                    } else {
+                        phpCAS::trace(
+                            "No regexp match " .  $search . " != " . $proxy_url
+                        );
+                        $mismatch = true;
+                        break;
+                    }
+                } else {
+                    if (strncasecmp($search, $proxy_url, strlen($search)) == 0) {
+                        phpCAS::trace(
+                            "Found string " .  $search . " matching " . $proxy_url
+                        );
+                    } else {
+                        phpCAS::trace(
+                            "No match " .  $search . " != " . $proxy_url
+                        );
+                        $mismatch = true;
+                        break;
+                    }
+                }
+            }
+            if (!$mismatch) {
+                phpCAS::trace("Proxy chain matches");
+                return true;
+            }
+        } else {
+            phpCAS::trace("Proxy chain skipped: size mismatch");
+        }
+        return false;
+    }
+
+    /**
+     * Validate the size of the the list as compared to our chain.
+     *
+     * @param array $list List of proxies
+     *
+     * @return bool
+     */
+    protected function isSizeValid (array $list)
+    {
+        return (sizeof($this->chain) == sizeof($list));
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/ProxyChain/AllowedList.php b/vendor/jasig/phpcas/source/CAS/ProxyChain/AllowedList.php
new file mode 100644
index 0000000000..988ddbb3c3
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxyChain/AllowedList.php
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxyChain/AllowedList.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+
+/**
+ * ProxyChain is a container for storing chains of valid proxies that can
+ * be used to validate proxied requests to a service
+ *
+ * @class    CAS_ProxyChain_AllowedList
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class CAS_ProxyChain_AllowedList
+{
+
+    private $_chains = array();
+
+    /**
+     * Check whether proxies are allowed by configuration
+     *
+     * @return bool
+     */
+    public function isProxyingAllowed()
+    {
+        return (count($this->_chains) > 0);
+    }
+
+    /**
+     * Add a chain of proxies to the list of possible chains
+     *
+     * @param CAS_ProxyChain_Interface $chain A chain of proxies
+     *
+     * @return void
+     */
+    public function allowProxyChain(CAS_ProxyChain_Interface $chain)
+    {
+        $this->_chains[] = $chain;
+    }
+
+    /**
+     * Check if the proxies found in the response match the allowed proxies
+     *
+     * @param array $proxies list of proxies to check
+     *
+     * @return bool whether the proxies match the allowed proxies
+     */
+    public function isProxyListAllowed(array $proxies)
+    {
+        phpCAS::traceBegin();
+        if (empty($proxies)) {
+            phpCAS::trace("No proxies were found in the response");
+            phpCAS::traceEnd(true);
+            return true;
+        } elseif (!$this->isProxyingAllowed()) {
+            phpCAS::trace("Proxies are not allowed");
+            phpCAS::traceEnd(false);
+            return false;
+        } else {
+            $res = $this->contains($proxies);
+            phpCAS::traceEnd($res);
+            return $res;
+        }
+    }
+
+    /**
+     * Validate the proxies from the proxy ticket validation against the
+     * chains that were definded.
+     *
+     * @param array $list List of proxies from the proxy ticket validation.
+     *
+     * @return bool if any chain fully matches the supplied list
+     */
+    public function contains(array $list)
+    {
+        phpCAS::traceBegin();
+        $count = 0;
+        foreach ($this->_chains as $chain) {
+            phpCAS::trace("Checking chain ". $count++);
+            if ($chain->matches($list)) {
+                phpCAS::traceEnd(true);
+                return true;
+            }
+        }
+        phpCAS::trace("No proxy chain matches.");
+        phpCAS::traceEnd(false);
+        return false;
+    }
+}
+?>
diff --git a/vendor/jasig/phpcas/source/CAS/ProxyChain/Any.php b/vendor/jasig/phpcas/source/CAS/ProxyChain/Any.php
new file mode 100644
index 0000000000..fe18c5fbf1
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxyChain/Any.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxyChain/Any.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * A proxy-chain definition that will match any list of proxies.
+ *
+ * Use this class for quick testing or in certain production screnarios you
+ * might want to allow allow any other valid service to proxy your service.
+ *
+ * THIS CLASS IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
+ * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
+ * ON THIS SERVICE.
+ *
+ * @class    CAS_ProxyChain_Any
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxyChain_Any
+implements CAS_ProxyChain_Interface
+{
+
+    /**
+     * Match a list of proxies.
+     *
+     * @param array $list The list of proxies in front of this service.
+     *
+     * @return bool
+     */
+    public function matches(array $list)
+    {
+        phpCAS::trace("Using CAS_ProxyChain_Any. No proxy validation is performed.");
+        return true;
+    }
+
+}
diff --git a/vendor/jasig/phpcas/source/CAS/ProxyChain/Interface.php b/vendor/jasig/phpcas/source/CAS/ProxyChain/Interface.php
new file mode 100644
index 0000000000..b1d6881747
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxyChain/Interface.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxyChain/Interface.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * An interface for classes that define a list of allowed proxies in front of
+ * the current application.
+ *
+ * @class    CAS_ProxyChain_Interface
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_ProxyChain_Interface
+{
+
+    /**
+     * Match a list of proxies.
+     *
+     * @param array $list The list of proxies in front of this service.
+     *
+     * @return bool
+     */
+    public function matches(array $list);
+
+}
diff --git a/vendor/jasig/phpcas/source/CAS/ProxyChain/Trusted.php b/vendor/jasig/phpcas/source/CAS/ProxyChain/Trusted.php
new file mode 100644
index 0000000000..e67d70852a
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxyChain/Trusted.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/ProxyChain/Trusted.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * A proxy-chain definition that defines a chain up to a trusted proxy and
+ * delegates the resposibility of validating the rest of the chain to that
+ * trusted proxy.
+ *
+ * @class    CAS_ProxyChain_Trusted
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxyChain_Trusted
+extends CAS_ProxyChain
+implements CAS_ProxyChain_Interface
+{
+
+    /**
+     * Validate the size of the the list as compared to our chain.
+     *
+     * @param array $list list of proxies
+     *
+     * @return bool
+     */
+    protected function isSizeValid (array $list)
+    {
+        return (sizeof($this->chain) <= sizeof($list));
+    }
+
+}
diff --git a/vendor/jasig/phpcas/source/CAS/ProxyTicketException.php b/vendor/jasig/phpcas/source/CAS/ProxyTicketException.php
new file mode 100644
index 0000000000..2f825b421c
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/ProxyTicketException.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @class    CAS/ProxyTicketException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ */
+
+/**
+ * An Exception for errors related to fetching or validating proxy tickets.
+ *
+ * @class    CAS_ProxyTicketException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxyTicketException
+extends BadMethodCallException
+implements CAS_Exception
+{
+
+    /**
+     * Constructor
+     *
+     * @param string $message Message text
+     * @param int    $code    Error code
+     *
+     * @return void
+     */
+    public function __construct ($message, $code = PHPCAS_SERVICE_PT_FAILURE)
+    {
+        // Warn if the code is not in our allowed list
+        $ptCodes = array(
+        PHPCAS_SERVICE_PT_FAILURE,
+        PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+        PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
+        );
+        if (!in_array($code, $ptCodes)) {
+            trigger_error(
+                'Invalid code '.$code
+                .' passed. Must be one of PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, or PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE.'
+            );
+        }
+
+        parent::__construct($message, $code);
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Request/AbstractRequest.php b/vendor/jasig/phpcas/source/CAS/Request/AbstractRequest.php
new file mode 100644
index 0000000000..4f9013ee2c
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Request/AbstractRequest.php
@@ -0,0 +1,380 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Request/AbstractRequest.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Provides support for performing web-requests via curl
+ *
+ * @class    CAS_Request_AbstractRequest
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+abstract class CAS_Request_AbstractRequest
+implements CAS_Request_RequestInterface
+{
+
+    protected $url = null;
+    protected $cookies = array();
+    protected $headers = array();
+    protected $isPost = false;
+    protected $postBody = null;
+    protected $caCertPath = null;
+    protected $validateCN = true;
+    private $_sent = false;
+    private $_responseHeaders = array();
+    private $_responseBody = null;
+    private $_errorMessage = '';
+
+    /*********************************************************
+     * Configure the Request
+    *********************************************************/
+
+    /**
+     * Set the URL of the Request
+     *
+     * @param string $url Url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setUrl ($url)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+
+        $this->url = $url;
+    }
+
+    /**
+     * Add a cookie to the request.
+     *
+     * @param string $name  Name of entry
+     * @param string $value value of entry
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addCookie ($name, $value)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+
+        $this->cookies[$name] = $value;
+    }
+
+    /**
+     * Add an array of cookies to the request.
+     * The cookie array is of the form
+     *     array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2')
+     *
+     * @param array $cookies cookies to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addCookies (array $cookies)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+
+        $this->cookies = array_merge($this->cookies, $cookies);
+    }
+
+    /**
+     * Add a header string to the request.
+     *
+     * @param string $header Header to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addHeader ($header)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+
+        $this->headers[] = $header;
+    }
+
+    /**
+     * Add an array of header strings to the request.
+     *
+     * @param array $headers headers to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addHeaders (array $headers)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+
+        $this->headers = array_merge($this->headers, $headers);
+    }
+
+    /**
+     * Make the request a POST request rather than the default GET request.
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function makePost ()
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+
+        $this->isPost = true;
+    }
+
+    /**
+     * Add a POST body to the request
+     *
+     * @param string $body body to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setPostBody ($body)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+        if (!$this->isPost) {
+            throw new CAS_OutOfSequenceException(
+                'Cannot add a POST body to a GET request, use makePost() first.'
+            );
+        }
+
+        $this->postBody = $body;
+    }
+
+    /**
+     * Specify the path to an SSL CA certificate to validate the server with.
+     *
+     * @param string $caCertPath  path to cert
+     * @param bool   $validate_cn valdiate CN of certificate
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setSslCaCert ($caCertPath,$validate_cn=true)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+        $this->caCertPath = $caCertPath;
+        $this->validateCN = $validate_cn;
+    }
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ()
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot send again.'
+            );
+        }
+        if (is_null($this->url) || !$this->url) {
+            throw new CAS_OutOfSequenceException(
+                'A url must be specified via setUrl() before the request can be sent.'
+            );
+        }
+        $this->_sent = true;
+        return $this->sendRequest();
+    }
+
+    /**
+     * Send the request and store the results.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     */
+    abstract protected function sendRequest ();
+
+    /**
+     * Store the response headers.
+     *
+     * @param array $headers headers to store
+     *
+     * @return void
+     */
+    protected function storeResponseHeaders (array $headers)
+    {
+        $this->_responseHeaders = array_merge($this->_responseHeaders, $headers);
+    }
+
+    /**
+     * Store a single response header to our array.
+     *
+     * @param string $header header to store
+     *
+     * @return void
+     */
+    protected function storeResponseHeader ($header)
+    {
+        $this->_responseHeaders[] = $header;
+    }
+
+    /**
+     * Store the response body.
+     *
+     * @param string $body body to store
+     *
+     * @return void
+     */
+    protected function storeResponseBody ($body)
+    {
+        $this->_responseBody = $body;
+    }
+
+    /**
+     * Add a string to our error message.
+     *
+     * @param string $message message to add
+     *
+     * @return void
+     */
+    protected function storeErrorMessage ($message)
+    {
+        $this->_errorMessage .= $message;
+    }
+
+    /*********************************************************
+     * 3. Access the response
+    *********************************************************/
+
+    /**
+     * Answer the headers of the response.
+     *
+     * @return array An array of header strings.
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseHeaders ()
+    {
+        if (!$this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has not been sent yet. Cannot '.__METHOD__
+            );
+        }
+        return $this->_responseHeaders;
+    }
+
+    /**
+     * Answer HTTP status code of the response
+     *
+     * @return int
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     * @throws CAS_Request_Exception if the response did not contain a status code
+     */
+    public function getResponseStatusCode ()
+    {
+        if (!$this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has not been sent yet. Cannot '.__METHOD__
+            );
+        }
+
+        if (!preg_match(
+            '/HTTP\/[0-9.]+\s+([0-9]+)\s*(.*)/',
+            $this->_responseHeaders[0], $matches
+        )
+        ) {
+            throw new CAS_Request_Exception(
+                'Bad response, no status code was found in the first line.'
+            );
+        }
+
+        return intval($matches[1]);
+    }
+
+    /**
+     * Answer the body of response.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseBody ()
+    {
+        if (!$this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has not been sent yet. Cannot '.__METHOD__
+            );
+        }
+
+        return $this->_responseBody;
+    }
+
+    /**
+     * Answer a message describing any errors if the request failed.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getErrorMessage ()
+    {
+        if (!$this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has not been sent yet. Cannot '.__METHOD__
+            );
+        }
+        return $this->_errorMessage;
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Request/CurlMultiRequest.php b/vendor/jasig/phpcas/source/CAS/Request/CurlMultiRequest.php
new file mode 100644
index 0000000000..850f6f0e4a
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Request/CurlMultiRequest.php
@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Request/AbstractRequest.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines a class library for performing multiple web requests
+ * in batches. Implementations of this interface may perform requests serially
+ * or in parallel.
+ *
+ * @class    CAS_Request_CurlMultiRequest
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_Request_CurlMultiRequest
+implements CAS_Request_MultiRequestInterface
+{
+    private $_requests = array();
+    private $_sent = false;
+
+    /*********************************************************
+     * Add Requests
+    *********************************************************/
+
+    /**
+     * Add a new Request to this batch.
+     * Note, implementations will likely restrict requests to their own concrete
+     * class hierarchy.
+     *
+     * @param CAS_Request_RequestInterface $request reqest to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     * @throws CAS_InvalidArgumentException If passed a Request of the wrong
+     * implmentation.
+     */
+    public function addRequest (CAS_Request_RequestInterface $request)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+        if (!$request instanceof CAS_Request_CurlRequest) {
+            throw new CAS_InvalidArgumentException(
+                'As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.'
+            );
+        }
+
+        $this->_requests[] = $request;
+    }
+
+    /**
+     * Retrieve the number of requests added to this batch.
+     *
+     * @return int number of request elements
+     * @throws CAS_OutOfSequenceException if the request has already been sent
+     */
+    public function getNumRequests()
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot '.__METHOD__
+            );
+        }
+        return count($this->_requests);
+    }
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request. After sending, all requests will have their
+     * responses poulated.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ()
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException(
+                'Request has already been sent cannot send again.'
+            );
+        }
+        if (!count($this->_requests)) {
+            throw new CAS_OutOfSequenceException(
+                'At least one request must be added via addRequest() before the multi-request can be sent.'
+            );
+        }
+
+        $this->_sent = true;
+
+        // Initialize our handles and configure all requests.
+        $handles = array();
+        $multiHandle = curl_multi_init();
+        foreach ($this->_requests as $i => $request) {
+            $handle = $request->initAndConfigure();
+            curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
+            $handles[$i] = $handle;
+            curl_multi_add_handle($multiHandle, $handle);
+        }
+
+        // Execute the requests in parallel.
+        do {
+            curl_multi_exec($multiHandle, $running);
+        } while ($running > 0);
+
+        // Populate all of the responses or errors back into the request objects.
+        foreach ($this->_requests as $i => $request) {
+            $buf = curl_multi_getcontent($handles[$i]);
+            $request->_storeResponseBody($buf);
+            curl_multi_remove_handle($multiHandle, $handles[$i]);
+            curl_close($handles[$i]);
+        }
+
+        curl_multi_close($multiHandle);
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Request/CurlRequest.php b/vendor/jasig/phpcas/source/CAS/Request/CurlRequest.php
new file mode 100644
index 0000000000..3eaa0d3c16
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Request/CurlRequest.php
@@ -0,0 +1,193 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Request/CurlRequest.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Provides support for performing web-requests via curl
+ *
+ * @class    CAS_Request_CurlRequest
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_Request_CurlRequest
+extends CAS_Request_AbstractRequest
+implements CAS_Request_RequestInterface
+{
+
+    /**
+     * Set additional curl options
+     *
+     * @param array $options option to set
+     *
+     * @return void
+     */
+    public function setCurlOptions (array $options)
+    {
+        $this->_curlOptions = $options;
+    }
+    private $_curlOptions = array();
+
+    /**
+     * Send the request and store the results.
+     *
+     * @return bool true on success, false on failure.
+     */
+    protected function sendRequest ()
+    {
+        phpCAS::traceBegin();
+
+        /*********************************************************
+         * initialize the CURL session
+        *********************************************************/
+        $ch = $this->initAndConfigure();
+
+        /*********************************************************
+         * Perform the query
+        *********************************************************/
+        $buf = curl_exec($ch);
+        if ( $buf === false ) {
+            phpCAS::trace('curl_exec() failed');
+            $this->storeErrorMessage(
+                'CURL error #'.curl_errno($ch).': '.curl_error($ch)
+            );
+            $res = false;
+        } else {
+            $this->storeResponseBody($buf);
+            phpCAS::trace("Response Body: \n".$buf."\n");
+            $res = true;
+
+        }
+        // close the CURL session
+        curl_close($ch);
+
+        phpCAS::traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * Internal method to initialize our cURL handle and configure the request.
+     * This method should NOT be used outside of the CurlRequest or the
+     * CurlMultiRequest.
+     *
+     * @return resource|false The cURL handle on success, false on failure
+     */
+    public function initAndConfigure()
+    {
+        /*********************************************************
+         * initialize the CURL session
+        *********************************************************/
+        $ch = curl_init($this->url);
+
+        curl_setopt_array($ch, $this->_curlOptions);
+
+        /*********************************************************
+         * Set SSL configuration
+        *********************************************************/
+        if ($this->caCertPath) {
+            if ($this->validateCN) {
+                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+            } else {
+                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+            }
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
+            curl_setopt($ch, CURLOPT_CAINFO, $this->caCertPath);
+            phpCAS::trace('CURL: Set CURLOPT_CAINFO ' . $this->caCertPath);
+        } else {
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+        }
+
+        /*********************************************************
+         * Configure curl to capture our output.
+        *********************************************************/
+        // return the CURL output into a variable
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+
+        // get the HTTP header with a callback
+        curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curlReadHeaders'));
+
+        /*********************************************************
+         * Add cookie headers to our request.
+        *********************************************************/
+        if (count($this->cookies)) {
+            $cookieStrings = array();
+            foreach ($this->cookies as $name => $val) {
+                $cookieStrings[] = $name.'='.$val;
+            }
+            curl_setopt($ch, CURLOPT_COOKIE, implode(';', $cookieStrings));
+        }
+
+        /*********************************************************
+         * Add any additional headers
+        *********************************************************/
+        if (count($this->headers)) {
+            curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
+        }
+
+        /*********************************************************
+         * Flag and Body for POST requests
+        *********************************************************/
+        if ($this->isPost) {
+            curl_setopt($ch, CURLOPT_POST, 1);
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $this->postBody);
+        }
+
+        return $ch;
+    }
+
+    /**
+     * Store the response body.
+     * This method should NOT be used outside of the CurlRequest or the
+     * CurlMultiRequest.
+     *
+     * @param string $body body to stor
+     *
+     * @return void
+     */
+    public function _storeResponseBody ($body)
+    {
+        $this->storeResponseBody($body);
+    }
+
+    /**
+     * Internal method for capturing the headers from a curl request.
+     *
+     * @param resource $ch     handle of curl
+     * @param string $header header
+     *
+     * @return int
+     */
+    public function _curlReadHeaders ($ch, $header)
+    {
+        $this->storeResponseHeader($header);
+        return strlen($header);
+    }
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Request/Exception.php b/vendor/jasig/phpcas/source/CAS/Request/Exception.php
new file mode 100644
index 0000000000..dd5a2a55a5
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Request/Exception.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Request/Exception.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * An Exception for problems performing requests
+ *
+ * @class    CAS_Request_Exception
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_Request_Exception
+extends Exception
+implements CAS_Exception
+{
+
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Request/MultiRequestInterface.php b/vendor/jasig/phpcas/source/CAS/Request/MultiRequestInterface.php
new file mode 100644
index 0000000000..41002c7776
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Request/MultiRequestInterface.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Request/MultiRequestInterface.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines a class library for performing multiple web requests
+ * in batches. Implementations of this interface may perform requests serially
+ * or in parallel.
+ *
+ * @class    CAS_Request_MultiRequestInterface
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_Request_MultiRequestInterface
+{
+
+    /*********************************************************
+     * Add Requests
+    *********************************************************/
+
+    /**
+     * Add a new Request to this batch.
+     * Note, implementations will likely restrict requests to their own concrete
+     * class hierarchy.
+     *
+     * @param CAS_Request_RequestInterface $request request interface
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been
+     * sent.
+     * @throws CAS_InvalidArgumentException If passed a Request of the wrong
+     * implmentation.
+     */
+    public function addRequest (CAS_Request_RequestInterface $request);
+
+    /**
+     * Retrieve the number of requests added to this batch.
+     *
+     * @return int number of request elements
+     */
+    public function getNumRequests ();
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request. After sending, all requests will have their
+     * responses poulated.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ();
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Request/RequestInterface.php b/vendor/jasig/phpcas/source/CAS/Request/RequestInterface.php
new file mode 100644
index 0000000000..b8e8772e93
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Request/RequestInterface.php
@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Request/RequestInterface.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines a class library for performing web requests.
+ *
+ * @class    CAS_Request_RequestInterface
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_Request_RequestInterface
+{
+
+    /*********************************************************
+     * Configure the Request
+    *********************************************************/
+
+    /**
+     * Set the URL of the Request
+     *
+     * @param string $url url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setUrl ($url);
+
+    /**
+     * Add a cookie to the request.
+     *
+     * @param string $name  name of cookie
+     * @param string $value value of cookie
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addCookie ($name, $value);
+
+    /**
+     * Add an array of cookies to the request.
+     * The cookie array is of the form
+     *     array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2')
+     *
+     * @param array $cookies cookies to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addCookies (array $cookies);
+
+    /**
+     * Add a header string to the request.
+     *
+     * @param string $header header to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addHeader ($header);
+
+    /**
+     * Add an array of header strings to the request.
+     *
+     * @param array $headers headers to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addHeaders (array $headers);
+
+    /**
+     * Make the request a POST request rather than the default GET request.
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function makePost ();
+
+    /**
+     * Add a POST body to the request
+     *
+     * @param string $body body to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setPostBody ($body);
+
+
+    /**
+     * Specify the path to an SSL CA certificate to validate the server with.
+     *
+     * @param string  $caCertPath  path to cert file
+     * @param boolean $validate_cn validate CN of SSL certificate
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setSslCaCert ($caCertPath, $validate_cn = true);
+
+
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ();
+
+    /*********************************************************
+     * 3. Access the response
+    *********************************************************/
+
+    /**
+     * Answer the headers of the response.
+     *
+     * @return array An array of header strings.
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseHeaders ();
+
+    /**
+     * Answer HTTP status code of the response
+     *
+     * @return int
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseStatusCode ();
+
+    /**
+     * Answer the body of response.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseBody ();
+
+    /**
+     * Answer a message describing any errors if the request failed.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getErrorMessage ();
+}
diff --git a/vendor/jasig/phpcas/source/CAS/Session/PhpSession.php b/vendor/jasig/phpcas/source/CAS/Session/PhpSession.php
new file mode 100644
index 0000000000..031cbbc70f
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/Session/PhpSession.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/Session/PhpSession.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Empty class used as a default implementation for phpCAS.
+ *
+ * Implements the standard PHP session handler without no alterations.
+ *
+ * @class    CAS_Session_PhpSession
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_Session_PhpSession extends SessionHandler implements SessionHandlerInterface
+{
+}
diff --git a/vendor/jasig/phpcas/source/CAS/TypeMismatchException.php b/vendor/jasig/phpcas/source/CAS/TypeMismatchException.php
new file mode 100644
index 0000000000..72bdc87a17
--- /dev/null
+++ b/vendor/jasig/phpcas/source/CAS/TypeMismatchException.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 7
+ *
+ * @file     CAS/InvalidArgumentException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Exception that denotes invalid arguments were passed.
+ *
+ * @class    CAS_InvalidArgumentException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_TypeMismatchException
+extends CAS_InvalidArgumentException
+{
+    /**
+     * Constructor, provides a nice message.
+     *
+     * @param mixed   $argument     Argument
+     * @param string  $argumentName Argument Name
+     * @param string  $type         Type
+     * @param string  $message      Error Message
+     * @param integer $code         Code
+     *
+     * @return void
+     */
+    public function __construct (
+        $argument, $argumentName, $type, $message = '', $code = 0
+    ) {
+        if (is_object($argument)) {
+            $foundType = get_class($argument).' object';
+        } else {
+            $foundType = gettype($argument);
+        }
+
+        parent::__construct(
+            'type mismatched for parameter '
+            . $argumentName . ' (should be \'' . $type .' \'), '
+            . $foundType . ' given. ' . $message, $code
+        );
+    }
+}
+?>
-- 
GitLab