1<?php
2
3/**
4 * Licensed to Jasig under one or more contributor license
5 * agreements. See the NOTICE file distributed with this work for
6 * additional information regarding copyright ownership.
7 *
8 * Jasig licenses this file to you under the Apache License,
9 * Version 2.0 (the "License"); you may not use this file except in
10 * compliance with the License. You may obtain a copy of the License at:
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *
21 *
22 * Interface class of the phpCAS library
23 * PHP Version 5
24 *
25 * @file     CAS/CAS.php
26 * @category Authentication
27 * @package  PhpCAS
28 * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
29 * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
30 * @author   Brett Bieber <brett.bieber@gmail.com>
31 * @author   Joachim Fritschi <jfritschi@freenet.de>
32 * @author   Adam Franco <afranco@middlebury.edu>
33 * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
34 * @link     https://wiki.jasig.org/display/CASC/phpCAS
35 * @ingroup public
36 */
37
38
39//
40// hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI']
41// in IIS
42//
43if (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['QUERY_STRING'])) {
44    $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
45}
46
47// Add a E_USER_DEPRECATED for php versions <= 5.2
48if (!defined('E_USER_DEPRECATED')) {
49    define('E_USER_DEPRECATED', E_USER_NOTICE);
50}
51
52
53// ########################################################################
54//  CONSTANTS
55// ########################################################################
56
57// ------------------------------------------------------------------------
58//  CAS VERSIONS
59// ------------------------------------------------------------------------
60
61/**
62 * phpCAS version. accessible for the user by phpCAS::getVersion().
63 */
64define('PHPCAS_VERSION', '1.3.8');
65
66/**
67 * @addtogroup public
68 * @{
69 */
70
71/**
72 * phpCAS supported protocols. accessible for the user by phpCAS::getSupportedProtocols().
73 */
74
75/**
76 * CAS version 1.0
77 */
78define("CAS_VERSION_1_0", '1.0');
79/*!
80 * CAS version 2.0
81*/
82define("CAS_VERSION_2_0", '2.0');
83/**
84 * CAS version 3.0
85 */
86define("CAS_VERSION_3_0", '3.0');
87
88// ------------------------------------------------------------------------
89//  SAML defines
90// ------------------------------------------------------------------------
91
92/**
93 * SAML protocol
94 */
95define("SAML_VERSION_1_1", 'S1');
96
97/**
98 * XML header for SAML POST
99 */
100define("SAML_XML_HEADER", '<?xml version="1.0" encoding="UTF-8"?>');
101
102/**
103 * SOAP envelope for SAML POST
104 */
105define("SAML_SOAP_ENV", '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/>');
106
107/**
108 * SOAP body for SAML POST
109 */
110define("SAML_SOAP_BODY", '<SOAP-ENV:Body>');
111
112/**
113 * SAMLP request
114 */
115define("SAMLP_REQUEST", '<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"  MajorVersion="1" MinorVersion="1" RequestID="_192.168.16.51.1024506224022" IssueInstant="2002-06-19T17:03:44.022Z">');
116define("SAMLP_REQUEST_CLOSE", '</samlp:Request>');
117
118/**
119 * SAMLP artifact tag (for the ticket)
120 */
121define("SAML_ASSERTION_ARTIFACT", '<samlp:AssertionArtifact>');
122
123/**
124 * SAMLP close
125 */
126define("SAML_ASSERTION_ARTIFACT_CLOSE", '</samlp:AssertionArtifact>');
127
128/**
129 * SOAP body close
130 */
131define("SAML_SOAP_BODY_CLOSE", '</SOAP-ENV:Body>');
132
133/**
134 * SOAP envelope close
135 */
136define("SAML_SOAP_ENV_CLOSE", '</SOAP-ENV:Envelope>');
137
138/**
139 * SAML Attributes
140 */
141define("SAML_ATTRIBUTES", 'SAMLATTRIBS');
142
143/**
144 * SAML Attributes
145 */
146define("DEFAULT_ERROR", 'Internal script failure');
147
148/** @} */
149/**
150 * @addtogroup publicPGTStorage
151 * @{
152 */
153// ------------------------------------------------------------------------
154//  FILE PGT STORAGE
155// ------------------------------------------------------------------------
156/**
157 * Default path used when storing PGT's to file
158 */
159define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH", session_save_path());
160/** @} */
161// ------------------------------------------------------------------------
162// SERVICE ACCESS ERRORS
163// ------------------------------------------------------------------------
164/**
165 * @addtogroup publicServices
166 * @{
167 */
168
169/**
170 * phpCAS::service() error code on success
171 */
172define("PHPCAS_SERVICE_OK", 0);
173/**
174 * phpCAS::service() error code when the PT could not retrieve because
175 * the CAS server did not respond.
176 */
177define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE", 1);
178/**
179 * phpCAS::service() error code when the PT could not retrieve because
180 * the response of the CAS server was ill-formed.
181 */
182define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE", 2);
183/**
184 * phpCAS::service() error code when the PT could not retrieve because
185 * the CAS server did not want to.
186 */
187define("PHPCAS_SERVICE_PT_FAILURE", 3);
188/**
189 * phpCAS::service() error code when the service was not available.
190 */
191define("PHPCAS_SERVICE_NOT_AVAILABLE", 4);
192
193// ------------------------------------------------------------------------
194// SERVICE TYPES
195// ------------------------------------------------------------------------
196/**
197 * phpCAS::getProxiedService() type for HTTP GET
198 */
199define("PHPCAS_PROXIED_SERVICE_HTTP_GET", 'CAS_ProxiedService_Http_Get');
200/**
201 * phpCAS::getProxiedService() type for HTTP POST
202 */
203define("PHPCAS_PROXIED_SERVICE_HTTP_POST", 'CAS_ProxiedService_Http_Post');
204/**
205 * phpCAS::getProxiedService() type for IMAP
206 */
207define("PHPCAS_PROXIED_SERVICE_IMAP", 'CAS_ProxiedService_Imap');
208
209
210/** @} */
211// ------------------------------------------------------------------------
212//  LANGUAGES
213// ------------------------------------------------------------------------
214/**
215 * @addtogroup publicLang
216 * @{
217 */
218
219define("PHPCAS_LANG_ENGLISH", 'CAS_Languages_English');
220define("PHPCAS_LANG_FRENCH", 'CAS_Languages_French');
221define("PHPCAS_LANG_GREEK", 'CAS_Languages_Greek');
222define("PHPCAS_LANG_GERMAN", 'CAS_Languages_German');
223define("PHPCAS_LANG_JAPANESE", 'CAS_Languages_Japanese');
224define("PHPCAS_LANG_SPANISH", 'CAS_Languages_Spanish');
225define("PHPCAS_LANG_CATALAN", 'CAS_Languages_Catalan');
226define("PHPCAS_LANG_CHINESE_SIMPLIFIED", 'CAS_Languages_ChineseSimplified');
227
228/** @} */
229
230/**
231 * @addtogroup internalLang
232 * @{
233 */
234
235/**
236 * phpCAS default language (when phpCAS::setLang() is not used)
237 */
238define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH);
239
240/** @} */
241// ------------------------------------------------------------------------
242//  DEBUG
243// ------------------------------------------------------------------------
244/**
245 * @addtogroup publicDebug
246 * @{
247 */
248
249/**
250 * The default directory for the debug file under Unix.
251 * @return  string directory for the debug file
252 */
253function gettmpdir() {
254if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
255if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
256if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
257return "/tmp";
258}
259define('DEFAULT_DEBUG_DIR', gettmpdir()."/");
260
261/** @} */
262
263// include the class autoloader
264require_once dirname(__FILE__) . '/CAS/Autoload.php';
265
266/**
267 * The phpCAS class is a simple container for the phpCAS library. It provides CAS
268 * authentication for web applications written in PHP.
269 *
270 * @ingroup public
271 * @class phpCAS
272 * @category Authentication
273 * @package  PhpCAS
274 * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
275 * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
276 * @author   Brett Bieber <brett.bieber@gmail.com>
277 * @author   Joachim Fritschi <jfritschi@freenet.de>
278 * @author   Adam Franco <afranco@middlebury.edu>
279 * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
280 * @link     https://wiki.jasig.org/display/CASC/phpCAS
281 */
282
283class phpCAS
284{
285
286    /**
287     * This variable is used by the interface class phpCAS.
288     *
289     * @var CAS_Client
290     * @hideinitializer
291     */
292    private static $_PHPCAS_CLIENT;
293
294    /**
295     * @var array
296     * This variable is used to store where the initializer is called from
297     * (to print a comprehensive error in case of multiple calls).
298     *
299     * @hideinitializer
300     */
301    private static $_PHPCAS_INIT_CALL;
302
303    /**
304     * @var array
305     * This variable is used to store phpCAS debug mode.
306     *
307     * @hideinitializer
308     */
309    private static $_PHPCAS_DEBUG;
310
311    /**
312     * This variable is used to enable verbose mode
313     * This pevents debug info to be show to the user. Since it's a security
314     * feature the default is false
315     *
316     * @hideinitializer
317     */
318    private static $_PHPCAS_VERBOSE = false;
319
320
321    // ########################################################################
322    //  INITIALIZATION
323    // ########################################################################
324
325    /**
326     * @addtogroup publicInit
327     * @{
328     */
329
330    /**
331     * phpCAS client initializer.
332     *
333     * @param string $server_version  the version of the CAS server
334     * @param string $server_hostname the hostname of the CAS server
335     * @param int    $server_port     the port the CAS server is running on
336     * @param string $server_uri      the URI the CAS server is responding on
337     * @param bool   $changeSessionID Allow phpCAS to change the session_id (Single
338     * Sign Out/handleLogoutRequests is based on that change)
339     *
340     * @return void a newly created CAS_Client object
341     * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
342     * called, only once, and before all other methods (except phpCAS::getVersion()
343     * and phpCAS::setDebug()).
344     */
345    public static function client($server_version, $server_hostname,
346        $server_port, $server_uri, $changeSessionID = true
347    ) {
348        phpCAS :: traceBegin();
349        if (is_object(self::$_PHPCAS_CLIENT)) {
350            phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
351        }
352
353        // store where the initializer is called from
354        $dbg = debug_backtrace();
355        self::$_PHPCAS_INIT_CALL = array (
356            'done' => true,
357            'file' => $dbg[0]['file'],
358            'line' => $dbg[0]['line'],
359            'method' => __CLASS__ . '::' . __FUNCTION__
360        );
361
362        // initialize the object $_PHPCAS_CLIENT
363        try {
364            self::$_PHPCAS_CLIENT = new CAS_Client(
365                $server_version, false, $server_hostname, $server_port, $server_uri,
366                $changeSessionID
367            );
368        } catch (Exception $e) {
369            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
370        }
371        phpCAS :: traceEnd();
372    }
373
374    /**
375     * phpCAS proxy initializer.
376     *
377     * @param string $server_version  the version of the CAS server
378     * @param string $server_hostname the hostname of the CAS server
379     * @param int    $server_port     the port the CAS server is running on
380     * @param string $server_uri      the URI the CAS server is responding on
381     * @param bool   $changeSessionID Allow phpCAS to change the session_id (Single
382     * Sign Out/handleLogoutRequests is based on that change)
383     *
384     * @return void a newly created CAS_Client object
385     * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
386     * called, only once, and before all other methods (except phpCAS::getVersion()
387     * and phpCAS::setDebug()).
388     */
389    public static function proxy($server_version, $server_hostname,
390        $server_port, $server_uri, $changeSessionID = true
391    ) {
392        phpCAS :: traceBegin();
393        if (is_object(self::$_PHPCAS_CLIENT)) {
394            phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
395        }
396
397        // store where the initialzer is called from
398        $dbg = debug_backtrace();
399        self::$_PHPCAS_INIT_CALL = array (
400            'done' => true,
401            'file' => $dbg[0]['file'],
402            'line' => $dbg[0]['line'],
403            'method' => __CLASS__ . '::' . __FUNCTION__
404        );
405
406        // initialize the object $_PHPCAS_CLIENT
407        try {
408            self::$_PHPCAS_CLIENT = new CAS_Client(
409                $server_version, true, $server_hostname, $server_port, $server_uri,
410                $changeSessionID
411            );
412        } catch (Exception $e) {
413            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
414        }
415        phpCAS :: traceEnd();
416    }
417
418    /**
419     * Answer whether or not the client or proxy has been initialized
420     *
421     * @return bool
422     */
423    public static function isInitialized ()
424    {
425        return (is_object(self::$_PHPCAS_CLIENT));
426    }
427
428    /** @} */
429    // ########################################################################
430    //  DEBUGGING
431    // ########################################################################
432
433    /**
434     * @addtogroup publicDebug
435     * @{
436     */
437
438    /**
439     * Set/unset debug mode
440     *
441     * @param string $filename the name of the file used for logging, or false
442     * to stop debugging.
443     *
444     * @return void
445     */
446    public static function setDebug($filename = '')
447    {
448        if ($filename != false && gettype($filename) != 'string') {
449            phpCAS :: error('type mismatched for parameter $dbg (should be false or the name of the log file)');
450        }
451        if ($filename === false) {
452            self::$_PHPCAS_DEBUG['filename'] = false;
453
454        } else {
455            if (empty ($filename)) {
456                if (preg_match('/^Win.*/', getenv('OS'))) {
457                    if (isset ($_ENV['TMP'])) {
458                        $debugDir = $_ENV['TMP'] . '/';
459                    } else {
460                        $debugDir = '';
461                    }
462                } else {
463                    $debugDir = DEFAULT_DEBUG_DIR;
464                }
465                $filename = $debugDir . 'phpCAS.log';
466            }
467
468            if (empty (self::$_PHPCAS_DEBUG['unique_id'])) {
469                self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);
470            }
471
472            self::$_PHPCAS_DEBUG['filename'] = $filename;
473            self::$_PHPCAS_DEBUG['indent'] = 0;
474
475            phpCAS :: trace('START ('.date("Y-m-d H:i:s").') phpCAS-' . PHPCAS_VERSION . ' ******************');
476        }
477    }
478
479    /**
480     * Enable verbose errors messages in the website output
481     * This is a security relevant since internal status info may leak an may
482     * help an attacker. Default is therefore false
483     *
484     * @param bool $verbose enable verbose output
485     *
486     * @return void
487     */
488    public static function setVerbose($verbose)
489    {
490        if ($verbose === true) {
491            self::$_PHPCAS_VERBOSE = true;
492        } else {
493            self::$_PHPCAS_VERBOSE = false;
494        }
495    }
496
497
498    /**
499     * Show is verbose mode is on
500     *
501     * @return bool verbose
502     */
503    public static function getVerbose()
504    {
505        return self::$_PHPCAS_VERBOSE;
506    }
507
508    /**
509     * Logs a string in debug mode.
510     *
511     * @param string $str the string to write
512     *
513     * @return void
514     * @private
515     */
516    public static function log($str)
517    {
518        $indent_str = ".";
519
520
521        if (!empty(self::$_PHPCAS_DEBUG['filename'])) {
522            // Check if file exists and modifiy file permissions to be only
523            // readable by the webserver
524            if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {
525                touch(self::$_PHPCAS_DEBUG['filename']);
526                // Chmod will fail on windows
527                @chmod(self::$_PHPCAS_DEBUG['filename'], 0600);
528            }
529            for ($i = 0; $i < self::$_PHPCAS_DEBUG['indent']; $i++) {
530
531                $indent_str .= '|    ';
532            }
533            // allow for multiline output with proper identing. Usefull for
534            // dumping cas answers etc.
535            $str2 = str_replace("\n", "\n" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str);
536            error_log(self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2 . "\n", 3, self::$_PHPCAS_DEBUG['filename']);
537        }
538
539    }
540
541    /**
542     * This method is used by interface methods to print an error and where the
543     * function was originally called from.
544     *
545     * @param string $msg the message to print
546     *
547     * @return void
548     * @private
549     */
550    public static function error($msg)
551    {
552        phpCAS :: traceBegin();
553        $dbg = debug_backtrace();
554        $function = '?';
555        $file = '?';
556        $line = '?';
557        if (is_array($dbg)) {
558            for ($i = 1; $i < sizeof($dbg); $i++) {
559                if (is_array($dbg[$i]) && isset($dbg[$i]['class']) ) {
560                    if ($dbg[$i]['class'] == __CLASS__) {
561                        $function = $dbg[$i]['function'];
562                        $file = $dbg[$i]['file'];
563                        $line = $dbg[$i]['line'];
564                    }
565                }
566            }
567        }
568        if (self::$_PHPCAS_VERBOSE) {
569            echo "<br />\n<b>phpCAS error</b>: <font color=\"FF0000\"><b>" . __CLASS__ . "::" . $function . '(): ' . htmlentities($msg) . "</b></font> in <b>" . $file . "</b> on line <b>" . $line . "</b><br />\n";
570        } else {
571            echo "<br />\n<b>Error</b>: <font color=\"FF0000\"><b>". DEFAULT_ERROR ."</b><br />\n";
572        }
573        phpCAS :: trace($msg . ' in ' . $file . 'on line ' . $line );
574        phpCAS :: traceEnd();
575
576        throw new CAS_GracefullTerminationException(__CLASS__ . "::" . $function . '(): ' . $msg);
577    }
578
579    /**
580     * This method is used to log something in debug mode.
581     *
582     * @param string $str string to log
583     *
584     * @return void
585     */
586    public static function trace($str)
587    {
588        $dbg = debug_backtrace();
589        phpCAS :: log($str . ' [' . basename($dbg[0]['file']) . ':' . $dbg[0]['line'] . ']');
590    }
591
592    /**
593     * This method is used to indicate the start of the execution of a function
594     * in debug mode.
595     *
596     * @return void
597     */
598    public static function traceBegin()
599    {
600        $dbg = debug_backtrace();
601        $str = '=> ';
602        if (!empty ($dbg[1]['class'])) {
603            $str .= $dbg[1]['class'] . '::';
604        }
605        $str .= $dbg[1]['function'] . '(';
606        if (is_array($dbg[1]['args'])) {
607            foreach ($dbg[1]['args'] as $index => $arg) {
608                if ($index != 0) {
609                    $str .= ', ';
610                }
611                if (is_object($arg)) {
612                    $str .= get_class($arg);
613                } else {
614                    $str .= str_replace(array("\r\n", "\n", "\r"), "", var_export($arg, true));
615                }
616            }
617        }
618        if (isset($dbg[1]['file'])) {
619            $file = basename($dbg[1]['file']);
620        } else {
621            $file = 'unknown_file';
622        }
623        if (isset($dbg[1]['line'])) {
624            $line = $dbg[1]['line'];
625        } else {
626            $line = 'unknown_line';
627        }
628        $str .= ') [' . $file . ':' . $line . ']';
629        phpCAS :: log($str);
630        if (!isset(self::$_PHPCAS_DEBUG['indent'])) {
631            self::$_PHPCAS_DEBUG['indent'] = 0;
632        } else {
633            self::$_PHPCAS_DEBUG['indent']++;
634        }
635    }
636
637    /**
638     * This method is used to indicate the end of the execution of a function in
639     * debug mode.
640     *
641     * @param mixed $res the result of the function
642     *
643     * @return void
644     */
645    public static function traceEnd($res = '')
646    {
647        if (empty(self::$_PHPCAS_DEBUG['indent'])) {
648            self::$_PHPCAS_DEBUG['indent'] = 0;
649        } else {
650            self::$_PHPCAS_DEBUG['indent']--;
651        }
652        $str = '';
653        if (is_object($res)) {
654            $str .= '<= ' . get_class($res);
655        } else {
656            $str .= '<= ' . str_replace(array("\r\n", "\n", "\r"), "", var_export($res, true));
657        }
658
659        phpCAS :: log($str);
660    }
661
662    /**
663     * This method is used to indicate the end of the execution of the program
664     *
665     * @return void
666     */
667    public static function traceExit()
668    {
669        phpCAS :: log('exit()');
670        while (self::$_PHPCAS_DEBUG['indent'] > 0) {
671            phpCAS :: log('-');
672            self::$_PHPCAS_DEBUG['indent']--;
673        }
674    }
675
676    /** @} */
677    // ########################################################################
678    //  INTERNATIONALIZATION
679    // ########################################################################
680    /**
681    * @addtogroup publicLang
682    * @{
683    */
684
685    /**
686     * This method is used to set the language used by phpCAS.
687     *
688     * @param string $lang string representing the language.
689     *
690     * @return void
691     *
692     * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH
693     * @note Can be called only once.
694     */
695    public static function setLang($lang)
696    {
697        phpCAS::_validateClientExists();
698
699        try {
700            self::$_PHPCAS_CLIENT->setLang($lang);
701        } catch (Exception $e) {
702            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
703        }
704    }
705
706    /** @} */
707    // ########################################################################
708    //  VERSION
709    // ########################################################################
710    /**
711    * @addtogroup public
712    * @{
713    */
714
715    /**
716     * This method returns the phpCAS version.
717     *
718     * @return string the phpCAS version.
719     */
720    public static function getVersion()
721    {
722        return PHPCAS_VERSION;
723    }
724
725    /**
726     * This method returns supported protocols.
727     *
728     * @return array an array of all supported protocols. Use internal protocol name as array key.
729     */
730    public static function getSupportedProtocols()
731    {
732        $supportedProtocols = array();
733        $supportedProtocols[CAS_VERSION_1_0] = 'CAS 1.0';
734        $supportedProtocols[CAS_VERSION_2_0] = 'CAS 2.0';
735        $supportedProtocols[CAS_VERSION_3_0] = 'CAS 3.0';
736        $supportedProtocols[SAML_VERSION_1_1] = 'SAML 1.1';
737
738        return $supportedProtocols;
739    }
740
741    /** @} */
742    // ########################################################################
743    //  HTML OUTPUT
744    // ########################################################################
745    /**
746    * @addtogroup publicOutput
747    * @{
748    */
749
750    /**
751     * This method sets the HTML header used for all outputs.
752     *
753     * @param string $header the HTML header.
754     *
755     * @return void
756     */
757    public static function setHTMLHeader($header)
758    {
759        phpCAS::_validateClientExists();
760
761        try {
762            self::$_PHPCAS_CLIENT->setHTMLHeader($header);
763        } catch (Exception $e) {
764            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
765        }
766    }
767
768    /**
769     * This method sets the HTML footer used for all outputs.
770     *
771     * @param string $footer the HTML footer.
772     *
773     * @return void
774     */
775    public static function setHTMLFooter($footer)
776    {
777        phpCAS::_validateClientExists();
778
779        try {
780            self::$_PHPCAS_CLIENT->setHTMLFooter($footer);
781        } catch (Exception $e) {
782            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
783        }
784    }
785
786    /** @} */
787    // ########################################################################
788    //  PGT STORAGE
789    // ########################################################################
790    /**
791    * @addtogroup publicPGTStorage
792    * @{
793    */
794
795    /**
796     * This method can be used to set a custom PGT storage object.
797     *
798     * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that inherits from the
799     * CAS_PGTStorage_AbstractStorage class
800     *
801     * @return void
802     */
803    public static function setPGTStorage($storage)
804    {
805        phpCAS :: traceBegin();
806        phpCAS::_validateProxyExists();
807
808        try {
809            self::$_PHPCAS_CLIENT->setPGTStorage($storage);
810        } catch (Exception $e) {
811            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
812        }
813        phpCAS :: traceEnd();
814    }
815
816    /**
817     * This method is used to tell phpCAS to store the response of the
818     * CAS server to PGT requests in a database.
819     *
820     * @param string $dsn_or_pdo     a dsn string to use for creating a PDO
821     * object or a PDO object
822     * @param string $username       the username to use when connecting to the
823     * database
824     * @param string $password       the password to use when connecting to the
825     * database
826     * @param string $table          the table to use for storing and retrieving
827     * PGT's
828     * @param string $driver_options any driver options to use when connecting
829     * to the database
830     *
831     * @return void
832     */
833    public static function setPGTStorageDb($dsn_or_pdo, $username='',
834        $password='', $table='', $driver_options=null
835    ) {
836        phpCAS :: traceBegin();
837        phpCAS::_validateProxyExists();
838
839        try {
840            self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);
841        } catch (Exception $e) {
842            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
843        }
844        phpCAS :: traceEnd();
845    }
846
847    /**
848     * This method is used to tell phpCAS to store the response of the
849     * CAS server to PGT requests onto the filesystem.
850     *
851     * @param string $path the path where the PGT's should be stored
852     *
853     * @return void
854     */
855    public static function setPGTStorageFile($path = '')
856    {
857        phpCAS :: traceBegin();
858        phpCAS::_validateProxyExists();
859
860        try {
861            self::$_PHPCAS_CLIENT->setPGTStorageFile($path);
862        } catch (Exception $e) {
863            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
864        }
865        phpCAS :: traceEnd();
866    }
867    /** @} */
868    // ########################################################################
869    // ACCESS TO EXTERNAL SERVICES
870    // ########################################################################
871    /**
872    * @addtogroup publicServices
873    * @{
874    */
875
876    /**
877     * Answer a proxy-authenticated service handler.
878     *
879     * @param string $type The service type. One of
880     * PHPCAS_PROXIED_SERVICE_HTTP_GET; PHPCAS_PROXIED_SERVICE_HTTP_POST;
881     * PHPCAS_PROXIED_SERVICE_IMAP
882     *
883     * @return CAS_ProxiedService
884     * @throws InvalidArgumentException If the service type is unknown.
885     */
886    public static function getProxiedService ($type)
887    {
888        phpCAS :: traceBegin();
889        phpCAS::_validateProxyExists();
890
891        try {
892            $res = self::$_PHPCAS_CLIENT->getProxiedService($type);
893        } catch (Exception $e) {
894            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
895        }
896
897        phpCAS :: traceEnd();
898        return $res;
899    }
900
901    /**
902     * Initialize a proxied-service handler with the proxy-ticket it should use.
903     *
904     * @param CAS_ProxiedService $proxiedService Proxied Service Handler
905     *
906     * @return void
907     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
908     *		The code of the Exception will be one of:
909     *			PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
910     *			PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
911     *			PHPCAS_SERVICE_PT_FAILURE
912     */
913    public static function initializeProxiedService (CAS_ProxiedService $proxiedService)
914    {
915        phpCAS::_validateProxyExists();
916
917        try {
918            self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);
919        } catch (Exception $e) {
920            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
921        }
922    }
923
924    /**
925     * This method is used to access an HTTP[S] service.
926     *
927     * @param string $url       the service to access.
928     * @param int &$err_code an error code Possible values are
929     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
930     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
931     * PHPCAS_SERVICE_NOT_AVAILABLE.
932     * @param string &$output   the output of the service (also used to give an
933     * error message on failure).
934     *
935     * @return bool true on success, false otherwise (in this later case,
936     * $err_code gives the reason why it failed and $output contains an error
937     * message).
938     */
939    public static function serviceWeb($url, & $err_code, & $output)
940    {
941        phpCAS :: traceBegin();
942        phpCAS::_validateProxyExists();
943
944        try {
945            $res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);
946        } catch (Exception $e) {
947            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
948        }
949
950        phpCAS :: traceEnd($res);
951        return $res;
952    }
953
954    /**
955     * This method is used to access an IMAP/POP3/NNTP service.
956     *
957     * @param string $url       a string giving the URL of the service,
958     * including the mailing box for IMAP URLs, as accepted by imap_open().
959     * @param string $service   a string giving for CAS retrieve Proxy ticket
960     * @param string $flags     options given to imap_open().
961     * @param int &$err_code an error code Possible values are
962     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
963     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
964     * PHPCAS_SERVICE_NOT_AVAILABLE.
965     * @param string &$err_msg  an error message on failure
966     * @param string &$pt       the Proxy Ticket (PT) retrieved from the CAS
967     * server to access the URL on success, false on error).
968     *
969     * @return object|false IMAP stream on success, false otherwise (in this later
970     * case, $err_code gives the reason why it failed and $err_msg contains an
971     * error message).
972     */
973    public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt)
974    {
975        phpCAS :: traceBegin();
976        phpCAS::_validateProxyExists();
977
978        try {
979            $res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);
980        } catch (Exception $e) {
981            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
982        }
983
984        phpCAS :: traceEnd($res);
985        return $res;
986    }
987
988    /** @} */
989    // ########################################################################
990    //  AUTHENTICATION
991    // ########################################################################
992    /**
993    * @addtogroup publicAuth
994    * @{
995    */
996
997    /**
998     * Set the times authentication will be cached before really accessing the
999     * CAS server in gateway mode:
1000     * - -1: check only once, and then never again (until you pree login)
1001     * - 0: always check
1002     * - n: check every "n" time
1003     *
1004     * @param int $n an integer.
1005     *
1006     * @return void
1007     */
1008    public static function setCacheTimesForAuthRecheck($n)
1009    {
1010        phpCAS::_validateClientExists();
1011
1012        try {
1013            self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);
1014        } catch (Exception $e) {
1015            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1016        }
1017    }
1018
1019
1020    /**
1021     * Set a callback function to be run when receiving CAS attributes
1022     *
1023     * The callback function will be passed an $success_elements
1024     * payload of the response (\DOMElement) as its first parameter.
1025     *
1026     * @param string $function       Callback function
1027     * @param array  $additionalArgs optional array of arguments
1028     *
1029     * @return void
1030     */
1031    public static function setCasAttributeParserCallback($function, array $additionalArgs = array())
1032    {
1033        phpCAS::_validateClientExists();
1034
1035        self::$_PHPCAS_CLIENT->setCasAttributeParserCallback($function, $additionalArgs);
1036    }
1037
1038    /**
1039     * Set a callback function to be run when a user authenticates.
1040     *
1041     * The callback function will be passed a $logoutTicket as its first
1042     * parameter, followed by any $additionalArgs you pass. The $logoutTicket
1043     * parameter is an opaque string that can be used to map the session-id to
1044     * logout request in order to support single-signout in applications that
1045     * manage their own sessions (rather than letting phpCAS start the session).
1046     *
1047     * phpCAS::forceAuthentication() will always exit and forward client unless
1048     * they are already authenticated. To perform an action at the moment the user
1049     * logs in (such as registering an account, performing logging, etc), register
1050     * a callback function here.
1051     *
1052     * @param callable $function       Callback function
1053     * @param array  $additionalArgs optional array of arguments
1054     *
1055     * @return void
1056     */
1057    public static function setPostAuthenticateCallback ($function, array $additionalArgs = array())
1058    {
1059        phpCAS::_validateClientExists();
1060
1061        self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs);
1062    }
1063
1064    /**
1065     * Set a callback function to be run when a single-signout request is
1066     * received. The callback function will be passed a $logoutTicket as its
1067     * first parameter, followed by any $additionalArgs you pass. The
1068     * $logoutTicket parameter is an opaque string that can be used to map a
1069     * session-id to the logout request in order to support single-signout in
1070     * applications that manage their own sessions (rather than letting phpCAS
1071     * start and destroy the session).
1072     *
1073     * @param callable $function       Callback function
1074     * @param array  $additionalArgs optional array of arguments
1075     *
1076     * @return void
1077     */
1078    public static function setSingleSignoutCallback ($function, array $additionalArgs = array())
1079    {
1080        phpCAS::_validateClientExists();
1081
1082        self::$_PHPCAS_CLIENT->setSingleSignoutCallback($function, $additionalArgs);
1083    }
1084
1085    /**
1086     * This method is called to check if the user is already authenticated
1087     * locally or has a global cas session. A already existing cas session is
1088     * determined by a cas gateway call.(cas login call without any interactive
1089     * prompt)
1090     *
1091     * @return bool true when the user is authenticated, false when a previous
1092     * gateway login failed or the function will not return if the user is
1093     * redirected to the cas server for a gateway login attempt
1094     */
1095    public static function checkAuthentication()
1096    {
1097        phpCAS :: traceBegin();
1098        phpCAS::_validateClientExists();
1099
1100        $auth = self::$_PHPCAS_CLIENT->checkAuthentication();
1101
1102        // store where the authentication has been checked and the result
1103        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
1104
1105        phpCAS :: traceEnd($auth);
1106        return $auth;
1107    }
1108
1109    /**
1110     * This method is called to force authentication if the user was not already
1111     * authenticated. If the user is not authenticated, halt by redirecting to
1112     * the CAS server.
1113     *
1114     * @return bool Authentication
1115     */
1116    public static function forceAuthentication()
1117    {
1118        phpCAS :: traceBegin();
1119        phpCAS::_validateClientExists();
1120        $auth = self::$_PHPCAS_CLIENT->forceAuthentication();
1121
1122        // store where the authentication has been checked and the result
1123        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
1124
1125        /*      if (!$auth) {
1126         phpCAS :: trace('user is not authenticated, redirecting to the CAS server');
1127        self::$_PHPCAS_CLIENT->forceAuthentication();
1128        } else {
1129        phpCAS :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\' is already authenticated)');
1130        }*/
1131
1132        phpCAS :: traceEnd();
1133        return $auth;
1134    }
1135
1136    /**
1137     * This method is called to renew the authentication.
1138     *
1139     * @return void
1140     **/
1141    public static function renewAuthentication()
1142    {
1143        phpCAS :: traceBegin();
1144        phpCAS::_validateClientExists();
1145
1146        $auth = self::$_PHPCAS_CLIENT->renewAuthentication();
1147
1148        // store where the authentication has been checked and the result
1149        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
1150
1151        //self::$_PHPCAS_CLIENT->renewAuthentication();
1152        phpCAS :: traceEnd();
1153    }
1154
1155    /**
1156     * This method is called to check if the user is authenticated (previously or by
1157     * tickets given in the URL).
1158     *
1159     * @return bool true when the user is authenticated.
1160     */
1161    public static function isAuthenticated()
1162    {
1163        phpCAS :: traceBegin();
1164        phpCAS::_validateClientExists();
1165
1166        // call the isAuthenticated method of the $_PHPCAS_CLIENT object
1167        $auth = self::$_PHPCAS_CLIENT->isAuthenticated();
1168
1169        // store where the authentication has been checked and the result
1170        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
1171
1172        phpCAS :: traceEnd($auth);
1173        return $auth;
1174    }
1175
1176    /**
1177     * Checks whether authenticated based on $_SESSION. Useful to avoid
1178     * server calls.
1179     *
1180     * @return bool true if authenticated, false otherwise.
1181     * @since 0.4.22 by Brendan Arnold
1182     */
1183    public static function isSessionAuthenticated()
1184    {
1185        phpCAS::_validateClientExists();
1186
1187        return (self::$_PHPCAS_CLIENT->isSessionAuthenticated());
1188    }
1189
1190    /**
1191     * This method returns the CAS user's login name.
1192     *
1193     * @return string the login name of the authenticated user
1194     * @warning should only be called after phpCAS::forceAuthentication()
1195     * or phpCAS::checkAuthentication().
1196     * */
1197    public static function getUser()
1198    {
1199        phpCAS::_validateClientExists();
1200
1201        try {
1202            return self::$_PHPCAS_CLIENT->getUser();
1203        } catch (Exception $e) {
1204            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1205        }
1206    }
1207
1208    /**
1209     * Answer attributes about the authenticated user.
1210     *
1211     * @warning should only be called after phpCAS::forceAuthentication()
1212     * or phpCAS::checkAuthentication().
1213     *
1214     * @return array
1215     */
1216    public static function getAttributes()
1217    {
1218        phpCAS::_validateClientExists();
1219
1220        try {
1221            return self::$_PHPCAS_CLIENT->getAttributes();
1222        } catch (Exception $e) {
1223            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1224        }
1225    }
1226
1227    /**
1228     * Answer true if there are attributes for the authenticated user.
1229     *
1230     * @warning should only be called after phpCAS::forceAuthentication()
1231     * or phpCAS::checkAuthentication().
1232     *
1233     * @return bool
1234     */
1235    public static function hasAttributes()
1236    {
1237        phpCAS::_validateClientExists();
1238
1239        try {
1240            return self::$_PHPCAS_CLIENT->hasAttributes();
1241        } catch (Exception $e) {
1242            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1243        }
1244    }
1245
1246    /**
1247     * Answer true if an attribute exists for the authenticated user.
1248     *
1249     * @param string $key attribute name
1250     *
1251     * @return bool
1252     * @warning should only be called after phpCAS::forceAuthentication()
1253     * or phpCAS::checkAuthentication().
1254     */
1255    public static function hasAttribute($key)
1256    {
1257        phpCAS::_validateClientExists();
1258
1259        try {
1260            return self::$_PHPCAS_CLIENT->hasAttribute($key);
1261        } catch (Exception $e) {
1262            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1263        }
1264    }
1265
1266    /**
1267     * Answer an attribute for the authenticated user.
1268     *
1269     * @param string $key attribute name
1270     *
1271     * @return mixed string for a single value or an array if multiple values exist.
1272     * @warning should only be called after phpCAS::forceAuthentication()
1273     * or phpCAS::checkAuthentication().
1274     */
1275    public static function getAttribute($key)
1276    {
1277        phpCAS::_validateClientExists();
1278
1279        try {
1280            return self::$_PHPCAS_CLIENT->getAttribute($key);
1281        } catch (Exception $e) {
1282            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1283        }
1284    }
1285
1286    /**
1287     * Handle logout requests.
1288     *
1289     * @param bool  $check_client    additional safety check
1290     * @param array $allowed_clients array of allowed clients
1291     *
1292     * @return void
1293     */
1294    public static function handleLogoutRequests($check_client = true, $allowed_clients = array())
1295    {
1296        phpCAS::_validateClientExists();
1297
1298        return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients));
1299    }
1300
1301    /**
1302     * This method returns the URL to be used to login.
1303     *
1304     * @return string the login URL
1305     */
1306    public static function getServerLoginURL()
1307    {
1308        phpCAS::_validateClientExists();
1309
1310        return self::$_PHPCAS_CLIENT->getServerLoginURL();
1311    }
1312
1313    /**
1314     * Set the login URL of the CAS server.
1315     *
1316     * @param string $url the login URL
1317     *
1318     * @return void
1319     * @since 0.4.21 by Wyman Chan
1320     */
1321    public static function setServerLoginURL($url = '')
1322    {
1323        phpCAS :: traceBegin();
1324        phpCAS::_validateClientExists();
1325
1326        try {
1327            self::$_PHPCAS_CLIENT->setServerLoginURL($url);
1328        } catch (Exception $e) {
1329            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1330        }
1331
1332        phpCAS :: traceEnd();
1333    }
1334
1335    /**
1336     * Set the serviceValidate URL of the CAS server.
1337     * Used for all CAS versions of URL validations.
1338     * Examples:
1339     * CAS 1.0 http://www.exemple.com/validate
1340     * CAS 2.0 http://www.exemple.com/validateURL
1341     * CAS 3.0 http://www.exemple.com/p3/serviceValidate
1342     *
1343     * @param string $url the serviceValidate URL
1344     *
1345     * @return void
1346     */
1347    public static function setServerServiceValidateURL($url = '')
1348    {
1349        phpCAS :: traceBegin();
1350        phpCAS::_validateClientExists();
1351
1352        try {
1353            self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);
1354        } catch (Exception $e) {
1355            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1356        }
1357
1358        phpCAS :: traceEnd();
1359    }
1360
1361    /**
1362     * Set the proxyValidate URL of the CAS server.
1363     * Used for all CAS versions of proxy URL validations
1364     * Examples:
1365     * CAS 1.0 http://www.exemple.com/
1366     * CAS 2.0 http://www.exemple.com/proxyValidate
1367     * CAS 3.0 http://www.exemple.com/p3/proxyValidate
1368     *
1369     * @param string $url the proxyValidate URL
1370     *
1371     * @return void
1372     */
1373    public static function setServerProxyValidateURL($url = '')
1374    {
1375        phpCAS :: traceBegin();
1376        phpCAS::_validateClientExists();
1377
1378        try {
1379            self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);
1380        } catch (Exception $e) {
1381            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1382        }
1383
1384        phpCAS :: traceEnd();
1385    }
1386
1387    /**
1388     * Set the samlValidate URL of the CAS server.
1389     *
1390     * @param string $url the samlValidate URL
1391     *
1392     * @return void
1393     */
1394    public static function setServerSamlValidateURL($url = '')
1395    {
1396        phpCAS :: traceBegin();
1397        phpCAS::_validateClientExists();
1398
1399        try {
1400            self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);
1401        } catch (Exception $e) {
1402            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1403        }
1404
1405        phpCAS :: traceEnd();
1406    }
1407
1408    /**
1409     * This method returns the URL to be used to logout.
1410     *
1411     * @return string the URL to use to log out
1412     */
1413    public static function getServerLogoutURL()
1414    {
1415        phpCAS::_validateClientExists();
1416
1417        return self::$_PHPCAS_CLIENT->getServerLogoutURL();
1418    }
1419
1420    /**
1421     * Set the logout URL of the CAS server.
1422     *
1423     * @param string $url the logout URL
1424     *
1425     * @return void
1426     * @since 0.4.21 by Wyman Chan
1427     */
1428    public static function setServerLogoutURL($url = '')
1429    {
1430        phpCAS :: traceBegin();
1431        phpCAS::_validateClientExists();
1432
1433        try {
1434            self::$_PHPCAS_CLIENT->setServerLogoutURL($url);
1435        } catch (Exception $e) {
1436            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1437        }
1438
1439        phpCAS :: traceEnd();
1440    }
1441
1442    /**
1443     * This method is used to logout from CAS.
1444     *
1445     * @param string $params an array that contains the optional url and
1446     * service parameters that will be passed to the CAS server
1447     *
1448     * @return void
1449     */
1450    public static function logout($params = "")
1451    {
1452        phpCAS :: traceBegin();
1453        phpCAS::_validateClientExists();
1454
1455        $parsedParams = array ();
1456        if ($params != "") {
1457            if (is_string($params)) {
1458                phpCAS :: error('method `phpCAS::logout($url)\' is now deprecated, use `phpCAS::logoutWithUrl($url)\' instead');
1459            }
1460            if (!is_array($params)) {
1461                phpCAS :: error('type mismatched for parameter $params (should be `array\')');
1462            }
1463            foreach ($params as $key => $value) {
1464                if ($key != "service" && $key != "url") {
1465                    phpCAS :: error('only `url\' and `service\' parameters are allowed for method `phpCAS::logout($params)\'');
1466                }
1467                $parsedParams[$key] = $value;
1468            }
1469        }
1470        self::$_PHPCAS_CLIENT->logout($parsedParams);
1471        // never reached
1472        phpCAS :: traceEnd();
1473    }
1474
1475    /**
1476     * This method is used to logout from CAS. Halts by redirecting to the CAS
1477     * server.
1478     *
1479     * @param string $service a URL that will be transmitted to the CAS server
1480     *
1481     * @return void
1482     */
1483    public static function logoutWithRedirectService($service)
1484    {
1485        phpCAS :: traceBegin();
1486        phpCAS::_validateClientExists();
1487
1488        if (!is_string($service)) {
1489            phpCAS :: error('type mismatched for parameter $service (should be `string\')');
1490        }
1491        self::$_PHPCAS_CLIENT->logout(array ( "service" => $service ));
1492        // never reached
1493        phpCAS :: traceEnd();
1494    }
1495
1496    /**
1497     * This method is used to logout from CAS. Halts by redirecting to the CAS
1498     * server.
1499     *
1500     * @param string $url a URL that will be transmitted to the CAS server
1501     *
1502     * @return void
1503     * @deprecated The url parameter has been removed from the CAS server as of
1504     * version 3.3.5.1
1505     */
1506    public static function logoutWithUrl($url)
1507    {
1508        trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
1509        phpCAS :: traceBegin();
1510        if (!is_object(self::$_PHPCAS_CLIENT)) {
1511            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
1512        }
1513        if (!is_string($url)) {
1514            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
1515        }
1516        self::$_PHPCAS_CLIENT->logout(array ( "url" => $url ));
1517        // never reached
1518        phpCAS :: traceEnd();
1519    }
1520
1521    /**
1522     * This method is used to logout from CAS. Halts by redirecting to the CAS
1523     * server.
1524     *
1525     * @param string $service a URL that will be transmitted to the CAS server
1526     * @param string $url     a URL that will be transmitted to the CAS server
1527     *
1528     * @return void
1529     *
1530     * @deprecated The url parameter has been removed from the CAS server as of
1531     * version 3.3.5.1
1532     */
1533    public static function logoutWithRedirectServiceAndUrl($service, $url)
1534    {
1535        trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
1536        phpCAS :: traceBegin();
1537        phpCAS::_validateClientExists();
1538
1539        if (!is_string($service)) {
1540            phpCAS :: error('type mismatched for parameter $service (should be `string\')');
1541        }
1542        if (!is_string($url)) {
1543            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
1544        }
1545        self::$_PHPCAS_CLIENT->logout(
1546            array (
1547                "service" => $service,
1548                "url" => $url
1549            )
1550        );
1551        // never reached
1552        phpCAS :: traceEnd();
1553    }
1554
1555    /**
1556     * Set the fixed URL that will be used by the CAS server to transmit the
1557     * PGT. When this method is not called, a phpCAS script uses its own URL
1558     * for the callback.
1559     *
1560     * @param string $url the URL
1561     *
1562     * @return void
1563     */
1564    public static function setFixedCallbackURL($url = '')
1565    {
1566        phpCAS :: traceBegin();
1567        phpCAS::_validateProxyExists();
1568
1569        try {
1570            self::$_PHPCAS_CLIENT->setCallbackURL($url);
1571        } catch (Exception $e) {
1572            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1573        }
1574
1575        phpCAS :: traceEnd();
1576    }
1577
1578    /**
1579     * Set the fixed URL that will be set as the CAS service parameter. When this
1580     * method is not called, a phpCAS script uses its own URL.
1581     *
1582     * @param string $url the URL
1583     *
1584     * @return void
1585     */
1586    public static function setFixedServiceURL($url)
1587    {
1588        phpCAS :: traceBegin();
1589        phpCAS::_validateProxyExists();
1590
1591        try {
1592            self::$_PHPCAS_CLIENT->setURL($url);
1593        } catch (Exception $e) {
1594            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1595        }
1596
1597        phpCAS :: traceEnd();
1598    }
1599
1600    /**
1601     * Get the URL that is set as the CAS service parameter.
1602     *
1603     * @return string Service Url
1604     */
1605    public static function getServiceURL()
1606    {
1607        phpCAS::_validateProxyExists();
1608        return (self::$_PHPCAS_CLIENT->getURL());
1609    }
1610
1611    /**
1612     * Retrieve a Proxy Ticket from the CAS server.
1613     *
1614     * @param string $target_service Url string of service to proxy
1615     * @param int &$err_code      error code
1616     * @param string &$err_msg       error message
1617     *
1618     * @return string Proxy Ticket
1619     */
1620    public static function retrievePT($target_service, & $err_code, & $err_msg)
1621    {
1622        phpCAS::_validateProxyExists();
1623
1624        try {
1625            return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));
1626        } catch (Exception $e) {
1627            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1628        }
1629    }
1630
1631    /**
1632     * Set the certificate of the CAS server CA and if the CN should be properly
1633     * verified.
1634     *
1635     * @param string $cert        CA certificate file name
1636     * @param bool   $validate_cn Validate CN in certificate (default true)
1637     *
1638     * @return void
1639     */
1640    public static function setCasServerCACert($cert, $validate_cn = true)
1641    {
1642        phpCAS :: traceBegin();
1643        phpCAS::_validateClientExists();
1644
1645        try {
1646            self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);
1647        } catch (Exception $e) {
1648            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1649        }
1650
1651        phpCAS :: traceEnd();
1652    }
1653
1654    /**
1655     * Set no SSL validation for the CAS server.
1656     *
1657     * @return void
1658     */
1659    public static function setNoCasServerValidation()
1660    {
1661        phpCAS :: traceBegin();
1662        phpCAS::_validateClientExists();
1663
1664        phpCAS :: trace('You have configured no validation of the legitimacy of the cas server. This is not recommended for production use.');
1665        self::$_PHPCAS_CLIENT->setNoCasServerValidation();
1666        phpCAS :: traceEnd();
1667    }
1668
1669
1670    /**
1671     * Disable the removal of a CAS-Ticket from the URL when authenticating
1672     * DISABLING POSES A SECURITY RISK:
1673     * We normally remove the ticket by an additional redirect as a security
1674     * precaution to prevent a ticket in the HTTP_REFERRER or be carried over in
1675     * the URL parameter
1676     *
1677     * @return void
1678     */
1679    public static function setNoClearTicketsFromUrl()
1680    {
1681        phpCAS :: traceBegin();
1682        phpCAS::_validateClientExists();
1683
1684        self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl();
1685        phpCAS :: traceEnd();
1686    }
1687
1688    /** @} */
1689
1690    /**
1691     * Change CURL options.
1692     * CURL is used to connect through HTTPS to CAS server
1693     *
1694     * @param string $key   the option key
1695     * @param string $value the value to set
1696     *
1697     * @return void
1698     */
1699    public static function setExtraCurlOption($key, $value)
1700    {
1701        phpCAS :: traceBegin();
1702        phpCAS::_validateClientExists();
1703
1704        self::$_PHPCAS_CLIENT->setExtraCurlOption($key, $value);
1705        phpCAS :: traceEnd();
1706    }
1707
1708    /**
1709     * Set a salt/seed for the session-id hash to make it harder to guess.
1710     *
1711     * When $changeSessionID = true phpCAS will create a session-id that is derived
1712     * from the service ticket. Doing so allows phpCAS to look-up and destroy the
1713     * proper session on single-log-out requests. While the service tickets
1714     * provided by the CAS server may include enough data to generate a strong
1715     * hash, clients may provide an additional salt to ensure that session ids
1716     * are not guessable if the session tickets do not have enough entropy.
1717     *
1718     * @param string $salt The salt to combine with the session ticket.
1719     *
1720     * @return void
1721     */
1722     public static function setSessionIdSalt($salt) {
1723       phpCAS :: traceBegin();
1724       phpCAS::_validateClientExists();
1725       self::$_PHPCAS_CLIENT->setSessionIdSalt($salt);
1726       phpCAS :: traceEnd();
1727     }
1728
1729    /**
1730     * If you want your service to be proxied you have to enable it (default
1731     * disabled) and define an accepable list of proxies that are allowed to
1732     * proxy your service.
1733     *
1734     * Add each allowed proxy definition object. For the normal CAS_ProxyChain
1735     * class, the constructor takes an array of proxies to match. The list is in
1736     * reverse just as seen from the service. Proxies have to be defined in reverse
1737     * from the service to the user. If a user hits service A and gets proxied via
1738     * B to service C the list of acceptable on C would be array(B,A). The definition
1739     * of an individual proxy can be either a string or a regexp (preg_match is used)
1740     * that will be matched against the proxy list supplied by the cas server
1741     * when validating the proxy tickets. The strings are compared starting from
1742     * the beginning and must fully match with the proxies in the list.
1743     * Example:
1744     * 		phpCAS::allowProxyChain(new CAS_ProxyChain(array(
1745     *				'https://app.example.com/'
1746     *			)));
1747     * 		phpCAS::allowProxyChain(new CAS_ProxyChain(array(
1748     *				'/^https:\/\/app[0-9]\.example\.com\/rest\//',
1749     *				'http://client.example.com/'
1750     *			)));
1751     *
1752     * For quick testing or in certain production screnarios you might want to
1753     * allow allow any other valid service to proxy your service. To do so, add
1754     * the "Any" chain:
1755     *		phpCAS::allowProxyChain(new CAS_ProxyChain_Any);
1756     * THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
1757     * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
1758     * ON THIS SERVICE.
1759     *
1760     * @param CAS_ProxyChain_Interface $proxy_chain A proxy-chain that will be
1761     * matched against the proxies requesting access
1762     *
1763     * @return void
1764     */
1765    public static function allowProxyChain(CAS_ProxyChain_Interface $proxy_chain)
1766    {
1767        phpCAS :: traceBegin();
1768        phpCAS::_validateClientExists();
1769
1770        if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0
1771            && self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_3_0
1772        ) {
1773            phpCAS :: error('this method can only be used with the cas 2.0/3.0 protocols');
1774        }
1775        self::$_PHPCAS_CLIENT->getAllowedProxyChains()->allowProxyChain($proxy_chain);
1776        phpCAS :: traceEnd();
1777    }
1778
1779    /**
1780     * Answer an array of proxies that are sitting in front of this application.
1781     * This method will only return a non-empty array if we have received and
1782     * validated a Proxy Ticket.
1783     *
1784     * @return array
1785     * @access public
1786     * @since 6/25/09
1787     */
1788    public static function getProxies ()
1789    {
1790        phpCAS::_validateProxyExists();
1791
1792        return(self::$_PHPCAS_CLIENT->getProxies());
1793    }
1794
1795    // ########################################################################
1796    // PGTIOU/PGTID and logoutRequest rebroadcasting
1797    // ########################################################################
1798
1799    /**
1800     * Add a pgtIou/pgtId and logoutRequest rebroadcast node.
1801     *
1802     * @param string $rebroadcastNodeUrl The rebroadcast node URL. Can be
1803     * hostname or IP.
1804     *
1805     * @return void
1806     */
1807    public static function addRebroadcastNode($rebroadcastNodeUrl)
1808    {
1809        phpCAS::traceBegin();
1810        phpCAS::log('rebroadcastNodeUrl:'.$rebroadcastNodeUrl);
1811        phpCAS::_validateClientExists();
1812
1813        try {
1814            self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);
1815        } catch (Exception $e) {
1816            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1817        }
1818
1819        phpCAS::traceEnd();
1820    }
1821
1822    /**
1823     * This method is used to add header parameters when rebroadcasting
1824     * pgtIou/pgtId or logoutRequest.
1825     *
1826     * @param String $header Header to send when rebroadcasting.
1827     *
1828     * @return void
1829     */
1830    public static function addRebroadcastHeader($header)
1831    {
1832        phpCAS :: traceBegin();
1833        phpCAS::_validateClientExists();
1834
1835        try {
1836            self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);
1837        } catch (Exception $e) {
1838            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
1839        }
1840
1841        phpCAS :: traceEnd();
1842    }
1843
1844    /**
1845     * Checks if a client already exists
1846     *
1847     * @throws CAS_OutOfSequenceBeforeClientException
1848     *
1849     * @return void
1850     */
1851    private static function _validateClientExists()
1852    {
1853        if (!is_object(self::$_PHPCAS_CLIENT)) {
1854            throw new CAS_OutOfSequenceBeforeClientException();
1855        }
1856    }
1857
1858    /**
1859     * Checks of a proxy client aready exists
1860     *
1861     * @throws CAS_OutOfSequenceBeforeProxyException
1862     *
1863     * @return void
1864     */
1865    private static function _validateProxyExists()
1866    {
1867        if (!is_object(self::$_PHPCAS_CLIENT)) {
1868            throw new CAS_OutOfSequenceBeforeProxyException();
1869        }
1870    }
1871
1872    /**
1873     * For testing purposes, use this method to set the client to a test double
1874     *
1875     * @return void
1876     */
1877    public static function setCasClient(\CAS_Client $client)
1878    {
1879        self::$_PHPCAS_CLIENT = $client;
1880    }
1881}
1882// ########################################################################
1883// DOCUMENTATION
1884// ########################################################################
1885
1886// ########################################################################
1887//  MAIN PAGE
1888
1889/**
1890 * @mainpage
1891 *
1892 * The following pages only show the source documentation.
1893 *
1894 */
1895
1896// ########################################################################
1897//  MODULES DEFINITION
1898
1899/** @defgroup public User interface */
1900
1901/** @defgroup publicInit Initialization
1902 *  @ingroup public */
1903
1904/** @defgroup publicAuth Authentication
1905 *  @ingroup public */
1906
1907/** @defgroup publicServices Access to external services
1908 *  @ingroup public */
1909
1910/** @defgroup publicConfig Configuration
1911 *  @ingroup public */
1912
1913/** @defgroup publicLang Internationalization
1914 *  @ingroup publicConfig */
1915
1916/** @defgroup publicOutput HTML output
1917 *  @ingroup publicConfig */
1918
1919/** @defgroup publicPGTStorage PGT storage
1920 *  @ingroup publicConfig */
1921
1922/** @defgroup publicDebug Debugging
1923 *  @ingroup public */
1924
1925/** @defgroup internal Implementation */
1926
1927/** @defgroup internalAuthentication Authentication
1928 *  @ingroup internal */
1929
1930/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets)
1931 *  @ingroup internal */
1932
1933/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets)
1934 *  @ingroup internal */
1935
1936/** @defgroup internalSAML CAS SAML features (SAML 1.1)
1937 *  @ingroup internal */
1938
1939/** @defgroup internalPGTStorage PGT storage
1940 *  @ingroup internalProxy */
1941
1942/** @defgroup internalPGTStorageDb PGT storage in a database
1943 *  @ingroup internalPGTStorage */
1944
1945/** @defgroup internalPGTStorageFile PGT storage on the filesystem
1946 *  @ingroup internalPGTStorage */
1947
1948/** @defgroup internalCallback Callback from the CAS server
1949 *  @ingroup internalProxy */
1950
1951/** @defgroup internalProxyServices Proxy other services
1952 *  @ingroup internalProxy */
1953
1954/** @defgroup internalService CAS client features (CAS 2.0, Proxied service)
1955 *  @ingroup internal */
1956
1957/** @defgroup internalConfig Configuration
1958 *  @ingroup internal */
1959
1960/** @defgroup internalBehave Internal behaviour of phpCAS
1961 *  @ingroup internalConfig */
1962
1963/** @defgroup internalOutput HTML output
1964 *  @ingroup internalConfig */
1965
1966/** @defgroup internalLang Internationalization
1967 *  @ingroup internalConfig
1968 *
1969 * To add a new language:
1970 * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php
1971 * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php
1972 * - 3. Make the translations
1973 */
1974
1975/** @defgroup internalDebug Debugging
1976 *  @ingroup internal */
1977
1978/** @defgroup internalMisc Miscellaneous
1979 *  @ingroup internal */
1980
1981// ########################################################################
1982//  EXAMPLES
1983
1984/**
1985 * @example example_simple.php
1986 */
1987/**
1988 * @example example_service.php
1989 */
1990/**
1991 * @example example_service_that_proxies.php
1992 */
1993/**
1994 * @example example_service_POST.php
1995 */
1996/**
1997 * @example example_proxy_serviceWeb.php
1998 */
1999/**
2000 * @example example_proxy_serviceWeb_chaining.php
2001 */
2002/**
2003 * @example example_proxy_POST.php
2004 */
2005/**
2006 * @example example_proxy_GET.php
2007 */
2008/**
2009 * @example example_lang.php
2010 */
2011/**
2012 * @example example_html.php
2013 */
2014/**
2015 * @example example_pgt_storage_file.php
2016 */
2017/**
2018 * @example example_pgt_storage_db.php
2019 */
2020/**
2021 * @example example_gateway.php
2022 */
2023/**
2024 * @example example_logout.php
2025 */
2026/**
2027 * @example example_rebroadcast.php
2028 */
2029/**
2030 * @example example_custom_urls.php
2031 */
2032/**
2033 * @example example_advanced_saml11.php
2034 */
2035