!C99Shell v. 2.1 [PHP 8 Update] [02.02.2022]!

Software: Apache/2.4.53 (Unix) OpenSSL/1.1.1o PHP/7.4.29 mod_perl/2.0.12 Perl/v5.34.1. PHP/7.4.29 

uname -a: Linux vps-2738122-x 4.15.0-213-generic #224-Ubuntu SMP Mon Jun 19 13:30:12 UTC 2023 x86_64 

uid=1(daemon) gid=1(daemon) grupos=1(daemon) 

Safe-mode: OFF (not secure)

/opt/apex_tdfonline/php/3ros/phpCAS/CAS/CAS/   drwxr-xr-x
Free 14.52 GB of 61.93 GB (23.45%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     Client.php (119.81 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?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 5
 *
 * @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>
 * @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>
 * @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)
    {
        
$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()
    {
        
$lang $this->getLangObj();
        
$this->_htmlFilterOutput(
            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 method set the HTML header used for all outputs.
     *
     * @param string $header the HTML header.
     *
     * @return void
     */
    
public function setHTMLHeader($header)
    {
        
$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)
    {
        
$this->_output_footer $footer;
    }


    
/** @} */


    // ########################################################################
    //  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)
    {
        
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' => -1,
        
'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 string 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 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->_getServerBaseURL();
            
$this->_server['login_url'] .= 'login?service=';
            
$this->_server['login_url'] .= 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)
    {
        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)
    {
        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)
    {
        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)
    {
        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;
            }
        }
        
$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;
            }
        }
        
$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:
                
$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)
    {
        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 $_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 string $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 callback $_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 string $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.
    // ########################################################################

    /**
     * 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);
    }

    
/**
     * 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 ()
    {
        if (empty(
$this->_authentication_caller)) {
            throw new 
CAS_OutOfSequenceException('markAuthenticationCall() hasn\'t happened.');
        }
        return 
$this->_authentication_caller['result'];
    }

    
/**
     * Answer information about the authentication caller.
     *
     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
     * and markAuthenticationCall() didn't happen.
     *
     * @return array Keys are 'file', 'line', and 'method'
     */
    
public function getAuthenticationCallerFile ()
    {
        if (empty(
$this->_authentication_caller)) {
            throw new 
CAS_OutOfSequenceException('markAuthenticationCall() hasn\'t happened.');
        }
        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 array Keys are 'file', 'line', and 'method'
     */
    
public function getAuthenticationCallerLine ()
    {
        if (empty(
$this->_authentication_caller)) {
            throw new 
CAS_OutOfSequenceException('markAuthenticationCall() hasn\'t happened.');
        }
        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 array Keys are 'file', 'line', and 'method'
     */
    
public function getAuthenticationCallerMethod ()
    {
        if (empty(
$this->_authentication_caller)) {
            throw new 
CAS_OutOfSequenceException('markAuthenticationCall() hasn\'t happened.');
        }
        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)
     *
     * @return a newly created CAS_Client object
     */
    
public function __construct(
        
$server_version,
        
$proxy,
        
$server_hostname,
        
$server_port,
        
$server_uri,
        
$changeSessionID true
    
) {

        
phpCAS::traceBegin();

        
$this->_setChangeSessionID($changeSessionID); // true : allow to change the session_id(), false session_id won't be change and logout won't be handle because of that

        // skip Session Handling for logout requests and if don't want it'
        
if (session_id()=="" && !$this->_isLogoutRequest()) {
            
phpCAS :: trace("Starting a new session");
            
session_start();
        }

        
// are we in proxy mode ?
        
$this->_proxy $proxy;

        
// Make cookie handling available.
        
if ($this->isProxy()) {
            if (!isset(
$_SESSION['phpCAS'])) {
                
$_SESSION['phpCAS'] = array();
            }
            if (!isset(
$_SESSION['phpCAS']['service_cookies'])) {
                
$_SESSION['phpCAS']['service_cookies'] = array();
            }
            
$this->_serviceCookieJar = new CAS_CookieJar($_SESSION['phpCAS']['service_cookies']);
        }

        
//check version
        
switch ($server_version) {
        case 
CAS_VERSION_1_0:
            if ( 
$this->isProxy() ) {
                
phpCAS::error(
                    
'CAS proxies are not supported in CAS '.$server_version
                
);
            }
            break;
        case 
CAS_VERSION_2_0:
            break;
        case 
SAML_VERSION_1_1:
            break;
        default:
            
phpCAS::error(
                
'this version of CAS (`'.$server_version
                
.'\') is not supported by phpCAS '.phpCAS::getVersion()
            );
        }
        
$this->_server['version'] = $server_version;

        
// check hostname
        
if ( empty($server_hostname)
            || !
preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/'$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\-_abcdefghijklmnopqrstuvwxyz\/]*/'$server_uri) ) {
            
phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
        }
        
// add leading and trailing `/' and remove doubles
        
$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() ) {
            
$this->_setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
        }

        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'] : null);
            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
     * @{
     */


    /**
     * A variable to whether phpcas will use its own session handling. Default = true
     * @hideinitializer
     */
    
private $_change_session_id true;

    
/**
     * 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;
    }

    
/** @} */

    // 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()
    {
        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 arry of attributes
     */
    
public function getAttributes()
    {
        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()
    {
        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)
    {
        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)
    {
        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  void
     */
    
public function renewAuthentication()
    {
        
phpCAS::traceBegin();
        
// Either way, the user is authenticated by CAS
        
if (isset( $_SESSION['phpCAS']['auth_checked'])) {
            unset(
$_SESSION['phpCAS']['auth_checked']);
        }
        if ( 
$this->isAuthenticated() ) {
            
phpCAS::trace('user already authenticated; renew');
            
$this->redirectToCas(falsetrue);
        } else {
            
$this->redirectToCas();
        }
        
phpCAS::traceEnd();
    }

    
/**
     * 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 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
            
if (isset($_SESSION['phpCAS']['auth_checked'])) {
                unset(
$_SESSION['phpCAS']['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)
    {
        
$this->_cache_times_for_auth_recheck $n;
    }

    
/**
     * This method is called to check whether the user is authenticated or not.
     *
     * @return 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;
        if ( 
$this->isAuthenticated() ) {
            
phpCAS::trace('user is authenticated');
            
/* The 'auth_checked' variable is removed just in case it's set. */
            
unset($_SESSION['phpCAS']['auth_checked']);
            
$res true;
        } else if (isset(
$_SESSION['phpCAS']['auth_checked'])) {
            
// the previous request has redirected the client to the CAS server
            // with gateway=true
            
unset($_SESSION['phpCAS']['auth_checked']);
            
$res false;
        } else {
            
// avoid a check against CAS on every request
            
if (!isset($_SESSION['phpCAS']['unauth_count'])) {
                
$_SESSION['phpCAS']['unauth_count'] = -2// uninitialized
            
}

            if ((
$_SESSION['phpCAS']['unauth_count'] != -2
                
&& $this->_cache_times_for_auth_recheck == -1)
                || (
$_SESSION['phpCAS']['unauth_count'] >= 0
                
&& $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck)
            ) {
                
$res false;

                if (
$this->_cache_times_for_auth_recheck != -1) {
                    
$_SESSION['phpCAS']['unauth_count']++;
                    
phpCAS::trace(
                        
'user is not authenticated (cached for '
                        
.$_SESSION['phpCAS']['unauth_count'].' times of '
                        
.$this->_cache_times_for_auth_recheck.')'
                    
);
                } else {
                    
phpCAS::trace('user is not authenticated (cached for until login pressed)');
                }
            } else {
                
$_SESSION['phpCAS']['unauth_count'] = 0;
                
$_SESSION['phpCAS']['auth_checked'] = true;
                
phpCAS::trace('user is not authenticated (cache reset)');
                
$this->redirectToCas(true/* gateway */);
                
// never reached
                
$res false;
            }
        }
        
phpCAS::traceEnd($res);
        return 
$res;
    }

    
/**
     * This method is called to check if the user is authenticated (previously or by
     * tickets given in the URL).
     *
     * @return true when the user is authenticated. Also may redirect to the
     * same URL without the ticket.
     */
    
public function isAuthenticated()
    {
        
phpCAS::traceBegin();
        
$res false;
        
$validate_url '';
        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());
                    
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;
            }
        } else {
            if (
$this->hasTicket()) {
                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); // if it fails, it halts
                    
phpCAS::trace('CAS 1.0 ticket `'.$this->getTicket().'\' was validated');
                    
$_SESSION['phpCAS']['user'] = $this->getUser();
                    
$res true;
                    
$logoutTicket $this->getTicket();
                    break;
                case 
CAS_VERSION_2_0:
                    
// if a Proxy Ticket was given, validate it
                    
phpCAS::trace('CAS 2.0 ticket `'.$this->getTicket().'\' is present');
                    
$this->validateCAS20($validate_url$text_response$tree_response); // note: if it fails, it halts
                    
phpCAS::trace('CAS 2.0 ticket `'.$this->getTicket().'\' was validated');
                    if ( 
$this->isProxy() ) {
                        
$this->_validatePGT($validate_url$text_response$tree_response); // idem
                        
phpCAS::trace('PGT `'.$this->_getPGT().'\' was validated');
                        
$_SESSION['phpCAS']['pgt'] = $this->_getPGT();
                    }
                    
$_SESSION['phpCAS']['user'] = $this->getUser();
                    if (
$this->hasAttributes()) {
                        
$_SESSION['phpCAS']['attributes'] = $this->getAttributes();
                    }
                    
$proxies $this->getProxies();
                    if (!empty(
$proxies)) {
                        
$_SESSION['phpCAS']['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); // if it fails, it halts
                    
phpCAS::trace('SAML 1.1 ticket `'.$this->getTicket().'\' was validated');
                    
$_SESSION['phpCAS']['user'] = $this->getUser();
                    
$_SESSION['phpCAS']['attributes'] = $this->getAttributes();
                    
$res true;
                    
$logoutTicket $this->getTicket();
                    break;
                default:
                    
phpCAS::trace('Protocoll error');
                    break;
                }
            } else {
                
// no ticket given, not authenticated
                
phpCAS::trace('no ticket found');
            }
            if (
$res) {
                
// Mark the auth-check as complete to allow post-authentication
                // callbacks to make use of phpCAS::getUser() and similar methods
                
$this->markAuthenticationCall($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());
                    
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 true if authenticated based soley on $_SESSION variable
     */
    
public function isSessionAuthenticated ()
    {
        return !empty(
$_SESSION['phpCAS']['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 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() && !empty($_SESSION['phpCAS']['pgt']) ) {
                
// authentication already done
                
$this->_setUser($_SESSION['phpCAS']['user']);
                if (isset(
$_SESSION['phpCAS']['attributes'])) {
                    
$this->setAttributes($_SESSION['phpCAS']['attributes']);
                }
                
$this->_setPGT($_SESSION['phpCAS']['pgt']);
                
phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\'');

                
// Include the list of proxies
                
if (isset($_SESSION['phpCAS']['proxies'])) {
                    
$this->_setProxies($_SESSION['phpCAS']['proxies']);
                    
phpCAS::trace('proxies = "'.implode('", "'$_SESSION['phpCAS']['proxies']).'"');
                }

                
$auth true;
            } elseif ( 
$this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
                
// these two variables should be empty or not empty at the same time
                
phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
                
// unset all tickets to enforce authentication
                
unset($_SESSION['phpCAS']);
                
$this->setTicket('');
            } elseif ( !
$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
                
// these two variables should be empty or not empty at the same time
                
phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty');
                
// unset all tickets to enforce authentication
                
unset($_SESSION['phpCAS']);
                
$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($_SESSION['phpCAS']['user']);
                if (isset(
$_SESSION['phpCAS']['attributes'])) {
                    
$this->setAttributes($_SESSION['phpCAS']['attributes']);
                }
                
phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\'');

                
// Include the list of proxies
                
if (isset($_SESSION['phpCAS']['proxies'])) {
                    
$this->_setProxies($_SESSION['phpCAS']['proxies']);
                    
phpCAS::trace('proxies = "'.implode('", "'$_SESSION['phpCAS']['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);
        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());
        
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);

        
session_unset();
        
session_destroy();
        
$lang $this->getLangObj();
        
$this->printHTMLHeader($lang->getLogout());
        
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 bool $allowed_clients an array of host names allowed to send
     * logout requests.
     *
     * @return void
     */
    
public function handleLogoutRequests($check_client=true$allowed_clients=false)
    {
        
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) {
                
$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) or ($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$tickPREG_OFFSET_CAPTURE3);
            
$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 preg_replace('/[^a-zA-Z0-9\-]/'''$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
    * @{
    */

    /**
     * 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)
    {
        
$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.
     *
     * @return bool true when successfull and issue a CAS_AuthenticationException
     * and false on an error
     */
    
public function validateCAS10(&$validate_url,&$text_response,&$tree_response)
    {
        
phpCAS::traceBegin();
        
$result false;
        
// build the URL to validate the ticket
        
$validate_url $this->getServerServiceValidateURL().'&ticket='.$this->getTicket();

        
// 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*/
            
);
            
$result false;
        }

        if (
preg_match('/^no\n/'$text_response)) {
            
phpCAS::trace('Ticket has not been validated');
            throw new 
CAS_AuthenticationException(
                
$this'ST not validated'$validate_urlfalse/*$no_response*/,
                
false/*$bad_response*/$text_response
            
);
            
$result false;
        } 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
            
);
            
$result false;
        }
        
// ticket has been validated, extract the user name
        
$arr preg_split('/\n/'$text_response);
        
$this->_setUser(trim($arr[1]));
        
$result true;

        if (
$result) {
            
$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.
     *
     * @return bool true when successfull and issue a CAS_AuthenticationException
     * and false on an error
     */
    
public function validateSA(&$validate_url,&$text_response,&$tree_response)
    {
        
phpCAS::traceBegin();
        
$result false;
        
// build the URL to validate the ticket
        
$validate_url $this->getServerSamlValidateURL();

        
// 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_urltrue/*$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
                
);
                
$result false;
            }
            
// 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
                
);
                
$result false;
            } 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
                
);
                
$result false;
            } 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
                
);
                
$result false;
            }
        }
        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 "=" $attr_value);
                    } 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
    * @{
    */

    /**
     * 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;

    
/**
     * Handler for managing service cookies.
     */
    
private $_serviceCookieJar;

    
/**
     * Tells if a CAS client is a CAS proxy or not
     *
     * @return 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 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.
     */

    /**
     * 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 i callback mode,
     * false otherwise.
     *
     * @return A boolean.
     */
    
private function _isCallbackMode()
    {
        return 
$this->_callback_mode;
    }

    
/**
     * 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 The callback URL
     */
    
private function _getCallbackURL()
    {
        
// the URL is built when needed only
        
if ( empty($this->_callback_url) ) {
            
$final_uri '';
            
// remove the ticket if present in the URL
            
$final_uri 'https://';
            
$final_uri .= $this->_getServerUrl();
            
$request_uri $_SERVER['REQUEST_URI'];
            
$request_uri preg_replace('/\?.*$/'''$request_uri);
            
$final_uri .= $request_uri;
            
$this->setCallbackURL($final_uri);
        }
        return 
$this->_callback_url;
    }

    
/**
     * This method sets the callback url.
     *
     * @param string $url url to set callback
     *
     * @return void
     */
    
public function setCallbackURL($url)
    {
        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 (
preg_match('/PGTIOU-[\.\-\w]/'$_GET['pgtIou'])) {
            if (
preg_match('/[PT]GT-[\.\-\w]/'$_GET['pgtId'])) {
                
$this->printHTMLHeader('phpCAS callback');
                
$pgt_iou $_GET['pgtIou'];
                
$pgt $_GET['pgtId'];
                
phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
                echo 
'<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
                
$this->_storePGT($pgt$pgt_iou);
                
$this->printHTMLFooter();
                
phpCAS::traceExit("Successfull Callback");
            } else {
                
phpCAS::error('PGT format invalid' $_GET['pgtId']);
                
phpCAS::traceExit('PGT format invalid' $_GET['pgtId']);
            }
        } else {
            
phpCAS::error('PGTiou format invalid' $_GET['pgtIou']);
            
phpCAS::traceExit('PGTiou format invalid' $_GET['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();
    }


    
/** @} */

    // ########################################################################
    //  PGT STORAGE
    // ########################################################################
    /**
    * @addtogroup internalPGTStorage
    * @{
    */

    /**
     * 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 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)
    {
        
// 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) ) {
            
phpCAS::error('Invalid PGT storage 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 $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)
    {
        
// 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='')
    {
        
// 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 string $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
    */
    
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_urlfalse/*$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_urlfalse/*$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_urlfalse/*$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 string &$err_code      an error code (PHPCAS_SERVICE_OK on success).
     * @param string &$err_msg       an error message (empty on success).
     *
     * @return a Proxy Ticket, or false on error.
     */
    
public function retrievePT($target_service,&$err_code,&$err_msg)
    {
        
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();

        
// 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;

        if ( !
$bad_response ) {
            
// 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 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 the SOAP-encased SAMLP artifact (the ticket).
     */
    
private function _buildSAMLPayload()
    {
        
phpCAS::traceBegin();

        
//get the ticket
        
$sa $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)
    {
        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)
    {
        
$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 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)
    {
        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 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)
    {
        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 string &$tree_response the domxml tree of the respones
     *
     * @return bool true when successfull and issue a CAS_AuthenticationException
     * and false on an error
     */
    
public function validateCAS20(&$validate_url,&$text_response,&$tree_response)
    {
        
phpCAS::traceBegin();
        
phpCAS::trace($text_response);
        
$result false;
        
// build the URL to validate the ticket
        
if ($this->getAllowedProxyChains()->isProxyingAllowed()) {
            
$validate_url $this->getServerProxyValidateURL().'&ticket='.$this->getTicket();
        } else {
            
$validate_url $this->getServerServiceValidateURL().'&ticket='.$this->getTicket();
        }

        if ( 
$this->isProxy() ) {
            
// pass the callback url for CAS proxies
            
$validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL());
        }

        
// 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*/
            
);
            
$result false;
        }

        
// 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
            
);
            
$result false;
        } 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
            
);
            
$result false;
        } 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
            
);
            
$result false;
        } 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
                
);
                
$result false;
            } 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
                    
);
                    
$result false;
                } else {
                    
$result true;
                }
            }
        } else if ( 
$tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
            
// authentication succeded, extract the error code and message
            
$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*/
            
);
            
$result false;
        } else {
            throw new 
CAS_AuthenticationException(
                
$this'Ticket not validated'$validate_url,
                
false/*$no_response*/true/*$bad_response*/,
                
$text_response
            
);
            
$result false;
        }
        if (
$result) {
            
$this->_renameSession($this->getTicket());
        }
        
// at this step, Ticket 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 XML
     * payload and put them into an array, then put the array into the session.
     *
     * @param string $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();

        
// "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>
        //
        
if ( $success_elements->item(0)->getElementsByTagName("attributes")->length != 0) {
            
$attr_nodes $success_elements->item(0)->getElementsByTagName("attributes");
            
phpCas :: trace("Found nested jasig style attributes");
            if (
$attr_nodes->item(0)->hasChildNodes()) {
                
// Nested Attributes
                
foreach ($attr_nodes->item(0)->childNodes as $attr_child) {
                    
phpCas :: trace("Attribute [".$attr_child->localName."] = ".$attr_child->nodeValue);
                    
$this->_addAttributeToArray($extra_attributes$attr_child->localName$attr_child->nodeValue);
                }
            }
        } else {
            
// "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>
            //
            
phpCas :: trace("Testing for rubycas style attributes");
            
$childnodes $success_elements->item(0)->childNodes;
            foreach (
$childnodes as $attr_node) {
                switch (
$attr_node->localName) {
                case 
'user':
                case 
'proxies':
                case 
'proxyGrantingTicket':
                    continue;
                default:
                    if (
strlen(trim($attr_node->nodeValue))) {
                        
phpCas :: trace("Attribute [".$attr_node->localName."] = ".$attr_node->nodeValue);
                        
$this->_addAttributeToArray($extra_attributes$attr_node->localName$attr_node->nodeValue);
                    }
                }
            }
        }

        
// "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>
        //
        
if (!count($extra_attributes) && $success_elements->item(0)->getElementsByTagName("attribute")->length != 0) {
            
$attr_nodes $success_elements->item(0)->getElementsByTagName("attribute");
            
$firstAttr $attr_nodes->item(0);
            if (!
$firstAttr->hasChildNodes() && $firstAttr->hasAttribute('name') && $firstAttr->hasAttribute('value')) {
                
phpCas :: trace("Found Name-Value style attributes");
                
// Nested Attributes
                
foreach ($attr_nodes as $attr_node) {
                    if (
$attr_node->hasAttribute('name') && $attr_node->hasAttribute('value')) {
                        
phpCas :: trace("Attribute [".$attr_node->getAttribute('name')."] = ".$attr_node->getAttribute('value'));
                        
$this->_addAttributeToArray($extra_attributes$attr_node->getAttribute('name'), $attr_node->getAttribute('value'));
                    }
                }
            }
        }

        
$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)
    {
        
$this->_url $url;
    }

    
/**
     * This method returns the URL of the current request (without any ticket
     * CGI parameter).
     *
     * @return The URL
     */
    
public function getURL()
    {
        
phpCAS::traceBegin();
        
// the URL is built when needed only
        
if ( empty($this->_url) ) {
            
$final_uri '';
            
// remove the ticket if present in the URL
            
$final_uri = ($this->_isHttps()) ? 'https' 'http';
            
$final_uri .= '://';

            
$final_uri .= $this->_getServerUrl();
            
$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;
    }


    
/**
     * Try to figure out the server URL with possible Proxys / Ports etc.
     *
     * @return string Server URL with domain:port
     */
    
private function _getServerUrl()
    {
        
$server_url '';
        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']);
            
$server_url $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 {
                
$server_port $_SERVER['HTTP_X_FORWARDED_PORT'];
            }

            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 ( isset(
$_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
            return 
true;
        } else {
            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 url with query params
     */
    
private function _buildQueryUrl($url$query)
    {
        
$url .= (strstr($url'?') === false) ? '?' '&';
        
$url .= $query;
        return 
$url;
    }

    
/**
     * Renaming the session
     *
     * @param string $ticket name of the ticket
     *
     * @return void
     */
    
private function _renameSession($ticket)
    {
        
phpCAS::traceBegin();
        if (
$this->getChangeSessionID()) {
            if (!empty(
$this->_user)) {
                
$old_session $_SESSION;
                
session_destroy();
                
// set up a new session, of name based on the ticket
                
$session_id preg_replace('/[^a-zA-Z0-9\-]/'''$ticket);
                
phpCAS :: trace("Session ID: ".$session_id);
                
session_id($session_id);
                
session_start();
                
phpCAS :: trace("Restoring old session vars");
                
$_SESSION $old_session;
            } else {
                
phpCAS :: error('Session should only be renamed after successfull authentication');
            }
        } else {
            
phpCAS :: trace("Skipping session rename since phpCAS is not handling the session.");
        }
        
phpCAS::traceEnd();
    }


    
// ########################################################################
    //  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,
        
$bad_response='',
        
$cas_response='',
        
$err_code='',
        
$err_msg=''
    
) {
        
phpCAS::traceBegin();
        
$lang $this->getLangObj();
        
$this->printHTMLHeader($lang->getAuthenticationFailed());
        
printf($lang->getYouWereNotAuthenticated(), htmlentities($this->getURL()), $_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:
                    if ( empty(
$err_code) ) {
                        
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 string 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)
    {
        
// 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)
    {
        
$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();
    }

    
/** @} */
}

?>

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.1 [PHP 8 Update] [02.02.2022] maintained byC99Shell Github | Generation time: 0.6956 ]--