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