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