diff --git a/auth/cas/CAS/CAS.php b/auth/cas/CAS/CAS.php index fbc71d52373..9023d78dd51 100644 --- a/auth/cas/CAS/CAS.php +++ b/auth/cas/CAS/CAS.php @@ -1,1284 +1,1284 @@ -=')) { - require_once(dirname(__FILE__).'/domxml-php4-php5.php'); -} - -/** - * @file CAS/CAS.php - * Interface class of the phpCAS library - * - * @ingroup public - */ - -// ######################################################################## -// CONSTANTS -// ######################################################################## - -// ------------------------------------------------------------------------ -// CAS VERSIONS -// ------------------------------------------------------------------------ - -/** - * phpCAS version. accessible for the user by phpCAS::getVersion(). - */ -define('PHPCAS_VERSION','0.5.1-1'); - -// ------------------------------------------------------------------------ -// CAS VERSIONS -// ------------------------------------------------------------------------ -/** - * @addtogroup public - * @{ - */ - -/** - * CAS version 1.0 - */ -define("CAS_VERSION_1_0",'1.0'); -/*! - * CAS version 2.0 - */ -define("CAS_VERSION_2_0",'2.0'); - -/** @} */ -/** - * @addtogroup publicPGTStorage - * @{ - */ -// ------------------------------------------------------------------------ -// FILE PGT STORAGE -// ------------------------------------------------------------------------ -/** - * Default path used when storing PGT's to file - */ -define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH",'/tmp'); -/** - * phpCAS::setPGTStorageFile()'s 2nd parameter to write plain text files - */ -define("CAS_PGT_STORAGE_FILE_FORMAT_PLAIN",'plain'); -/** - * phpCAS::setPGTStorageFile()'s 2nd parameter to write xml files - */ -define("CAS_PGT_STORAGE_FILE_FORMAT_XML",'xml'); -/** - * Default format used when storing PGT's to file - */ -define("CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT",CAS_PGT_STORAGE_FILE_FORMAT_PLAIN); -// ------------------------------------------------------------------------ -// DATABASE PGT STORAGE -// ------------------------------------------------------------------------ -/** - * default database type when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE",'mysql'); -/** - * default host when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME",'localhost'); -/** - * default port when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_PORT",''); -/** - * default database when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE",'phpCAS'); -/** - * default table when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_TABLE",'pgt'); - -/** @} */ -// ------------------------------------------------------------------------ -// SERVICE ACCESS ERRORS -// ------------------------------------------------------------------------ -/** - * @addtogroup publicServices - * @{ - */ - -/** - * phpCAS::service() error code on success - */ -define("PHPCAS_SERVICE_OK",0); -/** - * phpCAS::service() error code when the PT could not retrieve because - * the CAS server did not respond. - */ -define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE",1); -/** - * phpCAS::service() error code when the PT could not retrieve because - * the response of the CAS server was ill-formed. - */ -define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE",2); -/** - * phpCAS::service() error code when the PT could not retrieve because - * the CAS server did not want to. - */ -define("PHPCAS_SERVICE_PT_FAILURE",3); -/** - * phpCAS::service() error code when the service was not available. - */ -define("PHPCAS_SERVICE_NOT AVAILABLE",4); - -/** @} */ -// ------------------------------------------------------------------------ -// LANGUAGES -// ------------------------------------------------------------------------ -/** - * @addtogroup publicLang - * @{ - */ - -define("PHPCAS_LANG_ENGLISH", 'english'); -define("PHPCAS_LANG_FRENCH", 'french'); -define("PHPCAS_LANG_GREEK", 'greek'); -define("PHPCAS_LANG_GERMAN", 'german'); -define("PHPCAS_LANG_JAPANESE", 'japanese'); - -/** @} */ - -/** - * @addtogroup internalLang - * @{ - */ - -/** - * phpCAS default language (when phpCAS::setLang() is not used) - */ -define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH); - -/** @} */ -// ------------------------------------------------------------------------ -// MISC -// ------------------------------------------------------------------------ -/** - * @addtogroup internalMisc - * @{ - */ - -/** - * This global variable is used by the interface class phpCAS. - * - * @hideinitializer - */ -$PHPCAS_CLIENT = null; - -/** - * This global variable is used to store where the initializer is called from - * (to print a comprehensive error in case of multiple calls). - * - * @hideinitializer - */ -$PHPCAS_INIT_CALL = array('done' => FALSE, - 'file' => '?', - 'line' => -1, - 'method' => '?'); - -/** - * This global variable is used to store where the method checking - * the authentication is called from (to print comprehensive errors) - * - * @hideinitializer - */ -$PHPCAS_AUTH_CHECK_CALL = array('done' => FALSE, - 'file' => '?', - 'line' => -1, - 'method' => '?', - 'result' => FALSE); - -/** - * This global variable is used to store phpCAS debug mode. - * - * @hideinitializer - */ -$PHPCAS_DEBUG = array('filename' => FALSE, - 'indent' => 0, - 'unique_id' => ''); - -/** @} */ - -// ######################################################################## -// CLIENT CLASS -// ######################################################################## - -// include client class -include_once(dirname(__FILE__).'/client.php'); - -// ######################################################################## -// INTERFACE CLASS -// ######################################################################## - -/** - * @class phpCAS - * The phpCAS class is a simple container for the phpCAS library. It provides CAS - * authentication for web applications written in PHP. - * - * @ingroup public - * @author Pascal Aubry - * - * \internal All its methods access the same object ($PHPCAS_CLIENT, declared - * at the end of CAS/client.php). - */ - - - -class phpCAS -{ - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * @addtogroup publicInit - * @{ - */ - - /** - * phpCAS client initializer. - * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be - * called, only once, and before all other methods (except phpCAS::getVersion() - * and phpCAS::setDebug()). - * - * @param $server_version the version of the CAS server - * @param $server_hostname the hostname of the CAS server - * @param $server_port the port the CAS server is running on - * @param $server_uri the URI the CAS server is responding on - * @param $start_session Have phpCAS start PHP sessions (default true) - * - * @return a newly created CASClient object - */ - function client($server_version, - $server_hostname, - $server_port, - $server_uri, - $start_session = true) - { - global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL; - - phpCAS::traceBegin(); - if ( is_object($PHPCAS_CLIENT) ) { - phpCAS::error($PHPCAS_INIT_CALL['method'].'() has already been called (at '.$PHPCAS_INIT_CALL['file'].':'.$PHPCAS_INIT_CALL['line'].')'); - } - if ( gettype($server_version) != 'string' ) { - phpCAS::error('type mismatched for parameter $server_version (should be `string\')'); - } - if ( gettype($server_hostname) != 'string' ) { - phpCAS::error('type mismatched for parameter $server_hostname (should be `string\')'); - } - if ( gettype($server_port) != 'integer' ) { - phpCAS::error('type mismatched for parameter $server_port (should be `integer\')'); - } - if ( gettype($server_uri) != 'string' ) { - phpCAS::error('type mismatched for parameter $server_uri (should be `string\')'); - } - - // store where the initialzer is called from - $dbg = phpCAS::backtrace(); - $PHPCAS_INIT_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__); - - // initialize the global object $PHPCAS_CLIENT - $PHPCAS_CLIENT = new CASClient($server_version,FALSE/*proxy*/,$server_hostname,$server_port,$server_uri,$start_session); - phpCAS::traceEnd(); - } - - /** - * phpCAS proxy initializer. - * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be - * called, only once, and before all other methods (except phpCAS::getVersion() - * and phpCAS::setDebug()). - * - * @param $server_version the version of the CAS server - * @param $server_hostname the hostname of the CAS server - * @param $server_port the port the CAS server is running on - * @param $server_uri the URI the CAS server is responding on - * @param $start_session Have phpCAS start PHP sessions (default true) - * - * @return a newly created CASClient object - */ - function proxy($server_version, - $server_hostname, - $server_port, - $server_uri, - $start_session = true) - { - global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL; - - phpCAS::traceBegin(); - if ( is_object($PHPCAS_CLIENT) ) { - phpCAS::error($PHPCAS_INIT_CALL['method'].'() has already been called (at '.$PHPCAS_INIT_CALL['file'].':'.$PHPCAS_INIT_CALL['line'].')'); - } - if ( gettype($server_version) != 'string' ) { - phpCAS::error('type mismatched for parameter $server_version (should be `string\')'); - } - if ( gettype($server_hostname) != 'string' ) { - phpCAS::error('type mismatched for parameter $server_hostname (should be `string\')'); - } - if ( gettype($server_port) != 'integer' ) { - phpCAS::error('type mismatched for parameter $server_port (should be `integer\')'); - } - if ( gettype($server_uri) != 'string' ) { - phpCAS::error('type mismatched for parameter $server_uri (should be `string\')'); - } - - // store where the initialzer is called from - $dbg = phpCAS::backtrace(); - $PHPCAS_INIT_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__); - - // initialize the global object $PHPCAS_CLIENT - $PHPCAS_CLIENT = new CASClient($server_version,TRUE/*proxy*/,$server_hostname,$server_port,$server_uri,$start_session); - phpCAS::traceEnd(); - } - - /** @} */ - // ######################################################################## - // DEBUGGING - // ######################################################################## - - /** - * @addtogroup publicDebug - * @{ - */ - - /** - * Set/unset debug mode - * - * @param $filename the name of the file used for logging, or FALSE to stop debugging. - */ - function setDebug($filename='') - { - global $PHPCAS_DEBUG; - - if ( $filename != FALSE && gettype($filename) != 'string' ) { - phpCAS::error('type mismatched for parameter $dbg (should be FALSE or the name of the log file)'); - } - - if ( empty($filename) ) { - if ( preg_match('/^Win.*/',getenv('OS')) ) { - if ( isset($_ENV['TMP']) ) { - $debugDir = $_ENV['TMP'].'/'; - } else if ( isset($_ENV['TEMP']) ) { - $debugDir = $_ENV['TEMP'].'/'; - } else { - $debugDir = ''; - } - } else { - $debugDir = '/tmp/'; - } - $filename = $debugDir . 'phpCAS.log'; - } - - if ( empty($PHPCAS_DEBUG['unique_id']) ) { - $PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))),0,4); - } - - $PHPCAS_DEBUG['filename'] = $filename; - - phpCAS::trace('START ******************'); - } - - /** @} */ - /** - * @addtogroup internalDebug - * @{ - */ - - /** - * This method is a wrapper for debug_backtrace() that is not available - * in all PHP versions (>= 4.3.0 only) - */ - function backtrace() - { - if ( function_exists('debug_backtrace') ) { - return debug_backtrace(); - } else { - // poor man's hack ... but it does work ... - return array(); - } - } - - /** - * Logs a string in debug mode. - * - * @param $str the string to write - * - * @private - */ - function log($str) - { - $indent_str = "."; - global $PHPCAS_DEBUG; - - if ( $PHPCAS_DEBUG['filename'] ) { - for ($i=0;$i<$PHPCAS_DEBUG['indent'];$i++) { - $indent_str .= '| '; - } - error_log($PHPCAS_DEBUG['unique_id'].' '.$indent_str.$str."\n",3,$PHPCAS_DEBUG['filename']); - } - - } - - /** - * This method is used by interface methods to print an error and where the function - * was originally called from. - * - * @param $msg the message to print - * - * @private - */ - function error($msg) - { - $dbg = phpCAS::backtrace(); - $function = '?'; - $file = '?'; - $line = '?'; - if ( is_array($dbg) ) { - for ( $i=1; $i\nphpCAS error: ".__CLASS__."::".$function.'(): '.htmlentities($msg)." in ".$file." on line ".$line."
\n"; - phpCAS::trace($msg); - phpCAS::traceExit(); - exit(); - } - - /** - * This method is used to log something in debug mode. - */ - function trace($str) - { - $dbg = phpCAS::backtrace(); - phpCAS::log($str.' ['.basename($dbg[1]['file']).':'.$dbg[1]['line'].']'); - } - - /** - * This method is used to indicate the start of the execution of a function in debug mode. - */ - function traceBegin() - { - global $PHPCAS_DEBUG; - - $dbg = phpCAS::backtrace(); - $str = '=> '; - if ( !empty($dbg[2]['class']) ) { - $str .= $dbg[2]['class'].'::'; - } - $str .= $dbg[2]['function'].'('; - if ( is_array($dbg[2]['args']) ) { - foreach ($dbg[2]['args'] as $index => $arg) { - if ( $index != 0 ) { - $str .= ', '; - } - $str .= str_replace("\n","",var_export($arg,TRUE)); - } - } - $str .= ') ['.basename($dbg[2]['file']).':'.$dbg[2]['line'].']'; - phpCAS::log($str); - $PHPCAS_DEBUG['indent'] ++; - } - - /** - * This method is used to indicate the end of the execution of a function in debug mode. - * - * @param $res the result of the function - */ - function traceEnd($res='') - { - global $PHPCAS_DEBUG; - - $PHPCAS_DEBUG['indent'] --; - $dbg = phpCAS::backtrace(); - $str = ''; - $str .= '<= '.str_replace("\n","",var_export($res,TRUE)); - phpCAS::log($str); - } - - /** - * This method is used to indicate the end of the execution of the program - */ - function traceExit() - { - global $PHPCAS_DEBUG; - - phpCAS::log('exit()'); - while ( $PHPCAS_DEBUG['indent'] > 0 ) { - phpCAS::log('-'); - $PHPCAS_DEBUG['indent'] --; - } - } - - /** @} */ - // ######################################################################## - // INTERNATIONALIZATION - // ######################################################################## - /** - * @addtogroup publicLang - * @{ - */ - - /** - * This method is used to set the language used by phpCAS. - * @note Can be called only once. - * - * @param $lang a string representing the language. - * - * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH - */ - function setLang($lang) - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - if ( gettype($lang) != 'string' ) { - phpCAS::error('type mismatched for parameter $lang (should be `string\')'); - } - $PHPCAS_CLIENT->setLang($lang); - } - - /** @} */ - // ######################################################################## - // VERSION - // ######################################################################## - /** - * @addtogroup public - * @{ - */ - - /** - * This method returns the phpCAS version. - * - * @return the phpCAS version. - */ - function getVersion() - { - return PHPCAS_VERSION; - } - - /** @} */ - // ######################################################################## - // HTML OUTPUT - // ######################################################################## - /** - * @addtogroup publicOutput - * @{ - */ - - /** - * This method sets the HTML header used for all outputs. - * - * @param $header the HTML header. - */ - function setHTMLHeader($header) - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - if ( gettype($header) != 'string' ) { - phpCAS::error('type mismatched for parameter $header (should be `string\')'); - } - $PHPCAS_CLIENT->setHTMLHeader($header); - } - - /** - * This method sets the HTML footer used for all outputs. - * - * @param $footer the HTML footer. - */ - function setHTMLFooter($footer) - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - if ( gettype($footer) != 'string' ) { - phpCAS::error('type mismatched for parameter $footer (should be `string\')'); - } - $PHPCAS_CLIENT->setHTMLFooter($footer); - } - - /** @} */ - // ######################################################################## - // PGT STORAGE - // ######################################################################## - /** - * @addtogroup publicPGTStorage - * @{ - */ - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests onto the filesystem. - * - * @param $format the format used to store the PGT's (`plain' and `xml' allowed) - * @param $path the path where the PGT's should be stored - */ - function setPGTStorageFile($format='', - $path='') - { - global $PHPCAS_CLIENT,$PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( $PHPCAS_AUTH_CHECK_CALL['done'] ) { - phpCAS::error('this method should only be called before '.$PHPCAS_AUTH_CHECK_CALL['method'].'() (called at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].')'); - } - if ( gettype($format) != 'string' ) { - phpCAS::error('type mismatched for parameter $format (should be `string\')'); - } - if ( gettype($path) != 'string' ) { - phpCAS::error('type mismatched for parameter $format (should be `string\')'); - } - $PHPCAS_CLIENT->setPGTStorageFile($format,$path); - phpCAS::traceEnd(); - } - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests into a database. - * @note The connection to the database is done only when needed. - * As a consequence, bad parameters are detected only when - * initializing PGT storage, except in debug mode. - * - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data - */ - function setPGTStorageDB($user, - $password, - $database_type='', - $hostname='', - $port=0, - $database='', - $table='') - { - global $PHPCAS_CLIENT,$PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( $PHPCAS_AUTH_CHECK_CALL['done'] ) { - phpCAS::error('this method should only be called before '.$PHPCAS_AUTH_CHECK_CALL['method'].'() (called at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].')'); - } - if ( gettype($user) != 'string' ) { - phpCAS::error('type mismatched for parameter $user (should be `string\')'); - } - if ( gettype($password) != 'string' ) { - phpCAS::error('type mismatched for parameter $password (should be `string\')'); - } - if ( gettype($database_type) != 'string' ) { - phpCAS::error('type mismatched for parameter $database_type (should be `string\')'); - } - if ( gettype($hostname) != 'string' ) { - phpCAS::error('type mismatched for parameter $hostname (should be `string\')'); - } - if ( gettype($port) != 'integer' ) { - phpCAS::error('type mismatched for parameter $port (should be `integer\')'); - } - if ( gettype($database) != 'string' ) { - phpCAS::error('type mismatched for parameter $database (should be `string\')'); - } - if ( gettype($table) != 'string' ) { - phpCAS::error('type mismatched for parameter $table (should be `string\')'); - } - $PHPCAS_CLIENT->setPGTStorageDB($this,$user,$password,$hostname,$port,$database,$table); - phpCAS::traceEnd(); - } - - /** @} */ - // ######################################################################## - // ACCESS TO EXTERNAL SERVICES - // ######################################################################## - /** - * @addtogroup publicServices - * @{ - */ - - /** - * This method is used to access an HTTP[S] service. - * - * @param $url the service to access. - * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on - * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, - * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. - * @param $output the output of the service (also used to give an error - * message on failure). - * - * @return TRUE on success, FALSE otherwise (in this later case, $err_code - * gives the reason why it failed and $output contains an error message). - */ - function serviceWeb($url,&$err_code,&$output) - { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { - phpCAS::error('this method should only be called after the programmer is sure the user has been authenticated (by calling '.__CLASS__.'::checkAuthentication() or '.__CLASS__.'::forceAuthentication()'); - } - if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { - phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE'); - } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be `string\')'); - } - - $res = $PHPCAS_CLIENT->serviceWeb($url,$err_code,$output); - - phpCAS::traceEnd($res); - return $res; - } - - /** - * This method is used to access an IMAP/POP3/NNTP service. - * - * @param $url a string giving the URL of the service, including the mailing box - * for IMAP URLs, as accepted by imap_open(). - * @param $flags options given to imap_open(). - * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on - * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, - * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. - * @param $err_msg an error message on failure - * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL - * on success, FALSE on error). - * - * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code - * gives the reason why it failed and $err_msg contains an error message). - */ - function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt) - { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { - phpCAS::error('this method should only be called after the programmer is sure the user has been authenticated (by calling '.__CLASS__.'::checkAuthentication() or '.__CLASS__.'::forceAuthentication()'); - } - if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { - phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE'); - } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be `string\')'); - } - - if ( gettype($flags) != 'integer' ) { - phpCAS::error('type mismatched for parameter $flags (should be `integer\')'); - } - - $res = $PHPCAS_CLIENT->serviceMail($url,$flags,$err_code,$err_msg,$pt); - - phpCAS::traceEnd($res); - return $res; - } - - /** @} */ - // ######################################################################## - // AUTHENTICATION - // ######################################################################## - /** - * @addtogroup publicAuth - * @{ - */ - - /** - * Set the times authentication will be cached before really accessing the CAS server in gateway mode: - * - -1: check only once, and then never again (until you pree login) - * - 0: always check - * - n: check every "n" time - * - * @param $n an integer. - */ - function setCacheTimesForAuthRecheck($n) - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - if ( gettype($header) != 'integer' ) { - phpCAS::error('type mismatched for parameter $header (should be `string\')'); - } - $PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n); - } - - /** - * This method is called to check if the user is authenticated (use the gateway feature). - * @return TRUE when the user is authenticated; otherwise FALSE. - */ - function checkAuthentication() - { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - - $auth = $PHPCAS_CLIENT->checkAuthentication(); - - // store where the authentication has been checked and the result - $dbg = phpCAS::backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__, - 'result' => $auth ); - phpCAS::traceEnd($auth); - return $auth; - } - - /** - * This method is called to force authentication if the user was not already - * authenticated. If the user is not authenticated, halt by redirecting to - * the CAS server. - */ - function forceAuthentication() - { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - - $auth = $PHPCAS_CLIENT->forceAuthentication(); - - // store where the authentication has been checked and the result - $dbg = phpCAS::backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__, - 'result' => $auth ); - - if ( !$auth ) { - phpCAS::trace('user is not authenticated, redirecting to the CAS server'); - $PHPCAS_CLIENT->forceAuthentication(); - } else { - phpCAS::trace('no need to authenticate (user `'.phpCAS::getUser().'\' is already authenticated)'); - } - - phpCAS::traceEnd(); - return $auth; - } - - /** - * This method has been left from version 0.4.1 for compatibility reasons. - */ - function authenticate() - { - phpCAS::error('this method is deprecated. You should use '.__CLASS__.'::forceAuthentication() instead'); - } - - /** - * This method is called to check if the user is authenticated (previously or by - * tickets given in the URL). - * - * @return TRUE when the user is authenticated. - */ - function isAuthenticated() - { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - - // call the isAuthenticated method of the global $PHPCAS_CLIENT object - $auth = $PHPCAS_CLIENT->isAuthenticated(); - - // store where the authentication has been checked and the result - $dbg = phpCAS::backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__, - 'result' => $auth ); - phpCAS::traceEnd($auth); - return $auth; - } - - /** - * Checks whether authenticated based on $_SESSION. Useful to avoid - * server calls. - * @return true if authenticated, false otherwise. - * @since 0.4.22 by Brendan Arnold - */ - function isSessionAuthenticated () - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - return($PHPCAS_CLIENT->isSessionAuthenticated()); - } - - /** - * This method returns the CAS user's login name. - * @warning should not be called only after phpCAS::forceAuthentication() - * or phpCAS::checkAuthentication(). - * - * @return the login name of the authenticated user - */ - function getUser() - { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'); - } - if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { - phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE'); - } - return $PHPCAS_CLIENT->getUser(); - } - - /** - * This method returns the URL to be used to login. - * or phpCAS::isAuthenticated(). - * - * @return the login name of the authenticated user - */ - function getServerLoginURL() - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - return $PHPCAS_CLIENT->getServerLoginURL(); - } - - /** - * Set the login URL of the CAS server. - * @param $url the login URL - * @since 0.4.21 by Wyman Chan - */ - function setServerLoginURL($url='') - { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after -'.__CLASS__.'::client()'); - } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be -`string\')'); - } - $PHPCAS_CLIENT->setServerLoginURL($url); - phpCAS::traceEnd(); - } - - /** - * This method returns the URL to be used to login. - * or phpCAS::isAuthenticated(). - * - * @return the login name of the authenticated user - */ - function getServerLogoutURL() - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - return $PHPCAS_CLIENT->getServerLogoutURL(); - } - - /** - * Set the logout URL of the CAS server. - * @param $url the logout URL - * @since 0.4.21 by Wyman Chan - */ - function setServerLogoutURL($url='') - { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after -'.__CLASS__.'::client()'); - } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be -`string\')'); - } - $PHPCAS_CLIENT->setServerLogoutURL($url); - phpCAS::traceEnd(); - } - - /** - * This method is used to logout from CAS. Halts by redirecting to the CAS server. - * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out) - */ - function logout($url = "") - { - global $PHPCAS_CLIENT; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::client() or'.__CLASS__.'::proxy()'); - } - $PHPCAS_CLIENT->logout($url); - // never reached - phpCAS::traceEnd(); - } - - /** - * Set the fixed URL that will be used by the CAS server to transmit the PGT. - * When this method is not called, a phpCAS script uses its own URL for the callback. - * - * @param $url the URL - */ - function setFixedCallbackURL($url='') - { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be `string\')'); - } - $PHPCAS_CLIENT->setCallbackURL($url); - phpCAS::traceEnd(); - } - - /** - * Set the fixed URL that will be set as the CAS service parameter. When this - * method is not called, a phpCAS script uses its own URL. - * - * @param $url the URL - */ - function setFixedServiceURL($url) - { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be `string\')'); - } - $PHPCAS_CLIENT->setURL($url); - phpCAS::traceEnd(); - } - - /** - * Get the URL that is set as the CAS service parameter. - */ - function getServiceURL() - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - return($PHPCAS_CLIENT->getURL()); - } - - /** - * Retrieve a Proxy Ticket from the CAS server. - */ - function retrievePT($target_service,&$err_code,&$err_msg) - { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( gettype($target_service) != 'string' ) { - phpCAS::error('type mismatched for parameter $target_service(should be `string\')'); - } - return($PHPCAS_CLIENT->retrievePT($target_service,$err_code,$err_msg)); - } - /** @} */ - -} - -// ######################################################################## -// DOCUMENTATION -// ######################################################################## - -// ######################################################################## -// MAIN PAGE - -/** - * @mainpage - * - * The following pages only show the source documentation. - * - * For more information on phpCAS, please refer to http://esup-phpcas.sourceforge.net - * - */ - -// ######################################################################## -// MODULES DEFINITION - -/** @defgroup public User interface */ - -/** @defgroup publicInit Initialization - * @ingroup public */ - -/** @defgroup publicAuth Authentication - * @ingroup public */ - -/** @defgroup publicServices Access to external services - * @ingroup public */ - -/** @defgroup publicConfig Configuration - * @ingroup public */ - -/** @defgroup publicLang Internationalization - * @ingroup publicConfig */ - -/** @defgroup publicOutput HTML output - * @ingroup publicConfig */ - -/** @defgroup publicPGTStorage PGT storage - * @ingroup publicConfig */ - -/** @defgroup publicDebug Debugging - * @ingroup public */ - - -/** @defgroup internal Implementation */ - -/** @defgroup internalAuthentication Authentication - * @ingroup internal */ - -/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets) - * @ingroup internal */ - -/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets) - * @ingroup internal */ - -/** @defgroup internalPGTStorage PGT storage - * @ingroup internalProxy */ - -/** @defgroup internalPGTStorageDB PGT storage in a database - * @ingroup internalPGTStorage */ - -/** @defgroup internalPGTStorageFile PGT storage on the filesystem - * @ingroup internalPGTStorage */ - -/** @defgroup internalCallback Callback from the CAS server - * @ingroup internalProxy */ - -/** @defgroup internalProxied CAS proxied client features (CAS 2.0, Proxy Tickets) - * @ingroup internal */ - -/** @defgroup internalConfig Configuration - * @ingroup internal */ - -/** @defgroup internalOutput HTML output - * @ingroup internalConfig */ - -/** @defgroup internalLang Internationalization - * @ingroup internalConfig - * - * To add a new language: - * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php - * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php - * - 3. Make the translations - */ - -/** @defgroup internalDebug Debugging - * @ingroup internal */ - -/** @defgroup internalMisc Miscellaneous - * @ingroup internal */ - -// ######################################################################## -// EXAMPLES - -/** - * @example example_simple.php - */ -/** - * @example example_proxy.php - */ -/** - * @example example_proxy2.php - */ -/** - * @example example_lang.php - */ -/** - * @example example_html.php - */ -/** - * @example example_file.php - */ -/** - * @example example_db.php - */ -/** - * @example example_service.php - */ -/** - * @example example_session_proxy.php - */ -/** - * @example example_session_service.php - */ -/** - * @example example_gateway.php - */ - - - -?> +=')) { + require_once(dirname(__FILE__).'/domxml-php4-php5.php'); +} + +/** + * @file CAS/CAS.php + * Interface class of the phpCAS library + * + * @ingroup public + */ + +// ######################################################################## +// CONSTANTS +// ######################################################################## + +// ------------------------------------------------------------------------ +// CAS VERSIONS +// ------------------------------------------------------------------------ + +/** + * phpCAS version. accessible for the user by phpCAS::getVersion(). + */ +define('PHPCAS_VERSION','0.5.1-1'); + +// ------------------------------------------------------------------------ +// CAS VERSIONS +// ------------------------------------------------------------------------ +/** + * @addtogroup public + * @{ + */ + +/** + * CAS version 1.0 + */ +define("CAS_VERSION_1_0",'1.0'); +/*! + * CAS version 2.0 + */ +define("CAS_VERSION_2_0",'2.0'); + +/** @} */ +/** + * @addtogroup publicPGTStorage + * @{ + */ +// ------------------------------------------------------------------------ +// FILE PGT STORAGE +// ------------------------------------------------------------------------ +/** + * Default path used when storing PGT's to file + */ +define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH",'/tmp'); +/** + * phpCAS::setPGTStorageFile()'s 2nd parameter to write plain text files + */ +define("CAS_PGT_STORAGE_FILE_FORMAT_PLAIN",'plain'); +/** + * phpCAS::setPGTStorageFile()'s 2nd parameter to write xml files + */ +define("CAS_PGT_STORAGE_FILE_FORMAT_XML",'xml'); +/** + * Default format used when storing PGT's to file + */ +define("CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT",CAS_PGT_STORAGE_FILE_FORMAT_PLAIN); +// ------------------------------------------------------------------------ +// DATABASE PGT STORAGE +// ------------------------------------------------------------------------ +/** + * default database type when storing PGT's to database + */ +define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE",'mysql'); +/** + * default host when storing PGT's to database + */ +define("CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME",'localhost'); +/** + * default port when storing PGT's to database + */ +define("CAS_PGT_STORAGE_DB_DEFAULT_PORT",''); +/** + * default database when storing PGT's to database + */ +define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE",'phpCAS'); +/** + * default table when storing PGT's to database + */ +define("CAS_PGT_STORAGE_DB_DEFAULT_TABLE",'pgt'); + +/** @} */ +// ------------------------------------------------------------------------ +// SERVICE ACCESS ERRORS +// ------------------------------------------------------------------------ +/** + * @addtogroup publicServices + * @{ + */ + +/** + * phpCAS::service() error code on success + */ +define("PHPCAS_SERVICE_OK",0); +/** + * phpCAS::service() error code when the PT could not retrieve because + * the CAS server did not respond. + */ +define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE",1); +/** + * phpCAS::service() error code when the PT could not retrieve because + * the response of the CAS server was ill-formed. + */ +define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE",2); +/** + * phpCAS::service() error code when the PT could not retrieve because + * the CAS server did not want to. + */ +define("PHPCAS_SERVICE_PT_FAILURE",3); +/** + * phpCAS::service() error code when the service was not available. + */ +define("PHPCAS_SERVICE_NOT AVAILABLE",4); + +/** @} */ +// ------------------------------------------------------------------------ +// LANGUAGES +// ------------------------------------------------------------------------ +/** + * @addtogroup publicLang + * @{ + */ + +define("PHPCAS_LANG_ENGLISH", 'english'); +define("PHPCAS_LANG_FRENCH", 'french'); +define("PHPCAS_LANG_GREEK", 'greek'); +define("PHPCAS_LANG_GERMAN", 'german'); +define("PHPCAS_LANG_JAPANESE", 'japanese'); + +/** @} */ + +/** + * @addtogroup internalLang + * @{ + */ + +/** + * phpCAS default language (when phpCAS::setLang() is not used) + */ +define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH); + +/** @} */ +// ------------------------------------------------------------------------ +// MISC +// ------------------------------------------------------------------------ +/** + * @addtogroup internalMisc + * @{ + */ + +/** + * This global variable is used by the interface class phpCAS. + * + * @hideinitializer + */ +$PHPCAS_CLIENT = null; + +/** + * This global variable is used to store where the initializer is called from + * (to print a comprehensive error in case of multiple calls). + * + * @hideinitializer + */ +$PHPCAS_INIT_CALL = array('done' => FALSE, + 'file' => '?', + 'line' => -1, + 'method' => '?'); + +/** + * This global variable is used to store where the method checking + * the authentication is called from (to print comprehensive errors) + * + * @hideinitializer + */ +$PHPCAS_AUTH_CHECK_CALL = array('done' => FALSE, + 'file' => '?', + 'line' => -1, + 'method' => '?', + 'result' => FALSE); + +/** + * This global variable is used to store phpCAS debug mode. + * + * @hideinitializer + */ +$PHPCAS_DEBUG = array('filename' => FALSE, + 'indent' => 0, + 'unique_id' => ''); + +/** @} */ + +// ######################################################################## +// CLIENT CLASS +// ######################################################################## + +// include client class +include_once(dirname(__FILE__).'/client.php'); + +// ######################################################################## +// INTERFACE CLASS +// ######################################################################## + +/** + * @class phpCAS + * The phpCAS class is a simple container for the phpCAS library. It provides CAS + * authentication for web applications written in PHP. + * + * @ingroup public + * @author Pascal Aubry + * + * \internal All its methods access the same object ($PHPCAS_CLIENT, declared + * at the end of CAS/client.php). + */ + + + +class phpCAS +{ + + // ######################################################################## + // INITIALIZATION + // ######################################################################## + + /** + * @addtogroup publicInit + * @{ + */ + + /** + * phpCAS client initializer. + * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be + * called, only once, and before all other methods (except phpCAS::getVersion() + * and phpCAS::setDebug()). + * + * @param $server_version the version of the CAS server + * @param $server_hostname the hostname of the CAS server + * @param $server_port the port the CAS server is running on + * @param $server_uri the URI the CAS server is responding on + * @param $start_session Have phpCAS start PHP sessions (default true) + * + * @return a newly created CASClient object + */ + function client($server_version, + $server_hostname, + $server_port, + $server_uri, + $start_session = true) + { + global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL; + + phpCAS::traceBegin(); + if ( is_object($PHPCAS_CLIENT) ) { + phpCAS::error($PHPCAS_INIT_CALL['method'].'() has already been called (at '.$PHPCAS_INIT_CALL['file'].':'.$PHPCAS_INIT_CALL['line'].')'); + } + if ( gettype($server_version) != 'string' ) { + phpCAS::error('type mismatched for parameter $server_version (should be `string\')'); + } + if ( gettype($server_hostname) != 'string' ) { + phpCAS::error('type mismatched for parameter $server_hostname (should be `string\')'); + } + if ( gettype($server_port) != 'integer' ) { + phpCAS::error('type mismatched for parameter $server_port (should be `integer\')'); + } + if ( gettype($server_uri) != 'string' ) { + phpCAS::error('type mismatched for parameter $server_uri (should be `string\')'); + } + + // store where the initialzer is called from + $dbg = phpCAS::backtrace(); + $PHPCAS_INIT_CALL = array('done' => TRUE, + 'file' => $dbg[0]['file'], + 'line' => $dbg[0]['line'], + 'method' => __CLASS__.'::'.__FUNCTION__); + + // initialize the global object $PHPCAS_CLIENT + $PHPCAS_CLIENT = new CASClient($server_version,FALSE/*proxy*/,$server_hostname,$server_port,$server_uri,$start_session); + phpCAS::traceEnd(); + } + + /** + * phpCAS proxy initializer. + * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be + * called, only once, and before all other methods (except phpCAS::getVersion() + * and phpCAS::setDebug()). + * + * @param $server_version the version of the CAS server + * @param $server_hostname the hostname of the CAS server + * @param $server_port the port the CAS server is running on + * @param $server_uri the URI the CAS server is responding on + * @param $start_session Have phpCAS start PHP sessions (default true) + * + * @return a newly created CASClient object + */ + function proxy($server_version, + $server_hostname, + $server_port, + $server_uri, + $start_session = true) + { + global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL; + + phpCAS::traceBegin(); + if ( is_object($PHPCAS_CLIENT) ) { + phpCAS::error($PHPCAS_INIT_CALL['method'].'() has already been called (at '.$PHPCAS_INIT_CALL['file'].':'.$PHPCAS_INIT_CALL['line'].')'); + } + if ( gettype($server_version) != 'string' ) { + phpCAS::error('type mismatched for parameter $server_version (should be `string\')'); + } + if ( gettype($server_hostname) != 'string' ) { + phpCAS::error('type mismatched for parameter $server_hostname (should be `string\')'); + } + if ( gettype($server_port) != 'integer' ) { + phpCAS::error('type mismatched for parameter $server_port (should be `integer\')'); + } + if ( gettype($server_uri) != 'string' ) { + phpCAS::error('type mismatched for parameter $server_uri (should be `string\')'); + } + + // store where the initialzer is called from + $dbg = phpCAS::backtrace(); + $PHPCAS_INIT_CALL = array('done' => TRUE, + 'file' => $dbg[0]['file'], + 'line' => $dbg[0]['line'], + 'method' => __CLASS__.'::'.__FUNCTION__); + + // initialize the global object $PHPCAS_CLIENT + $PHPCAS_CLIENT = new CASClient($server_version,TRUE/*proxy*/,$server_hostname,$server_port,$server_uri,$start_session); + phpCAS::traceEnd(); + } + + /** @} */ + // ######################################################################## + // DEBUGGING + // ######################################################################## + + /** + * @addtogroup publicDebug + * @{ + */ + + /** + * Set/unset debug mode + * + * @param $filename the name of the file used for logging, or FALSE to stop debugging. + */ + function setDebug($filename='') + { + global $PHPCAS_DEBUG; + + if ( $filename != FALSE && gettype($filename) != 'string' ) { + phpCAS::error('type mismatched for parameter $dbg (should be FALSE or the name of the log file)'); + } + + if ( empty($filename) ) { + if ( preg_match('/^Win.*/',getenv('OS')) ) { + if ( isset($_ENV['TMP']) ) { + $debugDir = $_ENV['TMP'].'/'; + } else if ( isset($_ENV['TEMP']) ) { + $debugDir = $_ENV['TEMP'].'/'; + } else { + $debugDir = ''; + } + } else { + $debugDir = '/tmp/'; + } + $filename = $debugDir . 'phpCAS.log'; + } + + if ( empty($PHPCAS_DEBUG['unique_id']) ) { + $PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))),0,4); + } + + $PHPCAS_DEBUG['filename'] = $filename; + + phpCAS::trace('START ******************'); + } + + /** @} */ + /** + * @addtogroup internalDebug + * @{ + */ + + /** + * This method is a wrapper for debug_backtrace() that is not available + * in all PHP versions (>= 4.3.0 only) + */ + function backtrace() + { + if ( function_exists('debug_backtrace') ) { + return debug_backtrace(); + } else { + // poor man's hack ... but it does work ... + return array(); + } + } + + /** + * Logs a string in debug mode. + * + * @param $str the string to write + * + * @private + */ + function log($str) + { + $indent_str = "."; + global $PHPCAS_DEBUG; + + if ( $PHPCAS_DEBUG['filename'] ) { + for ($i=0;$i<$PHPCAS_DEBUG['indent'];$i++) { + $indent_str .= '| '; + } + error_log($PHPCAS_DEBUG['unique_id'].' '.$indent_str.$str."\n",3,$PHPCAS_DEBUG['filename']); + } + + } + + /** + * This method is used by interface methods to print an error and where the function + * was originally called from. + * + * @param $msg the message to print + * + * @private + */ + function error($msg) + { + $dbg = phpCAS::backtrace(); + $function = '?'; + $file = '?'; + $line = '?'; + if ( is_array($dbg) ) { + for ( $i=1; $i\nphpCAS error: ".__CLASS__."::".$function.'(): '.htmlentities($msg)." in ".$file." on line ".$line."
\n"; + phpCAS::trace($msg); + phpCAS::traceExit(); + exit(); + } + + /** + * This method is used to log something in debug mode. + */ + function trace($str) + { + $dbg = phpCAS::backtrace(); + phpCAS::log($str.' ['.basename($dbg[1]['file']).':'.$dbg[1]['line'].']'); + } + + /** + * This method is used to indicate the start of the execution of a function in debug mode. + */ + function traceBegin() + { + global $PHPCAS_DEBUG; + + $dbg = phpCAS::backtrace(); + $str = '=> '; + if ( !empty($dbg[2]['class']) ) { + $str .= $dbg[2]['class'].'::'; + } + $str .= $dbg[2]['function'].'('; + if ( is_array($dbg[2]['args']) ) { + foreach ($dbg[2]['args'] as $index => $arg) { + if ( $index != 0 ) { + $str .= ', '; + } + $str .= str_replace("\n","",var_export($arg,TRUE)); + } + } + $str .= ') ['.basename($dbg[2]['file']).':'.$dbg[2]['line'].']'; + phpCAS::log($str); + $PHPCAS_DEBUG['indent'] ++; + } + + /** + * This method is used to indicate the end of the execution of a function in debug mode. + * + * @param $res the result of the function + */ + function traceEnd($res='') + { + global $PHPCAS_DEBUG; + + $PHPCAS_DEBUG['indent'] --; + $dbg = phpCAS::backtrace(); + $str = ''; + $str .= '<= '.str_replace("\n","",var_export($res,TRUE)); + phpCAS::log($str); + } + + /** + * This method is used to indicate the end of the execution of the program + */ + function traceExit() + { + global $PHPCAS_DEBUG; + + phpCAS::log('exit()'); + while ( $PHPCAS_DEBUG['indent'] > 0 ) { + phpCAS::log('-'); + $PHPCAS_DEBUG['indent'] --; + } + } + + /** @} */ + // ######################################################################## + // INTERNATIONALIZATION + // ######################################################################## + /** + * @addtogroup publicLang + * @{ + */ + + /** + * This method is used to set the language used by phpCAS. + * @note Can be called only once. + * + * @param $lang a string representing the language. + * + * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH + */ + function setLang($lang) + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + if ( gettype($lang) != 'string' ) { + phpCAS::error('type mismatched for parameter $lang (should be `string\')'); + } + $PHPCAS_CLIENT->setLang($lang); + } + + /** @} */ + // ######################################################################## + // VERSION + // ######################################################################## + /** + * @addtogroup public + * @{ + */ + + /** + * This method returns the phpCAS version. + * + * @return the phpCAS version. + */ + function getVersion() + { + return PHPCAS_VERSION; + } + + /** @} */ + // ######################################################################## + // HTML OUTPUT + // ######################################################################## + /** + * @addtogroup publicOutput + * @{ + */ + + /** + * This method sets the HTML header used for all outputs. + * + * @param $header the HTML header. + */ + function setHTMLHeader($header) + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + if ( gettype($header) != 'string' ) { + phpCAS::error('type mismatched for parameter $header (should be `string\')'); + } + $PHPCAS_CLIENT->setHTMLHeader($header); + } + + /** + * This method sets the HTML footer used for all outputs. + * + * @param $footer the HTML footer. + */ + function setHTMLFooter($footer) + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + if ( gettype($footer) != 'string' ) { + phpCAS::error('type mismatched for parameter $footer (should be `string\')'); + } + $PHPCAS_CLIENT->setHTMLFooter($footer); + } + + /** @} */ + // ######################################################################## + // PGT STORAGE + // ######################################################################## + /** + * @addtogroup publicPGTStorage + * @{ + */ + + /** + * This method is used to tell phpCAS to store the response of the + * CAS server to PGT requests onto the filesystem. + * + * @param $format the format used to store the PGT's (`plain' and `xml' allowed) + * @param $path the path where the PGT's should be stored + */ + function setPGTStorageFile($format='', + $path='') + { + global $PHPCAS_CLIENT,$PHPCAS_AUTH_CHECK_CALL; + + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( !$PHPCAS_CLIENT->isProxy() ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( $PHPCAS_AUTH_CHECK_CALL['done'] ) { + phpCAS::error('this method should only be called before '.$PHPCAS_AUTH_CHECK_CALL['method'].'() (called at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].')'); + } + if ( gettype($format) != 'string' ) { + phpCAS::error('type mismatched for parameter $format (should be `string\')'); + } + if ( gettype($path) != 'string' ) { + phpCAS::error('type mismatched for parameter $format (should be `string\')'); + } + $PHPCAS_CLIENT->setPGTStorageFile($format,$path); + phpCAS::traceEnd(); + } + + /** + * This method is used to tell phpCAS to store the response of the + * CAS server to PGT requests into a database. + * @note The connection to the database is done only when needed. + * As a consequence, bad parameters are detected only when + * initializing PGT storage, except in debug mode. + * + * @param $user the user to access the data with + * @param $password the user's password + * @param $database_type the type of the database hosting the data + * @param $hostname the server hosting the database + * @param $port the port the server is listening on + * @param $database the name of the database + * @param $table the name of the table storing the data + */ + function setPGTStorageDB($user, + $password, + $database_type='', + $hostname='', + $port=0, + $database='', + $table='') + { + global $PHPCAS_CLIENT,$PHPCAS_AUTH_CHECK_CALL; + + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( !$PHPCAS_CLIENT->isProxy() ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( $PHPCAS_AUTH_CHECK_CALL['done'] ) { + phpCAS::error('this method should only be called before '.$PHPCAS_AUTH_CHECK_CALL['method'].'() (called at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].')'); + } + if ( gettype($user) != 'string' ) { + phpCAS::error('type mismatched for parameter $user (should be `string\')'); + } + if ( gettype($password) != 'string' ) { + phpCAS::error('type mismatched for parameter $password (should be `string\')'); + } + if ( gettype($database_type) != 'string' ) { + phpCAS::error('type mismatched for parameter $database_type (should be `string\')'); + } + if ( gettype($hostname) != 'string' ) { + phpCAS::error('type mismatched for parameter $hostname (should be `string\')'); + } + if ( gettype($port) != 'integer' ) { + phpCAS::error('type mismatched for parameter $port (should be `integer\')'); + } + if ( gettype($database) != 'string' ) { + phpCAS::error('type mismatched for parameter $database (should be `string\')'); + } + if ( gettype($table) != 'string' ) { + phpCAS::error('type mismatched for parameter $table (should be `string\')'); + } + $PHPCAS_CLIENT->setPGTStorageDB($this,$user,$password,$hostname,$port,$database,$table); + phpCAS::traceEnd(); + } + + /** @} */ + // ######################################################################## + // ACCESS TO EXTERNAL SERVICES + // ######################################################################## + /** + * @addtogroup publicServices + * @{ + */ + + /** + * This method is used to access an HTTP[S] service. + * + * @param $url the service to access. + * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on + * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, + * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. + * @param $output the output of the service (also used to give an error + * message on failure). + * + * @return TRUE on success, FALSE otherwise (in this later case, $err_code + * gives the reason why it failed and $output contains an error message). + */ + function serviceWeb($url,&$err_code,&$output) + { + global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( !$PHPCAS_CLIENT->isProxy() ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { + phpCAS::error('this method should only be called after the programmer is sure the user has been authenticated (by calling '.__CLASS__.'::checkAuthentication() or '.__CLASS__.'::forceAuthentication()'); + } + if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { + phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE'); + } + if ( gettype($url) != 'string' ) { + phpCAS::error('type mismatched for parameter $url (should be `string\')'); + } + + $res = $PHPCAS_CLIENT->serviceWeb($url,$err_code,$output); + + phpCAS::traceEnd($res); + return $res; + } + + /** + * This method is used to access an IMAP/POP3/NNTP service. + * + * @param $url a string giving the URL of the service, including the mailing box + * for IMAP URLs, as accepted by imap_open(). + * @param $flags options given to imap_open(). + * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on + * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, + * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. + * @param $err_msg an error message on failure + * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL + * on success, FALSE on error). + * + * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code + * gives the reason why it failed and $err_msg contains an error message). + */ + function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt) + { + global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( !$PHPCAS_CLIENT->isProxy() ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { + phpCAS::error('this method should only be called after the programmer is sure the user has been authenticated (by calling '.__CLASS__.'::checkAuthentication() or '.__CLASS__.'::forceAuthentication()'); + } + if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { + phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE'); + } + if ( gettype($url) != 'string' ) { + phpCAS::error('type mismatched for parameter $url (should be `string\')'); + } + + if ( gettype($flags) != 'integer' ) { + phpCAS::error('type mismatched for parameter $flags (should be `integer\')'); + } + + $res = $PHPCAS_CLIENT->serviceMail($url,$flags,$err_code,$err_msg,$pt); + + phpCAS::traceEnd($res); + return $res; + } + + /** @} */ + // ######################################################################## + // AUTHENTICATION + // ######################################################################## + /** + * @addtogroup publicAuth + * @{ + */ + + /** + * Set the times authentication will be cached before really accessing the CAS server in gateway mode: + * - -1: check only once, and then never again (until you pree login) + * - 0: always check + * - n: check every "n" time + * + * @param $n an integer. + */ + function setCacheTimesForAuthRecheck($n) + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + if ( gettype($header) != 'integer' ) { + phpCAS::error('type mismatched for parameter $header (should be `string\')'); + } + $PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n); + } + + /** + * This method is called to check if the user is authenticated (use the gateway feature). + * @return TRUE when the user is authenticated; otherwise FALSE. + */ + function checkAuthentication() + { + global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + + $auth = $PHPCAS_CLIENT->checkAuthentication(); + + // store where the authentication has been checked and the result + $dbg = phpCAS::backtrace(); + $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, + 'file' => $dbg[0]['file'], + 'line' => $dbg[0]['line'], + 'method' => __CLASS__.'::'.__FUNCTION__, + 'result' => $auth ); + phpCAS::traceEnd($auth); + return $auth; + } + + /** + * This method is called to force authentication if the user was not already + * authenticated. If the user is not authenticated, halt by redirecting to + * the CAS server. + */ + function forceAuthentication() + { + global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + + $auth = $PHPCAS_CLIENT->forceAuthentication(); + + // store where the authentication has been checked and the result + $dbg = phpCAS::backtrace(); + $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, + 'file' => $dbg[0]['file'], + 'line' => $dbg[0]['line'], + 'method' => __CLASS__.'::'.__FUNCTION__, + 'result' => $auth ); + + if ( !$auth ) { + phpCAS::trace('user is not authenticated, redirecting to the CAS server'); + $PHPCAS_CLIENT->forceAuthentication(); + } else { + phpCAS::trace('no need to authenticate (user `'.phpCAS::getUser().'\' is already authenticated)'); + } + + phpCAS::traceEnd(); + return $auth; + } + + /** + * This method has been left from version 0.4.1 for compatibility reasons. + */ + function authenticate() + { + phpCAS::error('this method is deprecated. You should use '.__CLASS__.'::forceAuthentication() instead'); + } + + /** + * This method is called to check if the user is authenticated (previously or by + * tickets given in the URL). + * + * @return TRUE when the user is authenticated. + */ + function isAuthenticated() + { + global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + + // call the isAuthenticated method of the global $PHPCAS_CLIENT object + $auth = $PHPCAS_CLIENT->isAuthenticated(); + + // store where the authentication has been checked and the result + $dbg = phpCAS::backtrace(); + $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, + 'file' => $dbg[0]['file'], + 'line' => $dbg[0]['line'], + 'method' => __CLASS__.'::'.__FUNCTION__, + 'result' => $auth ); + phpCAS::traceEnd($auth); + return $auth; + } + + /** + * Checks whether authenticated based on $_SESSION. Useful to avoid + * server calls. + * @return true if authenticated, false otherwise. + * @since 0.4.22 by Brendan Arnold + */ + function isSessionAuthenticated () + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + return($PHPCAS_CLIENT->isSessionAuthenticated()); + } + + /** + * This method returns the CAS user's login name. + * @warning should not be called only after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + * + * @return the login name of the authenticated user + */ + function getUser() + { + global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'); + } + if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { + phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE'); + } + return $PHPCAS_CLIENT->getUser(); + } + + /** + * This method returns the URL to be used to login. + * or phpCAS::isAuthenticated(). + * + * @return the login name of the authenticated user + */ + function getServerLoginURL() + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + return $PHPCAS_CLIENT->getServerLoginURL(); + } + + /** + * Set the login URL of the CAS server. + * @param $url the login URL + * @since 0.4.21 by Wyman Chan + */ + function setServerLoginURL($url='') + { + global $PHPCAS_CLIENT; + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after +'.__CLASS__.'::client()'); + } + if ( gettype($url) != 'string' ) { + phpCAS::error('type mismatched for parameter $url (should be +`string\')'); + } + $PHPCAS_CLIENT->setServerLoginURL($url); + phpCAS::traceEnd(); + } + + /** + * This method returns the URL to be used to login. + * or phpCAS::isAuthenticated(). + * + * @return the login name of the authenticated user + */ + function getServerLogoutURL() + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + } + return $PHPCAS_CLIENT->getServerLogoutURL(); + } + + /** + * Set the logout URL of the CAS server. + * @param $url the logout URL + * @since 0.4.21 by Wyman Chan + */ + function setServerLogoutURL($url='') + { + global $PHPCAS_CLIENT; + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after +'.__CLASS__.'::client()'); + } + if ( gettype($url) != 'string' ) { + phpCAS::error('type mismatched for parameter $url (should be +`string\')'); + } + $PHPCAS_CLIENT->setServerLogoutURL($url); + phpCAS::traceEnd(); + } + + /** + * This method is used to logout from CAS. Halts by redirecting to the CAS server. + * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out) + */ + function logout($url = "") + { + global $PHPCAS_CLIENT; + + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::client() or'.__CLASS__.'::proxy()'); + } + $PHPCAS_CLIENT->logout($url); + // never reached + phpCAS::traceEnd(); + } + + /** + * Set the fixed URL that will be used by the CAS server to transmit the PGT. + * When this method is not called, a phpCAS script uses its own URL for the callback. + * + * @param $url the URL + */ + function setFixedCallbackURL($url='') + { + global $PHPCAS_CLIENT; + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( !$PHPCAS_CLIENT->isProxy() ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( gettype($url) != 'string' ) { + phpCAS::error('type mismatched for parameter $url (should be `string\')'); + } + $PHPCAS_CLIENT->setCallbackURL($url); + phpCAS::traceEnd(); + } + + /** + * Set the fixed URL that will be set as the CAS service parameter. When this + * method is not called, a phpCAS script uses its own URL. + * + * @param $url the URL + */ + function setFixedServiceURL($url) + { + global $PHPCAS_CLIENT; + phpCAS::traceBegin(); + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( gettype($url) != 'string' ) { + phpCAS::error('type mismatched for parameter $url (should be `string\')'); + } + $PHPCAS_CLIENT->setURL($url); + phpCAS::traceEnd(); + } + + /** + * Get the URL that is set as the CAS service parameter. + */ + function getServiceURL() + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + return($PHPCAS_CLIENT->getURL()); + } + + /** + * Retrieve a Proxy Ticket from the CAS server. + */ + function retrievePT($target_service,&$err_code,&$err_msg) + { + global $PHPCAS_CLIENT; + if ( !is_object($PHPCAS_CLIENT) ) { + phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + } + if ( gettype($target_service) != 'string' ) { + phpCAS::error('type mismatched for parameter $target_service(should be `string\')'); + } + return($PHPCAS_CLIENT->retrievePT($target_service,$err_code,$err_msg)); + } + /** @} */ + +} + +// ######################################################################## +// DOCUMENTATION +// ######################################################################## + +// ######################################################################## +// MAIN PAGE + +/** + * @mainpage + * + * The following pages only show the source documentation. + * + * For more information on phpCAS, please refer to http://esup-phpcas.sourceforge.net + * + */ + +// ######################################################################## +// MODULES DEFINITION + +/** @defgroup public User interface */ + +/** @defgroup publicInit Initialization + * @ingroup public */ + +/** @defgroup publicAuth Authentication + * @ingroup public */ + +/** @defgroup publicServices Access to external services + * @ingroup public */ + +/** @defgroup publicConfig Configuration + * @ingroup public */ + +/** @defgroup publicLang Internationalization + * @ingroup publicConfig */ + +/** @defgroup publicOutput HTML output + * @ingroup publicConfig */ + +/** @defgroup publicPGTStorage PGT storage + * @ingroup publicConfig */ + +/** @defgroup publicDebug Debugging + * @ingroup public */ + + +/** @defgroup internal Implementation */ + +/** @defgroup internalAuthentication Authentication + * @ingroup internal */ + +/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets) + * @ingroup internal */ + +/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets) + * @ingroup internal */ + +/** @defgroup internalPGTStorage PGT storage + * @ingroup internalProxy */ + +/** @defgroup internalPGTStorageDB PGT storage in a database + * @ingroup internalPGTStorage */ + +/** @defgroup internalPGTStorageFile PGT storage on the filesystem + * @ingroup internalPGTStorage */ + +/** @defgroup internalCallback Callback from the CAS server + * @ingroup internalProxy */ + +/** @defgroup internalProxied CAS proxied client features (CAS 2.0, Proxy Tickets) + * @ingroup internal */ + +/** @defgroup internalConfig Configuration + * @ingroup internal */ + +/** @defgroup internalOutput HTML output + * @ingroup internalConfig */ + +/** @defgroup internalLang Internationalization + * @ingroup internalConfig + * + * To add a new language: + * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php + * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php + * - 3. Make the translations + */ + +/** @defgroup internalDebug Debugging + * @ingroup internal */ + +/** @defgroup internalMisc Miscellaneous + * @ingroup internal */ + +// ######################################################################## +// EXAMPLES + +/** + * @example example_simple.php + */ +/** + * @example example_proxy.php + */ +/** + * @example example_proxy2.php + */ +/** + * @example example_lang.php + */ +/** + * @example example_html.php + */ +/** + * @example example_file.php + */ +/** + * @example example_db.php + */ +/** + * @example example_service.php + */ +/** + * @example example_session_proxy.php + */ +/** + * @example example_session_service.php + */ +/** + * @example example_gateway.php + */ + + + +?> \ No newline at end of file diff --git a/auth/cas/CAS/PGTStorage/pgt-db.php b/auth/cas/CAS/PGTStorage/pgt-db.php index 2e1528c6130..79b8e4262ee 100644 --- a/auth/cas/CAS/PGTStorage/pgt-db.php +++ b/auth/cas/CAS/PGTStorage/pgt-db.php @@ -1,190 +1,190 @@ - - * - * @ingroup internalPGTStorageDB - */ - -class PGTStorageDB extends PGTStorage -{ - /** - * @addtogroup internalPGTStorageDB - * @{ - */ - - /** - * a string representing a PEAR DB URL to connect to the database. Written by - * PGTStorageDB::PGTStorageDB(), read by getURL(). - * - * @hideinitializer - * @private - */ - var $_url=''; - - /** - * This method returns the PEAR DB URL to use to connect to the database. - * - * @return a PEAR DB URL - * - * @private - */ - function getURL() - { - return $this->_url; - } - - /** - * The handle of the connection to the database where PGT's are stored. Written by - * PGTStorageDB::init(), read by getLink(). - * - * @hideinitializer - * @private - */ - var $_link = null; - - /** - * This method returns the handle of the connection to the database where PGT's are - * stored. - * - * @return a handle of connection. - * - * @private - */ - function getLink() - { - return $this->_link; - } - - /** - * The name of the table where PGT's are stored. Written by - * PGTStorageDB::PGTStorageDB(), read by getTable(). - * - * @hideinitializer - * @private - */ - var $_table = ''; - - /** - * This method returns the name of the table where PGT's are stored. - * - * @return the name of a table. - * - * @private - */ - function getTable() - { - return $this->_table; - } - - // ######################################################################## - // DEBUGGING - // ######################################################################## - - /** - * This method returns an informational string giving the type of storage - * used by the object (used for debugging purposes). - * - * @return an informational string. - * @public - */ - function getStorageType() - { - return "database"; - } - - /** - * This method returns an informational string giving informations on the - * parameters of the storage.(used for debugging purposes). - * - * @public - */ - function getStorageInfo() - { - return 'url=`'.$this->getURL().'\', table=`'.$this->getTable().'\''; - } - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - - /** - * The class constructor, called by CASClient::SetPGTStorageDB(). - * - * @param $cas_parent the CASClient instance that creates the object. - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data - * - * @public - */ - function PGTStorageDB($cas_parent,$user,$password,$database_type,$hostname,$port,$database,$table) - { - phpCAS::traceBegin(); - - // call the ancestor's constructor - $this->PGTStorage($cas_parent); - - if ( empty($database_type) ) $database_type = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE; - if ( empty($hostname) ) $hostname = CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME; - if ( $port==0 ) $port = CAS_PGT_STORAGE_DB_DEFAULT_PORT; - if ( empty($database) ) $database = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE; - if ( empty($table) ) $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE; - - // build and store the PEAR DB URL - $this->_url = $database_type.':'.'//'.$user.':'.$password.'@'.$hostname.':'.$port.'/'.$database; - - // XXX should use setURL and setTable - phpCAS::traceEnd(); - } - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * This method is used to initialize the storage. Halts on error. - * - * @public - */ - function init() - { - phpCAS::traceBegin(); - // if the storage has already been initialized, return immediatly - if ( $this->isInitialized() ) - return; - // call the ancestor's method (mark as initialized) - parent::init(); - - // try to connect to the database - $this->_link = DB::connect($this->getURL()); - if ( DB::isError($this->_link) ) { - phpCAS::error('could not connect to database ('.DB::errorMessage($this->_link).')'); - } - var_dump($this->_link); - phpCAS::traceBEnd(); - } - - /** @} */ -} - + + * + * @ingroup internalPGTStorageDB + */ + +class PGTStorageDB extends PGTStorage +{ + /** + * @addtogroup internalPGTStorageDB + * @{ + */ + + /** + * a string representing a PEAR DB URL to connect to the database. Written by + * PGTStorageDB::PGTStorageDB(), read by getURL(). + * + * @hideinitializer + * @private + */ + var $_url=''; + + /** + * This method returns the PEAR DB URL to use to connect to the database. + * + * @return a PEAR DB URL + * + * @private + */ + function getURL() + { + return $this->_url; + } + + /** + * The handle of the connection to the database where PGT's are stored. Written by + * PGTStorageDB::init(), read by getLink(). + * + * @hideinitializer + * @private + */ + var $_link = null; + + /** + * This method returns the handle of the connection to the database where PGT's are + * stored. + * + * @return a handle of connection. + * + * @private + */ + function getLink() + { + return $this->_link; + } + + /** + * The name of the table where PGT's are stored. Written by + * PGTStorageDB::PGTStorageDB(), read by getTable(). + * + * @hideinitializer + * @private + */ + var $_table = ''; + + /** + * This method returns the name of the table where PGT's are stored. + * + * @return the name of a table. + * + * @private + */ + function getTable() + { + return $this->_table; + } + + // ######################################################################## + // DEBUGGING + // ######################################################################## + + /** + * This method returns an informational string giving the type of storage + * used by the object (used for debugging purposes). + * + * @return an informational string. + * @public + */ + function getStorageType() + { + return "database"; + } + + /** + * This method returns an informational string giving informations on the + * parameters of the storage.(used for debugging purposes). + * + * @public + */ + function getStorageInfo() + { + return 'url=`'.$this->getURL().'\', table=`'.$this->getTable().'\''; + } + + // ######################################################################## + // CONSTRUCTOR + // ######################################################################## + + /** + * The class constructor, called by CASClient::SetPGTStorageDB(). + * + * @param $cas_parent the CASClient instance that creates the object. + * @param $user the user to access the data with + * @param $password the user's password + * @param $database_type the type of the database hosting the data + * @param $hostname the server hosting the database + * @param $port the port the server is listening on + * @param $database the name of the database + * @param $table the name of the table storing the data + * + * @public + */ + function PGTStorageDB($cas_parent,$user,$password,$database_type,$hostname,$port,$database,$table) + { + phpCAS::traceBegin(); + + // call the ancestor's constructor + $this->PGTStorage($cas_parent); + + if ( empty($database_type) ) $database_type = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE; + if ( empty($hostname) ) $hostname = CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME; + if ( $port==0 ) $port = CAS_PGT_STORAGE_DB_DEFAULT_PORT; + if ( empty($database) ) $database = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE; + if ( empty($table) ) $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE; + + // build and store the PEAR DB URL + $this->_url = $database_type.':'.'//'.$user.':'.$password.'@'.$hostname.':'.$port.'/'.$database; + + // XXX should use setURL and setTable + phpCAS::traceEnd(); + } + + // ######################################################################## + // INITIALIZATION + // ######################################################################## + + /** + * This method is used to initialize the storage. Halts on error. + * + * @public + */ + function init() + { + phpCAS::traceBegin(); + // if the storage has already been initialized, return immediatly + if ( $this->isInitialized() ) + return; + // call the ancestor's method (mark as initialized) + parent::init(); + + // try to connect to the database + $this->_link = DB::connect($this->getURL()); + if ( DB::isError($this->_link) ) { + phpCAS::error('could not connect to database ('.DB::errorMessage($this->_link).')'); + } + var_dump($this->_link); + phpCAS::traceBEnd(); + } + + /** @} */ +} + ?> \ No newline at end of file diff --git a/auth/cas/CAS/PGTStorage/pgt-file.php b/auth/cas/CAS/PGTStorage/pgt-file.php index 5c211088337..603e7233377 100644 --- a/auth/cas/CAS/PGTStorage/pgt-file.php +++ b/auth/cas/CAS/PGTStorage/pgt-file.php @@ -1,240 +1,240 @@ - - * - * @ingroup internalPGTStorageFile - */ - -class PGTStorageFile extends PGTStorage -{ - /** - * @addtogroup internalPGTStorageFile - * @{ - */ - - /** - * a string telling where PGT's should be stored on the filesystem. Written by - * PGTStorageFile::PGTStorageFile(), read by getPath(). - * - * @private - */ - var $_path; - - /** - * This method returns the name of the directory where PGT's should be stored - * on the filesystem. - * - * @return the name of a directory (with leading and trailing '/') - * - * @private - */ - function getPath() - { - return $this->_path; - } - - /** - * a string telling the format to use to store PGT's (plain or xml). Written by - * PGTStorageFile::PGTStorageFile(), read by getFormat(). - * - * @private - */ - var $_format; - - /** - * This method returns the format to use when storing PGT's on the filesystem. - * - * @return a string corresponding to the format used (plain or xml). - * - * @private - */ - function getFormat() - { - return $this->_format; - } - - // ######################################################################## - // DEBUGGING - // ######################################################################## - - /** - * This method returns an informational string giving the type of storage - * used by the object (used for debugging purposes). - * - * @return an informational string. - * @public - */ - function getStorageType() - { - return "file"; - } - - /** - * This method returns an informational string giving informations on the - * parameters of the storage.(used for debugging purposes). - * - * @return an informational string. - * @public - */ - function getStorageInfo() - { - return 'path=`'.$this->getPath().'\', format=`'.$this->getFormat().'\''; - } - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - - /** - * The class constructor, called by CASClient::SetPGTStorageFile(). - * - * @param $cas_parent the CASClient instance that creates the object. - * @param $format the format used to store the PGT's (`plain' and `xml' allowed). - * @param $path the path where the PGT's should be stored - * - * @public - */ - function PGTStorageFile($cas_parent,$format,$path) - { - phpCAS::traceBegin(); - // call the ancestor's constructor - $this->PGTStorage($cas_parent); - - if (empty($format) ) $format = CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT; - if (empty($path) ) $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH; - - // check that the path is an absolute path - if ( $path[0] != '/' ) { - phpCAS::error('an absolute path is needed for PGT storage to file'); - } - - // store the path (with a leading and trailing '/') - $path = preg_replace('|[/]*$|','/',$path); - $path = preg_replace('|^[/]*|','/',$path); - $this->_path = $path; - - // check the format and store it - switch ($format) { - case CAS_PGT_STORAGE_FILE_FORMAT_PLAIN: - case CAS_PGT_STORAGE_FILE_FORMAT_XML: - $this->_format = $format; - break; - default: - phpCAS::error('unknown PGT file storage format (`'.CAS_PGT_STORAGE_FILE_FORMAT_PLAIN.'\' and `'.CAS_PGT_STORAGE_FILE_FORMAT_XML.'\' allowed)'); - } - phpCAS::traceEnd(); - } - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * This method is used to initialize the storage. Halts on error. - * - * @public - */ - function init() - { - phpCAS::traceBegin(); - // if the storage has already been initialized, return immediatly - if ( $this->isInitialized() ) - return; - // call the ancestor's method (mark as initialized) - parent::init(); - phpCAS::traceEnd(); - } - - // ######################################################################## - // PGT I/O - // ######################################################################## - - /** - * This method returns the filename corresponding to a PGT Iou. - * - * @param $pgt_iou the PGT iou. - * - * @return a filename - * @private - */ - function getPGTIouFilename($pgt_iou) - { - phpCAS::traceBegin(); - $filename = $this->getPath().$pgt_iou.'.'.$this->getFormat(); - - phpCAS::traceEnd($filename); - return $filename; - } - - /** - * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a - * warning on error. - * - * @param $pgt the PGT - * @param $pgt_iou the PGT iou - * - * @public - */ - function write($pgt,$pgt_iou) - { - phpCAS::traceBegin(); - $fname = $this->getPGTIouFilename($pgt_iou); - if ( $f=fopen($fname,"w") ) { - if ( fputs($f,$pgt) === FALSE ) { - phpCAS::error('could not write PGT to `'.$fname.'\''); - } - fclose($f); - } else { - phpCAS::error('could not open `'.$fname.'\''); - } - phpCAS::traceEnd(); - } - - /** - * This method reads a PGT corresponding to a PGT Iou and deletes the - * corresponding file. - * - * @param $pgt_iou the PGT iou - * - * @return the corresponding PGT, or FALSE on error - * - * @public - */ - function read($pgt_iou) - { - phpCAS::traceBegin(); - $pgt = FALSE; - $fname = $this->getPGTIouFilename($pgt_iou); - - if ( !($f=fopen($fname,"r")) ) { - phpCAS::trace('could not open `'.$fname.'\''); - } else { - if ( ($pgt=fgets($f)) === FALSE ) { - phpCAS::trace('could not read PGT from `'.$fname.'\''); - } - fclose($f); - } - - // delete the PGT file - @unlink($fname); - - phpCAS::traceEnd($pgt); - return $pgt; - } - - /** @} */ - -} - - -?> + + * + * @ingroup internalPGTStorageFile + */ + +class PGTStorageFile extends PGTStorage +{ + /** + * @addtogroup internalPGTStorageFile + * @{ + */ + + /** + * a string telling where PGT's should be stored on the filesystem. Written by + * PGTStorageFile::PGTStorageFile(), read by getPath(). + * + * @private + */ + var $_path; + + /** + * This method returns the name of the directory where PGT's should be stored + * on the filesystem. + * + * @return the name of a directory (with leading and trailing '/') + * + * @private + */ + function getPath() + { + return $this->_path; + } + + /** + * a string telling the format to use to store PGT's (plain or xml). Written by + * PGTStorageFile::PGTStorageFile(), read by getFormat(). + * + * @private + */ + var $_format; + + /** + * This method returns the format to use when storing PGT's on the filesystem. + * + * @return a string corresponding to the format used (plain or xml). + * + * @private + */ + function getFormat() + { + return $this->_format; + } + + // ######################################################################## + // DEBUGGING + // ######################################################################## + + /** + * This method returns an informational string giving the type of storage + * used by the object (used for debugging purposes). + * + * @return an informational string. + * @public + */ + function getStorageType() + { + return "file"; + } + + /** + * This method returns an informational string giving informations on the + * parameters of the storage.(used for debugging purposes). + * + * @return an informational string. + * @public + */ + function getStorageInfo() + { + return 'path=`'.$this->getPath().'\', format=`'.$this->getFormat().'\''; + } + + // ######################################################################## + // CONSTRUCTOR + // ######################################################################## + + /** + * The class constructor, called by CASClient::SetPGTStorageFile(). + * + * @param $cas_parent the CASClient instance that creates the object. + * @param $format the format used to store the PGT's (`plain' and `xml' allowed). + * @param $path the path where the PGT's should be stored + * + * @public + */ + function PGTStorageFile($cas_parent,$format,$path) + { + phpCAS::traceBegin(); + // call the ancestor's constructor + $this->PGTStorage($cas_parent); + + if (empty($format) ) $format = CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT; + if (empty($path) ) $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH; + + // check that the path is an absolute path + if ( $path[0] != '/' ) { + phpCAS::error('an absolute path is needed for PGT storage to file'); + } + + // store the path (with a leading and trailing '/') + $path = preg_replace('|[/]*$|','/',$path); + $path = preg_replace('|^[/]*|','/',$path); + $this->_path = $path; + + // check the format and store it + switch ($format) { + case CAS_PGT_STORAGE_FILE_FORMAT_PLAIN: + case CAS_PGT_STORAGE_FILE_FORMAT_XML: + $this->_format = $format; + break; + default: + phpCAS::error('unknown PGT file storage format (`'.CAS_PGT_STORAGE_FILE_FORMAT_PLAIN.'\' and `'.CAS_PGT_STORAGE_FILE_FORMAT_XML.'\' allowed)'); + } + phpCAS::traceEnd(); + } + + // ######################################################################## + // INITIALIZATION + // ######################################################################## + + /** + * This method is used to initialize the storage. Halts on error. + * + * @public + */ + function init() + { + phpCAS::traceBegin(); + // if the storage has already been initialized, return immediatly + if ( $this->isInitialized() ) + return; + // call the ancestor's method (mark as initialized) + parent::init(); + phpCAS::traceEnd(); + } + + // ######################################################################## + // PGT I/O + // ######################################################################## + + /** + * This method returns the filename corresponding to a PGT Iou. + * + * @param $pgt_iou the PGT iou. + * + * @return a filename + * @private + */ + function getPGTIouFilename($pgt_iou) + { + phpCAS::traceBegin(); + $filename = $this->getPath().$pgt_iou.'.'.$this->getFormat(); + + phpCAS::traceEnd($filename); + return $filename; + } + + /** + * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a + * warning on error. + * + * @param $pgt the PGT + * @param $pgt_iou the PGT iou + * + * @public + */ + function write($pgt,$pgt_iou) + { + phpCAS::traceBegin(); + $fname = $this->getPGTIouFilename($pgt_iou); + if ( $f=fopen($fname,"w") ) { + if ( fputs($f,$pgt) === FALSE ) { + phpCAS::error('could not write PGT to `'.$fname.'\''); + } + fclose($f); + } else { + phpCAS::error('could not open `'.$fname.'\''); + } + phpCAS::traceEnd(); + } + + /** + * This method reads a PGT corresponding to a PGT Iou and deletes the + * corresponding file. + * + * @param $pgt_iou the PGT iou + * + * @return the corresponding PGT, or FALSE on error + * + * @public + */ + function read($pgt_iou) + { + phpCAS::traceBegin(); + $pgt = FALSE; + $fname = $this->getPGTIouFilename($pgt_iou); + + if ( !($f=fopen($fname,"r")) ) { + phpCAS::trace('could not open `'.$fname.'\''); + } else { + if ( ($pgt=fgets($f)) === FALSE ) { + phpCAS::trace('could not read PGT from `'.$fname.'\''); + } + fclose($f); + } + + // delete the PGT file + @unlink($fname); + + phpCAS::traceEnd($pgt); + return $pgt; + } + + /** @} */ + +} + + +?> \ No newline at end of file diff --git a/auth/cas/CAS/PGTStorage/pgt-main.php b/auth/cas/CAS/PGTStorage/pgt-main.php index f8485313225..14338043b67 100644 --- a/auth/cas/CAS/PGTStorage/pgt-main.php +++ b/auth/cas/CAS/PGTStorage/pgt-main.php @@ -1,188 +1,188 @@ - - * - * @ingroup internalPGTStorage - */ - -class PGTStorage -{ - /** - * @addtogroup internalPGTStorage - * @{ - */ - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - - /** - * The constructor of the class, should be called only by inherited classes. - * - * @param $cas_parent the CASclient instance that creates the current object. - * - * @protected - */ - function PGTStorage($cas_parent) - { - phpCAS::traceBegin(); - if ( !$cas_parent->isProxy() ) { - phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy'); - } - phpCAS::traceEnd(); - } - - // ######################################################################## - // DEBUGGING - // ######################################################################## - - /** - * This virtual method returns an informational string giving the type of storage - * used by the object (used for debugging purposes). - * - * @public - */ - function getStorageType() - { - phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); - } - - /** - * This virtual method returns an informational string giving informations on the - * parameters of the storage.(used for debugging purposes). - * - * @public - */ - function getStorageInfo() - { - phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); - } - - // ######################################################################## - // ERROR HANDLING - // ######################################################################## - - /** - * string used to store an error message. Written by PGTStorage::setErrorMessage(), - * read by PGTStorage::getErrorMessage(). - * - * @hideinitializer - * @private - * @deprecated not used. - */ - var $_error_message=FALSE; - - /** - * This method sets en error message, which can be read later by - * PGTStorage::getErrorMessage(). - * - * @param $error_message an error message - * - * @protected - * @deprecated not used. - */ - function setErrorMessage($error_message) - { - $this->_error_message = $error_message; - } - - /** - * This method returns an error message set by PGTStorage::setErrorMessage(). - * - * @return an error message when set by PGTStorage::setErrorMessage(), FALSE - * otherwise. - * - * @public - * @deprecated not used. - */ - function getErrorMessage() - { - return $this->_error_message; - } - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * a boolean telling if the storage has already been initialized. Written by - * PGTStorage::init(), read by PGTStorage::isInitialized(). - * - * @hideinitializer - * @private - */ - var $_initialized = FALSE; - - /** - * This method tells if the storage has already been intialized. - * - * @return a boolean - * - * @protected - */ - function isInitialized() - { - return $this->_initialized; - } - - /** - * This virtual method initializes the object. - * - * @protected - */ - function init() - { - $this->_initialized = TRUE; - } - - // ######################################################################## - // PGT I/O - // ######################################################################## - - /** - * This virtual method stores a PGT and its corresponding PGT Iuo. - * @note Should never be called. - * - * @param $pgt the PGT - * @param $pgt_iou the PGT iou - * - * @protected - */ - function write($pgt,$pgt_iou) - { - phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); - } - - /** - * This virtual method reads a PGT corresponding to a PGT Iou and deletes - * the corresponding storage entry. - * @note Should never be called. - * - * @param $pgt_iou the PGT iou - * - * @protected - */ - function read($pgt_iou) - { - phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); - } - - /** @} */ - -} - -// include specific PGT storage classes -include_once(dirname(__FILE__).'/pgt-file.php'); -include_once(dirname(__FILE__).'/pgt-db.php'); - -?> + + * + * @ingroup internalPGTStorage + */ + +class PGTStorage +{ + /** + * @addtogroup internalPGTStorage + * @{ + */ + + // ######################################################################## + // CONSTRUCTOR + // ######################################################################## + + /** + * The constructor of the class, should be called only by inherited classes. + * + * @param $cas_parent the CASclient instance that creates the current object. + * + * @protected + */ + function PGTStorage($cas_parent) + { + phpCAS::traceBegin(); + if ( !$cas_parent->isProxy() ) { + phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy'); + } + phpCAS::traceEnd(); + } + + // ######################################################################## + // DEBUGGING + // ######################################################################## + + /** + * This virtual method returns an informational string giving the type of storage + * used by the object (used for debugging purposes). + * + * @public + */ + function getStorageType() + { + phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); + } + + /** + * This virtual method returns an informational string giving informations on the + * parameters of the storage.(used for debugging purposes). + * + * @public + */ + function getStorageInfo() + { + phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); + } + + // ######################################################################## + // ERROR HANDLING + // ######################################################################## + + /** + * string used to store an error message. Written by PGTStorage::setErrorMessage(), + * read by PGTStorage::getErrorMessage(). + * + * @hideinitializer + * @private + * @deprecated not used. + */ + var $_error_message=FALSE; + + /** + * This method sets en error message, which can be read later by + * PGTStorage::getErrorMessage(). + * + * @param $error_message an error message + * + * @protected + * @deprecated not used. + */ + function setErrorMessage($error_message) + { + $this->_error_message = $error_message; + } + + /** + * This method returns an error message set by PGTStorage::setErrorMessage(). + * + * @return an error message when set by PGTStorage::setErrorMessage(), FALSE + * otherwise. + * + * @public + * @deprecated not used. + */ + function getErrorMessage() + { + return $this->_error_message; + } + + // ######################################################################## + // INITIALIZATION + // ######################################################################## + + /** + * a boolean telling if the storage has already been initialized. Written by + * PGTStorage::init(), read by PGTStorage::isInitialized(). + * + * @hideinitializer + * @private + */ + var $_initialized = FALSE; + + /** + * This method tells if the storage has already been intialized. + * + * @return a boolean + * + * @protected + */ + function isInitialized() + { + return $this->_initialized; + } + + /** + * This virtual method initializes the object. + * + * @protected + */ + function init() + { + $this->_initialized = TRUE; + } + + // ######################################################################## + // PGT I/O + // ######################################################################## + + /** + * This virtual method stores a PGT and its corresponding PGT Iuo. + * @note Should never be called. + * + * @param $pgt the PGT + * @param $pgt_iou the PGT iou + * + * @protected + */ + function write($pgt,$pgt_iou) + { + phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); + } + + /** + * This virtual method reads a PGT corresponding to a PGT Iou and deletes + * the corresponding storage entry. + * @note Should never be called. + * + * @param $pgt_iou the PGT iou + * + * @protected + */ + function read($pgt_iou) + { + phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); + } + + /** @} */ + +} + +// include specific PGT storage classes +include_once(dirname(__FILE__).'/pgt-file.php'); // incompatibility with Moodle +//include_once(dirname(__FILE__).'/pgt-db.php'); + +?> \ No newline at end of file diff --git a/auth/cas/CAS/client.php b/auth/cas/CAS/client.php index fa83dd52a68..923e86dc010 100644 --- a/auth/cas/CAS/client.php +++ b/auth/cas/CAS/client.php @@ -1,2078 +1,2078 @@ - - */ - -class CASClient -{ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX CONFIGURATION XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - // ######################################################################## - // HTML OUTPUT - // ######################################################################## - /** - * @addtogroup internalOutput - * @{ - */ - - /** - * This method filters a string by replacing special tokens by appropriate values - * and prints it. The corresponding tokens are taken into account: - * - __CAS_VERSION__ - * - __PHPCAS_VERSION__ - * - __SERVER_BASE_URL__ - * - * Used by CASClient::PrintHTMLHeader() and CASClient::printHTMLFooter(). - * - * @param $str the string to filter and output - * - * @private - */ - function HTMLFilterOutput($str) - { - $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str); - $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str); - $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str); - echo $str; - } - - /** - * A string used to print the header of HTML pages. Written by CASClient::setHTMLHeader(), - * read by CASClient::printHTMLHeader(). - * - * @hideinitializer - * @private - * @see CASClient::setHTMLHeader, CASClient::printHTMLHeader() - */ - var $_output_header = ''; - - /** - * This method prints the header of the HTML output (after filtering). If - * CASClient::setHTMLHeader() was not used, a default header is output. - * - * @param $title the title of the page - * - * @see HTMLFilterOutput() - * @private - */ - function printHTMLHeader($title) - { - $this->HTMLFilterOutput(str_replace('__TITLE__', - $title, - (empty($this->_output_header) - ? '__TITLE__

__TITLE__

' - : $this->_output_header) - ) - ); - } - - /** - * A string used to print the footer of HTML pages. Written by CASClient::setHTMLFooter(), - * read by printHTMLFooter(). - * - * @hideinitializer - * @private - * @see CASClient::setHTMLFooter, CASClient::printHTMLFooter() - */ - var $_output_footer = ''; - - /** - * This method prints the footer of the HTML output (after filtering). If - * CASClient::setHTMLFooter() was not used, a default footer is output. - * - * @see HTMLFilterOutput() - * @private - */ - function printHTMLFooter() - { - $this->HTMLFilterOutput(empty($this->_output_footer) - ?('
phpCAS __PHPCAS_VERSION__ '.$this->getString(CAS_STR_USING_SERVER).' __SERVER_BASE_URL__ (CAS __CAS_VERSION__)
') - :$this->_output_footer); - } - - /** - * This method set the HTML header used for all outputs. - * - * @param $header the HTML header. - * - * @public - */ - function setHTMLHeader($header) - { - $this->_output_header = $header; - } - - /** - * This method set the HTML footer used for all outputs. - * - * @param $footer the HTML footer. - * - * @public - */ - function setHTMLFooter($footer) - { - $this->_output_footer = $footer; - } - - /** @} */ - // ######################################################################## - // INTERNATIONALIZATION - // ######################################################################## - /** - * @addtogroup internalLang - * @{ - */ - /** - * A string corresponding to the language used by phpCAS. Written by - * CASClient::setLang(), read by CASClient::getLang(). - - * @note debugging information is always in english (debug purposes only). - * - * @hideinitializer - * @private - * @sa CASClient::_strings, CASClient::getString() - */ - var $_lang = ''; - - /** - * This method returns the language used by phpCAS. - * - * @return a string representing the language - * - * @private - */ - function getLang() - { - if ( empty($this->_lang) ) - $this->setLang(PHPCAS_LANG_DEFAULT); - return $this->_lang; - } - - /** - * array containing the strings used by phpCAS. Written by CASClient::setLang(), read by - * CASClient::getString() and used by CASClient::setLang(). - * - * @note This array is filled by instructions in CAS/languages/<$this->_lang>.php - * - * @private - * @see CASClient::_lang, CASClient::getString(), CASClient::setLang(), CASClient::getLang() - */ - var $_strings; - - /** - * This method returns a string depending on the language. - * - * @param $str the index of the string in $_string. - * - * @return the string corresponding to $index in $string. - * - * @private - */ - function getString($str) - { - // call CASclient::getLang() to be sure the language is initialized - $this->getLang(); - - if ( !isset($this->_strings[$str]) ) { - trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR); - } - return $this->_strings[$str]; - } - - /** - * This method is used to set the language used by phpCAS. - * @note Can be called only once. - * - * @param $lang a string representing the language. - * - * @public - * @sa CAS_LANG_FRENCH, CAS_LANG_ENGLISH - */ - function setLang($lang) - { - // include the corresponding language file - include_once(dirname(__FILE__).'/languages/'.$lang.'.php'); - - if ( !is_array($this->_strings) ) { - trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR); - } - $this->_lang = $lang; - } - - /** @} */ - // ######################################################################## - // CAS SERVER CONFIG - // ######################################################################## - /** - * @addtogroup internalConfig - * @{ - */ - - /** - * a record to store information about the CAS server. - * - $_server["version"]: the version of the CAS server - * - $_server["hostname"]: the hostname of the CAS server - * - $_server["port"]: the port the CAS server is running on - * - $_server["uri"]: the base URI the CAS server is responding on - * - $_server["base_url"]: the base URL of the CAS server - * - $_server["login_url"]: the login URL of the CAS server - * - $_server["service_validate_url"]: the service validating URL of the CAS server - * - $_server["proxy_url"]: the proxy URL of the CAS server - * - $_server["proxy_validate_url"]: the proxy validating URL of the CAS server - * - $_server["logout_url"]: the logout URL of the CAS server - * - * $_server["version"], $_server["hostname"], $_server["port"] and $_server["uri"] - * are written by CASClient::CASClient(), read by CASClient::getServerVersion(), - * CASClient::getServerHostname(), CASClient::getServerPort() and CASClient::getServerURI(). - * - * The other fields are written and read by CASClient::getServerBaseURL(), - * CASClient::getServerLoginURL(), CASClient::getServerServiceValidateURL(), - * CASClient::getServerProxyValidateURL() and CASClient::getServerLogoutURL(). - * - * @hideinitializer - * @private - */ - var $_server = array( - 'version' => -1, - 'hostname' => 'none', - 'port' => -1, - 'uri' => 'none' - ); - - /** - * This method is used to retrieve the version of the CAS server. - * @return the version of the CAS server. - * @private - */ - function getServerVersion() - { - return $this->_server['version']; - } - - /** - * This method is used to retrieve the hostname of the CAS server. - * @return the hostname of the CAS server. - * @private - */ - function getServerHostname() - { return $this->_server['hostname']; } - - /** - * This method is used to retrieve the port of the CAS server. - * @return the port of the CAS server. - * @private - */ - function getServerPort() - { return $this->_server['port']; } - - /** - * This method is used to retrieve the URI of the CAS server. - * @return a URI. - * @private - */ - function getServerURI() - { return $this->_server['uri']; } - - /** - * This method is used to retrieve the base URL of the CAS server. - * @return a URL. - * @private - */ - function getServerBaseURL() - { - // the URL is build only when needed - if ( empty($this->_server['base_url']) ) { - $this->_server['base_url'] = 'https://' - .$this->getServerHostname() - .':' - .$this->getServerPort() - .$this->getServerURI(); - } - return $this->_server['base_url']; - } - - /** - * This method is used to retrieve the login URL of the CAS server. - * @param $gateway true to check authentication, false to force it - * @return a URL. - * @private - */ - function getServerLoginURL($gateway=false) - { - phpCAS::traceBegin(); - // the URL is build only when needed - if ( empty($this->_server['login_url']) ) { - $this->_server['login_url'] = $this->getServerBaseURL(); - $this->_server['login_url'] .= 'login?service='; -// $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL()); - $this->_server['login_url'] .= urlencode($this->getURL()); - if ($gateway) { - $this->_server['login_url'] .= '&gateway=true'; - } - } - phpCAS::traceEnd($this->_server['login_url']); - return $this->_server['login_url']; - } - - /** - * This method sets the login URL of the CAS server. - * @param $url the login URL - * @private - * @since 0.4.21 by Wyman Chan - */ - function setServerLoginURL($url) - { - return $this->_server['login_url'] = $url; - } - - /** - * This method is used to retrieve the service validating URL of the CAS server. - * @return a URL. - * @private - */ - function getServerServiceValidateURL() - { - // the URL is build only when needed - if ( empty($this->_server['service_validate_url']) ) { - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate'; - break; - case CAS_VERSION_2_0: - $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate'; - break; - } - } -// return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); - return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL()); - } - - /** - * This method is used to retrieve the proxy validating URL of the CAS server. - * @return a URL. - * @private - */ - function getServerProxyValidateURL() - { - // the URL is build only when needed - if ( empty($this->_server['proxy_validate_url']) ) { - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - $this->_server['proxy_validate_url'] = ''; - break; - case CAS_VERSION_2_0: - $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate'; - break; - } - } -// return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); - return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL()); - } - - /** - * This method is used to retrieve the proxy URL of the CAS server. - * @return a URL. - * @private - */ - function getServerProxyURL() - { - // the URL is build only when needed - if ( empty($this->_server['proxy_url']) ) { - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - $this->_server['proxy_url'] = ''; - break; - case CAS_VERSION_2_0: - $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy'; - break; - } - } - return $this->_server['proxy_url']; - } - - /** - * This method is used to retrieve the logout URL of the CAS server. - * @return a URL. - * @private - */ - function getServerLogoutURL() - { - // the URL is build only when needed - if ( empty($this->_server['logout_url']) ) { - $this->_server['logout_url'] = $this->getServerBaseURL().'logout'; - } - return $this->_server['logout_url']; - } - - /** - * This method sets the logout URL of the CAS server. - * @param $url the logout URL - * @private - * @since 0.4.21 by Wyman Chan - */ - function setServerLogoutURL($url) - { - return $this->_server['logout_url'] = $url; - } - - /** - * This method checks to see if the request is secured via HTTPS - * @return true if https, false otherwise - * @private - */ - function isHttps() { - //if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ) { - //0.4.24 by Hinnack - if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { - return true; - } else { - return false; - } - } - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - /** - * CASClient constructor. - * - * @param $server_version the version of the CAS server - * @param $proxy TRUE if the CAS client is a CAS proxy, FALSE otherwise - * @param $server_hostname the hostname of the CAS server - * @param $server_port the port the CAS server is running on - * @param $server_uri the URI the CAS server is responding on - * @param $start_session Have phpCAS start PHP sessions (default true) - * - * @return a newly created CASClient object - * - * @public - */ - function CASClient( - $server_version, - $proxy, - $server_hostname, - $server_port, - $server_uri, - $start_session = true) { - - phpCAS::traceBegin(); - - //activate session mechanism if desired - if ($start_session) { - session_start(); - } - - $this->_proxy = $proxy; - - //check version - switch ($server_version) { - case CAS_VERSION_1_0: - if ( $this->isProxy() ) - phpCAS::error('CAS proxies are not supported in CAS ' - .$server_version); - break; - case CAS_VERSION_2_0: - break; - default: - phpCAS::error('this version of CAS (`' - .$server_version - .'\') is not supported by phpCAS ' - .phpCAS::getVersion()); - } - $this->_server['version'] = $server_version; - - //check hostname - if ( empty($server_hostname) - || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) { - phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')'); - } - $this->_server['hostname'] = $server_hostname; - - //check port - if ( $server_port == 0 - || !is_int($server_port) ) { - phpCAS::error('bad CAS server port (`'.$server_hostname.'\')'); - } - $this->_server['port'] = $server_port; - - //check URI - if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) { - phpCAS::error('bad CAS server URI (`'.$server_uri.'\')'); - } - //add leading and trailing `/' and remove doubles - $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/'); - $this->_server['uri'] = $server_uri; - - //set to callback mode if PgtIou and PgtId CGI GET parameters are provided - if ( $this->isProxy() ) { - $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId'])); - } - - if ( $this->isCallbackMode() ) { - //callback mode: check that phpCAS is secured - if ( !$this->isHttps() ) { - phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server'); - } - } else { - //normal mode: get ticket and remove it from CGI parameters for developpers - $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null); - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: // check for a Service Ticket - if( preg_match('/^ST-/',$ticket) ) { - phpCAS::trace('ST \''.$ticket.'\' found'); - //ST present - $this->setST($ticket); - //ticket has been taken into account, unset it to hide it to applications - unset($_GET['ticket']); - } else if ( !empty($ticket) ) { - //ill-formed ticket, halt - phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')'); - } - break; - case CAS_VERSION_2_0: // check for a Service or Proxy Ticket - if( preg_match('/^[SP]T-/',$ticket) ) { - phpCAS::trace('ST or PT \''.$ticket.'\' found'); - $this->setPT($ticket); - unset($_GET['ticket']); - } else if ( !empty($ticket) ) { - //ill-formed ticket, halt - phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')'); - } - break; - } - } - phpCAS::traceEnd(); - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX AUTHENTICATION XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - /** - * @addtogroup internalAuthentication - * @{ - */ - - /** - * The Authenticated user. Written by CASClient::setUser(), read by CASClient::getUser(). - * @attention client applications should use phpCAS::getUser(). - * - * @hideinitializer - * @private - */ - var $_user = ''; - - /** - * This method sets the CAS user's login name. - * - * @param $user the login name of the authenticated user. - * - * @private - */ - function setUser($user) - { - $this->_user = $user; - } - - /** - * This method returns the CAS user's login name. - * @warning should be called only after CASClient::forceAuthentication() or - * CASClient::isAuthenticated(), otherwise halt with an error. - * - * @return the login name of the authenticated user - */ - function getUser() - { - if ( empty($this->_user) ) { - phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'); - } - return $this->_user; - } - - /** - * This method is called to be sure that the user is authenticated. When not - * authenticated, halt by redirecting to the CAS server; otherwise return TRUE. - * @return TRUE when the user is authenticated; otherwise halt. - * @public - */ - function forceAuthentication() - { - phpCAS::traceBegin(); - - if ( $this->isAuthenticated() ) { - // the user is authenticated, nothing to be done. - phpCAS::trace('no need to authenticate'); - $res = TRUE; - - } else { - // the user is not authenticated, redirect to the CAS server - unset($_SESSION['phpCAS']['auth_checked']); - $this->redirectToCas(FALSE/* no gateway */); - // never reached - $res = FALSE; - } - phpCAS::traceEnd($res); - return $res; - } - - /** - * An integer that gives the number of times authentication will be cached before rechecked. - * - * @hideinitializer - * @private - */ - var $_cache_times_for_auth_recheck = 0; - - /** - * Set the number of times authentication will be cached before rechecked. - * - * @param $n an integer. - * - * @public - */ - function setCacheTimesForAuthRequest($n) - { - $this->_cache_times_for_auth_recheck = n; - } - - /** - * This method is called to check whether the user is authenticated or not. - * @return TRUE when the user is authenticated, FALSE otherwise. - * @public - */ - function checkAuthentication() - { - phpCAS::traceBegin(); - - if ( $this->isAuthenticated() ) { - phpCAS::trace('user is authenticated'); - $res = TRUE; - } else if (isset($_SESSION['phpCAS']['auth_checked'])) { - // the previous request has redirected the client to the CAS server with gateway=true - unset($_SESSION['phpCAS']['auth_checked']); - $res = FALSE; - } else { -// $_SESSION['phpCAS']['auth_checked'] = true; -// $this->redirectToCas(TRUE/* gateway */); -// // never reached -// $res = FALSE; - // avoid a check against CAS on every request - if (! isset($_SESSION['phpCAS']['unauth_count']) ) - $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized - - if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1) - || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck)) - { - $res = FALSE; - - if ($this->_cache_times_for_auth_recheck != -1) - { - $_SESSION['phpCAS']['unauth_count']++; - phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')'); - } - else - { - phpCAS::trace('user is not authenticated (cached for until login pressed)'); - } - } - else - { - $_SESSION['phpCAS']['unauth_count'] = 0; - $_SESSION['phpCAS']['auth_checked'] = true; - phpCAS::trace('user is not authenticated (cache reset)'); - $this->redirectToCas(TRUE/* gateway */); - // never reached - $res = FALSE; - } - } - phpCAS::traceEnd($res); - return $res; - } - - /** - * This method is called to check if the user is authenticated (previously or by - * tickets given in the URL). - * - * @return TRUE when the user is authenticated. - * - * @public - */ - function isAuthenticated() - { - phpCAS::traceBegin(); - $res = FALSE; - $validate_url = ''; - - if ( $this->wasPreviouslyAuthenticated() ) { - // the user has already (previously during the session) been - // authenticated, nothing to be done. - phpCAS::trace('user was already authenticated, no need to look for tickets'); - $res = TRUE; - } - elseif ( $this->hasST() ) { - // if a Service Ticket was given, validate it - phpCAS::trace('ST `'.$this->getST().'\' is present'); - $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts - phpCAS::trace('ST `'.$this->getST().'\' was validated'); - if ( $this->isProxy() ) { - $this->validatePGT($validate_url,$text_response,$tree_response); // idem - phpCAS::trace('PGT `'.$this->getPGT().'\' was validated'); - $_SESSION['phpCAS']['pgt'] = $this->getPGT(); - } - $_SESSION['phpCAS']['user'] = $this->getUser(); - $res = TRUE; - } - elseif ( $this->hasPT() ) { - // if a Proxy Ticket was given, validate it - phpCAS::trace('PT `'.$this->getPT().'\' is present'); - $this->validatePT($validate_url,$text_response,$tree_response); // note: if it fails, it halts - phpCAS::trace('PT `'.$this->getPT().'\' was validated'); - - if ( $this->isProxy() ) { - - $this->validatePGT($validate_url,$text_response,$tree_response); // idem - phpCAS::trace('PGT `'.$this->getPGT().'\' was validated'); - $_SESSION['phpCAS']['pgt'] = $this->getPGT(); - } - $_SESSION['phpCAS']['user'] = $this->getUser(); - $res = TRUE; - } - else { - // no ticket given, not authenticated - phpCAS::trace('no ticket found'); - } - - phpCAS::traceEnd($res); - return $res; - } - - /** - * This method tells if the current session is authenticated. - * @return true if authenticated based soley on $_SESSION variable - * @since 0.4.22 by Brendan Arnold - */ - function isSessionAuthenticated () - { - return !empty($_SESSION['phpCAS']['user']); - } - - /** - * This method tells if the user has already been (previously) authenticated - * by looking into the session variables. - * - * @note This function switches to callback mode when needed. - * - * @return TRUE when the user has already been authenticated; FALSE otherwise. - * - * @private - */ - function wasPreviouslyAuthenticated() - { - phpCAS::traceBegin(); - - if ( $this->isCallbackMode() ) { - - $this->callback(); - } - - $auth = FALSE; - - if ( $this->isProxy() ) { - // CAS proxy: username and PGT must be present - if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) { - // authentication already done - $this->setUser($_SESSION['phpCAS']['user']); - $this->setPGT($_SESSION['phpCAS']['pgt']); - phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\''); - $auth = TRUE; - } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) { - // these two variables should be empty or not empty at the same time - phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty'); - // unset all tickets to enforce authentication - unset($_SESSION['phpCAS']); - $this->setST(''); - $this->setPT(''); - } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) { - // these two variables should be empty or not empty at the same time - phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty'); - // unset all tickets to enforce authentication - unset($_SESSION['phpCAS']); - $this->setST(''); - $this->setPT(''); - } else { - phpCAS::trace('neither user not PGT found'); - } - } else { - // `simple' CAS client (not a proxy): username must be present - if ( $this->isSessionAuthenticated() ) { - // authentication already done - $this->setUser($_SESSION['phpCAS']['user']); - phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); - $auth = TRUE; - } else { - phpCAS::trace('no user found'); - } - } - - phpCAS::traceEnd($auth); - return $auth; - } - - /** - * This method is used to redirect the client to the CAS server. - * It is used by CASClient::forceAuthentication() and CASClient::checkAuthentication(). - * @param $gateway true to check authentication, false to force it - * @public - */ - function redirectToCas($gateway=false) - { - phpCAS::traceBegin(); - $cas_url = $this->getServerLoginURL($gateway); - header('Location: '.$cas_url); - $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED)); - printf('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$cas_url); - $this->printHTMLFooter(); - phpCAS::traceExit(); - exit(); - } - - /** - * This method is used to logout from CAS. - * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out) - * @public - */ - function logout($url = "") - { - phpCAS::traceBegin(); - $cas_url = $this->getServerLogoutURL(); - // v0.4.14 sebastien.gougeon at univ-rennes1.fr - // header('Location: '.$cas_url); - if ( $url != "" ) { - $url = '?service=' . $url; - } - header('Location: '.$cas_url . $url); - session_unset(); - session_destroy(); - $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT)); - printf('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$cas_url); - $this->printHTMLFooter(); - phpCAS::traceExit(); - exit(); - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX BASIC CLIENT FEATURES (CAS 1.0) XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - // ######################################################################## - // ST - // ######################################################################## - /** - * @addtogroup internalBasic - * @{ - */ - - /** - * the Service Ticket provided in the URL of the request if present - * (empty otherwise). Written by CASClient::CASClient(), read by - * CASClient::getST() and CASClient::hasPGT(). - * - * @hideinitializer - * @private - */ - var $_st = ''; - - /** - * This method returns the Service Ticket provided in the URL of the request. - * @return The service ticket. - * @private - */ - function getST() - { return $this->_st; } - - /** - * This method stores the Service Ticket. - * @param $st The Service Ticket. - * @private - */ - function setST($st) - { $this->_st = $st; } - - /** - * This method tells if a Service Ticket was stored. - * @return TRUE if a Service Ticket has been stored. - * @private - */ - function hasST() - { return !empty($this->_st); } - - /** @} */ - - // ######################################################################## - // ST VALIDATION - // ######################################################################## - /** - * @addtogroup internalBasic - * @{ - */ - - /** - * This method is used to validate a ST; halt on failure, and sets $validate_url, - * $text_reponse and $tree_response on success. These parameters are used later - * by CASClient::validatePGT() for CAS proxies. - * - * @param $validate_url the URL of the request to the CAS server. - * @param $text_response the response of the CAS server, as is (XML text). - * @param $tree_response the response of the CAS server, as a DOM XML tree. - * - * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). - * - * @private - */ - function validateST($validate_url,&$text_response,&$tree_response) - { - phpCAS::traceBegin(); - // build the URL to validate the ticket - $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST(); - if ( $this->isProxy() ) { - // pass the callback url for CAS proxies - $validate_url .= '&pgtUrl='.$this->getCallbackURL(); - } - - // open and read the URL - if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) { - phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'); - $this->authError('ST not validated', - $validate_url, - TRUE/*$no_response*/); - } - - // analyze the result depending on the version - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - if (preg_match('/^no\n/',$text_response)) { - phpCAS::trace('ST has not been validated'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response); - } - if (!preg_match('/^yes\n/',$text_response)) { - phpCAS::trace('ill-formed response'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // ST has been validated, extract the user name - $arr = preg_split('/\n/',$text_response); - $this->setUser(trim($arr[1])); - break; - case CAS_VERSION_2_0: - // read the response of the CAS server into a DOM object - if ( !($dom = domxml_open_mem($text_response))) { - phpCAS::trace('domxml_open_mem() failed'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // read the root node of the XML tree - if ( !($tree_response = $dom->document_element()) ) { - phpCAS::trace('document_element() failed'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // insure that tag name is 'serviceResponse' - if ( $tree_response->node_name() != 'serviceResponse' ) { - phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\''); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) { - // authentication succeded, extract the user name - if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) { - phpCAS::trace(' found, but no '); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - $user = trim($user_elements[0]->get_content()); - phpCAS::trace('user = `'.$user); - $this->setUser($user); - - } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) { - phpCAS::trace(' found'); - // authentication failed, extract the error code and message - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response, - $failure_elements[0]->get_attribute('code')/*$err_code*/, - trim($failure_elements[0]->get_content())/*$err_msg*/); - } else { - phpCAS::trace('neither nor found'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - break; - } - - // at this step, ST has been validated and $this->_user has been set, - phpCAS::traceEnd(TRUE); - return TRUE; - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX PROXY FEATURES (CAS 2.0) XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - // ######################################################################## - // PROXYING - // ######################################################################## - /** - * @addtogroup internalProxy - * @{ - */ - - /** - * A boolean telling if the client is a CAS proxy or not. Written by CASClient::CASClient(), - * read by CASClient::isProxy(). - * - * @private - */ - var $_proxy; - - /** - * Tells if a CAS client is a CAS proxy or not - * - * @return TRUE when the CAS client is a CAs proxy, FALSE otherwise - * - * @private - */ - function isProxy() - { - return $this->_proxy; - } - - /** @} */ - // ######################################################################## - // PGT - // ######################################################################## - /** - * @addtogroup internalProxy - * @{ - */ - - /** - * the Proxy Grnting Ticket given by the CAS server (empty otherwise). - * Written by CASClient::setPGT(), read by CASClient::getPGT() and CASClient::hasPGT(). - * - * @hideinitializer - * @private - */ - var $_pgt = ''; - - /** - * This method returns the Proxy Granting Ticket given by the CAS server. - * @return The Proxy Granting Ticket. - * @private - */ - function getPGT() - { return $this->_pgt; } - - /** - * This method stores the Proxy Granting Ticket. - * @param $pgt The Proxy Granting Ticket. - * @private - */ - function setPGT($pgt) - { $this->_pgt = $pgt; } - - /** - * This method tells if a Proxy Granting Ticket was stored. - * @return TRUE if a Proxy Granting Ticket has been stored. - * @private - */ - function hasPGT() - { return !empty($this->_pgt); } - - /** @} */ - - // ######################################################################## - // CALLBACK MODE - // ######################################################################## - /** - * @addtogroup internalCallback - * @{ - */ - /** - * each PHP script using phpCAS in proxy mode is its own callback to get the - * PGT back from the CAS server. callback_mode is detected by the constructor - * thanks to the GET parameters. - */ - - /** - * a boolean to know if the CAS client is running in callback mode. Written by - * CASClient::setCallBackMode(), read by CASClient::isCallbackMode(). - * - * @hideinitializer - * @private - */ - var $_callback_mode = FALSE; - - /** - * This method sets/unsets callback mode. - * - * @param $callback_mode TRUE to set callback mode, FALSE otherwise. - * - * @private - */ - function setCallbackMode($callback_mode) - { - $this->_callback_mode = $callback_mode; - } - - /** - * This method returns TRUE when the CAs client is running i callback mode, - * FALSE otherwise. - * - * @return A boolean. - * - * @private - */ - function isCallbackMode() - { - return $this->_callback_mode; - } - - /** - * the URL that should be used for the PGT callback (in fact the URL of the - * current request without any CGI parameter). Written and read by - * CASClient::getCallbackURL(). - * - * @hideinitializer - * @private - */ - var $_callback_url = ''; - - /** - * This method returns the URL that should be used for the PGT callback (in - * fact the URL of the current request without any CGI parameter, except if - * phpCAS::setFixedCallbackURL() was used). - * - * @return The callback URL - * - * @private - */ - function getCallbackURL() - { - // the URL is built when needed only - if ( empty($this->_callback_url) ) { - $final_uri = ''; - // remove the ticket if present in the URL - $final_uri = 'https://'; - /* replaced by Julien Marchal - v0.4.6 - * $this->uri .= $_SERVER['SERVER_NAME']; - */ - if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){ - /* replaced by teedog - v0.4.12 - * $final_uri .= $_SERVER['SERVER_NAME']; - */ - if (empty($_SERVER['SERVER_NAME'])) { - $final_uri .= $_SERVER['HTTP_HOST']; - } else { - $final_uri .= $_SERVER['SERVER_NAME']; - } - } else { - $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER']; - } - if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443) - || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) { - $final_uri .= ':'; - $final_uri .= $_SERVER['SERVER_PORT']; - } - $request_uri = $_SERVER['REQUEST_URI']; - $request_uri = preg_replace('/\?.*$/','',$request_uri); - $final_uri .= $request_uri; - $this->setCallbackURL($final_uri); - } - return $this->_callback_url; - } - - /** - * This method sets the callback url. - * - * @param $callback_url url to set callback - * - * @private - */ - function setCallbackURL($url) - { - return $this->_callback_url = $url; - } - - /** - * This method is called by CASClient::CASClient() when running in callback - * mode. It stores the PGT and its PGT Iou, prints its output and halts. - * - * @private - */ - function callback() - { - phpCAS::traceBegin(); - $this->printHTMLHeader('phpCAS callback'); - $pgt_iou = $_GET['pgtIou']; - $pgt = $_GET['pgtId']; - phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')'); - echo '

Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').

'; - $this->storePGT($pgt,$pgt_iou); - $this->printHTMLFooter(); - phpCAS::traceExit(); - } - - /** @} */ - - // ######################################################################## - // PGT STORAGE - // ######################################################################## - /** - * @addtogroup internalPGTStorage - * @{ - */ - - /** - * an instance of a class inheriting of PGTStorage, used to deal with PGT - * storage. Created by CASClient::setPGTStorageFile() or CASClient::setPGTStorageDB(), used - * by CASClient::setPGTStorageFile(), CASClient::setPGTStorageDB() and CASClient::initPGTStorage(). - * - * @hideinitializer - * @private - */ - var $_pgt_storage = null; - - /** - * This method is used to initialize the storage of PGT's. - * Halts on error. - * - * @private - */ - function initPGTStorage() - { - // if no SetPGTStorageXxx() has been used, default to file - if ( !is_object($this->_pgt_storage) ) { - $this->setPGTStorageFile(); - } - - // initializes the storage - $this->_pgt_storage->init(); - } - - /** - * This method stores a PGT. Halts on error. - * - * @param $pgt the PGT to store - * @param $pgt_iou its corresponding Iou - * - * @private - */ - function storePGT($pgt,$pgt_iou) - { - // ensure that storage is initialized - $this->initPGTStorage(); - - // writes the PGT - $this->_pgt_storage->write($pgt,$pgt_iou); - } - - /** - * This method reads a PGT from its Iou and deletes the corresponding storage entry. - * - * @param $pgt_iou the PGT Iou - * - * @return The PGT corresponding to the Iou, FALSE when not found. - * - * @private - */ - function loadPGT($pgt_iou) - { - // ensure that storage is initialized - $this->initPGTStorage(); - - // read the PGT - return $this->_pgt_storage->read($pgt_iou); - } - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests onto the filesystem. - * - * @param $format the format used to store the PGT's (`plain' and `xml' allowed) - * @param $path the path where the PGT's should be stored - * - * @public - */ - function setPGTStorageFile($format='', - $path='') - { - // check that the storage has not already been set - if ( is_object($this->_pgt_storage) ) { - phpCAS::error('PGT storage already defined'); - } - - // create the storage object - $this->_pgt_storage = &new PGTStorageFile($this,$format,$path); - } - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests into a database. - * @note The connection to the database is done only when needed. - * As a consequence, bad parameters are detected only when - * initializing PGT storage. - * - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data - * - * @public - */ - function setPGTStorageDB($user, - $password, - $database_type, - $hostname, - $port, - $database, - $table) - { - // check that the storage has not already been set - if ( is_object($this->_pgt_storage) ) { - phpCAS::error('PGT storage already defined'); - } - - // warn the user that he should use file storage... - trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING); - - // create the storage object - $this->_pgt_storage = & new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table); - } - - // ######################################################################## - // PGT VALIDATION - // ######################################################################## - /** - * This method is used to validate a PGT; halt on failure. - * - * @param $validate_url the URL of the request to the CAS server. - * @param $text_response the response of the CAS server, as is (XML text); result - * of CASClient::validateST() or CASClient::validatePT(). - * @param $tree_response the response of the CAS server, as a DOM XML tree; result - * of CASClient::validateST() or CASClient::validatePT(). - * - * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). - * - * @private - */ - function validatePGT(&$validate_url,$text_response,$tree_response) - { - phpCAS::traceBegin(); - if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) { - phpCAS::trace(' not found'); - // authentication succeded, but no PGT Iou was transmitted - $this->authError('Ticket validated but no PGT Iou transmitted', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response); - } else { - // PGT Iou transmitted, extract it - $pgt_iou = trim($arr[0]->get_content()); - $pgt = $this->loadPGT($pgt_iou); - if ( $pgt == FALSE ) { - - phpCAS::trace('could not load PGT'); - - $this->authError('PGT Iou was transmitted but PGT could not be retrieved', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response); - - - } - $this->setPGT($pgt); - } - phpCAS::traceEnd(TRUE); - return TRUE; - } - - // ######################################################################## - // PGT VALIDATION - // ######################################################################## - - /** - * This method is used to retrieve PT's from the CAS server thanks to a PGT. - * - * @param $target_service the service to ask for with the PT. - * @param $err_code an error code (PHPCAS_SERVICE_OK on success). - * @param $err_msg an error message (empty on success). - * - * @return a Proxy Ticket, or FALSE on error. - * - * @private - */ - function retrievePT($target_service,&$err_code,&$err_msg) - { - phpCAS::traceBegin(); - - // by default, $err_msg is set empty and $pt to TRUE. On error, $pt is - // set to false and $err_msg to an error message. At the end, if $pt is FALSE - // and $error_msg is still empty, it is set to 'invalid response' (the most - // commonly encountered error). - $err_msg = ''; - - // build the URL to retrieve the PT -// $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT(); - $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT(); - - // open and read the URL - if ( !$this->readURL($cas_url,''/*cookies*/,$headers,$cas_response,$err_msg) ) { - phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')'); - $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE; - $err_msg = 'could not retrieve PT (no response from the CAS server)'; - phpCAS::traceEnd(FALSE); - return FALSE; - } - - $bad_response = FALSE; - - if ( !$bad_response ) { - // read the response of the CAS server into a DOM object - if ( !($dom = @domxml_open_mem($cas_response))) { - phpCAS::trace('domxml_open_mem() failed'); - // read failed - $bad_response = TRUE; - } - } - - if ( !$bad_response ) { - // read the root node of the XML tree - if ( !($root = $dom->document_element()) ) { - phpCAS::trace('document_element() failed'); - // read failed - $bad_response = TRUE; - } - } - - if ( !$bad_response ) { - // insure that tag name is 'serviceResponse' - if ( $root->node_name() != 'serviceResponse' ) { - phpCAS::trace('node_name() failed'); - // bad root node - $bad_response = TRUE; - } - } - - if ( !$bad_response ) { - // look for a proxySuccess tag - if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) { - // authentication succeded, look for a proxyTicket tag - if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) { - $err_code = PHPCAS_SERVICE_OK; - $err_msg = ''; - phpCAS::trace('original PT: '.trim($arr[0]->get_content())); - $pt = trim($arr[0]->get_content()); - phpCAS::traceEnd($pt); - return $pt; - } else { - phpCAS::trace(' was found, but not '); - } - } - // look for a proxyFailure tag - else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) { - // authentication failed, extract the error - $err_code = PHPCAS_SERVICE_PT_FAILURE; - $err_msg = 'PT retrieving failed (code=`' - .$arr[0]->get_attribute('code') - .'\', message=`' - .trim($arr[0]->get_content()) - .'\')'; - phpCAS::traceEnd(FALSE); - return FALSE; - } else { - phpCAS::trace('neither nor found'); - } - } - - // at this step, we are sure that the response of the CAS server was ill-formed - $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE; - $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')'; - - phpCAS::traceEnd(FALSE); - return FALSE; - } - - // ######################################################################## - // ACCESS TO EXTERNAL SERVICES - // ######################################################################## - - /** - * This method is used to acces a remote URL. - * - * @param $url the URL to access. - * @param $cookies an array containing cookies strings such as 'name=val' - * @param $headers an array containing the HTTP header lines of the response - * (an empty array on failure). - * @param $body the body of the response, as a string (empty on failure). - * @param $err_msg an error message, filled on failure. - * - * @return TRUE on success, FALSE otherwise (in this later case, $err_msg - * contains an error message). - * - * @private - */ - function readURL($url,$cookies,&$headers,&$body,&$err_msg) - { - phpCAS::traceBegin(); - $headers = ''; - $body = ''; - $err_msg = ''; - - $res = TRUE; - - // initialize the CURL session - $ch = curl_init($url); - - // verify the the server's certificate corresponds to its name - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); - // but do not verify the certificate itself - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - - // return the CURL output into a variable - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - // include the HTTP header with the body - curl_setopt($ch, CURLOPT_HEADER, 1); - // add cookies headers - if ( is_array($cookies) ) { - curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies)); - } - // perform the query - $buf = curl_exec ($ch); - if ( $buf === FALSE ) { - phpCAS::trace('cur_exec() failed'); - $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch); - // close the CURL session - curl_close ($ch); - $res = FALSE; - } else { - // close the CURL session - curl_close ($ch); - - // find the end of the headers - // note: strpos($str,"\n\r\n\r") does not work (?) - $pos = FALSE; - for ($i=0; $iretrievePT($url,$err_code,$output); - - $res = TRUE; - - // test if PT was retrieved correctly - if ( !$pt ) { - // note: $err_code and $err_msg are filled by CASClient::retrievePT() - phpCAS::trace('PT was not retrieved correctly'); - $res = FALSE; - } else { - // add cookies if necessary - if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) { - foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { - $cookies[] = $name.'='.$val; - } - } - - // build the URL including the PT - if ( strstr($url,'?') === FALSE ) { - $service_url = $url.'?ticket='.$pt; - } else { - $service_url = $url.'&ticket='.$pt; - } - - phpCAS::trace('reading URL`'.$service_url.'\''); - if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) { - phpCAS::trace('could not read URL`'.$service_url.'\''); - $err_code = PHPCAS_SERVICE_NOT_AVAILABLE; - // give an error message - $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE), - $service_url, - $err_msg); - $res = FALSE; - } else { - // URL has been fetched, extract the cookies - phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:'); - foreach ( $headers as $header ) { - // test if the header is a cookie - if ( preg_match('/^Set-Cookie:/',$header) ) { - // the header is a cookie, remove the beginning - $header_val = preg_replace('/^Set-Cookie: */','',$header); - // extract interesting information - $name_val = strtok($header_val,'; '); - // extract the name and the value of the cookie - $cookie_name = strtok($name_val,'='); - $cookie_val = strtok('='); - // store the cookie - $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val; - phpCAS::trace($cookie_name.' -> '.$cookie_val); - } - } - } - } - - phpCAS::traceEnd($res); - return $res; - } - - /** - * This method is used to access an IMAP/POP3/NNTP service. - * - * @param $url a string giving the URL of the service, including the mailing box - * for IMAP URLs, as accepted by imap_open(). - * @param $flags options given to imap_open(). - * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on - * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, - * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. - * @param $err_msg an error message on failure - * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL - * on success, FALSE on error). - * - * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code - * gives the reason why it failed and $err_msg contains an error message). - * - * @public - */ - function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt) - { - phpCAS::traceBegin(); - // at first retrieve a PT - $pt = $this->retrievePT($target_service,$err_code,$output); - - $stream = FALSE; - - // test if PT was retrieved correctly - if ( !$pt ) { - // note: $err_code and $err_msg are filled by CASClient::retrievePT() - phpCAS::trace('PT was not retrieved correctly'); - } else { - phpCAS::trace('opening IMAP URL `'.$url.'\'...'); - $stream = @imap_open($url,$this->getUser(),$pt,$flags); - if ( !$stream ) { - phpCAS::trace('could not open URL'); - $err_code = PHPCAS_SERVICE_NOT_AVAILABLE; - // give an error message - $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE), - $service_url, - var_export(imap_errors(),TRUE)); - $pt = FALSE; - $stream = FALSE; - } else { - phpCAS::trace('ok'); - } - } - - phpCAS::traceEnd($stream); - return $stream; - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX PROXIED CLIENT FEATURES (CAS 2.0) XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - // ######################################################################## - // PT - // ######################################################################## - /** - * @addtogroup internalProxied - * @{ - */ - - /** - * the Proxy Ticket provided in the URL of the request if present - * (empty otherwise). Written by CASClient::CASClient(), read by - * CASClient::getPT() and CASClient::hasPGT(). - * - * @hideinitializer - * @private - */ - var $_pt = ''; - - /** - * This method returns the Proxy Ticket provided in the URL of the request. - * @return The proxy ticket. - * @private - */ - function getPT() - { - return 'ST'.substr($this->_pt, 2); - } - - /** - * This method stores the Proxy Ticket. - * @param $pt The Proxy Ticket. - * @private - */ - function setPT($pt) - { $this->_pt = $pt; } - - /** - * This method tells if a Proxy Ticket was stored. - * @return TRUE if a Proxy Ticket has been stored. - * @private - */ - function hasPT() - { return !empty($this->_pt); } - - /** @} */ - // ######################################################################## - // PT VALIDATION - // ######################################################################## - /** - * @addtogroup internalProxied - * @{ - */ - - /** - * This method is used to validate a PT; halt on failure - * - * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). - * - * @private - */ - function validatePT(&$validate_url,&$text_response,&$tree_response) - { - phpCAS::traceBegin(); - // build the URL to validate the ticket - $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT(); - - if ( $this->isProxy() ) { - // pass the callback url for CAS proxies - $validate_url .= '&pgtUrl='.$this->getCallbackURL(); - } - - // open and read the URL - if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) { - phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'); - $this->authError('PT not validated', - $validate_url, - TRUE/*$no_response*/); - } - - // read the response of the CAS server into a DOM object - if ( !($dom = domxml_open_mem($text_response))) { - // read failed - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // read the root node of the XML tree - if ( !($tree_response = $dom->document_element()) ) { - // read failed - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - // insure that tag name is 'serviceResponse' - if ( $tree_response->node_name() != 'serviceResponse' ) { - // bad root node - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) { - // authentication succeded, extract the user name - if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) { - // no user specified => error - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - $this->setUser(trim($arr[0]->get_content())); - - } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) { - // authentication succeded, extract the error code and message - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - FALSE/*$bad_response*/, - $text_response, - $arr[0]->get_attribute('code')/*$err_code*/, - trim($arr[0]->get_content())/*$err_msg*/); - } else { - $this->authError('PT not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - - // at this step, PT has been validated and $this->_user has been set, - - phpCAS::traceEnd(TRUE); - return TRUE; - } - - /** @} */ - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // XX XX - // XX MISC XX - // XX XX - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - /** - * @addtogroup internalMisc - * @{ - */ - - // ######################################################################## - // URL - // ######################################################################## - /** - * the URL of the current request (without any ticket CGI parameter). Written - * and read by CASClient::getURL(). - * - * @hideinitializer - * @private - */ - var $_url = ''; - - /** - * This method returns the URL of the current request (without any ticket - * CGI parameter). - * - * @return The URL - * - * @private - */ - function getURL() - { - phpCAS::traceBegin(); - // the URL is built when needed only - if ( empty($this->_url) ) { - $final_uri = ''; - // remove the ticket if present in the URL - $final_uri = ($this->isHttps()) ? 'https' : 'http'; - $final_uri .= '://'; - /* replaced by Julien Marchal - v0.4.6 - * $this->_url .= $_SERVER['SERVER_NAME']; - */ - if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){ - /* replaced by teedog - v0.4.12 - * $this->_url .= $_SERVER['SERVER_NAME']; - */ - if (empty($_SERVER['SERVER_NAME'])) { - $server_name = $_SERVER['HTTP_HOST']; - } else { - $server_name = $_SERVER['SERVER_NAME']; - } - } else { - $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER']; - } - $final_uri .= $server_name; - if (!strpos($server_name, ':')) { - if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443) - || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) { - $final_uri .= ':'; - $final_uri .= $_SERVER['SERVER_PORT']; - } - } - - $final_uri .= strtok($_SERVER['REQUEST_URI'],"?"); - $cgi_params = '?'.strtok("?"); - // remove the ticket if present in the CGI parameters - $cgi_params = preg_replace('/&ticket=[^&]*/','',$cgi_params); - $cgi_params = preg_replace('/\?ticket=[^&;]*/','?',$cgi_params); - $cgi_params = preg_replace('/\?%26/','?',$cgi_params); - $cgi_params = preg_replace('/\?&/','?',$cgi_params); - $cgi_params = preg_replace('/\?$/','',$cgi_params); - $final_uri .= $cgi_params; - $this->setURL($final_uri); - } - phpCAS::traceEnd($this->_url); - return $this->_url; - } - - /** - * This method sets the URL of the current request - * - * @param $url url to set for service - * - * @private - */ - function setURL($url) - { - $this->_url = $url; - } - - // ######################################################################## - // AUTHENTICATION ERROR HANDLING - // ######################################################################## - /** - * This method is used to print the HTML output when the user was not authenticated. - * - * @param $failure the failure that occured - * @param $cas_url the URL the CAS server was asked for - * @param $no_response the response from the CAS server (other - * parameters are ignored if TRUE) - * @param $bad_response bad response from the CAS server ($err_code - * and $err_msg ignored if TRUE) - * @param $cas_response the response of the CAS server - * @param $err_code the error code given by the CAS server - * @param $err_msg the error message given by the CAS server - * - * @private - */ - function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='') - { - phpCAS::traceBegin(); - - $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED)); - printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),$this->getURL(),$_SERVER['SERVER_ADMIN']); - phpCAS::trace('CAS URL: '.$cas_url); - phpCAS::trace('Authentication failure: '.$failure); - if ( $no_response ) { - phpCAS::trace('Reason: no response from the CAS server'); - } else { - if ( $bad_response ) { - phpCAS::trace('Reason: bad response from the CAS server'); - } else { - switch ($this->getServerVersion()) { - case CAS_VERSION_1_0: - phpCAS::trace('Reason: CAS error'); - break; - case CAS_VERSION_2_0: - if ( empty($err_code) ) - phpCAS::trace('Reason: no CAS error'); - else - phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg); - break; - } - } - phpCAS::trace('CAS response: '.$cas_response); - } - $this->printHTMLFooter(); - phpCAS::traceExit(); - exit(); - } - - /** @} */ -} - -?> + + */ + +class CASClient +{ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX CONFIGURATION XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + // ######################################################################## + // HTML OUTPUT + // ######################################################################## + /** + * @addtogroup internalOutput + * @{ + */ + + /** + * This method filters a string by replacing special tokens by appropriate values + * and prints it. The corresponding tokens are taken into account: + * - __CAS_VERSION__ + * - __PHPCAS_VERSION__ + * - __SERVER_BASE_URL__ + * + * Used by CASClient::PrintHTMLHeader() and CASClient::printHTMLFooter(). + * + * @param $str the string to filter and output + * + * @private + */ + function HTMLFilterOutput($str) + { + $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str); + $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str); + $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str); + echo $str; + } + + /** + * A string used to print the header of HTML pages. Written by CASClient::setHTMLHeader(), + * read by CASClient::printHTMLHeader(). + * + * @hideinitializer + * @private + * @see CASClient::setHTMLHeader, CASClient::printHTMLHeader() + */ + var $_output_header = ''; + + /** + * This method prints the header of the HTML output (after filtering). If + * CASClient::setHTMLHeader() was not used, a default header is output. + * + * @param $title the title of the page + * + * @see HTMLFilterOutput() + * @private + */ + function printHTMLHeader($title) + { + $this->HTMLFilterOutput(str_replace('__TITLE__', + $title, + (empty($this->_output_header) + ? '__TITLE__

__TITLE__

' + : $this->_output_header) + ) + ); + } + + /** + * A string used to print the footer of HTML pages. Written by CASClient::setHTMLFooter(), + * read by printHTMLFooter(). + * + * @hideinitializer + * @private + * @see CASClient::setHTMLFooter, CASClient::printHTMLFooter() + */ + var $_output_footer = ''; + + /** + * This method prints the footer of the HTML output (after filtering). If + * CASClient::setHTMLFooter() was not used, a default footer is output. + * + * @see HTMLFilterOutput() + * @private + */ + function printHTMLFooter() + { + $this->HTMLFilterOutput(empty($this->_output_footer) + ?('
phpCAS __PHPCAS_VERSION__ '.$this->getString(CAS_STR_USING_SERVER).' __SERVER_BASE_URL__ (CAS __CAS_VERSION__)
') + :$this->_output_footer); + } + + /** + * This method set the HTML header used for all outputs. + * + * @param $header the HTML header. + * + * @public + */ + function setHTMLHeader($header) + { + $this->_output_header = $header; + } + + /** + * This method set the HTML footer used for all outputs. + * + * @param $footer the HTML footer. + * + * @public + */ + function setHTMLFooter($footer) + { + $this->_output_footer = $footer; + } + + /** @} */ + // ######################################################################## + // INTERNATIONALIZATION + // ######################################################################## + /** + * @addtogroup internalLang + * @{ + */ + /** + * A string corresponding to the language used by phpCAS. Written by + * CASClient::setLang(), read by CASClient::getLang(). + + * @note debugging information is always in english (debug purposes only). + * + * @hideinitializer + * @private + * @sa CASClient::_strings, CASClient::getString() + */ + var $_lang = ''; + + /** + * This method returns the language used by phpCAS. + * + * @return a string representing the language + * + * @private + */ + function getLang() + { + if ( empty($this->_lang) ) + $this->setLang(PHPCAS_LANG_DEFAULT); + return $this->_lang; + } + + /** + * array containing the strings used by phpCAS. Written by CASClient::setLang(), read by + * CASClient::getString() and used by CASClient::setLang(). + * + * @note This array is filled by instructions in CAS/languages/<$this->_lang>.php + * + * @private + * @see CASClient::_lang, CASClient::getString(), CASClient::setLang(), CASClient::getLang() + */ + var $_strings; + + /** + * This method returns a string depending on the language. + * + * @param $str the index of the string in $_string. + * + * @return the string corresponding to $index in $string. + * + * @private + */ + function getString($str) + { + // call CASclient::getLang() to be sure the language is initialized + $this->getLang(); + + if ( !isset($this->_strings[$str]) ) { + trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR); + } + return $this->_strings[$str]; + } + + /** + * This method is used to set the language used by phpCAS. + * @note Can be called only once. + * + * @param $lang a string representing the language. + * + * @public + * @sa CAS_LANG_FRENCH, CAS_LANG_ENGLISH + */ + function setLang($lang) + { + // include the corresponding language file + include_once(dirname(__FILE__).'/languages/'.$lang.'.php'); + + if ( !is_array($this->_strings) ) { + trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR); + } + $this->_lang = $lang; + } + + /** @} */ + // ######################################################################## + // CAS SERVER CONFIG + // ######################################################################## + /** + * @addtogroup internalConfig + * @{ + */ + + /** + * a record to store information about the CAS server. + * - $_server["version"]: the version of the CAS server + * - $_server["hostname"]: the hostname of the CAS server + * - $_server["port"]: the port the CAS server is running on + * - $_server["uri"]: the base URI the CAS server is responding on + * - $_server["base_url"]: the base URL of the CAS server + * - $_server["login_url"]: the login URL of the CAS server + * - $_server["service_validate_url"]: the service validating URL of the CAS server + * - $_server["proxy_url"]: the proxy URL of the CAS server + * - $_server["proxy_validate_url"]: the proxy validating URL of the CAS server + * - $_server["logout_url"]: the logout URL of the CAS server + * + * $_server["version"], $_server["hostname"], $_server["port"] and $_server["uri"] + * are written by CASClient::CASClient(), read by CASClient::getServerVersion(), + * CASClient::getServerHostname(), CASClient::getServerPort() and CASClient::getServerURI(). + * + * The other fields are written and read by CASClient::getServerBaseURL(), + * CASClient::getServerLoginURL(), CASClient::getServerServiceValidateURL(), + * CASClient::getServerProxyValidateURL() and CASClient::getServerLogoutURL(). + * + * @hideinitializer + * @private + */ + var $_server = array( + 'version' => -1, + 'hostname' => 'none', + 'port' => -1, + 'uri' => 'none' + ); + + /** + * This method is used to retrieve the version of the CAS server. + * @return the version of the CAS server. + * @private + */ + function getServerVersion() + { + return $this->_server['version']; + } + + /** + * This method is used to retrieve the hostname of the CAS server. + * @return the hostname of the CAS server. + * @private + */ + function getServerHostname() + { return $this->_server['hostname']; } + + /** + * This method is used to retrieve the port of the CAS server. + * @return the port of the CAS server. + * @private + */ + function getServerPort() + { return $this->_server['port']; } + + /** + * This method is used to retrieve the URI of the CAS server. + * @return a URI. + * @private + */ + function getServerURI() + { return $this->_server['uri']; } + + /** + * This method is used to retrieve the base URL of the CAS server. + * @return a URL. + * @private + */ + function getServerBaseURL() + { + // the URL is build only when needed + if ( empty($this->_server['base_url']) ) { + $this->_server['base_url'] = 'https://' + .$this->getServerHostname() + .':' + .$this->getServerPort() + .$this->getServerURI(); + } + return $this->_server['base_url']; + } + + /** + * This method is used to retrieve the login URL of the CAS server. + * @param $gateway true to check authentication, false to force it + * @return a URL. + * @private + */ + function getServerLoginURL($gateway=false) + { + phpCAS::traceBegin(); + // the URL is build only when needed + if ( empty($this->_server['login_url']) ) { + $this->_server['login_url'] = $this->getServerBaseURL(); + $this->_server['login_url'] .= 'login?service='; +// $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL()); + $this->_server['login_url'] .= urlencode($this->getURL()); + if ($gateway) { + $this->_server['login_url'] .= '&gateway=true'; + } + } + phpCAS::traceEnd($this->_server['login_url']); + return $this->_server['login_url']; + } + + /** + * This method sets the login URL of the CAS server. + * @param $url the login URL + * @private + * @since 0.4.21 by Wyman Chan + */ + function setServerLoginURL($url) + { + return $this->_server['login_url'] = $url; + } + + /** + * This method is used to retrieve the service validating URL of the CAS server. + * @return a URL. + * @private + */ + function getServerServiceValidateURL() + { + // the URL is build only when needed + if ( empty($this->_server['service_validate_url']) ) { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate'; + break; + case CAS_VERSION_2_0: + $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate'; + break; + } + } +// return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); + return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL()); + } + + /** + * This method is used to retrieve the proxy validating URL of the CAS server. + * @return a URL. + * @private + */ + function getServerProxyValidateURL() + { + // the URL is build only when needed + if ( empty($this->_server['proxy_validate_url']) ) { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + $this->_server['proxy_validate_url'] = ''; + break; + case CAS_VERSION_2_0: + $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate'; + break; + } + } +// return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); + return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL()); + } + + /** + * This method is used to retrieve the proxy URL of the CAS server. + * @return a URL. + * @private + */ + function getServerProxyURL() + { + // the URL is build only when needed + if ( empty($this->_server['proxy_url']) ) { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + $this->_server['proxy_url'] = ''; + break; + case CAS_VERSION_2_0: + $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy'; + break; + } + } + return $this->_server['proxy_url']; + } + + /** + * This method is used to retrieve the logout URL of the CAS server. + * @return a URL. + * @private + */ + function getServerLogoutURL() + { + // the URL is build only when needed + if ( empty($this->_server['logout_url']) ) { + $this->_server['logout_url'] = $this->getServerBaseURL().'logout'; + } + return $this->_server['logout_url']; + } + + /** + * This method sets the logout URL of the CAS server. + * @param $url the logout URL + * @private + * @since 0.4.21 by Wyman Chan + */ + function setServerLogoutURL($url) + { + return $this->_server['logout_url'] = $url; + } + + /** + * This method checks to see if the request is secured via HTTPS + * @return true if https, false otherwise + * @private + */ + function isHttps() { + //if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ) { + //0.4.24 by Hinnack + if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { + return true; + } else { + return false; + } + } + + // ######################################################################## + // CONSTRUCTOR + // ######################################################################## + /** + * CASClient constructor. + * + * @param $server_version the version of the CAS server + * @param $proxy TRUE if the CAS client is a CAS proxy, FALSE otherwise + * @param $server_hostname the hostname of the CAS server + * @param $server_port the port the CAS server is running on + * @param $server_uri the URI the CAS server is responding on + * @param $start_session Have phpCAS start PHP sessions (default true) + * + * @return a newly created CASClient object + * + * @public + */ + function CASClient( + $server_version, + $proxy, + $server_hostname, + $server_port, + $server_uri, + $start_session = true) { + + phpCAS::traceBegin(); + + //activate session mechanism if desired + if ($start_session) { + session_start(); + } + + $this->_proxy = $proxy; + + //check version + switch ($server_version) { + case CAS_VERSION_1_0: + if ( $this->isProxy() ) + phpCAS::error('CAS proxies are not supported in CAS ' + .$server_version); + break; + case CAS_VERSION_2_0: + break; + default: + phpCAS::error('this version of CAS (`' + .$server_version + .'\') is not supported by phpCAS ' + .phpCAS::getVersion()); + } + $this->_server['version'] = $server_version; + + //check hostname + if ( empty($server_hostname) + || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) { + phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')'); + } + $this->_server['hostname'] = $server_hostname; + + //check port + if ( $server_port == 0 + || !is_int($server_port) ) { + phpCAS::error('bad CAS server port (`'.$server_hostname.'\')'); + } + $this->_server['port'] = $server_port; + + //check URI + if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) { + phpCAS::error('bad CAS server URI (`'.$server_uri.'\')'); + } + //add leading and trailing `/' and remove doubles + $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/'); + $this->_server['uri'] = $server_uri; + + //set to callback mode if PgtIou and PgtId CGI GET parameters are provided + if ( $this->isProxy() ) { + $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId'])); + } + + if ( $this->isCallbackMode() ) { + //callback mode: check that phpCAS is secured + if ( !$this->isHttps() ) { + phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server'); + } + } else { + //normal mode: get ticket and remove it from CGI parameters for developpers + $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null); + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: // check for a Service Ticket + if( preg_match('/^ST-/',$ticket) ) { + phpCAS::trace('ST \''.$ticket.'\' found'); + //ST present + $this->setST($ticket); + //ticket has been taken into account, unset it to hide it to applications + unset($_GET['ticket']); + } else if ( !empty($ticket) ) { + //ill-formed ticket, halt + phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')'); + } + break; + case CAS_VERSION_2_0: // check for a Service or Proxy Ticket + if( preg_match('/^[SP]T-/',$ticket) ) { + phpCAS::trace('ST or PT \''.$ticket.'\' found'); + $this->setPT($ticket); + unset($_GET['ticket']); + } else if ( !empty($ticket) ) { + //ill-formed ticket, halt + phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')'); + } + break; + } + } + phpCAS::traceEnd(); + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX AUTHENTICATION XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + /** + * @addtogroup internalAuthentication + * @{ + */ + + /** + * The Authenticated user. Written by CASClient::setUser(), read by CASClient::getUser(). + * @attention client applications should use phpCAS::getUser(). + * + * @hideinitializer + * @private + */ + var $_user = ''; + + /** + * This method sets the CAS user's login name. + * + * @param $user the login name of the authenticated user. + * + * @private + */ + function setUser($user) + { + $this->_user = $user; + } + + /** + * This method returns the CAS user's login name. + * @warning should be called only after CASClient::forceAuthentication() or + * CASClient::isAuthenticated(), otherwise halt with an error. + * + * @return the login name of the authenticated user + */ + function getUser() + { + if ( empty($this->_user) ) { + phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'); + } + return $this->_user; + } + + /** + * This method is called to be sure that the user is authenticated. When not + * authenticated, halt by redirecting to the CAS server; otherwise return TRUE. + * @return TRUE when the user is authenticated; otherwise halt. + * @public + */ + function forceAuthentication() + { + phpCAS::traceBegin(); + + if ( $this->isAuthenticated() ) { + // the user is authenticated, nothing to be done. + phpCAS::trace('no need to authenticate'); + $res = TRUE; + + } else { + // the user is not authenticated, redirect to the CAS server + unset($_SESSION['phpCAS']['auth_checked']); + $this->redirectToCas(FALSE/* no gateway */); + // never reached + $res = FALSE; + } + phpCAS::traceEnd($res); + return $res; + } + + /** + * An integer that gives the number of times authentication will be cached before rechecked. + * + * @hideinitializer + * @private + */ + var $_cache_times_for_auth_recheck = 0; + + /** + * Set the number of times authentication will be cached before rechecked. + * + * @param $n an integer. + * + * @public + */ + function setCacheTimesForAuthRequest($n) + { + $this->_cache_times_for_auth_recheck = n; + } + + /** + * This method is called to check whether the user is authenticated or not. + * @return TRUE when the user is authenticated, FALSE otherwise. + * @public + */ + function checkAuthentication() + { + phpCAS::traceBegin(); + + if ( $this->isAuthenticated() ) { + phpCAS::trace('user is authenticated'); + $res = TRUE; + } else if (isset($_SESSION['phpCAS']['auth_checked'])) { + // the previous request has redirected the client to the CAS server with gateway=true + unset($_SESSION['phpCAS']['auth_checked']); + $res = FALSE; + } else { +// $_SESSION['phpCAS']['auth_checked'] = true; +// $this->redirectToCas(TRUE/* gateway */); +// // never reached +// $res = FALSE; + // avoid a check against CAS on every request + if (! isset($_SESSION['phpCAS']['unauth_count']) ) + $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized + + if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1) + || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck)) + { + $res = FALSE; + + if ($this->_cache_times_for_auth_recheck != -1) + { + $_SESSION['phpCAS']['unauth_count']++; + phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')'); + } + else + { + phpCAS::trace('user is not authenticated (cached for until login pressed)'); + } + } + else + { + $_SESSION['phpCAS']['unauth_count'] = 0; + $_SESSION['phpCAS']['auth_checked'] = true; + phpCAS::trace('user is not authenticated (cache reset)'); + $this->redirectToCas(TRUE/* gateway */); + // never reached + $res = FALSE; + } + } + phpCAS::traceEnd($res); + return $res; + } + + /** + * This method is called to check if the user is authenticated (previously or by + * tickets given in the URL). + * + * @return TRUE when the user is authenticated. + * + * @public + */ + function isAuthenticated() + { + phpCAS::traceBegin(); + $res = FALSE; + $validate_url = ''; + + if ( $this->wasPreviouslyAuthenticated() ) { + // the user has already (previously during the session) been + // authenticated, nothing to be done. + phpCAS::trace('user was already authenticated, no need to look for tickets'); + $res = TRUE; + } + elseif ( $this->hasST() ) { + // if a Service Ticket was given, validate it + phpCAS::trace('ST `'.$this->getST().'\' is present'); + $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts + phpCAS::trace('ST `'.$this->getST().'\' was validated'); + if ( $this->isProxy() ) { + $this->validatePGT($validate_url,$text_response,$tree_response); // idem + phpCAS::trace('PGT `'.$this->getPGT().'\' was validated'); + $_SESSION['phpCAS']['pgt'] = $this->getPGT(); + } + $_SESSION['phpCAS']['user'] = $this->getUser(); + $res = TRUE; + } + elseif ( $this->hasPT() ) { + // if a Proxy Ticket was given, validate it + phpCAS::trace('PT `'.$this->getPT().'\' is present'); + $this->validatePT($validate_url,$text_response,$tree_response); // note: if it fails, it halts + phpCAS::trace('PT `'.$this->getPT().'\' was validated'); + + if ( $this->isProxy() ) { + + $this->validatePGT($validate_url,$text_response,$tree_response); // idem + phpCAS::trace('PGT `'.$this->getPGT().'\' was validated'); + $_SESSION['phpCAS']['pgt'] = $this->getPGT(); + } + $_SESSION['phpCAS']['user'] = $this->getUser(); + $res = TRUE; + } + else { + // no ticket given, not authenticated + phpCAS::trace('no ticket found'); + } + + phpCAS::traceEnd($res); + return $res; + } + + /** + * This method tells if the current session is authenticated. + * @return true if authenticated based soley on $_SESSION variable + * @since 0.4.22 by Brendan Arnold + */ + function isSessionAuthenticated () + { + return !empty($_SESSION['phpCAS']['user']); + } + + /** + * This method tells if the user has already been (previously) authenticated + * by looking into the session variables. + * + * @note This function switches to callback mode when needed. + * + * @return TRUE when the user has already been authenticated; FALSE otherwise. + * + * @private + */ + function wasPreviouslyAuthenticated() + { + phpCAS::traceBegin(); + + if ( $this->isCallbackMode() ) { + + $this->callback(); + } + + $auth = FALSE; + + if ( $this->isProxy() ) { + // CAS proxy: username and PGT must be present + if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) { + // authentication already done + $this->setUser($_SESSION['phpCAS']['user']); + $this->setPGT($_SESSION['phpCAS']['pgt']); + phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\''); + $auth = TRUE; + } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) { + // these two variables should be empty or not empty at the same time + phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty'); + // unset all tickets to enforce authentication + unset($_SESSION['phpCAS']); + $this->setST(''); + $this->setPT(''); + } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) { + // these two variables should be empty or not empty at the same time + phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty'); + // unset all tickets to enforce authentication + unset($_SESSION['phpCAS']); + $this->setST(''); + $this->setPT(''); + } else { + phpCAS::trace('neither user not PGT found'); + } + } else { + // `simple' CAS client (not a proxy): username must be present + if ( $this->isSessionAuthenticated() ) { + // authentication already done + $this->setUser($_SESSION['phpCAS']['user']); + phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); + $auth = TRUE; + } else { + phpCAS::trace('no user found'); + } + } + + phpCAS::traceEnd($auth); + return $auth; + } + + /** + * This method is used to redirect the client to the CAS server. + * It is used by CASClient::forceAuthentication() and CASClient::checkAuthentication(). + * @param $gateway true to check authentication, false to force it + * @public + */ + function redirectToCas($gateway=false) + { + phpCAS::traceBegin(); + $cas_url = $this->getServerLoginURL($gateway); + header('Location: '.$cas_url); + $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED)); + printf('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$cas_url); + $this->printHTMLFooter(); + phpCAS::traceExit(); + exit(); + } + + /** + * This method is used to logout from CAS. + * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out) + * @public + */ + function logout($url = "") + { + phpCAS::traceBegin(); + $cas_url = $this->getServerLogoutURL(); + // v0.4.14 sebastien.gougeon at univ-rennes1.fr + // header('Location: '.$cas_url); + if ( $url != "" ) { + $url = '?service=' . $url; + } + header('Location: '.$cas_url . $url); + session_unset(); + session_destroy(); + $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT)); + printf('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$cas_url); + $this->printHTMLFooter(); + phpCAS::traceExit(); + exit(); + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX BASIC CLIENT FEATURES (CAS 1.0) XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + // ######################################################################## + // ST + // ######################################################################## + /** + * @addtogroup internalBasic + * @{ + */ + + /** + * the Service Ticket provided in the URL of the request if present + * (empty otherwise). Written by CASClient::CASClient(), read by + * CASClient::getST() and CASClient::hasPGT(). + * + * @hideinitializer + * @private + */ + var $_st = ''; + + /** + * This method returns the Service Ticket provided in the URL of the request. + * @return The service ticket. + * @private + */ + function getST() + { return $this->_st; } + + /** + * This method stores the Service Ticket. + * @param $st The Service Ticket. + * @private + */ + function setST($st) + { $this->_st = $st; } + + /** + * This method tells if a Service Ticket was stored. + * @return TRUE if a Service Ticket has been stored. + * @private + */ + function hasST() + { return !empty($this->_st); } + + /** @} */ + + // ######################################################################## + // ST VALIDATION + // ######################################################################## + /** + * @addtogroup internalBasic + * @{ + */ + + /** + * This method is used to validate a ST; halt on failure, and sets $validate_url, + * $text_reponse and $tree_response on success. These parameters are used later + * by CASClient::validatePGT() for CAS proxies. + * + * @param $validate_url the URL of the request to the CAS server. + * @param $text_response the response of the CAS server, as is (XML text). + * @param $tree_response the response of the CAS server, as a DOM XML tree. + * + * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). + * + * @private + */ + function validateST($validate_url,&$text_response,&$tree_response) + { + phpCAS::traceBegin(); + // build the URL to validate the ticket + $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST(); + if ( $this->isProxy() ) { + // pass the callback url for CAS proxies + $validate_url .= '&pgtUrl='.$this->getCallbackURL(); + } + + // open and read the URL + if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) { + phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'); + $this->authError('ST not validated', + $validate_url, + TRUE/*$no_response*/); + } + + // analyze the result depending on the version + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + if (preg_match('/^no\n/',$text_response)) { + phpCAS::trace('ST has not been validated'); + $this->authError('ST not validated', + $validate_url, + FALSE/*$no_response*/, + FALSE/*$bad_response*/, + $text_response); + } + if (!preg_match('/^yes\n/',$text_response)) { + phpCAS::trace('ill-formed response'); + $this->authError('ST not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + // ST has been validated, extract the user name + $arr = preg_split('/\n/',$text_response); + $this->setUser(trim($arr[1])); + break; + case CAS_VERSION_2_0: + // read the response of the CAS server into a DOM object + if ( !($dom = domxml_open_mem($text_response))) { + phpCAS::trace('domxml_open_mem() failed'); + $this->authError('ST not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + // read the root node of the XML tree + if ( !($tree_response = $dom->document_element()) ) { + phpCAS::trace('document_element() failed'); + $this->authError('ST not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + // insure that tag name is 'serviceResponse' + if ( $tree_response->node_name() != 'serviceResponse' ) { + phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\''); + $this->authError('ST not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) { + // authentication succeded, extract the user name + if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) { + phpCAS::trace(' found, but no '); + $this->authError('ST not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + $user = trim($user_elements[0]->get_content()); + phpCAS::trace('user = `'.$user); + $this->setUser($user); + + } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) { + phpCAS::trace(' found'); + // authentication failed, extract the error code and message + $this->authError('ST not validated', + $validate_url, + FALSE/*$no_response*/, + FALSE/*$bad_response*/, + $text_response, + $failure_elements[0]->get_attribute('code')/*$err_code*/, + trim($failure_elements[0]->get_content())/*$err_msg*/); + } else { + phpCAS::trace('neither nor found'); + $this->authError('ST not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + break; + } + + // at this step, ST has been validated and $this->_user has been set, + phpCAS::traceEnd(TRUE); + return TRUE; + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX PROXY FEATURES (CAS 2.0) XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + // ######################################################################## + // PROXYING + // ######################################################################## + /** + * @addtogroup internalProxy + * @{ + */ + + /** + * A boolean telling if the client is a CAS proxy or not. Written by CASClient::CASClient(), + * read by CASClient::isProxy(). + * + * @private + */ + var $_proxy; + + /** + * Tells if a CAS client is a CAS proxy or not + * + * @return TRUE when the CAS client is a CAs proxy, FALSE otherwise + * + * @private + */ + function isProxy() + { + return $this->_proxy; + } + + /** @} */ + // ######################################################################## + // PGT + // ######################################################################## + /** + * @addtogroup internalProxy + * @{ + */ + + /** + * the Proxy Grnting Ticket given by the CAS server (empty otherwise). + * Written by CASClient::setPGT(), read by CASClient::getPGT() and CASClient::hasPGT(). + * + * @hideinitializer + * @private + */ + var $_pgt = ''; + + /** + * This method returns the Proxy Granting Ticket given by the CAS server. + * @return The Proxy Granting Ticket. + * @private + */ + function getPGT() + { return $this->_pgt; } + + /** + * This method stores the Proxy Granting Ticket. + * @param $pgt The Proxy Granting Ticket. + * @private + */ + function setPGT($pgt) + { $this->_pgt = $pgt; } + + /** + * This method tells if a Proxy Granting Ticket was stored. + * @return TRUE if a Proxy Granting Ticket has been stored. + * @private + */ + function hasPGT() + { return !empty($this->_pgt); } + + /** @} */ + + // ######################################################################## + // CALLBACK MODE + // ######################################################################## + /** + * @addtogroup internalCallback + * @{ + */ + /** + * each PHP script using phpCAS in proxy mode is its own callback to get the + * PGT back from the CAS server. callback_mode is detected by the constructor + * thanks to the GET parameters. + */ + + /** + * a boolean to know if the CAS client is running in callback mode. Written by + * CASClient::setCallBackMode(), read by CASClient::isCallbackMode(). + * + * @hideinitializer + * @private + */ + var $_callback_mode = FALSE; + + /** + * This method sets/unsets callback mode. + * + * @param $callback_mode TRUE to set callback mode, FALSE otherwise. + * + * @private + */ + function setCallbackMode($callback_mode) + { + $this->_callback_mode = $callback_mode; + } + + /** + * This method returns TRUE when the CAs client is running i callback mode, + * FALSE otherwise. + * + * @return A boolean. + * + * @private + */ + function isCallbackMode() + { + return $this->_callback_mode; + } + + /** + * the URL that should be used for the PGT callback (in fact the URL of the + * current request without any CGI parameter). Written and read by + * CASClient::getCallbackURL(). + * + * @hideinitializer + * @private + */ + var $_callback_url = ''; + + /** + * This method returns the URL that should be used for the PGT callback (in + * fact the URL of the current request without any CGI parameter, except if + * phpCAS::setFixedCallbackURL() was used). + * + * @return The callback URL + * + * @private + */ + function getCallbackURL() + { + // the URL is built when needed only + if ( empty($this->_callback_url) ) { + $final_uri = ''; + // remove the ticket if present in the URL + $final_uri = 'https://'; + /* replaced by Julien Marchal - v0.4.6 + * $this->uri .= $_SERVER['SERVER_NAME']; + */ + if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){ + /* replaced by teedog - v0.4.12 + * $final_uri .= $_SERVER['SERVER_NAME']; + */ + if (empty($_SERVER['SERVER_NAME'])) { + $final_uri .= $_SERVER['HTTP_HOST']; + } else { + $final_uri .= $_SERVER['SERVER_NAME']; + } + } else { + $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER']; + } + if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443) + || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) { + $final_uri .= ':'; + $final_uri .= $_SERVER['SERVER_PORT']; + } + $request_uri = $_SERVER['REQUEST_URI']; + $request_uri = preg_replace('/\?.*$/','',$request_uri); + $final_uri .= $request_uri; + $this->setCallbackURL($final_uri); + } + return $this->_callback_url; + } + + /** + * This method sets the callback url. + * + * @param $callback_url url to set callback + * + * @private + */ + function setCallbackURL($url) + { + return $this->_callback_url = $url; + } + + /** + * This method is called by CASClient::CASClient() when running in callback + * mode. It stores the PGT and its PGT Iou, prints its output and halts. + * + * @private + */ + function callback() + { + phpCAS::traceBegin(); + $this->printHTMLHeader('phpCAS callback'); + $pgt_iou = $_GET['pgtIou']; + $pgt = $_GET['pgtId']; + phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')'); + echo '

Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').

'; + $this->storePGT($pgt,$pgt_iou); + $this->printHTMLFooter(); + phpCAS::traceExit(); + } + + /** @} */ + + // ######################################################################## + // PGT STORAGE + // ######################################################################## + /** + * @addtogroup internalPGTStorage + * @{ + */ + + /** + * an instance of a class inheriting of PGTStorage, used to deal with PGT + * storage. Created by CASClient::setPGTStorageFile() or CASClient::setPGTStorageDB(), used + * by CASClient::setPGTStorageFile(), CASClient::setPGTStorageDB() and CASClient::initPGTStorage(). + * + * @hideinitializer + * @private + */ + var $_pgt_storage = null; + + /** + * This method is used to initialize the storage of PGT's. + * Halts on error. + * + * @private + */ + function initPGTStorage() + { + // if no SetPGTStorageXxx() has been used, default to file + if ( !is_object($this->_pgt_storage) ) { + $this->setPGTStorageFile(); + } + + // initializes the storage + $this->_pgt_storage->init(); + } + + /** + * This method stores a PGT. Halts on error. + * + * @param $pgt the PGT to store + * @param $pgt_iou its corresponding Iou + * + * @private + */ + function storePGT($pgt,$pgt_iou) + { + // ensure that storage is initialized + $this->initPGTStorage(); + + // writes the PGT + $this->_pgt_storage->write($pgt,$pgt_iou); + } + + /** + * This method reads a PGT from its Iou and deletes the corresponding storage entry. + * + * @param $pgt_iou the PGT Iou + * + * @return The PGT corresponding to the Iou, FALSE when not found. + * + * @private + */ + function loadPGT($pgt_iou) + { + // ensure that storage is initialized + $this->initPGTStorage(); + + // read the PGT + return $this->_pgt_storage->read($pgt_iou); + } + + /** + * This method is used to tell phpCAS to store the response of the + * CAS server to PGT requests onto the filesystem. + * + * @param $format the format used to store the PGT's (`plain' and `xml' allowed) + * @param $path the path where the PGT's should be stored + * + * @public + */ + function setPGTStorageFile($format='', + $path='') + { + // check that the storage has not already been set + if ( is_object($this->_pgt_storage) ) { + phpCAS::error('PGT storage already defined'); + } + + // create the storage object + $this->_pgt_storage = &new PGTStorageFile($this,$format,$path); + } + + /** + * This method is used to tell phpCAS to store the response of the + * CAS server to PGT requests into a database. + * @note The connection to the database is done only when needed. + * As a consequence, bad parameters are detected only when + * initializing PGT storage. + * + * @param $user the user to access the data with + * @param $password the user's password + * @param $database_type the type of the database hosting the data + * @param $hostname the server hosting the database + * @param $port the port the server is listening on + * @param $database the name of the database + * @param $table the name of the table storing the data + * + * @public + */ + function setPGTStorageDB($user, + $password, + $database_type, + $hostname, + $port, + $database, + $table) + { + // check that the storage has not already been set + if ( is_object($this->_pgt_storage) ) { + phpCAS::error('PGT storage already defined'); + } + + // warn the user that he should use file storage... + trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING); + + // create the storage object + $this->_pgt_storage = & new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table); + } + + // ######################################################################## + // PGT VALIDATION + // ######################################################################## + /** + * This method is used to validate a PGT; halt on failure. + * + * @param $validate_url the URL of the request to the CAS server. + * @param $text_response the response of the CAS server, as is (XML text); result + * of CASClient::validateST() or CASClient::validatePT(). + * @param $tree_response the response of the CAS server, as a DOM XML tree; result + * of CASClient::validateST() or CASClient::validatePT(). + * + * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). + * + * @private + */ + function validatePGT(&$validate_url,$text_response,$tree_response) + { + phpCAS::traceBegin(); + if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) { + phpCAS::trace(' not found'); + // authentication succeded, but no PGT Iou was transmitted + $this->authError('Ticket validated but no PGT Iou transmitted', + $validate_url, + FALSE/*$no_response*/, + FALSE/*$bad_response*/, + $text_response); + } else { + // PGT Iou transmitted, extract it + $pgt_iou = trim($arr[0]->get_content()); + $pgt = $this->loadPGT($pgt_iou); + if ( $pgt == FALSE ) { + + phpCAS::trace('could not load PGT'); + + $this->authError('PGT Iou was transmitted but PGT could not be retrieved', + $validate_url, + FALSE/*$no_response*/, + FALSE/*$bad_response*/, + $text_response); + + + } + $this->setPGT($pgt); + } + phpCAS::traceEnd(TRUE); + return TRUE; + } + + // ######################################################################## + // PGT VALIDATION + // ######################################################################## + + /** + * This method is used to retrieve PT's from the CAS server thanks to a PGT. + * + * @param $target_service the service to ask for with the PT. + * @param $err_code an error code (PHPCAS_SERVICE_OK on success). + * @param $err_msg an error message (empty on success). + * + * @return a Proxy Ticket, or FALSE on error. + * + * @private + */ + function retrievePT($target_service,&$err_code,&$err_msg) + { + phpCAS::traceBegin(); + + // by default, $err_msg is set empty and $pt to TRUE. On error, $pt is + // set to false and $err_msg to an error message. At the end, if $pt is FALSE + // and $error_msg is still empty, it is set to 'invalid response' (the most + // commonly encountered error). + $err_msg = ''; + + // build the URL to retrieve the PT +// $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT(); + $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT(); + + // open and read the URL + if ( !$this->readURL($cas_url,''/*cookies*/,$headers,$cas_response,$err_msg) ) { + phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')'); + $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE; + $err_msg = 'could not retrieve PT (no response from the CAS server)'; + phpCAS::traceEnd(FALSE); + return FALSE; + } + + $bad_response = FALSE; + + if ( !$bad_response ) { + // read the response of the CAS server into a DOM object + if ( !($dom = @domxml_open_mem($cas_response))) { + phpCAS::trace('domxml_open_mem() failed'); + // read failed + $bad_response = TRUE; + } + } + + if ( !$bad_response ) { + // read the root node of the XML tree + if ( !($root = $dom->document_element()) ) { + phpCAS::trace('document_element() failed'); + // read failed + $bad_response = TRUE; + } + } + + if ( !$bad_response ) { + // insure that tag name is 'serviceResponse' + if ( $root->node_name() != 'serviceResponse' ) { + phpCAS::trace('node_name() failed'); + // bad root node + $bad_response = TRUE; + } + } + + if ( !$bad_response ) { + // look for a proxySuccess tag + if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) { + // authentication succeded, look for a proxyTicket tag + if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) { + $err_code = PHPCAS_SERVICE_OK; + $err_msg = ''; + phpCAS::trace('original PT: '.trim($arr[0]->get_content())); + $pt = trim($arr[0]->get_content()); + phpCAS::traceEnd($pt); + return $pt; + } else { + phpCAS::trace(' was found, but not '); + } + } + // look for a proxyFailure tag + else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) { + // authentication failed, extract the error + $err_code = PHPCAS_SERVICE_PT_FAILURE; + $err_msg = 'PT retrieving failed (code=`' + .$arr[0]->get_attribute('code') + .'\', message=`' + .trim($arr[0]->get_content()) + .'\')'; + phpCAS::traceEnd(FALSE); + return FALSE; + } else { + phpCAS::trace('neither nor found'); + } + } + + // at this step, we are sure that the response of the CAS server was ill-formed + $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE; + $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')'; + + phpCAS::traceEnd(FALSE); + return FALSE; + } + + // ######################################################################## + // ACCESS TO EXTERNAL SERVICES + // ######################################################################## + + /** + * This method is used to acces a remote URL. + * + * @param $url the URL to access. + * @param $cookies an array containing cookies strings such as 'name=val' + * @param $headers an array containing the HTTP header lines of the response + * (an empty array on failure). + * @param $body the body of the response, as a string (empty on failure). + * @param $err_msg an error message, filled on failure. + * + * @return TRUE on success, FALSE otherwise (in this later case, $err_msg + * contains an error message). + * + * @private + */ + function readURL($url,$cookies,&$headers,&$body,&$err_msg) + { + phpCAS::traceBegin(); + $headers = ''; + $body = ''; + $err_msg = ''; + + $res = TRUE; + + // initialize the CURL session + $ch = curl_init($url); + + // verify the the server's certificate corresponds to its name + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); + // but do not verify the certificate itself + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + + // return the CURL output into a variable + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + // include the HTTP header with the body + curl_setopt($ch, CURLOPT_HEADER, 1); + // add cookies headers + if ( is_array($cookies) ) { + curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies)); + } + // perform the query + $buf = curl_exec ($ch); + if ( $buf === FALSE ) { + phpCAS::trace('cur_exec() failed'); + $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch); + // close the CURL session + curl_close ($ch); + $res = FALSE; + } else { + // close the CURL session + curl_close ($ch); + + // find the end of the headers + // note: strpos($str,"\n\r\n\r") does not work (?) + $pos = FALSE; + for ($i=0; $iretrievePT($url,$err_code,$output); + + $res = TRUE; + + // test if PT was retrieved correctly + if ( !$pt ) { + // note: $err_code and $err_msg are filled by CASClient::retrievePT() + phpCAS::trace('PT was not retrieved correctly'); + $res = FALSE; + } else { + // add cookies if necessary + if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) { + foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { + $cookies[] = $name.'='.$val; + } + } + + // build the URL including the PT + if ( strstr($url,'?') === FALSE ) { + $service_url = $url.'?ticket='.$pt; + } else { + $service_url = $url.'&ticket='.$pt; + } + + phpCAS::trace('reading URL`'.$service_url.'\''); + if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) { + phpCAS::trace('could not read URL`'.$service_url.'\''); + $err_code = PHPCAS_SERVICE_NOT_AVAILABLE; + // give an error message + $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE), + $service_url, + $err_msg); + $res = FALSE; + } else { + // URL has been fetched, extract the cookies + phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:'); + foreach ( $headers as $header ) { + // test if the header is a cookie + if ( preg_match('/^Set-Cookie:/',$header) ) { + // the header is a cookie, remove the beginning + $header_val = preg_replace('/^Set-Cookie: */','',$header); + // extract interesting information + $name_val = strtok($header_val,'; '); + // extract the name and the value of the cookie + $cookie_name = strtok($name_val,'='); + $cookie_val = strtok('='); + // store the cookie + $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val; + phpCAS::trace($cookie_name.' -> '.$cookie_val); + } + } + } + } + + phpCAS::traceEnd($res); + return $res; + } + + /** + * This method is used to access an IMAP/POP3/NNTP service. + * + * @param $url a string giving the URL of the service, including the mailing box + * for IMAP URLs, as accepted by imap_open(). + * @param $flags options given to imap_open(). + * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on + * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, + * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE. + * @param $err_msg an error message on failure + * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL + * on success, FALSE on error). + * + * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code + * gives the reason why it failed and $err_msg contains an error message). + * + * @public + */ + function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt) + { + phpCAS::traceBegin(); + // at first retrieve a PT + $pt = $this->retrievePT($target_service,$err_code,$output); + + $stream = FALSE; + + // test if PT was retrieved correctly + if ( !$pt ) { + // note: $err_code and $err_msg are filled by CASClient::retrievePT() + phpCAS::trace('PT was not retrieved correctly'); + } else { + phpCAS::trace('opening IMAP URL `'.$url.'\'...'); + $stream = @imap_open($url,$this->getUser(),$pt,$flags); + if ( !$stream ) { + phpCAS::trace('could not open URL'); + $err_code = PHPCAS_SERVICE_NOT_AVAILABLE; + // give an error message + $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE), + $service_url, + var_export(imap_errors(),TRUE)); + $pt = FALSE; + $stream = FALSE; + } else { + phpCAS::trace('ok'); + } + } + + phpCAS::traceEnd($stream); + return $stream; + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX PROXIED CLIENT FEATURES (CAS 2.0) XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + // ######################################################################## + // PT + // ######################################################################## + /** + * @addtogroup internalProxied + * @{ + */ + + /** + * the Proxy Ticket provided in the URL of the request if present + * (empty otherwise). Written by CASClient::CASClient(), read by + * CASClient::getPT() and CASClient::hasPGT(). + * + * @hideinitializer + * @private + */ + var $_pt = ''; + + /** + * This method returns the Proxy Ticket provided in the URL of the request. + * @return The proxy ticket. + * @private + */ + function getPT() + { + return 'ST'.substr($this->_pt, 2); + } + + /** + * This method stores the Proxy Ticket. + * @param $pt The Proxy Ticket. + * @private + */ + function setPT($pt) + { $this->_pt = $pt; } + + /** + * This method tells if a Proxy Ticket was stored. + * @return TRUE if a Proxy Ticket has been stored. + * @private + */ + function hasPT() + { return !empty($this->_pt); } + + /** @} */ + // ######################################################################## + // PT VALIDATION + // ######################################################################## + /** + * @addtogroup internalProxied + * @{ + */ + + /** + * This method is used to validate a PT; halt on failure + * + * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError(). + * + * @private + */ + function validatePT(&$validate_url,&$text_response,&$tree_response) + { + phpCAS::traceBegin(); + // build the URL to validate the ticket + $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT(); + + if ( $this->isProxy() ) { + // pass the callback url for CAS proxies + $validate_url .= '&pgtUrl='.$this->getCallbackURL(); + } + + // open and read the URL + if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) { + phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'); + $this->authError('PT not validated', + $validate_url, + TRUE/*$no_response*/); + } + + // read the response of the CAS server into a DOM object + if ( !($dom = domxml_open_mem($text_response))) { + // read failed + $this->authError('PT not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + // read the root node of the XML tree + if ( !($tree_response = $dom->document_element()) ) { + // read failed + $this->authError('PT not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + // insure that tag name is 'serviceResponse' + if ( $tree_response->node_name() != 'serviceResponse' ) { + // bad root node + $this->authError('PT not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) { + // authentication succeded, extract the user name + if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) { + // no user specified => error + $this->authError('PT not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + $this->setUser(trim($arr[0]->get_content())); + + } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) { + // authentication succeded, extract the error code and message + $this->authError('PT not validated', + $validate_url, + FALSE/*$no_response*/, + FALSE/*$bad_response*/, + $text_response, + $arr[0]->get_attribute('code')/*$err_code*/, + trim($arr[0]->get_content())/*$err_msg*/); + } else { + $this->authError('PT not validated', + $validate_url, + FALSE/*$no_response*/, + TRUE/*$bad_response*/, + $text_response); + } + + // at this step, PT has been validated and $this->_user has been set, + + phpCAS::traceEnd(TRUE); + return TRUE; + } + + /** @} */ + + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // XX XX + // XX MISC XX + // XX XX + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + /** + * @addtogroup internalMisc + * @{ + */ + + // ######################################################################## + // URL + // ######################################################################## + /** + * the URL of the current request (without any ticket CGI parameter). Written + * and read by CASClient::getURL(). + * + * @hideinitializer + * @private + */ + var $_url = ''; + + /** + * This method returns the URL of the current request (without any ticket + * CGI parameter). + * + * @return The URL + * + * @private + */ + function getURL() + { + phpCAS::traceBegin(); + // the URL is built when needed only + if ( empty($this->_url) ) { + $final_uri = ''; + // remove the ticket if present in the URL + $final_uri = ($this->isHttps()) ? 'https' : 'http'; + $final_uri .= '://'; + /* replaced by Julien Marchal - v0.4.6 + * $this->_url .= $_SERVER['SERVER_NAME']; + */ + if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){ + /* replaced by teedog - v0.4.12 + * $this->_url .= $_SERVER['SERVER_NAME']; + */ + if (empty($_SERVER['SERVER_NAME'])) { + $server_name = $_SERVER['HTTP_HOST']; + } else { + $server_name = $_SERVER['SERVER_NAME']; + } + } else { + $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER']; + } + $final_uri .= $server_name; + if (!strpos($server_name, ':')) { + if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443) + || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) { + $final_uri .= ':'; + $final_uri .= $_SERVER['SERVER_PORT']; + } + } + + $final_uri .= strtok($_SERVER['REQUEST_URI'],"?"); + $cgi_params = '?'.strtok("?"); + // remove the ticket if present in the CGI parameters + $cgi_params = preg_replace('/&ticket=[^&]*/','',$cgi_params); + $cgi_params = preg_replace('/\?ticket=[^&;]*/','?',$cgi_params); + $cgi_params = preg_replace('/\?%26/','?',$cgi_params); + $cgi_params = preg_replace('/\?&/','?',$cgi_params); + $cgi_params = preg_replace('/\?$/','',$cgi_params); + $final_uri .= $cgi_params; + $this->setURL($final_uri); + } + phpCAS::traceEnd($this->_url); + return $this->_url; + } + + /** + * This method sets the URL of the current request + * + * @param $url url to set for service + * + * @private + */ + function setURL($url) + { + $this->_url = $url; + } + + // ######################################################################## + // AUTHENTICATION ERROR HANDLING + // ######################################################################## + /** + * This method is used to print the HTML output when the user was not authenticated. + * + * @param $failure the failure that occured + * @param $cas_url the URL the CAS server was asked for + * @param $no_response the response from the CAS server (other + * parameters are ignored if TRUE) + * @param $bad_response bad response from the CAS server ($err_code + * and $err_msg ignored if TRUE) + * @param $cas_response the response of the CAS server + * @param $err_code the error code given by the CAS server + * @param $err_msg the error message given by the CAS server + * + * @private + */ + function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='') + { + phpCAS::traceBegin(); + + $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED)); + printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),$this->getURL(),$_SERVER['SERVER_ADMIN']); + phpCAS::trace('CAS URL: '.$cas_url); + phpCAS::trace('Authentication failure: '.$failure); + if ( $no_response ) { + phpCAS::trace('Reason: no response from the CAS server'); + } else { + if ( $bad_response ) { + phpCAS::trace('Reason: bad response from the CAS server'); + } else { + switch ($this->getServerVersion()) { + case CAS_VERSION_1_0: + phpCAS::trace('Reason: CAS error'); + break; + case CAS_VERSION_2_0: + if ( empty($err_code) ) + phpCAS::trace('Reason: no CAS error'); + else + phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg); + break; + } + } + phpCAS::trace('CAS response: '.$cas_response); + } + $this->printHTMLFooter(); + phpCAS::traceExit(); + exit(); + } + + /** @} */ +} + +?> \ No newline at end of file diff --git a/auth/cas/CAS/domxml-php4-php5.php b/auth/cas/CAS/domxml-php4-php5.php index d64747514c3..4d5f5e47abd 100644 --- a/auth/cas/CAS/domxml-php4-php5.php +++ b/auth/cas/CAS/domxml-php4-php5.php @@ -1,277 +1,277 @@ - - * { - * if (version_compare(PHP_VERSION,'5','>=')) - * require_once('domxml-php4-to-php5.php'); - * } - * - * - * Version 1.5.5, 2005-01-18, http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/ - * - * ------------------------------------------------------------------
- * Written by Alexandre Alapetite, http://alexandre.alapetite.net/cv/ - * - * Copyright 2004, Licence: Creative Commons "Attribution-ShareAlike 2.0 France" BY-SA (FR), - * http://creativecommons.org/licenses/by-sa/2.0/fr/ - * http://alexandre.alapetite.net/divers/apropos/#by-sa - * - Attribution. You must give the original author credit - * - Share Alike. If you alter, transform, or build upon this work, - * you may distribute the resulting work only under a license identical to this one - * - The French law is authoritative - * - Any of these conditions can be waived if you get permission from Alexandre Alapetite - * - Please send to Alexandre Alapetite the modifications you make, - * in order to improve this file for the benefit of everybody - * - * If you want to distribute this code, please do it as a link to: - * http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/ - */ - -function domxml_new_doc($version) {return new php4DOMDocument('');} -function domxml_open_file($filename) {return new php4DOMDocument($filename);} -function domxml_open_mem($str) -{ - $dom=new php4DOMDocument(''); - $dom->myDOMNode->loadXML($str); - return $dom; -} -function xpath_eval($xpath_context,$eval_str,$contextnode=null) {return $xpath_context->query($eval_str,$contextnode);} -function xpath_new_context($dom_document) {return new php4DOMXPath($dom_document);} - -class php4DOMAttr extends php4DOMNode -{ - function php4DOMAttr($aDOMAttr) {$this->myDOMNode=$aDOMAttr;} - function Name() {return $this->myDOMNode->name;} - function Specified() {return $this->myDOMNode->specified;} - function Value() {return $this->myDOMNode->value;} -} - -class php4DOMDocument extends php4DOMNode -{ - function php4DOMDocument($filename='') - { - $this->myDOMNode=new DOMDocument(); - if ($filename!='') $this->myDOMNode->load($filename); - } - function create_attribute($name,$value) - { - $myAttr=$this->myDOMNode->createAttribute($name); - $myAttr->value=$value; - return new php4DOMAttr($myAttr,$this); - } - function create_cdata_section($content) {return new php4DOMNode($this->myDOMNode->createCDATASection($content),$this);} - function create_comment($data) {return new php4DOMNode($this->myDOMNode->createComment($data),$this);} - function create_element($name) {return new php4DOMElement($this->myDOMNode->createElement($name),$this);} - function create_text_node($content) {return new php4DOMNode($this->myDOMNode->createTextNode($content),$this);} - function document_element() {return new php4DOMElement($this->myDOMNode->documentElement,$this);} - function dump_file($filename,$compressionmode=false,$format=false) {return $this->myDOMNode->save($filename);} - function dump_mem($format=false,$encoding=false) {return $this->myDOMNode->saveXML();} - function get_element_by_id($id) {return new php4DOMElement($this->myDOMNode->getElementById($id),$this);} - function get_elements_by_tagname($name) - { - $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name); - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i)) - { - $nodeSet[]=new php4DOMElement($node,$this); - $i++; - } - return $nodeSet; - } - function html_dump_mem() {return $this->myDOMNode->saveHTML();} - function root() {return new php4DOMElement($this->myDOMNode->documentElement,$this);} -} - -class php4DOMElement extends php4DOMNode -{ - function get_attribute($name) {return $this->myDOMNode->getAttribute($name);} - function get_elements_by_tagname($name) - { - $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name); - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i)) - { - $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument); - $i++; - } - return $nodeSet; - } - function has_attribute($name) {return $this->myDOMNode->hasAttribute($name);} - function remove_attribute($name) {return $this->myDOMNode->removeAttribute($name);} - function set_attribute($name,$value) {return $this->myDOMNode->setAttribute($name,$value);} - function tagname() {return $this->myDOMNode->tagName;} -} - -class php4DOMNode -{ - var $myDOMNode; - var $myOwnerDocument; - function php4DOMNode($aDomNode,$aOwnerDocument) - { - $this->myDOMNode=$aDomNode; - $this->myOwnerDocument=$aOwnerDocument; - } - function __get($name) - { - if ($name=='type') return $this->myDOMNode->nodeType; - elseif ($name=='tagname') return $this->myDOMNode->tagName; - elseif ($name=='content') return $this->myDOMNode->textContent; - else - { - $myErrors=debug_backtrace(); - trigger_error('Undefined property: '.get_class($this).'::$'.$name.' ['.$myErrors[0]['file'].':'.$myErrors[0]['line'].']',E_USER_NOTICE); - return false; - } - } - function append_child($newnode) {return new php4DOMElement($this->myDOMNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);} - function append_sibling($newnode) {return new php4DOMElement($this->myDOMNode->parentNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);} - function attributes() - { - $myDOMNodeList=$this->myDOMNode->attributes; - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i)) - { - $nodeSet[]=new php4DOMAttr($node,$this->myOwnerDocument); - $i++; - } - return $nodeSet; - } - function child_nodes() - { - $myDOMNodeList=$this->myDOMNode->childNodes; - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i)) - { - $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument); - $i++; - } - return $nodeSet; - } - function children() {return $this->child_nodes();} - function clone_node($deep=false) {return new php4DOMElement($this->myDOMNode->cloneNode($deep),$this->myOwnerDocument);} - function first_child() {return new php4DOMElement($this->myDOMNode->firstChild,$this->myOwnerDocument);} - function get_content() {return $this->myDOMNode->textContent;} - function has_attributes() {return $this->myDOMNode->hasAttributes();} - function has_child_nodes() {return $this->myDOMNode->hasChildNodes();} - function insert_before($newnode,$refnode) {return new php4DOMElement($this->myDOMNode->insertBefore($newnode->myDOMNode,$refnode->myDOMNode),$this->myOwnerDocument);} - function is_blank_node() - { - $myDOMNodeList=$this->myDOMNode->childNodes; - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i)) - { - if (($node->nodeType==XML_ELEMENT_NODE)|| - (($node->nodeType==XML_TEXT_NODE)&&!ereg('^([[:cntrl:]]|[[:space:]])*$',$node->nodeValue))) - return false; - $i++; - } - return true; - } - function last_child() {return new php4DOMElement($this->myDOMNode->lastChild,$this->myOwnerDocument);} - function new_child($name,$content) - { - $mySubNode=$this->myDOMNode->ownerDocument->createElement($name); - $mySubNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($content)); - $this->myDOMNode->appendChild($mySubNode); - return new php4DOMElement($mySubNode,$this->myOwnerDocument); - } - function next_sibling() {return new php4DOMElement($this->myDOMNode->nextSibling,$this->myOwnerDocument);} - function node_name() {return $this->myDOMNode->localName;} - function node_type() {return $this->myDOMNode->nodeType;} - function node_value() {return $this->myDOMNode->nodeValue;} - function owner_document() {return $this->myOwnerDocument;} - function parent_node() {return new php4DOMElement($this->myDOMNode->parentNode,$this->myOwnerDocument);} - function prefix() {return $this->myDOMNode->prefix;} - function previous_sibling() {return new php4DOMElement($this->myDOMNode->previousSibling,$this->myOwnerDocument);} - function remove_child($oldchild) {return new php4DOMElement($this->myDOMNode->removeChild($oldchild->myDOMNode),$this->myOwnerDocument);} - function replace_child($oldnode,$newnode) {return new php4DOMElement($this->myDOMNode->replaceChild($oldnode->myDOMNode,$newnode->myDOMNode),$this->myOwnerDocument);} - function set_content($text) - { - if (($this->myDOMNode->hasChildNodes())&&($this->myDOMNode->firstChild->nodeType==XML_TEXT_NODE)) - $this->myDOMNode->removeChild($this->myDOMNode->firstChild); - return $this->myDOMNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($text)); - } -} - -class php4DOMNodelist -{ - var $myDOMNodelist; - var $nodeset; - function php4DOMNodelist($aDOMNodelist,$aOwnerDocument) - { - $this->myDOMNodelist=$aDOMNodelist; - $this->nodeset=array(); - $i=0; - if (isset($this->myDOMNodelist)) - while ($node=$this->myDOMNodelist->item($i)) - { - $this->nodeset[]=new php4DOMElement($node,$aOwnerDocument); - $i++; - } - } -} - -class php4DOMXPath -{ - var $myDOMXPath; - var $myOwnerDocument; - function php4DOMXPath($dom_document) - { - $this->myOwnerDocument=$dom_document; - $this->myDOMXPath=new DOMXPath($dom_document->myDOMNode); - } - function query($eval_str,$contextnode) - { - if (isset($contextnode)) return new php4DOMNodelist($this->myDOMXPath->query($eval_str,$contextnode->myDOMNode),$this->myOwnerDocument); - else return new php4DOMNodelist($this->myDOMXPath->query($eval_str),$this->myOwnerDocument); - } - function xpath_register_ns($prefix,$namespaceURI) {return $this->myDOMXPath->registerNamespace($prefix,$namespaceURI);} -} - -if (extension_loaded('xsl')) -{//See also: http://alexandre.alapetite.net/doc-alex/xslt-php4-php5/ - function domxml_xslt_stylesheet($xslstring) {return new php4DomXsltStylesheet(DOMDocument::loadXML($xslstring));} - function domxml_xslt_stylesheet_doc($dom_document) {return new php4DomXsltStylesheet($dom_document);} - function domxml_xslt_stylesheet_file($xslfile) {return new php4DomXsltStylesheet(DOMDocument::load($xslfile));} - class php4DomXsltStylesheet - { - var $myxsltProcessor; - function php4DomXsltStylesheet($dom_document) - { - $this->myxsltProcessor=new xsltProcessor(); - $this->myxsltProcessor->importStyleSheet($dom_document); - } - function process($dom_document,$xslt_parameters=array(),$param_is_xpath=false) - { - foreach ($xslt_parameters as $param=>$value) - $this->myxsltProcessor->setParameter('',$param,$value); - $myphp4DOMDocument=new php4DOMDocument(); - $myphp4DOMDocument->myDOMNode=$this->myxsltProcessor->transformToDoc($dom_document->myDOMNode); - return $myphp4DOMDocument; - } - function result_dump_file($dom_document,$filename) - { - $html=$dom_document->myDOMNode->saveHTML(); - file_put_contents($filename,$html); - return $html; - } - function result_dump_mem($dom_document) {return $dom_document->myDOMNode->saveHTML();} - } -} + + * { + * if (version_compare(PHP_VERSION,'5','>=')) + * require_once('domxml-php4-to-php5.php'); + * } + * + * + * Version 1.5.5, 2005-01-18, http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/ + * + * ------------------------------------------------------------------
+ * Written by Alexandre Alapetite, http://alexandre.alapetite.net/cv/ + * + * Copyright 2004, Licence: Creative Commons "Attribution-ShareAlike 2.0 France" BY-SA (FR), + * http://creativecommons.org/licenses/by-sa/2.0/fr/ + * http://alexandre.alapetite.net/divers/apropos/#by-sa + * - Attribution. You must give the original author credit + * - Share Alike. If you alter, transform, or build upon this work, + * you may distribute the resulting work only under a license identical to this one + * - The French law is authoritative + * - Any of these conditions can be waived if you get permission from Alexandre Alapetite + * - Please send to Alexandre Alapetite the modifications you make, + * in order to improve this file for the benefit of everybody + * + * If you want to distribute this code, please do it as a link to: + * http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/ + */ + +function domxml_new_doc($version) {return new php4DOMDocument('');} +function domxml_open_file($filename) {return new php4DOMDocument($filename);} +function domxml_open_mem($str) +{ + $dom=new php4DOMDocument(''); + $dom->myDOMNode->loadXML($str); + return $dom; +} +function xpath_eval($xpath_context,$eval_str,$contextnode=null) {return $xpath_context->query($eval_str,$contextnode);} +function xpath_new_context($dom_document) {return new php4DOMXPath($dom_document);} + +class php4DOMAttr extends php4DOMNode +{ + function php4DOMAttr($aDOMAttr) {$this->myDOMNode=$aDOMAttr;} + function Name() {return $this->myDOMNode->name;} + function Specified() {return $this->myDOMNode->specified;} + function Value() {return $this->myDOMNode->value;} +} + +class php4DOMDocument extends php4DOMNode +{ + function php4DOMDocument($filename='') + { + $this->myDOMNode=new DOMDocument(); + if ($filename!='') $this->myDOMNode->load($filename); + } + function create_attribute($name,$value) + { + $myAttr=$this->myDOMNode->createAttribute($name); + $myAttr->value=$value; + return new php4DOMAttr($myAttr,$this); + } + function create_cdata_section($content) {return new php4DOMNode($this->myDOMNode->createCDATASection($content),$this);} + function create_comment($data) {return new php4DOMNode($this->myDOMNode->createComment($data),$this);} + function create_element($name) {return new php4DOMElement($this->myDOMNode->createElement($name),$this);} + function create_text_node($content) {return new php4DOMNode($this->myDOMNode->createTextNode($content),$this);} + function document_element() {return new php4DOMElement($this->myDOMNode->documentElement,$this);} + function dump_file($filename,$compressionmode=false,$format=false) {return $this->myDOMNode->save($filename);} + function dump_mem($format=false,$encoding=false) {return $this->myDOMNode->saveXML();} + function get_element_by_id($id) {return new php4DOMElement($this->myDOMNode->getElementById($id),$this);} + function get_elements_by_tagname($name) + { + $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name); + $nodeSet=array(); + $i=0; + if (isset($myDOMNodeList)) + while ($node=$myDOMNodeList->item($i)) + { + $nodeSet[]=new php4DOMElement($node,$this); + $i++; + } + return $nodeSet; + } + function html_dump_mem() {return $this->myDOMNode->saveHTML();} + function root() {return new php4DOMElement($this->myDOMNode->documentElement,$this);} +} + +class php4DOMElement extends php4DOMNode +{ + function get_attribute($name) {return $this->myDOMNode->getAttribute($name);} + function get_elements_by_tagname($name) + { + $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name); + $nodeSet=array(); + $i=0; + if (isset($myDOMNodeList)) + while ($node=$myDOMNodeList->item($i)) + { + $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument); + $i++; + } + return $nodeSet; + } + function has_attribute($name) {return $this->myDOMNode->hasAttribute($name);} + function remove_attribute($name) {return $this->myDOMNode->removeAttribute($name);} + function set_attribute($name,$value) {return $this->myDOMNode->setAttribute($name,$value);} + function tagname() {return $this->myDOMNode->tagName;} +} + +class php4DOMNode +{ + var $myDOMNode; + var $myOwnerDocument; + function php4DOMNode($aDomNode,$aOwnerDocument) + { + $this->myDOMNode=$aDomNode; + $this->myOwnerDocument=$aOwnerDocument; + } + function __get($name) + { + if ($name=='type') return $this->myDOMNode->nodeType; + elseif ($name=='tagname') return $this->myDOMNode->tagName; + elseif ($name=='content') return $this->myDOMNode->textContent; + else + { + $myErrors=debug_backtrace(); + trigger_error('Undefined property: '.get_class($this).'::$'.$name.' ['.$myErrors[0]['file'].':'.$myErrors[0]['line'].']',E_USER_NOTICE); + return false; + } + } + function append_child($newnode) {return new php4DOMElement($this->myDOMNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);} + function append_sibling($newnode) {return new php4DOMElement($this->myDOMNode->parentNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);} + function attributes() + { + $myDOMNodeList=$this->myDOMNode->attributes; + $nodeSet=array(); + $i=0; + if (isset($myDOMNodeList)) + while ($node=$myDOMNodeList->item($i)) + { + $nodeSet[]=new php4DOMAttr($node,$this->myOwnerDocument); + $i++; + } + return $nodeSet; + } + function child_nodes() + { + $myDOMNodeList=$this->myDOMNode->childNodes; + $nodeSet=array(); + $i=0; + if (isset($myDOMNodeList)) + while ($node=$myDOMNodeList->item($i)) + { + $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument); + $i++; + } + return $nodeSet; + } + function children() {return $this->child_nodes();} + function clone_node($deep=false) {return new php4DOMElement($this->myDOMNode->cloneNode($deep),$this->myOwnerDocument);} + function first_child() {return new php4DOMElement($this->myDOMNode->firstChild,$this->myOwnerDocument);} + function get_content() {return $this->myDOMNode->textContent;} + function has_attributes() {return $this->myDOMNode->hasAttributes();} + function has_child_nodes() {return $this->myDOMNode->hasChildNodes();} + function insert_before($newnode,$refnode) {return new php4DOMElement($this->myDOMNode->insertBefore($newnode->myDOMNode,$refnode->myDOMNode),$this->myOwnerDocument);} + function is_blank_node() + { + $myDOMNodeList=$this->myDOMNode->childNodes; + $i=0; + if (isset($myDOMNodeList)) + while ($node=$myDOMNodeList->item($i)) + { + if (($node->nodeType==XML_ELEMENT_NODE)|| + (($node->nodeType==XML_TEXT_NODE)&&!ereg('^([[:cntrl:]]|[[:space:]])*$',$node->nodeValue))) + return false; + $i++; + } + return true; + } + function last_child() {return new php4DOMElement($this->myDOMNode->lastChild,$this->myOwnerDocument);} + function new_child($name,$content) + { + $mySubNode=$this->myDOMNode->ownerDocument->createElement($name); + $mySubNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($content)); + $this->myDOMNode->appendChild($mySubNode); + return new php4DOMElement($mySubNode,$this->myOwnerDocument); + } + function next_sibling() {return new php4DOMElement($this->myDOMNode->nextSibling,$this->myOwnerDocument);} + function node_name() {return $this->myDOMNode->localName;} + function node_type() {return $this->myDOMNode->nodeType;} + function node_value() {return $this->myDOMNode->nodeValue;} + function owner_document() {return $this->myOwnerDocument;} + function parent_node() {return new php4DOMElement($this->myDOMNode->parentNode,$this->myOwnerDocument);} + function prefix() {return $this->myDOMNode->prefix;} + function previous_sibling() {return new php4DOMElement($this->myDOMNode->previousSibling,$this->myOwnerDocument);} + function remove_child($oldchild) {return new php4DOMElement($this->myDOMNode->removeChild($oldchild->myDOMNode),$this->myOwnerDocument);} + function replace_child($oldnode,$newnode) {return new php4DOMElement($this->myDOMNode->replaceChild($oldnode->myDOMNode,$newnode->myDOMNode),$this->myOwnerDocument);} + function set_content($text) + { + if (($this->myDOMNode->hasChildNodes())&&($this->myDOMNode->firstChild->nodeType==XML_TEXT_NODE)) + $this->myDOMNode->removeChild($this->myDOMNode->firstChild); + return $this->myDOMNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($text)); + } +} + +class php4DOMNodelist +{ + var $myDOMNodelist; + var $nodeset; + function php4DOMNodelist($aDOMNodelist,$aOwnerDocument) + { + $this->myDOMNodelist=$aDOMNodelist; + $this->nodeset=array(); + $i=0; + if (isset($this->myDOMNodelist)) + while ($node=$this->myDOMNodelist->item($i)) + { + $this->nodeset[]=new php4DOMElement($node,$aOwnerDocument); + $i++; + } + } +} + +class php4DOMXPath +{ + var $myDOMXPath; + var $myOwnerDocument; + function php4DOMXPath($dom_document) + { + $this->myOwnerDocument=$dom_document; + $this->myDOMXPath=new DOMXPath($dom_document->myDOMNode); + } + function query($eval_str,$contextnode) + { + if (isset($contextnode)) return new php4DOMNodelist($this->myDOMXPath->query($eval_str,$contextnode->myDOMNode),$this->myOwnerDocument); + else return new php4DOMNodelist($this->myDOMXPath->query($eval_str),$this->myOwnerDocument); + } + function xpath_register_ns($prefix,$namespaceURI) {return $this->myDOMXPath->registerNamespace($prefix,$namespaceURI);} +} + +if (extension_loaded('xsl')) +{//See also: http://alexandre.alapetite.net/doc-alex/xslt-php4-php5/ + function domxml_xslt_stylesheet($xslstring) {return new php4DomXsltStylesheet(DOMDocument::loadXML($xslstring));} + function domxml_xslt_stylesheet_doc($dom_document) {return new php4DomXsltStylesheet($dom_document);} + function domxml_xslt_stylesheet_file($xslfile) {return new php4DomXsltStylesheet(DOMDocument::load($xslfile));} + class php4DomXsltStylesheet + { + var $myxsltProcessor; + function php4DomXsltStylesheet($dom_document) + { + $this->myxsltProcessor=new xsltProcessor(); + $this->myxsltProcessor->importStyleSheet($dom_document); + } + function process($dom_document,$xslt_parameters=array(),$param_is_xpath=false) + { + foreach ($xslt_parameters as $param=>$value) + $this->myxsltProcessor->setParameter('',$param,$value); + $myphp4DOMDocument=new php4DOMDocument(); + $myphp4DOMDocument->myDOMNode=$this->myxsltProcessor->transformToDoc($dom_document->myDOMNode); + return $myphp4DOMDocument; + } + function result_dump_file($dom_document,$filename) + { + $html=$dom_document->myDOMNode->saveHTML(); + file_put_contents($filename,$html); + return $html; + } + function result_dump_mem($dom_document) {return $dom_document->myDOMNode->saveHTML();} + } +} ?> \ No newline at end of file diff --git a/auth/cas/CAS/languages/english.php b/auth/cas/CAS/languages/english.php index c1434503142..7a99b547fdd 100644 --- a/auth/cas/CAS/languages/english.php +++ b/auth/cas/CAS/languages/english.php @@ -1,27 +1,27 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => 'using server', - CAS_STR_AUTHENTICATION_WANTED - => 'CAS Authentication wanted!', - CAS_STR_LOGOUT - => 'CAS logout wanted!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'You should already have been redirected to the CAS server. Click here to continue.', - CAS_STR_AUTHENTICATION_FAILED - => 'CAS Authentication failed!', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

You were not authenticated.

You may submit your request again by clicking here.

If the problem persists, you may contact the administrator of this site.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'The service `%s\' is not available (%s).' -); - + + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ + +$this->_strings = array( + CAS_STR_USING_SERVER + => 'using server', + CAS_STR_AUTHENTICATION_WANTED + => 'CAS Authentication wanted!', + CAS_STR_LOGOUT + => 'CAS logout wanted!', + CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED + => 'You should already have been redirected to the CAS server. Click here to continue.', + CAS_STR_AUTHENTICATION_FAILED + => 'CAS Authentication failed!', + CAS_STR_YOU_WERE_NOT_AUTHENTICATED + => '

You were not authenticated.

You may submit your request again by clicking here.

If the problem persists, you may contact the administrator of this site.

', + CAS_STR_SERVICE_UNAVAILABLE + => 'The service `%s\' is not available (%s).' +); + ?> \ No newline at end of file diff --git a/auth/cas/CAS/languages/french.php b/auth/cas/CAS/languages/french.php index 675a7fc04ec..4434c80801e 100644 --- a/auth/cas/CAS/languages/french.php +++ b/auth/cas/CAS/languages/french.php @@ -1,28 +1,28 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => 'utilisant le serveur', - CAS_STR_AUTHENTICATION_WANTED - => 'Authentication CAS nécessaire !', - CAS_STR_LOGOUT - => 'Déconnexion demandée !', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'Vous auriez du etre redirigé(e) vers le serveur CAS. Cliquez ici pour continuer.', - CAS_STR_AUTHENTICATION_FAILED - => 'Authentification CAS infructueuse !', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

Vous n\'avez pas été authentifié(e).

Vous pouvez soumettre votre requete à nouveau en cliquant ici.

Si le problème persiste, vous pouvez contacter l\'administrateur de ce site.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'Le service `%s\' est indisponible (%s)' - -); - + + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ + +$this->_strings = array( + CAS_STR_USING_SERVER + => 'utilisant le serveur', + CAS_STR_AUTHENTICATION_WANTED + => 'Authentication CAS nécessaire !', + CAS_STR_LOGOUT + => 'Déconnexion demandée !', + CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED + => 'Vous auriez du etre redirigé(e) vers le serveur CAS. Cliquez ici pour continuer.', + CAS_STR_AUTHENTICATION_FAILED + => 'Authentification CAS infructueuse !', + CAS_STR_YOU_WERE_NOT_AUTHENTICATED + => '

Vous n\'avez pas été authentifié(e).

Vous pouvez soumettre votre requete à nouveau en cliquant ici.

Si le problème persiste, vous pouvez contacter l\'administrateur de ce site.

', + CAS_STR_SERVICE_UNAVAILABLE + => 'Le service `%s\' est indisponible (%s)' + +); + ?> \ No newline at end of file diff --git a/auth/cas/CAS/languages/german.php b/auth/cas/CAS/languages/german.php index 29daeb35dde..09342228319 100644 --- a/auth/cas/CAS/languages/german.php +++ b/auth/cas/CAS/languages/german.php @@ -1,27 +1,27 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => 'via Server', - CAS_STR_AUTHENTICATION_WANTED - => 'CAS Authentifizierung erforderlich!', - CAS_STR_LOGOUT - => 'CAS Abmeldung!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'eigentlich häten Sie zum CAS Server weitergeleitet werden sollen. Drücken Sie hier um fortzufahren.', - CAS_STR_AUTHENTICATION_FAILED - => 'CAS Anmeldung fehlgeschlagen!', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

Sie wurden nicht angemeldet.

Um es erneut zu versuchen klicken Sie hier.

Wenn das Problem bestehen bleibt, kontkatieren Sie den Administrator dieser Seite.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'Der Dienst `%s\' ist nicht verfügbar (%s).' -); - + + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ + +$this->_strings = array( + CAS_STR_USING_SERVER + => 'via Server', + CAS_STR_AUTHENTICATION_WANTED + => 'CAS Authentifizierung erforderlich!', + CAS_STR_LOGOUT + => 'CAS Abmeldung!', + CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED + => 'eigentlich häten Sie zum CAS Server weitergeleitet werden sollen. Drücken Sie hier um fortzufahren.', + CAS_STR_AUTHENTICATION_FAILED + => 'CAS Anmeldung fehlgeschlagen!', + CAS_STR_YOU_WERE_NOT_AUTHENTICATED + => '

Sie wurden nicht angemeldet.

Um es erneut zu versuchen klicken Sie hier.

Wenn das Problem bestehen bleibt, kontkatieren Sie den Administrator dieser Seite.

', + CAS_STR_SERVICE_UNAVAILABLE + => 'Der Dienst `%s\' ist nicht verfügbar (%s).' +); + ?> \ No newline at end of file diff --git a/auth/cas/CAS/languages/greek.php b/auth/cas/CAS/languages/greek.php index c17b1d66377..7b5adfdc065 100644 --- a/auth/cas/CAS/languages/greek.php +++ b/auth/cas/CAS/languages/greek.php @@ -1,27 +1,27 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( - CAS_STR_USING_SERVER - => '÷ñçóéìïðïéåßôáé ï åîõðçñåôçôÞò', - CAS_STR_AUTHENTICATION_WANTED - => 'Áðáéôåßôáé ç ôáõôïðïßçóç CAS!', - CAS_STR_LOGOUT - => 'Áðáéôåßôáé ç áðïóýíäåóç áðü CAS!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'Èá Ýðñåðå íá åß÷áôå áíáêáôåõèõíèåß óôïí åîõðçñåôçôÞ CAS. ÊÜíôå êëßê åäþ ãéá íá óõíå÷ßóåôå.', - CAS_STR_AUTHENTICATION_FAILED - => 'Ç ôáõôïðïßçóç CAS áðÝôõ÷å!', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

Äåí ôáõôïðïéçèÞêáôå.

Ìðïñåßôå íá îáíáðñïóðáèÞóåôå, êÜíïíôáò êëßê åäþ.

Åáí ôï ðñüâëçìá åðéìåßíåé, åëÜôå óå åðáöÞ ìå ôïí äéá÷åéñéóôÞ.

', - CAS_STR_SERVICE_UNAVAILABLE - => 'Ç õðçñåóßá `%s\' äåí åßíáé äéáèÝóéìç (%s).' -); - + + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ + +$this->_strings = array( + CAS_STR_USING_SERVER + => '÷ñçóéìïðïéåßôáé ï åîõðçñåôçôÞò', + CAS_STR_AUTHENTICATION_WANTED + => 'Áðáéôåßôáé ç ôáõôïðïßçóç CAS!', + CAS_STR_LOGOUT + => 'Áðáéôåßôáé ç áðïóýíäåóç áðü CAS!', + CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED + => 'Èá Ýðñåðå íá åß÷áôå áíáêáôåõèõíèåß óôïí åîõðçñåôçôÞ CAS. ÊÜíôå êëßê åäþ ãéá íá óõíå÷ßóåôå.', + CAS_STR_AUTHENTICATION_FAILED + => 'Ç ôáõôïðïßçóç CAS áðÝôõ÷å!', + CAS_STR_YOU_WERE_NOT_AUTHENTICATED + => '

Äåí ôáõôïðïéçèÞêáôå.

Ìðïñåßôå íá îáíáðñïóðáèÞóåôå, êÜíïíôáò êëßê åäþ.

Åáí ôï ðñüâëçìá åðéìåßíåé, åëÜôå óå åðáöÞ ìå ôïí äéá÷åéñéóôÞ.

', + CAS_STR_SERVICE_UNAVAILABLE + => 'Ç õðçñåóßá `%s\' äåí åßíáé äéáèÝóéìç (%s).' +); + ?> \ No newline at end of file diff --git a/auth/cas/CAS/languages/japanese.php b/auth/cas/CAS/languages/japanese.php index 333bb17b6a0..84cffe0d056 100644 --- a/auth/cas/CAS/languages/japanese.php +++ b/auth/cas/CAS/languages/japanese.php @@ -1,27 +1,27 @@ -_strings = array( - CAS_STR_USING_SERVER - => 'using server', - CAS_STR_AUTHENTICATION_WANTED - => 'CAS¤Ë¤è¤ëǧ¾Ú¤ò¹Ô¤¤¤Þ¤¹', - CAS_STR_LOGOUT - => 'CAS¤«¤é¥í¥°¥¢¥¦¥È¤·¤Þ¤¹!', - CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED - => 'CAS¥µ¡¼¥Ð¤Ë¹Ô¤¯É¬Íפ¬¤¢¤ê¤Þ¤¹¡£¼«Æ°Åª¤ËžÁ÷¤µ¤ì¤Ê¤¤¾ì¹ç¤Ï ¤³¤Á¤é ¤ò¥¯¥ê¥Ã¥¯¤·¤ÆÂ³¹Ô¤·¤Þ¤¹¡£', - CAS_STR_AUTHENTICATION_FAILED - => 'CAS¤Ë¤è¤ëǧ¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿', - CAS_STR_YOU_WERE_NOT_AUTHENTICATED - => '

ǧ¾Ú¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿.

¤â¤¦°ìÅ٥ꥯ¥¨¥¹¥È¤òÁ÷¿®¤¹¤ë¾ì¹ç¤Ï¤³¤Á¤é¤ò¥¯¥ê¥Ã¥¯.

ÌäÂ꤬²ò·è¤·¤Ê¤¤¾ì¹ç¤Ï ¤³¤Î¥µ¥¤¥È¤Î´ÉÍý¼Ô¤ËÌ䤤¹ç¤ï¤»¤Æ¤¯¤À¤µ¤¤.

', - CAS_STR_SERVICE_UNAVAILABLE - => '¥µ¡¼¥Ó¥¹ `%s\' ¤ÏÍøÍѤǤ­¤Þ¤»¤ó (%s).' -); - +_strings = array( + CAS_STR_USING_SERVER + => 'using server', + CAS_STR_AUTHENTICATION_WANTED + => 'CAS¤Ë¤è¤ëǧ¾Ú¤ò¹Ô¤¤¤Þ¤¹', + CAS_STR_LOGOUT + => 'CAS¤«¤é¥í¥°¥¢¥¦¥È¤·¤Þ¤¹!', + CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED + => 'CAS¥µ¡¼¥Ð¤Ë¹Ô¤¯É¬Íפ¬¤¢¤ê¤Þ¤¹¡£¼«Æ°Åª¤ËžÁ÷¤µ¤ì¤Ê¤¤¾ì¹ç¤Ï ¤³¤Á¤é ¤ò¥¯¥ê¥Ã¥¯¤·¤ÆÂ³¹Ô¤·¤Þ¤¹¡£', + CAS_STR_AUTHENTICATION_FAILED + => 'CAS¤Ë¤è¤ëǧ¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿', + CAS_STR_YOU_WERE_NOT_AUTHENTICATED + => '

ǧ¾Ú¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿.

¤â¤¦°ìÅ٥ꥯ¥¨¥¹¥È¤òÁ÷¿®¤¹¤ë¾ì¹ç¤Ï¤³¤Á¤é¤ò¥¯¥ê¥Ã¥¯.

ÌäÂ꤬²ò·è¤·¤Ê¤¤¾ì¹ç¤Ï ¤³¤Î¥µ¥¤¥È¤Î´ÉÍý¼Ô¤ËÌ䤤¹ç¤ï¤»¤Æ¤¯¤À¤µ¤¤.

', + CAS_STR_SERVICE_UNAVAILABLE + => '¥µ¡¼¥Ó¥¹ `%s\' ¤ÏÍøÍѤǤ­¤Þ¤»¤ó (%s).' +); + ?> \ No newline at end of file diff --git a/auth/cas/CAS/languages/languages.php b/auth/cas/CAS/languages/languages.php index 2c6f8bb3b30..b1d9f862300 100644 --- a/auth/cas/CAS/languages/languages.php +++ b/auth/cas/CAS/languages/languages.php @@ -1,24 +1,24 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -//@{ -/** - * a phpCAS string index - */ -define("CAS_STR_USING_SERVER", 1); -define("CAS_STR_AUTHENTICATION_WANTED", 2); -define("CAS_STR_LOGOUT", 3); -define("CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED", 4); -define("CAS_STR_AUTHENTICATION_FAILED", 5); -define("CAS_STR_YOU_WERE_NOT_AUTHENTICATED", 6); -define("CAS_STR_SERVICE_UNAVAILABLE", 7); -//@} - + + * @sa @link internalLang Internationalization @endlink + * @ingroup internalLang + */ + +//@{ +/** + * a phpCAS string index + */ +define("CAS_STR_USING_SERVER", 1); +define("CAS_STR_AUTHENTICATION_WANTED", 2); +define("CAS_STR_LOGOUT", 3); +define("CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED", 4); +define("CAS_STR_AUTHENTICATION_FAILED", 5); +define("CAS_STR_YOU_WERE_NOT_AUTHENTICATED", 6); +define("CAS_STR_SERVICE_UNAVAILABLE", 7); +//@} + ?> \ No newline at end of file diff --git a/auth/cas/auth.php b/auth/cas/auth.php index 5b0292b97ba..9e69902e4f6 100644 --- a/auth/cas/auth.php +++ b/auth/cas/auth.php @@ -1,1258 +1,1110 @@ -libdir.'/authlib.php'); -require_once($CFG->dirroot.'/auth/cas/CAS/CAS.php'); -/** - * CAS authentication plugin. - */ -class auth_plugin_cas extends auth_plugin_base { - - /** - * Constructor. - */ - function auth_plugin_cas() { - $this->authtype = 'cas'; - $this->config = get_config('auth/cas'); - if (empty($this->config->ldapencoding)) { - $this->config->ldapencoding = 'utf-8'; - } - if (empty($this->config->user_type)) { - $this->config->user_type = 'default'; - } - - $default = $this->ldap_getdefaults(); - - //use defaults if values not given - foreach ($default as $key => $value) { - // watch out - 0, false are correct values too - if (!isset($this->config->{$key}) or $this->config->{$key} == '') { - $this->config->{$key} = $value[$this->config->user_type]; - } - } - //hack prefix to objectclass - if (empty($this->config->objectclass)) { // Can't send empty filter - $this->config->objectclass='objectClass=*'; - } else if (strpos($this->config->objectclass, 'objectClass=') !== 0) { - $this->config->objectclass = 'objectClass='.$this->config->objectclass; - } - - } - - /** - * Authenticates user againt CAS - * Returns true if the username and password work and false if they are - * wrong or don't exist. - * - * @param string $username The username - * @param string $password The password - * @return bool Authentication success or failure. - */ - function user_login ($username, $password) { - return phpCAS::isAuthenticated(); - } - - - - /** - * Returns true if this authentication plugin is 'internal'. - * - * @return bool - */ - function is_internal() { - return false; - } - - /** - * Returns true if this authentication plugin can change the user's - * password. - * - * @return bool - */ - function can_change_password() { - return false; - } - - /** - * authentication choice (CAS or other) - * redirection to the CAS form or to login/index.php - * for other authentication - */ - function loginpage_hook() { - global $frm; - global $test; - global $CFG; - - $site = get_site(); - $CASform = get_string("CASform","auth"); - $username = optional_param("username"); - - if (!empty($username)) { - - return; - } - -// Connection to CAS server - $this->connectCAS(); - - - if ($this->config->multiauth) { - $authCAS = optional_param("authCAS"); - if ($authCAS=="NOCAS") - return; - -// choice authentication form for multi-authentication -// test pgtIou parameter for proxy mode (https connection -// in background from CAS server to the php server) - if ($authCAS!="CAS" && !isset($_GET["pgtIou"])) - { - print_header("$site->fullname: $CASform", $site->fullname, $CASform); - include($CFG->dirroot."/auth/cas/cas_form.html"); - print_footer(); - exit(); - } - } - -// CAS authentication - if (!phpCAS::isAuthenticated()) - {phpCAS::forceAuthentication();} - - $frm->username=phpCAS::getUser(); - $frm->password="cas"; - - -} - - /** - * logout from the cas - * - * This function is called from admin/auth.php - * - */ - function prelogout_hook() { - global $CFG; - if ($this->config->logoutcas ) { - $backurl = $CFG->wwwroot; - $this->connectCAS(); - phpCAS::logout($backurl); - } - } - - - /** - * Connect to the cas (clientcas connection or proxycas connection - * - * This function is called from admin/auth.php - * - */ - function connectCAS() { -// mode proxy CAS - if ($this->config->proxycas) { - phpCAS::proxy($this->config->casversion, $this-> config->hostname, (int) $this->config->port, $this->config->baseuri); - } -// mode client CAS - else { - phpCAS::client($this->config->casversion, $this-> config->hostname, (int) $this->config->port, $this->config->baseuri); - } - } - - /** - * Prints a form for configuring this authentication plugin. - * - * This function is called from admin/auth.php, and outputs a full page with - * a form for configuring this plugin. - * - * @param array $page An object containing all the data for this page. - */ - function config_form($config, $err, $user_fields) { - include 'config.html'; - } - - /** - * Returns the URL for changing the user's pw, or empty if the default can - * be used. - * - * @return string - */ - function change_password_url() { - return ""; - } - - /** - * returns predefined usertypes - * - * @return array of predefined usertypes - */ - function ldap_suppported_usertypes() { - $types = array(); - $types['edir']='Novell Edirectory'; - $types['rfc2307']='posixAccount (rfc2307)'; - $types['rfc2307bis']='posixAccount (rfc2307bis)'; - $types['samba']='sambaSamAccount (v.3.0.7)'; - $types['ad']='MS ActiveDirectory'; - $types['default']=get_string('default'); - return $types; - } - - - /** - * Processes and stores configuration data for this authentication plugin. - */ - function process_config($config) { - // set to defaults if undefined - // CAS settings - if (!isset ($config->hostname)) - $config->hostname = ''; - if (!isset ($config->port)) - $config->port = ''; - if (!isset ($config->casversion)) - $config->casversion = ''; - if (!isset ($config->baseuri)) - $config->baseuri = ''; - if (!isset ($config->language)) - $config->language = ''; - if (!isset ($config->use_cas)) - $config->use_cas = ''; - if (!isset ($config->proxycas)) - $config->proxycas = ''; - if (!isset ($config->logoutcas)) - $config->logoutcas = ''; - if (!isset ($config->multiauth)) - $config->multiauth = ''; - // LDAP settings - if (!isset($config->host_url)) - { $config->host_url = ''; } - if (empty($config->ldapencoding)) - { $config->ldapencoding = 'utf-8'; } - if (!isset($config->contexts)) - { $config->contexts = ''; } - if (!isset($config->user_type)) - { $config->user_type = 'default'; } - if (!isset($config->user_attribute)) - { $config->user_attribute = ''; } - if (!isset($config->search_sub)) - { $config->search_sub = ''; } - if (!isset($config->opt_deref)) - { $config->opt_deref = ''; } - if (!isset($config->bind_dn)) - {$config->bind_dn = ''; } - if (!isset($config->bind_pw)) - {$config->bind_pw = ''; } - if (!isset($config->version)) - {$config->version = '2'; } - if (!isset($config->objectclass)) - {$config->objectclass = ''; } - if (!isset($config->memberattribute)) - {$config->memberattribute = ''; } - if (!isset($config->memberattribute_isdn)) - {$config->memberattribute_isdn = ''; } - if (!isset($config->attrcreators)) - {$config->attrcreators = ''; } - if (!isset($config->groupecreators)) - {$config->groupecreators = ''; } - if (!isset($config->removeuser)) - {$config->removeuser = 0; } - - // save CAS settings - set_config('hostname', $config->hostname, 'auth/cas'); - set_config('port', $config->port, 'auth/cas'); - set_config('casversion', $config->casversion, 'auth/cas'); - set_config('baseuri', $config->baseuri, 'auth/cas'); - set_config('language', $config->language, 'auth/cas'); - set_config('use_cas', $config->use_cas, 'auth/cas'); - set_config('proxycas', $config->proxycas, 'auth/cas'); - set_config('logoutcas', $config->logoutcas, 'auth/cas'); - set_config('multiauth', $config->multiauth, 'auth/cas'); - // save LDAP settings - set_config('host_url', $config->host_url, 'auth/cas'); - set_config('ldapencoding', $config->ldapencoding, 'auth/cas'); - set_config('host_url', $config->host_url, 'auth/cas'); - set_config('contexts', $config->contexts, 'auth/cas'); - set_config('user_type', $config->user_type, 'auth/cas'); - set_config('user_attribute', $config->user_attribute, 'auth/cas'); - set_config('search_sub', $config->search_sub, 'auth/cas'); - set_config('opt_deref', $config->opt_deref, 'auth/cas'); - set_config('bind_dn', $config->bind_dn, 'auth/cas'); - set_config('bind_pw', $config->bind_pw, 'auth/cas'); - set_config('version', $config->version, 'auth/cas'); - set_config('objectclass', $config->objectclass, 'auth/cas'); - set_config('memberattribute', $config->memberattribute, 'auth/cas'); - set_config('memberattribute_isdn', $config->memberattribute_isdn, 'auth/cas'); - set_config('attrcreators', $config->attrcreators, 'auth/cas'); - set_config('groupecreators', $config->groupecreators, 'auth/cas'); - set_config('removeuser', $config->removeuser, 'auth/cas'); - - return true; - } - - /** - * Initializes needed ldap variables for cas-module - * - * Uses names defined in ldap_supported_usertypes. - * $default is first defined as: - * $default['pseudoname'] = array( - * 'typename1' => 'value', - * 'typename2' => 'value' - * .... - * ); - * - * @return array of default values - */ - function ldap_getdefaults() { - $default['objectclass'] = array( - 'edir' => 'User', - 'rfc2307' => 'posixAccount', - 'rfc2307bis' => 'posixAccount', - 'samba' => 'sambaSamAccount', - 'ad' => 'user', - 'default' => '*' - ); - $default['user_attribute'] = array( - 'edir' => 'cn', - 'rfc2307' => 'uid', - 'rfc2307bis' => 'uid', - 'samba' => 'uid', - 'ad' => 'cn', - 'default' => 'cn' - ); - $default['memberattribute'] = array( - 'edir' => 'member', - 'rfc2307' => 'member', - 'rfc2307bis' => 'member', - 'samba' => 'member', - 'ad' => 'member', - 'default' => 'member' - ); - $default['memberattribute_isdn'] = array( - 'edir' => '1', - 'rfc2307' => '0', - 'rfc2307bis' => '1', - 'samba' => '0', //is this right? - 'ad' => '1', - 'default' => '0' - ); - return $default; - } - - /** - * reads userinformation from ldap and return it in array() - * - * Read user information from external database and returns it as array(). - * Function should return all information available. If you are saving - * this information to moodle user-table you should honor syncronization flags - * - * @param string $username username (with system magic quotes) - * - * @return mixed array with no magic quotes or false on error - */ - function get_userinfo($username) { - - $textlib = textlib_get_instance(); - $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); - - $ldapconnection = $this->ldap_connect(); - $attrmap = $this->ldap_attributes(); - - $result = array(); - $search_attribs = array(); - - foreach ($attrmap as $key=>$values) { - if (!is_array($values)) { - $values = array($values); - } - foreach ($values as $value) { - if (!in_array($value, $search_attribs)) { - array_push($search_attribs, $value); - } - } - } - - $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); - - if (!$user_info_result = ldap_read($ldapconnection, $user_dn, $this->config->objectclass, $search_attribs)) { - return false; // error! - } - - $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result); - if (empty($user_entry)) { - return false; // entry not found - } - - foreach ($attrmap as $key=>$values) { - if (!is_array($values)) { - $values = array($values); - } - $ldapval = NULL; - foreach ($values as $value) { - if ($value == 'dn') { - $result[$key] = $user_dn; - } - if (!array_key_exists($value, $user_entry[0])) { - continue; // wrong data mapping! - } - if (is_array($user_entry[0][$value])) { - - $newval = $textlib->convert($user_entry[0][$value][0], $this->config->ldapencoding, 'utf-8'); - } else { - $newval = $textlib->convert($user_entry[0][$value], $this->config->ldapencoding, 'utf-8'); - } - if (!empty($newval)) { // favour ldap entries that are set - $ldapval = $newval; - } - } - if (!is_null($ldapval)) { - $result[$key] = $ldapval; - } - } - - @ldap_close($ldapconnection); - return $result; - } - - /** - * reads userinformation from ldap and return it in an object - * - * @param string $username username (with system magic quotes) - * @return mixed object or false on error - */ - function get_userinfo_asobj($username) { - $user_array = $this->get_userinfo($username); - if ($user_array == false) { - return false; //error or not found - } - $user_array = truncate_userinfo($user_array); - $user = new object(); - foreach ($user_array as $key=>$value) { - $user->{$key} = $value; - } - return $user; - } - - /** - * connects to ldap server - * - * Tries connect to specified ldap servers. - * Returns connection result or error. - * - * @return connection result - */ - function ldap_connect($binddn='',$bindpwd='') { - //Select bind password, With empty values use - //ldap_bind_* variables or anonymous bind if ldap_bind_* are empty - if ($binddn == '' and $bindpwd == '') { - if (!empty($this->config->bind_dn)) { - $binddn = $this->config->bind_dn; - } - if (!empty($this->config->bind_pw)) { - $bindpwd = $this->config->bind_pw; - } - } - - $urls = explode(";",$this->config->host_url); - - foreach ($urls as $server) { - $server = trim($server); - if (empty($server)) { - continue; - } - - $connresult = ldap_connect($server); - //ldap_connect returns ALWAYS true - - if (!empty($this->config->version)) { - ldap_set_option($connresult, LDAP_OPT_PROTOCOL_VERSION, $this->config->version); - } - - if (!empty($binddn)) { - //bind with search-user - //$debuginfo .= 'Using bind user'.$binddn.'and password:'.$bindpwd; - $bindresult=ldap_bind($connresult, $binddn,$bindpwd); - } - else { - //bind anonymously - $bindresult=@ldap_bind($connresult); - } - - if (!empty($this->config->opt_deref)) { - ldap_set_option($connresult, LDAP_OPT_DEREF, $this->config->opt_deref); - } - - if ($bindresult) { - return $connresult; - } - - $debuginfo .= "
Server: '$server'
Connection: '$connresult'
Bind result: '$bindresult'
"; - } - - //If any of servers are alive we have already returned connection - print_error('auth_ldap_noconnect_all','auth',$this->config->user_type); - return false; - } - - /** - * retuns user attribute mappings between moodle and ldap - * - * @return array - */ - - function ldap_attributes () { - $fields = array("firstname", "lastname", "email", "phone1", "phone2", - "department", "address", "city", "country", "description", - "idnumber", "lang" ); - $moodleattributes = array(); - foreach ($fields as $field) { - if (!empty($this->config->{"field_map_$field"})) { - $moodleattributes[$field] = $this->config->{"field_map_$field"}; - if (preg_match('/,/',$moodleattributes[$field])) { - $moodleattributes[$field] = explode(',', $moodleattributes[$field]); // split ? - } - } - } - $moodleattributes['username'] = $this->config->user_attribute; - return $moodleattributes; - } - - /** - * retuns dn of username - * - * Search specified contexts for username and return user dn - * like: cn=username,ou=suborg,o=org - * - * @param mixed $ldapconnection $ldapconnection result - * @param mixed $username username (external encoding no slashes) - * - */ - - function ldap_find_userdn ($ldapconnection, $extusername) { - - //default return value - $ldap_user_dn = FALSE; - - //get all contexts and look for first matching user - $ldap_contexts = explode(";",$this->config->contexts); - - if (!empty($this->config->create_context)) { - array_push($ldap_contexts, $this->config->create_context); - } - - foreach ($ldap_contexts as $context) { - - $context = trim($context); - if (empty($context)) { - continue; - } - - if ($this->config->search_sub) { - //use ldap_search to find first user from subtree - $ldap_result = ldap_search($ldapconnection, $context, "(".$this->config->user_attribute."=".$this->filter_addslashes($extusername).")",array($this->config->user_attribute)); - - } - else { - //search only in this context - $ldap_result = ldap_list($ldapconnection, $context, "(".$this->config->user_attribute."=".$this->filter_addslashes($extusername).")",array($this->config->user_attribute)); - } - - $entry = ldap_first_entry($ldapconnection,$ldap_result); - - if ($entry) { - $ldap_user_dn = ldap_get_dn($ldapconnection, $entry); - break ; - } - } - - return $ldap_user_dn; - } - - /** - * Quote control characters in quoted "texts" used in ldap - * - * @param string - */ - function ldap_addslashes($text) { - $text = str_replace('\\', '\\\\', $text); - $text = str_replace(array('"', "\0"), - array('\\"', '\\00'), $text); - return $text; - } - - /** - * returns all usernames from external database - * - * get_userlist returns all usernames from external database - * - * @return array - */ - function get_userlist() { - return $this->ldap_get_userlist("({$this->config->user_attribute}=*)"); - } - - /** - * checks if user exists on external db - * - * @param string $username (with system magic quotes) - */ - function user_exists($username) { - - $textlib = textlib_get_instance(); - $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); - - //returns true if given username exist on ldap - $users = $this->ldap_get_userlist("({$this->config->user_attribute}=".$this->filter_addslashes($extusername).")"); - return count($users); - } - - /** - * syncronizes user fron external db to moodle user table - * - * Sync is now using username attribute. - * - * Syncing users removes or suspends users that dont exists anymore in external db. - * Creates new users and updates coursecreator status of users. - * - * @param int $bulk_insert_records will insert $bulkinsert_records per insert statement - * valid only with $unsafe. increase to a couple thousand for - * blinding fast inserts -- but test it: you may hit mysqld's - * max_allowed_packet limit. - * @param bool $do_updates will do pull in data updates from ldap if relevant - */ - function sync_users ($bulk_insert_records = 1000, $do_updates = true) { - - global $CFG; - - $textlib = textlib_get_instance(); - - $droptablesql = array(); /// sql commands to drop the table (because session scope could be a problem for - /// some persistent drivers like ODBTP (mssql) or if this function is invoked - /// from within a PHP application using persistent connections - - // configure a temp table - print "Configuring temp table\n"; - switch (strtolower($CFG->dbfamily)) { - case 'mysql': - $temptable = $CFG->prefix . 'extuser'; - $droptablesql[] = 'DROP TEMPORARY TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) - execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later - echo "Creating temp table $temptable\n"; - execute_sql('CREATE TEMPORARY TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username)) TYPE=MyISAM', false); - break; - case 'postgres': - $temptable = $CFG->prefix . 'extuser'; - $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) - execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later - echo "Creating temp table $temptable\n"; - $bulk_insert_records = 1; // no support for multiple sets of values - execute_sql('CREATE TEMPORARY TABLE '. $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false); - break; - case 'mssql': - $temptable = '#'.$CFG->prefix . 'extuser'; /// MSSQL temp tables begin with # - $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) - execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later - echo "Creating temp table $temptable\n"; - $bulk_insert_records = 1; // no support for multiple sets of values - execute_sql('CREATE TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false); - break; - case 'oracle': - $temptable = $CFG->prefix . 'extuser'; - $droptablesql[] = 'TRUNCATE TABLE ' . $temptable; // oracle requires truncate before being able to drop a temp table - $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) - execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later - echo "Creating temp table $temptable\n"; - $bulk_insert_records = 1; // no support for multiple sets of values - execute_sql('CREATE GLOBAL TEMPORARY TABLE '.$temptable.' (username VARCHAR(64), PRIMARY KEY (username)) ON COMMIT PRESERVE ROWS', false); - break; - } - - print "Connecting to ldap...\n"; - $ldapconnection = $this->ldap_connect(); - - if (!$ldapconnection) { - @ldap_close($ldapconnection); - print get_string('auth_ldap_noconnect','auth',$this->config->host_url); - exit; - } - - //// - //// get user's list from ldap to sql in a scalable fashion - //// - // prepare some data we'll need - $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))"; - - $contexts = explode(";",$this->config->contexts); - - if (!empty($this->config->create_context)) { - array_push($contexts, $this->config->create_context); - } - - $fresult = array(); - foreach ($contexts as $context) { - $context = trim($context); - if (empty($context)) { - continue; - } - begin_sql(); - if ($this->config->search_sub) { - //use ldap_search to find first user from subtree - $ldap_result = ldap_search($ldapconnection, $context, - $filter, - array($this->config->user_attribute)); - } else { - //search only in this context - $ldap_result = ldap_list($ldapconnection, $context, - $filter, - array($this->config->user_attribute)); - } - - if ($entry = ldap_first_entry($ldapconnection, $ldap_result)) { - do { - $value = ldap_get_values_len($ldapconnection, $entry, $this->config->user_attribute); - $value = $textlib->convert($value[0], $this->config->ldapencoding, 'utf-8'); - array_push($fresult, $value); - if (count($fresult) >= $bulk_insert_records) { - $this->ldap_bulk_insert($fresult, $temptable); - $fresult = array(); - } - } while ($entry = ldap_next_entry($ldapconnection, $entry)); - } - unset($ldap_result); // free mem - - // insert any remaining users and release mem - if (count($fresult)) { - $this->ldap_bulk_insert($fresult, $temptable); - $fresult = array(); - } - commit_sql(); - } - - /// preserve our user database - /// if the temp table is empty, it probably means that something went wrong, exit - /// so as to avoid mass deletion of users; which is hard to undo - $count = get_record_sql('SELECT COUNT(username) AS count, 1 FROM ' . $temptable); - $count = $count->{'count'}; - if ($count < 1) { - print "Did not get any users from LDAP -- error? -- exiting\n"; - exit; - } else { - print "Got $count records from LDAP\n\n"; - } - - -/// User removal - // find users in DB that aren't in ldap -- to be removed! - // this is still not as scalable (but how often do we mass delete?) - if (!empty($this->config->removeuser)) { - $sql = "SELECT u.id, u.username, u.email - FROM {$CFG->prefix}user u - LEFT JOIN $temptable e ON u.username = e.username - WHERE u.auth='cas' - AND u.deleted=0 - AND e.username IS NULL"; - $remove_users = get_records_sql($sql); - - if (!empty($remove_users)) { - print "User entries to remove: ". count($remove_users) . "\n"; - - begin_sql(); - foreach ($remove_users as $user) { - if ($this->config->removeuser == 2) { - //following is copy pasted from admin/user.php - //maybe this should moved to function in lib/datalib.php - $updateuser = new object(); - $updateuser->id = $user->id; - $updateuser->deleted = 1; - $updateuser->username = addslashes("$user->email.".time()); // Remember it just in case - $updateuser->email = ''; // Clear this field to free it up - $updateuser->idnumber = ''; // Clear this field to free it up - $updateuser->timemodified = time(); - if (update_record('user', $updateuser)) { - delete_records('role_assignments', 'userid', $user->id); // unassign all roles - //copy pasted part ends - echo "\t"; print_string('auth_dbdeleteuser', 'auth', array($user->username, $user->id)); echo "\n"; - } else { - echo "\t"; print_string('auth_dbdeleteusererror', 'auth', $user->username); echo "\n"; - } - } else if ($this->config->removeuser == 1) { - $updateuser = new object(); - $updateuser->id = $user->id; - $updateuser->auth = 'nologin'; - if (update_record('user', $updateuser)) { - echo "\t"; print_string('auth_dbsuspenduser', 'auth', array($user->username, $user->id)); echo "\n"; - } else { - echo "\t"; print_string('auth_dbsuspendusererror', 'auth', $user->username); echo "\n"; - } - } - } - commit_sql(); - } else { - print "No user entries to be removed\n"; - } - unset($remove_users); // free mem! - } - -/// Revive suspended users - if (!empty($this->config->removeuser) and $this->config->removeuser == 1) { - $sql = "SELECT u.id, u.username - FROM $temptable e, {$CFG->prefix}user u - WHERE e.username=u.username - AND u.auth='nologin'"; - $revive_users = get_records_sql($sql); - - if (!empty($revive_users)) { - print "User entries to be revived: ". count($revive_users) . "\n"; - - begin_sql(); - foreach ($revive_users as $user) { - $updateuser = new object(); - $updateuser->id = $user->id; - $updateuser->auth = 'cas'; - if (update_record('user', $updateuser)) { - echo "\t"; print_string('auth_dbreviveser', 'auth', array($user->username, $user->id)); echo "\n"; - } else { - echo "\t"; print_string('auth_dbreviveusererror', 'auth', $user->username); echo "\n"; - } - } - commit_sql(); - } else { - print "No user entries to be revived\n"; - } - - unset($revive_users); - } - - -/// User Updates - time-consuming (optional) - if ($do_updates) { - // narrow down what fields we need to update - $all_keys = array_keys(get_object_vars($this->config)); - $updatekeys = array(); - foreach ($all_keys as $key) { - if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) { - // if we have a field to update it from - // and it must be updated 'onlogin' we - // update it on cron - if ( !empty($this->config->{'field_map_'.$match[1]}) - and $this->config->{$match[0]} === 'onlogin') { - array_push($updatekeys, $match[1]); // the actual key name - } - } - } - // print_r($all_keys); print_r($updatekeys); - unset($all_keys); unset($key); - - } else { - print "No updates to be done\n"; - } - if ( $do_updates and !empty($updatekeys) ) { // run updates only if relevant - $users = get_records_sql("SELECT u.username, u.id - FROM {$CFG->prefix}user u - WHERE u.deleted=0 AND u.auth='cas'"); - if (!empty($users)) { - print "User entries to update: ". count($users). "\n"; - - $sitecontext = get_context_instance(CONTEXT_SYSTEM); - if (!empty($this->config->creators) and !empty($this->config->memberattribute) - and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { - $creatorrole = array_shift($roles); // We can only use one, let's use the first one - } else { - $creatorrole = false; - } - - begin_sql(); - $xcount = 0; - $maxxcount = 100; - - foreach ($users as $user) { - echo "\t"; print_string('auth_dbupdatinguser', 'auth', array($user->username, $user->id)); - if (!$this->update_user_record(addslashes($user->username), $updatekeys)) { - echo " - ".get_string('skipped'); - } - echo "\n"; - $xcount++; - - // update course creators if needed - if ($creatorrole !== false) { - if ($this->iscreator($user->username)) { - role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'cas'); - } else { - role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id, 'cas'); - } - } - - if ($xcount++ > $maxxcount) { - commit_sql(); - begin_sql(); - $xcount = 0; - } - } - commit_sql(); - unset($users); // free mem - } - } else { // end do updates - print "No updates to be done\n"; - } - -/// User Additions - // find users missing in DB that are in LDAP - // note that get_records_sql wants at least 2 fields returned, - // and gives me a nifty object I don't want. - // note: we do not care about deleted accounts anymore, this feature was replaced by suspending to nologin auth plugin - $sql = "SELECT e.username, e.username - FROM $temptable e LEFT JOIN {$CFG->prefix}user u ON e.username = u.username - WHERE u.id IS NULL"; - $add_users = get_records_sql($sql); // get rid of the fat - - if (!empty($add_users)) { - print "User entries to add: ". count($add_users). "\n"; - - $sitecontext = get_context_instance(CONTEXT_SYSTEM); - if (!empty($this->config->creators) and !empty($this->config->memberattribute) - and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { - $creatorrole = array_shift($roles); // We can only use one, let's use the first one - } else { - $creatorrole = false; - } - - begin_sql(); - foreach ($add_users as $user) { - $user = $this->get_userinfo_asobj(addslashes($user->username)); - - // prep a few params - $user->modified = time(); - $user->confirmed = 1; - $user->auth = 'cas'; - $user->mnethostid = $CFG->mnet_localhost_id; - if (empty($user->lang)) { - $user->lang = $CFG->lang; - } - - $user = addslashes_recursive($user); - - if ($id = insert_record('user',$user)) { - echo "\t"; print_string('auth_dbinsertuser', 'auth', array(stripslashes($user->username), $id)); echo "\n"; - $userobj = $this->update_user_record($user->username); - if (!empty($this->config->forcechangepassword)) { - set_user_preference('auth_forcepasswordchange', 1, $userobj->id); - } - } else { - echo "\t"; print_string('auth_dbinsertusererror', 'auth', $user->username); echo "\n"; - } - - // add course creators if needed - if ($creatorrole !== false and $this->iscreator(stripslashes($user->username))) { - role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'cas'); - } - } - commit_sql(); - unset($add_users); // free mem - } else { - print "No users to be added\n"; - } - return true; - } - - /** - * Update a local user record from an external source. - * This is a lighter version of the one in moodlelib -- won't do - * expensive ops such as enrolment. - * - * If you don't pass $updatekeys, there is a performance hit and - * values removed from LDAP won't be removed from moodle. - * - * @param string $username username (with system magic quotes) - */ - function update_user_record($username, $updatekeys = false) { - global $CFG; - - //just in case check text case - $username = trim(moodle_strtolower($username)); - - // get the current user record - $user = get_record('user', 'username', $username, 'mnethostid', $CFG->mnet_localhost_id); - if (empty($user)) { // trouble - error_log("Cannot update non-existent user: ".stripslashes($username)); - print_error('auth_dbusernotexist','auth',$username); - die; - } - - // Protect the userid from being overwritten - $userid = $user->id; - - if ($newinfo = $this->get_userinfo($username)) { - $newinfo = truncate_userinfo($newinfo); - - if (empty($updatekeys)) { // all keys? this does not support removing values - $updatekeys = array_keys($newinfo); - } - - foreach ($updatekeys as $key) { - if (isset($newinfo[$key])) { - $value = $newinfo[$key]; - } else { - $value = ''; - } - - if (!empty($this->config->{'field_updatelocal_' . $key})) { - if ($user->{$key} != $value) { // only update if it's changed - set_field('user', $key, addslashes($value), 'id', $userid); - } - } - } - } else { - return false; - } - return get_record_select('user', "id = $userid AND deleted = 0"); - } - - /** - * Bulk insert in SQL's temp table - * @param array $users is an array of usernames - */ - function ldap_bulk_insert($users, $temptable) { - - // bulk insert -- superfast with $bulk_insert_records - $sql = 'INSERT INTO ' . $temptable . ' (username) VALUES '; - // make those values safe - $users = addslashes_recursive($users); - // join and quote the whole lot - $sql = $sql . "('" . implode("'),('", $users) . "')"; - print "\t+ " . count($users) . " users\n"; - execute_sql($sql, false); - } - - - - /** - * Returns true if user should be coursecreator. - * - * @param mixed $username username (without system magic quotes) - * @return boolean result - */ - function iscreator($username) { - - if ((empty($this->config->attrcreators) && empty($this->config->groupecreators)) or empty($this->config->memberattribute)) { - return null; - } - - $textlib = textlib_get_instance(); - $extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding); - -//test for groupe creator - -if (!empty($this->config->groupecreators)) - if ((boolean)$this->ldap_isgroupmember($extusername, $this->config->groupecreators)) - return true; - -//build filter for attrcreator -if (!empty($this->config->attrcreators)) { - $attrs = explode(";",$this->config->attrcreators); - $filter = "(& (".$this->config->user_attribute."=$username)(|"; - foreach ($attrs as $attr){ - if(strpos($attr, "=")) - $filter .= "($attr)"; - else - $filter .= "(".$this->config->memberattribute."=$attr)"; - } - $filter .= "))"; - //search - $result = $this->ldap_get_userlist($filter); - - if (count($result)!=0) - return true; - } - - return false; - } - - /** - * checks if user belong to specific group(s) - * - * Returns true if user belongs group in grupdns string. - * - * @param mixed $username username - * @param mixed $groupdns string of group dn separated by ; - * - */ - function ldap_isgroupmember($extusername='', $groupdns='') { - // Takes username and groupdn(s) , separated by ; - // Returns true if user is member of any given groups - - $ldapconnection = $this->ldap_connect(); - - if (empty($extusername) or empty($groupdns)) { - return false; - } - - if ($this->config->memberattribute_isdn) { - $memberuser = $this->ldap_find_userdn($ldapconnection, $extusername); - } else { - $memberuser = $extusername; - } - - if (empty($memberuser)) { - return false; - } - - $groups = explode(";",$groupdns); - - $result = false; - foreach ($groups as $group) { - $group = trim($group); - if (empty($group)) { - continue; - } - //echo "Checking group $group for member $username\n"; - $search = ldap_read($ldapconnection, $group, '('.$this->config->memberattribute.'='.$this->filter_addslashes($memberuser).')', array($this->config->memberattribute)); - if (!empty($search) and ldap_count_entries($ldapconnection, $search)) { - $info = $this->ldap_get_entries($ldapconnection, $search); - - if (count($info) > 0 ) { - // user is member of group - $result = true; - break; - } - } - } - - return $result; - - } - - /** - * return all usernames from ldap - * - * @return array - */ - - function ldap_get_userlist($filter="*") { - /// returns all users from ldap servers - $fresult = array(); - - $ldapconnection = $this->ldap_connect(); - - if ($filter=="*") { - $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))"; - } - - $contexts = explode(";",$this->config->contexts); - - if (!empty($this->config->create_context)) { - array_push($contexts, $this->config->create_context); - } - - foreach ($contexts as $context) { - - $context = trim($context); - if (empty($context)) { - continue; - } - - if ($this->config->search_sub) { - //use ldap_search to find first user from subtree - $ldap_result = ldap_search($ldapconnection, $context,$filter,array($this->config->user_attribute)); - } - else { - //search only in this context - $ldap_result = ldap_list($ldapconnection, $context, - $filter, - array($this->config->user_attribute)); - } - - $users = $this->ldap_get_entries($ldapconnection, $ldap_result); - - //add found users to list - for ($i=0;$iconfig->user_attribute][0]) ); - } - } - - return $fresult; - } - - /** - * return entries from ldap - * - * Returns values like ldap_get_entries but is - * binary compatible and return all attributes as array - * - * @return array ldap-entries - */ - - function ldap_get_entries($conn, $searchresult) { - //Returns values like ldap_get_entries but is - //binary compatible - $i=0; - $fresult=array(); - $entry = ldap_first_entry($conn, $searchresult); - - do { - $attributes = @ldap_get_attributes($conn, $entry); - for ($j=0; $j<$attributes['count']; $j++) { - $values = ldap_get_values_len($conn, $entry,$attributes[$j]); - if (is_array($values)) { - $fresult[$i][$attributes[$j]] = $values; - } - else { - $fresult[$i][$attributes[$j]] = array($values); - } - } - $i++; - } - while ($entry = @ldap_next_entry($conn, $entry)); - //were done - return ($fresult); - } - - /** - * Sync roles for this user - * - * @param $user object user object (without system magic quotes) - */ - function sync_roles($user) { - $iscreator = $this->iscreator($user->username); - if ($iscreator === null) { - return; //nothing to sync - creators not configured - } - - if ($roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { - $creatorrole = array_shift($roles); // We can only use one, let's use the first one - $systemcontext = get_context_instance(CONTEXT_SYSTEM); - - if ($iscreator) { // Following calls will not create duplicates - role_assign($creatorrole->id, $user->id, 0, $systemcontext->id, 0, 0, 0, 'cas'); - } else { - //unassign only if previously assigned by this plugin! - role_unassign($creatorrole->id, $user->id, 0, $systemcontext->id, 'cas'); - } - } - } - - /** - * Quote control characters in texts used in ldap filters - see rfc2254.txt - * - * @param string - */ - function filter_addslashes($text) { - $text = str_replace('\\', '\\5c', $text); - $text = str_replace(array('*', '(', ')', "\0"), - array('\\2a', '\\28', '\\29', '\\00'), $text); - return $text; - } - -} - - -?> +libdir.'/authlib.php'); +require_once($CFG->dirroot.'/auth/cas/CAS/CAS.php'); +/** + * CAS authentication plugin. + */ +class auth_plugin_cas extends auth_plugin_base { + /** + * Constructor. + */ + function auth_plugin_cas() { + $this->authtype = 'cas'; + $this->config = get_config('auth/cas'); + if (empty($this->config->ldapencoding)) { + $this->config->ldapencoding = 'utf-8'; + } + if (empty($this->config->user_type)) { + $this->config->user_type = 'default'; + } + $default = $this->ldap_getdefaults(); + //use defaults if values not given + foreach ($default as $key => $value) { + // watch out - 0, false are correct values too + if (!isset($this->config->{$key}) or $this->config->{$key} == '') { + $this->config->{$key} = $value[$this->config->user_type]; + } + } + //hack prefix to objectclass + if (empty($this->config->objectclass)) { // Can't send empty filter + $this->config->objectclass='objectClass=*'; + } else if (strpos($this->config->objectclass, 'objectClass=') !== 0) { + $this->config->objectclass = 'objectClass='.$this->config->objectclass; + } + } + /** + * Authenticates user againt CAS + * Returns true if the username and password work and false if they are + * wrong or don't exist. + * + * @param string $username The username + * @param string $password The password + * @return bool Authentication success or failure. + */ + function user_login ($username, $password) { + $this->connectCAS(); + return phpCAS::isAuthenticated(); + } + /** + * Returns true if this authentication plugin is 'internal'. + * + * @return bool + */ + function is_internal() { + return false; + } + /** + * Returns true if this authentication plugin can change the user's + * password. + * + * @return bool + */ + function can_change_password() { + return false; + } + /** + * authentication choice (CAS or other) + * redirection to the CAS form or to login/index.php + * for other authentication + */ + function loginpage_hook() { + global $frm; + global $test; + global $CFG; + $site = get_site(); + $CASform = get_string("CASform","auth"); + $username = optional_param("username"); + if (!empty($username)) { + return; + } + +// Connection to CAS server + $this->connectCAS(); + + // Gestion de la connection CAS si accès direct d'un ent ou autre + if (phpCAS::checkAuthentication()) { + $frm->username=phpCAS::getUser(); + $frm->password="cas"; + return; + } + + if ($this->config->multiauth) { + $authCAS = optional_param("authCAS"); + if ($authCAS=="NOCAS") + return; + +// choice authentication form for multi-authentication +// test pgtIou parameter for proxy mode (https connection +// in background from CAS server to the php server) + if ($authCAS!="CAS" && !isset($_GET["pgtIou"])) { + print_header("$site->fullname: $CASform", $site->fullname, $CASform); + include($CFG->dirroot."/auth/cas/cas_form.html"); + print_footer(); + exit(); + } + } +// CAS authentication + if (!phpCAS::isAuthenticated()) + {phpCAS::forceAuthentication();} +} + /** + * logout from the cas + * + * This function is called from admin/auth.php + * + */ + function prelogout_hook() { + global $CFG; + if ($this->config->logoutcas ) { + $backurl = $CFG->wwwroot; + $this->connectCAS(); + phpCAS::logout($backurl); + } + } + /** + * Connect to the cas (clientcas connection or proxycas connection + * + * This function is called from admin/auth.php + * + */ + function connectCAS() { + + global $PHPCAS_CLIENT; +// mode proxy CAS +if ( !is_object($PHPCAS_CLIENT) ) { + if ($this->config->proxycas) { + phpCAS::proxy($this->config->casversion, $this-> config->hostname, (int) $this->config->port, $this->config->baseuri); + } +// mode client CAS + else { + phpCAS::client($this->config->casversion, $this-> config->hostname, (int) $this->config->port, $this->config->baseuri); + } + } + + } + /** + * Prints a form for configuring this authentication plugin. + * + * This function is called from admin/auth.php, and outputs a full page with + * a form for configuring this plugin. + * + * @param array $page An object containing all the data for this page. + */ + function config_form($config, $err, $user_fields) { + include 'config.html'; + } + /** + * Returns the URL for changing the user's pw, or empty if the default can + * be used. + * + * @return string + */ + function change_password_url() { + return ""; + } + /** + * returns predefined usertypes + * + * @return array of predefined usertypes + */ + function ldap_suppported_usertypes() { + $types = array(); + $types['edir']='Novell Edirectory'; + $types['rfc2307']='posixAccount (rfc2307)'; + $types['rfc2307bis']='posixAccount (rfc2307bis)'; + $types['samba']='sambaSamAccount (v.3.0.7)'; + $types['ad']='MS ActiveDirectory'; + $types['default']=get_string('default'); + return $types; + } + /** + * Processes and stores configuration data for this authentication plugin. + */ + function process_config($config) { + // set to defaults if undefined + // CAS settings + if (!isset ($config->hostname)) + $config->hostname = ''; + if (!isset ($config->port)) + $config->port = ''; + if (!isset ($config->casversion)) + $config->casversion = ''; + if (!isset ($config->baseuri)) + $config->baseuri = ''; + if (!isset ($config->language)) + $config->language = ''; + if (!isset ($config->use_cas)) + $config->use_cas = ''; + if (!isset ($config->proxycas)) + $config->proxycas = ''; + if (!isset ($config->logoutcas)) + $config->logoutcas = ''; + if (!isset ($config->multiauth)) + $config->multiauth = ''; + // LDAP settings + if (!isset($config->host_url)) + { $config->host_url = ''; } + if (empty($config->ldapencoding)) + { $config->ldapencoding = 'utf-8'; } + if (!isset($config->contexts)) + { $config->contexts = ''; } + if (!isset($config->user_type)) + { $config->user_type = 'default'; } + if (!isset($config->user_attribute)) + { $config->user_attribute = ''; } + if (!isset($config->search_sub)) + { $config->search_sub = ''; } + if (!isset($config->opt_deref)) + { $config->opt_deref = ''; } + if (!isset($config->bind_dn)) + {$config->bind_dn = ''; } + if (!isset($config->bind_pw)) + {$config->bind_pw = ''; } + if (!isset($config->version)) + {$config->version = '2'; } + if (!isset($config->objectclass)) + {$config->objectclass = ''; } + if (!isset($config->memberattribute)) + {$config->memberattribute = ''; } + if (!isset($config->memberattribute_isdn)) + {$config->memberattribute_isdn = ''; } + if (!isset($config->attrcreators)) + {$config->attrcreators = ''; } + if (!isset($config->groupecreators)) + {$config->groupecreators = ''; } + if (!isset($config->removeuser)) + {$config->removeuser = 0; } + // save CAS settings + set_config('hostname', $config->hostname, 'auth/cas'); + set_config('port', $config->port, 'auth/cas'); + set_config('casversion', $config->casversion, 'auth/cas'); + set_config('baseuri', $config->baseuri, 'auth/cas'); + set_config('language', $config->language, 'auth/cas'); + set_config('use_cas', $config->use_cas, 'auth/cas'); + set_config('proxycas', $config->proxycas, 'auth/cas'); + set_config('logoutcas', $config->logoutcas, 'auth/cas'); + set_config('multiauth', $config->multiauth, 'auth/cas'); + // save LDAP settings + set_config('host_url', $config->host_url, 'auth/cas'); + set_config('ldapencoding', $config->ldapencoding, 'auth/cas'); + set_config('host_url', $config->host_url, 'auth/cas'); + set_config('contexts', $config->contexts, 'auth/cas'); + set_config('user_type', $config->user_type, 'auth/cas'); + set_config('user_attribute', $config->user_attribute, 'auth/cas'); + set_config('search_sub', $config->search_sub, 'auth/cas'); + set_config('opt_deref', $config->opt_deref, 'auth/cas'); + set_config('bind_dn', $config->bind_dn, 'auth/cas'); + set_config('bind_pw', $config->bind_pw, 'auth/cas'); + set_config('version', $config->version, 'auth/cas'); + set_config('objectclass', $config->objectclass, 'auth/cas'); + set_config('memberattribute', $config->memberattribute, 'auth/cas'); + set_config('memberattribute_isdn', $config->memberattribute_isdn, 'auth/cas'); + set_config('attrcreators', $config->attrcreators, 'auth/cas'); + set_config('groupecreators', $config->groupecreators, 'auth/cas'); + set_config('removeuser', $config->removeuser, 'auth/cas'); + return true; + } + /** + * Initializes needed ldap variables for cas-module + * + * Uses names defined in ldap_supported_usertypes. + * $default is first defined as: + * $default['pseudoname'] = array( + * 'typename1' => 'value', + * 'typename2' => 'value' + * .... + * ); + * + * @return array of default values + */ + function ldap_getdefaults() { + $default['objectclass'] = array( + 'edir' => 'User', + 'rfc2307' => 'posixAccount', + 'rfc2307bis' => 'posixAccount', + 'samba' => 'sambaSamAccount', + 'ad' => 'user', + 'default' => '*' + ); + $default['user_attribute'] = array( + 'edir' => 'cn', + 'rfc2307' => 'uid', + 'rfc2307bis' => 'uid', + 'samba' => 'uid', + 'ad' => 'cn', + 'default' => 'cn' + ); + $default['memberattribute'] = array( + 'edir' => 'member', + 'rfc2307' => 'member', + 'rfc2307bis' => 'member', + 'samba' => 'member', + 'ad' => 'member', + 'default' => 'member' + ); + $default['memberattribute_isdn'] = array( + 'edir' => '1', + 'rfc2307' => '0', + 'rfc2307bis' => '1', + 'samba' => '0', //is this right? + 'ad' => '1', + 'default' => '0' + ); + return $default; + } + /** + * reads userinformation from ldap and return it in array() + * + * Read user information from external database and returns it as array(). + * Function should return all information available. If you are saving + * this information to moodle user-table you should honor syncronization flags + * + * @param string $username username (with system magic quotes) + * + * @return mixed array with no magic quotes or false on error + */ + function get_userinfo($username) { + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); + $ldapconnection = $this->ldap_connect(); + $attrmap = $this->ldap_attributes(); + $result = array(); + $search_attribs = array(); + foreach ($attrmap as $key=>$values) { + if (!is_array($values)) { + $values = array($values); + } + foreach ($values as $value) { + if (!in_array($value, $search_attribs)) { + array_push($search_attribs, $value); + } + } + } + $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); + if (!$user_info_result = ldap_read($ldapconnection, $user_dn, $this->config->objectclass, $search_attribs)) { + return false; // error! + } + $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result); + if (empty($user_entry)) { + return false; // entry not found + } + foreach ($attrmap as $key=>$values) { + if (!is_array($values)) { + $values = array($values); + } + $ldapval = NULL; + foreach ($values as $value) { + if ($value == 'dn') { + $result[$key] = $user_dn; + } + if (!array_key_exists(strtolower($value), $user_entry[0])) { + continue; // wrong data mapping! + } + if (is_array($user_entry[0][strtolower($value)])) { + $newval = $textlib->convert($user_entry[0][strtolower($value)][0], $this->config->ldapencoding, 'utf-8'); + } else { + $newval = $textlib->convert($user_entry[0][strtolower($value)], $this->config->ldapencoding, 'utf-8'); + } + + if (!empty($newval)) { // favour ldap entries that are set + $ldapval = $newval; + } + } + if (!is_null($ldapval)) { + $result[$key] = $ldapval; + } + } + @ldap_close($ldapconnection); + return $result; + } + /** + * reads userinformation from ldap and return it in an object + * + * @param string $username username (with system magic quotes) + * @return mixed object or false on error + */ + function get_userinfo_asobj($username) { + $user_array = $this->get_userinfo($username); + if ($user_array == false) { + return false; //error or not found + } + $user_array = truncate_userinfo($user_array); + $user = new object(); + foreach ($user_array as $key=>$value) { + $user->{$key} = $value; + } + return $user; + } + /** + * connects to ldap server + * + * Tries connect to specified ldap servers. + * Returns connection result or error. + * + * @return connection result + */ + function ldap_connect($binddn='',$bindpwd='') { + //Select bind password, With empty values use + //ldap_bind_* variables or anonymous bind if ldap_bind_* are empty + if ($binddn == '' and $bindpwd == '') { + if (!empty($this->config->bind_dn)) { + $binddn = $this->config->bind_dn; + } + if (!empty($this->config->bind_pw)) { + $bindpwd = $this->config->bind_pw; + } + } + $urls = explode(";",$this->config->host_url); + foreach ($urls as $server) { + $server = trim($server); + if (empty($server)) { + continue; + } + $connresult = ldap_connect($server); + //ldap_connect returns ALWAYS true + if (!empty($this->config->version)) { + ldap_set_option($connresult, LDAP_OPT_PROTOCOL_VERSION, $this->config->version); + } + if (!empty($binddn)) { + //bind with search-user + //$debuginfo .= 'Using bind user'.$binddn.'and password:'.$bindpwd; + $bindresult=ldap_bind($connresult, $binddn,$bindpwd); + } + else { + //bind anonymously + $bindresult=@ldap_bind($connresult); + } + if (!empty($this->config->opt_deref)) { + ldap_set_option($connresult, LDAP_OPT_DEREF, $this->config->opt_deref); + } + if ($bindresult) { + return $connresult; + } + $debuginfo .= "
Server: '$server'
Connection: '$connresult'
Bind result: '$bindresult'
"; + } + //If any of servers are alive we have already returned connection + print_error('auth_ldap_noconnect_all','auth',$this->config->user_type); + return false; + } + /** + * retuns user attribute mappings between moodle and ldap + * + * @return array + */ + function ldap_attributes () { + $fields = array("firstname", "lastname", "email", "phone1", "phone2", + "department", "address", "city", "country", "description", + "idnumber", "lang" ); + $moodleattributes = array(); + foreach ($fields as $field) { + if (!empty($this->config->{"field_map_$field"})) { + $moodleattributes[$field] = $this->config->{"field_map_$field"}; + if (preg_match('/,/',$moodleattributes[$field])) { + $moodleattributes[$field] = explode(',', $moodleattributes[$field]); // split ? + } + } + } + $moodleattributes['username'] = $this->config->user_attribute; + return $moodleattributes; + } + /** + * retuns dn of username + * + * Search specified contexts for username and return user dn + * like: cn=username,ou=suborg,o=org + * + * @param mixed $ldapconnection $ldapconnection result + * @param mixed $username username (external encoding no slashes) + * + */ + function ldap_find_userdn ($ldapconnection, $extusername) { + //default return value + $ldap_user_dn = FALSE; + //get all contexts and look for first matching user + $ldap_contexts = explode(";",$this->config->contexts); + if (!empty($this->config->create_context)) { + array_push($ldap_contexts, $this->config->create_context); + } + foreach ($ldap_contexts as $context) { + $context = trim($context); + if (empty($context)) { + continue; + } + if ($this->config->search_sub) { + //use ldap_search to find first user from subtree + $ldap_result = ldap_search($ldapconnection, $context, "(".$this->config->user_attribute."=".$this->filter_addslashes($extusername).")",array($this->config->user_attribute)); + } + else { + //search only in this context + $ldap_result = ldap_list($ldapconnection, $context, "(".$this->config->user_attribute."=".$this->filter_addslashes($extusername).")",array($this->config->user_attribute)); + } + $entry = ldap_first_entry($ldapconnection,$ldap_result); + if ($entry) { + $ldap_user_dn = ldap_get_dn($ldapconnection, $entry); + break ; + } + } + return $ldap_user_dn; + } + /** + * Quote control characters in quoted "texts" used in ldap + * + * @param string + */ + function ldap_addslashes($text) { + $text = str_replace('\\', '\\\\', $text); + $text = str_replace(array('"', "\0"), + array('\\"', '\\00'), $text); + return $text; + } + /** + * returns all usernames from external database + * + * get_userlist returns all usernames from external database + * + * @return array + */ + function get_userlist() { + return $this->ldap_get_userlist("({$this->config->user_attribute}=*)"); + } + /** + * checks if user exists on external db + * + * @param string $username (with system magic quotes) + */ + function user_exists($username) { + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); + //returns true if given username exist on ldap + $users = $this->ldap_get_userlist("({$this->config->user_attribute}=".$this->filter_addslashes($extusername).")"); + return count($users); + } + /** + * syncronizes user fron external db to moodle user table + * + * Sync is now using username attribute. + * + * Syncing users removes or suspends users that dont exists anymore in external db. + * Creates new users and updates coursecreator status of users. + * + * @param int $bulk_insert_records will insert $bulkinsert_records per insert statement + * valid only with $unsafe. increase to a couple thousand for + * blinding fast inserts -- but test it: you may hit mysqld's + * max_allowed_packet limit. + * @param bool $do_updates will do pull in data updates from ldap if relevant + */ + function sync_users ($bulk_insert_records = 1000, $do_updates = true) { + global $CFG; + $textlib = textlib_get_instance(); + $droptablesql = array(); /// sql commands to drop the table (because session scope could be a problem for + /// some persistent drivers like ODBTP (mssql) or if this function is invoked + /// from within a PHP application using persistent connections + // configure a temp table + print "Configuring temp table\n"; + switch (strtolower($CFG->dbfamily)) { + case 'mysql': + $temptable = $CFG->prefix . 'extuser'; + $droptablesql[] = 'DROP TEMPORARY TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) + execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later + echo "Creating temp table $temptable\n"; + execute_sql('CREATE TEMPORARY TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username)) TYPE=MyISAM', false); + break; + case 'postgres': + $temptable = $CFG->prefix . 'extuser'; + $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) + execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later + echo "Creating temp table $temptable\n"; + $bulk_insert_records = 1; // no support for multiple sets of values + execute_sql('CREATE TEMPORARY TABLE '. $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false); + break; + case 'mssql': + $temptable = '#'.$CFG->prefix . 'extuser'; /// MSSQL temp tables begin with # + $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) + execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later + echo "Creating temp table $temptable\n"; + $bulk_insert_records = 1; // no support for multiple sets of values + execute_sql('CREATE TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false); + break; + case 'oracle': + $temptable = $CFG->prefix . 'extuser'; + $droptablesql[] = 'TRUNCATE TABLE ' . $temptable; // oracle requires truncate before being able to drop a temp table + $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) + execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later + echo "Creating temp table $temptable\n"; + $bulk_insert_records = 1; // no support for multiple sets of values + execute_sql('CREATE GLOBAL TEMPORARY TABLE '.$temptable.' (username VARCHAR(64), PRIMARY KEY (username)) ON COMMIT PRESERVE ROWS', false); + break; + } + print "Connecting to ldap...\n"; + $ldapconnection = $this->ldap_connect(); + if (!$ldapconnection) { + @ldap_close($ldapconnection); + print get_string('auth_ldap_noconnect','auth',$this->config->host_url); + exit; + } + //// + //// get user's list from ldap to sql in a scalable fashion + //// + // prepare some data we'll need + $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))"; + $contexts = explode(";",$this->config->contexts); + if (!empty($this->config->create_context)) { + array_push($contexts, $this->config->create_context); + } + $fresult = array(); + foreach ($contexts as $context) { + $context = trim($context); + if (empty($context)) { + continue; + } + begin_sql(); + if ($this->config->search_sub) { + //use ldap_search to find first user from subtree + $ldap_result = ldap_search($ldapconnection, $context, + $filter, + array($this->config->user_attribute)); + } else { + //search only in this context + $ldap_result = ldap_list($ldapconnection, $context, + $filter, + array($this->config->user_attribute)); + } + if ($entry = ldap_first_entry($ldapconnection, $ldap_result)) { + do { + $value = ldap_get_values_len($ldapconnection, $entry, $this->config->user_attribute); + $value = $textlib->convert($value[0], $this->config->ldapencoding, 'utf-8'); + array_push($fresult, $value); + if (count($fresult) >= $bulk_insert_records) { + $this->ldap_bulk_insert($fresult, $temptable); + $fresult = array(); + } + } while ($entry = ldap_next_entry($ldapconnection, $entry)); + } + unset($ldap_result); // free mem + // insert any remaining users and release mem + if (count($fresult)) { + $this->ldap_bulk_insert($fresult, $temptable); + $fresult = array(); + } + commit_sql(); + } + /// preserve our user database + /// if the temp table is empty, it probably means that something went wrong, exit + /// so as to avoid mass deletion of users; which is hard to undo + $count = get_record_sql('SELECT COUNT(username) AS count, 1 FROM ' . $temptable); + $count = $count->{'count'}; + if ($count < 1) { + print "Did not get any users from LDAP -- error? -- exiting\n"; + exit; + } else { + print "Got $count records from LDAP\n\n"; + } +/// User removal + // find users in DB that aren't in ldap -- to be removed! + // this is still not as scalable (but how often do we mass delete?) + if (!empty($this->config->removeuser)) { + $sql = "SELECT u.id, u.username, u.email + FROM {$CFG->prefix}user u + LEFT JOIN $temptable e ON u.username = e.username + WHERE u.auth='cas' + AND u.deleted=0 + AND e.username IS NULL"; + $remove_users = get_records_sql($sql); + if (!empty($remove_users)) { + print "User entries to remove: ". count($remove_users) . "\n"; + begin_sql(); + foreach ($remove_users as $user) { + if ($this->config->removeuser == 2) { + //following is copy pasted from admin/user.php + //maybe this should moved to function in lib/datalib.php + $updateuser = new object(); + $updateuser->id = $user->id; + $updateuser->deleted = 1; + $updateuser->username = addslashes("$user->email.".time()); // Remember it just in case + $updateuser->email = ''; // Clear this field to free it up + $updateuser->idnumber = ''; // Clear this field to free it up + $updateuser->timemodified = time(); + if (update_record('user', $updateuser)) { + delete_records('role_assignments', 'userid', $user->id); // unassign all roles + //copy pasted part ends + echo "\t"; print_string('auth_dbdeleteuser', 'auth', array($user->username, $user->id)); echo "\n"; + } else { + echo "\t"; print_string('auth_dbdeleteusererror', 'auth', $user->username); echo "\n"; + } + } else if ($this->config->removeuser == 1) { + $updateuser = new object(); + $updateuser->id = $user->id; + $updateuser->auth = 'nologin'; + if (update_record('user', $updateuser)) { + echo "\t"; print_string('auth_dbsuspenduser', 'auth', array($user->username, $user->id)); echo "\n"; + } else { + echo "\t"; print_string('auth_dbsuspendusererror', 'auth', $user->username); echo "\n"; + } + } + } + commit_sql(); + } else { + print "No user entries to be removed\n"; + } + unset($remove_users); // free mem! + } +/// Revive suspended users + if (!empty($this->config->removeuser) and $this->config->removeuser == 1) { + $sql = "SELECT u.id, u.username + FROM $temptable e, {$CFG->prefix}user u + WHERE e.username=u.username + AND u.auth='nologin'"; + $revive_users = get_records_sql($sql); + if (!empty($revive_users)) { + print "User entries to be revived: ". count($revive_users) . "\n"; + begin_sql(); + foreach ($revive_users as $user) { + $updateuser = new object(); + $updateuser->id = $user->id; + $updateuser->auth = 'cas'; + if (update_record('user', $updateuser)) { + echo "\t"; print_string('auth_dbreviveser', 'auth', array($user->username, $user->id)); echo "\n"; + } else { + echo "\t"; print_string('auth_dbreviveusererror', 'auth', $user->username); echo "\n"; + } + } + commit_sql(); + } else { + print "No user entries to be revived\n"; + } + unset($revive_users); + } +/// User Updates - time-consuming (optional) + if ($do_updates) { + // narrow down what fields we need to update + $all_keys = array_keys(get_object_vars($this->config)); + $updatekeys = array(); + foreach ($all_keys as $key) { + if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) { + // if we have a field to update it from + // and it must be updated 'onlogin' we + // update it on cron + if ( !empty($this->config->{'field_map_'.$match[1]}) + and $this->config->{$match[0]} === 'onlogin') { + array_push($updatekeys, $match[1]); // the actual key name + } + } + } + // print_r($all_keys); print_r($updatekeys); + unset($all_keys); unset($key); + } else { + print "No updates to be done\n"; + } + if ( $do_updates and !empty($updatekeys) ) { // run updates only if relevant + $users = get_records_sql("SELECT u.username, u.id + FROM {$CFG->prefix}user u + WHERE u.deleted=0 AND u.auth='cas'"); + if (!empty($users)) { + print "User entries to update: ". count($users). "\n"; + $sitecontext = get_context_instance(CONTEXT_SYSTEM); + if (!empty($this->config->creators) and !empty($this->config->memberattribute) + and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { + $creatorrole = array_shift($roles); // We can only use one, let's use the first one + } else { + $creatorrole = false; + } + begin_sql(); + $xcount = 0; + $maxxcount = 100; + foreach ($users as $user) { + echo "\t"; print_string('auth_dbupdatinguser', 'auth', array($user->username, $user->id)); + if (!$this->update_user_record(addslashes($user->username), $updatekeys)) { + echo " - ".get_string('skipped'); + } + echo "\n"; + $xcount++; + // update course creators if needed + if ($creatorrole !== false) { + if ($this->iscreator($user->username)) { + role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'cas'); + } else { + role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id, 'cas'); + } + } + if ($xcount++ > $maxxcount) { + commit_sql(); + begin_sql(); + $xcount = 0; + } + } + commit_sql(); + unset($users); // free mem + } + } else { // end do updates + print "No updates to be done\n"; + } +/// User Additions + // find users missing in DB that are in LDAP + // note that get_records_sql wants at least 2 fields returned, + // and gives me a nifty object I don't want. + // note: we do not care about deleted accounts anymore, this feature was replaced by suspending to nologin auth plugin + $sql = "SELECT e.username, e.username + FROM $temptable e LEFT JOIN {$CFG->prefix}user u ON e.username = u.username + WHERE u.id IS NULL"; + $add_users = get_records_sql($sql); // get rid of the fat + if (!empty($add_users)) { + print "User entries to add: ". count($add_users). "\n"; + $sitecontext = get_context_instance(CONTEXT_SYSTEM); + if (!empty($this->config->creators) and !empty($this->config->memberattribute) + and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { + $creatorrole = array_shift($roles); // We can only use one, let's use the first one + } else { + $creatorrole = false; + } + begin_sql(); + foreach ($add_users as $user) { + $user = $this->get_userinfo_asobj(addslashes($user->username)); + // prep a few params + $user->modified = time(); + $user->confirmed = 1; + $user->auth = 'cas'; + $user->mnethostid = $CFG->mnet_localhost_id; + if (empty($user->lang)) { + $user->lang = $CFG->lang; + } + $user = addslashes_recursive($user); + if ($id = insert_record('user',$user)) { + echo "\t"; print_string('auth_dbinsertuser', 'auth', array(stripslashes($user->username), $id)); echo "\n"; + $userobj = $this->update_user_record($user->username); + if (!empty($this->config->forcechangepassword)) { + set_user_preference('auth_forcepasswordchange', 1, $userobj->id); + } + } else { + echo "\t"; print_string('auth_dbinsertusererror', 'auth', $user->username); echo "\n"; + } + // add course creators if needed + if ($creatorrole !== false and $this->iscreator(stripslashes($user->username))) { + role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'cas'); + } + } + commit_sql(); + unset($add_users); // free mem + } else { + print "No users to be added\n"; + } + return true; + } + /** + * Update a local user record from an external source. + * This is a lighter version of the one in moodlelib -- won't do + * expensive ops such as enrolment. + * + * If you don't pass $updatekeys, there is a performance hit and + * values removed from LDAP won't be removed from moodle. + * + * @param string $username username (with system magic quotes) + */ + function update_user_record($username, $updatekeys = false) { + global $CFG; + //just in case check text case + $username = trim(moodle_strtolower($username)); + // get the current user record + $user = get_record('user', 'username', $username, 'mnethostid', $CFG->mnet_localhost_id); + if (empty($user)) { // trouble + error_log("Cannot update non-existent user: ".stripslashes($username)); + print_error('auth_dbusernotexist','auth',$username); + die; + } + // Protect the userid from being overwritten + $userid = $user->id; + if ($newinfo = $this->get_userinfo($username)) { + $newinfo = truncate_userinfo($newinfo); + if (empty($updatekeys)) { // all keys? this does not support removing values + $updatekeys = array_keys($newinfo); + } + foreach ($updatekeys as $key) { + if (isset($newinfo[$key])) { + $value = $newinfo[$key]; + } else { + $value = ''; + } + if (!empty($this->config->{'field_updatelocal_' . $key})) { + if ($user->{$key} != $value) { // only update if it's changed + set_field('user', $key, addslashes($value), 'id', $userid); + } + } + } + } else { + return false; + } + return get_record_select('user', "id = $userid AND deleted = 0"); + } + /** + * Bulk insert in SQL's temp table + * @param array $users is an array of usernames + */ + function ldap_bulk_insert($users, $temptable) { + // bulk insert -- superfast with $bulk_insert_records + $sql = 'INSERT INTO ' . $temptable . ' (username) VALUES '; + // make those values safe + $users = addslashes_recursive($users); + // join and quote the whole lot + $sql = $sql . "('" . implode("'),('", $users) . "')"; + print "\t+ " . count($users) . " users\n"; + execute_sql($sql, false); + } + /** + * Returns true if user should be coursecreator. + * + * @param mixed $username username (without system magic quotes) + * @return boolean result + */ + function iscreator($username) { + if ((empty($this->config->attrcreators) && empty($this->config->groupecreators)) or empty($this->config->memberattribute)) { + return null; + } + $textlib = textlib_get_instance(); + $extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding); +//test for groupe creator +if (!empty($this->config->groupecreators)) + if ((boolean)$this->ldap_isgroupmember($extusername, $this->config->groupecreators)) + return true; +//build filter for attrcreator +if (!empty($this->config->attrcreators)) { + $attrs = explode(";",$this->config->attrcreators); + $filter = "(& (".$this->config->user_attribute."=$username)(|"; + foreach ($attrs as $attr){ + if(strpos($attr, "=")) + $filter .= "($attr)"; + else + $filter .= "(".$this->config->memberattribute."=$attr)"; + } + $filter .= "))"; + //search + $result = $this->ldap_get_userlist($filter); + if (count($result)!=0) + return true; + } + + return false; + } + /** + * checks if user belong to specific group(s) + * + * Returns true if user belongs group in grupdns string. + * + * @param mixed $username username + * @param mixed $groupdns string of group dn separated by ; + * + */ + function ldap_isgroupmember($extusername='', $groupdns='') { + // Takes username and groupdn(s) , separated by ; + // Returns true if user is member of any given groups + $ldapconnection = $this->ldap_connect(); + if (empty($extusername) or empty($groupdns)) { + return false; + } + if ($this->config->memberattribute_isdn) { + $memberuser = $this->ldap_find_userdn($ldapconnection, $extusername); + } else { + $memberuser = $extusername; + } + if (empty($memberuser)) { + return false; + } + $groups = explode(";",$groupdns); + $result = false; + foreach ($groups as $group) { + $group = trim($group); + if (empty($group)) { + continue; + } + //echo "Checking group $group for member $username\n"; + $search = ldap_read($ldapconnection, $group, '('.$this->config->memberattribute.'='.$this->filter_addslashes($memberuser).')', array($this->config->memberattribute)); + if (!empty($search) and ldap_count_entries($ldapconnection, $search)) { + $info = $this->ldap_get_entries($ldapconnection, $search); + if (count($info) > 0 ) { + // user is member of group + $result = true; + break; + } + } + } + return $result; + } + /** + * return all usernames from ldap + * + * @return array + */ + function ldap_get_userlist($filter="*") { + /// returns all users from ldap servers + $fresult = array(); + $ldapconnection = $this->ldap_connect(); + if ($filter=="*") { + $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))"; + } + $contexts = explode(";",$this->config->contexts); + if (!empty($this->config->create_context)) { + array_push($contexts, $this->config->create_context); + } + foreach ($contexts as $context) { + $context = trim($context); + if (empty($context)) { + continue; + } + if ($this->config->search_sub) { + //use ldap_search to find first user from subtree + $ldap_result = ldap_search($ldapconnection, $context,$filter,array($this->config->user_attribute)); + } + else { + //search only in this context + $ldap_result = ldap_list($ldapconnection, $context, + $filter, + array($this->config->user_attribute)); + } + $users = $this->ldap_get_entries($ldapconnection, $ldap_result); + //add found users to list + for ($i=0;$iconfig->user_attribute][0]) ); + } + } + return $fresult; + } + /** + * return entries from ldap + * + * Returns values like ldap_get_entries but is + * binary compatible and return all attributes as array + * + * @return array ldap-entries + */ + function ldap_get_entries($conn, $searchresult) { + //Returns values like ldap_get_entries but is + //binary compatible + $i=0; + $fresult=array(); + $entry = ldap_first_entry($conn, $searchresult); + do { + $attributes = @ldap_get_attributes($conn, $entry); + for ($j=0; $j<$attributes['count']; $j++) { + $values = ldap_get_values_len($conn, $entry,$attributes[$j]); + + if (is_array($values)) { + $fresult[$i][strtolower($attributes[$j])] = $values; + } + else { + $fresult[$i][strtolower($attributes[$j])] = array($values); + } + } + $i++; + } + while ($entry = @ldap_next_entry($conn, $entry)); + //were done + + return ($fresult); + } + /** + * Sync roles for this user + * + * @param $user object user object (without system magic quotes) + */ + function sync_roles($user) { + $iscreator = $this->iscreator($user->username); + if ($iscreator === null) { + return; //nothing to sync - creators not configured + } + if ($roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { + $creatorrole = array_shift($roles); // We can only use one, let's use the first one + $systemcontext = get_context_instance(CONTEXT_SYSTEM); + if ($iscreator) { // Following calls will not create duplicates + role_assign($creatorrole->id, $user->id, 0, $systemcontext->id, 0, 0, 0, 'cas'); + } else { + //unassign only if previously assigned by this plugin! + role_unassign($creatorrole->id, $user->id, 0, $systemcontext->id, 'cas'); + } + } + } + /** + * Quote control characters in texts used in ldap filters - see rfc2254.txt + * + * @param string + */ + function filter_addslashes($text) { + $text = str_replace('\\', '\\5c', $text); + $text = str_replace(array('*', '(', ')', "\0"), + array('\\2a', '\\28', '\\29', '\\00'), $text); + return $text; + } +} +?> diff --git a/auth/cas/cas_form.html b/auth/cas/cas_form.html index 43eb05faf55..0df03121003 100644 --- a/auth/cas/cas_form.html +++ b/auth/cas/cas_form.html @@ -1,12 +1,12 @@ - -
-
-
- -
-
-
- -
-
-
+ +
+
+
+ +
+
+
+ +
+
+
diff --git a/auth/cas/cas_ldap_sync_users.php b/auth/cas/cas_ldap_sync_users.php index e4caec4b45d..a3d7cdab578 100644 --- a/auth/cas/cas_ldap_sync_users.php +++ b/auth/cas/cas_ldap_sync_users.php @@ -45,4 +45,4 @@ if (!is_enabled_auth('cas')) { $casauth = get_auth_plugin('cas'); $casauth->sync_users(1000, true); -?> \ No newline at end of file +?> diff --git a/auth/cas/config.html b/auth/cas/config.html index b7446fdb3c0..632ce3fad2a 100644 --- a/auth/cas/config.html +++ b/auth/cas/config.html @@ -1,434 +1,432 @@ -hostname)) - $config->hostname = ''; - if (!isset ($config->port)) - $config->port = ''; - if (!isset ($config->casversion)) - $config->casversion = ''; - if (!isset ($config->baseuri)) - $config->baseuri = ''; - if (!isset ($config->language)) - $config->language = ''; - if (!isset ($config->use_cas)) - $config->use_cas = ''; - if (!isset ($config->proxycas)) - $config->proxycas = ''; - if (!isset ($config->logoutcas)) - $config->logoutcas = ''; - if (!isset ($config->multiauth)) - $config->multiauth = ''; - // set to defaults if undefined (LDAP) - if (!isset($config->host_url)) - { $config->host_url = ''; } - if (empty($config->ldapencoding)) - { $config->ldapencoding = 'utf-8'; } - if (!isset($config->contexts)) - { $config->contexts = ''; } - if (!isset($config->user_type)) - { $config->user_type = 'default'; } - if (!isset($config->user_attribute)) - { $config->user_attribute = ''; } - if (!isset($config->search_sub)) - { $config->search_sub = ''; } - if (!isset($config->opt_deref)) - { $config->opt_deref = LDAP_DEREF_NEVER; } - if (!isset($config->bind_dn)) - {$config->bind_dn = ''; } - if (!isset($config->bind_pw)) - {$config->bind_pw = ''; } - if (!isset($config->version)) - {$config->version = '2'; } - if (!isset($config->objectclass)) - {$config->objectclass = ''; } - if (!isset($config->memberattribute)) - {$config->memberattribute = ''; } - if (!isset($config->memberattribute_isdn)) - {$config->memberattribute_isdn = ''; } - if (!isset($config->groupecreators)) - {$config->groupecreators = ''; } - if (!isset($config->attrcreators)) - {$config->attrcreators = ''; } - if (!isset($config->removeuser)) - {$config->removeuser = 0; } - - $yesno = array( get_string('no'), get_string('yes') ); - -if (!function_exists('ldap_connect')) { // Is php4-ldap really there? - notify(get_string('auth_ldap_noextension','auth')); - } - - -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

-
: - use_cas, get_string('no'), '', ''); - - ?> -
: - - -
: - - -
: - - -
: - - -
: - language, ''); - - ?> -
: - proxycas, get_string('no'), '', ''); - ?> -
: - logoutcas, get_string('no'), '', ''); - ?> -
: - multiauth, get_string('no'), '', ''); - ?> -
-

-
- - - - -
- version, ''); - if (isset($err['version'])) formerr($err['version']); - ?> - - -
- - -
-

-
- - - - -
- - - - -
-

-
- ldap_suppported_usertypes(), 'user_type', $config->user_type, ''); ?> - - - -
- - - - -
- search_sub, ''); ?> - - -
- opt_deref, LDAP_DEREF_NEVER, ''); - if (isset($err['opt_deref'])) formerr($err['opt_deref']); - ?> - - -
- - - - -
- - - - -
- - - - -
- - - - -
-

-
- - - - -
- - - - -
-

-
- removeuser, ''); - ?> - - -
- -'; -$help .= get_string('auth_updateremote_ldap','auth'); - -print_auth_lock_options('cas', $user_fields, $help, true, true); - -?> +hostname)) + $config->hostname = ''; + if (!isset ($config->port)) + $config->port = ''; + if (!isset ($config->casversion)) + $config->casversion = ''; + if (!isset ($config->baseuri)) + $config->baseuri = ''; + if (!isset ($config->language)) + $config->language = ''; + if (!isset ($config->use_cas)) + $config->use_cas = ''; + if (!isset ($config->proxycas)) + $config->proxycas = ''; + if (!isset ($config->logoutcas)) + $config->logoutcas = ''; + if (!isset ($config->multiauth)) + $config->multiauth = ''; + // set to defaults if undefined (LDAP) + if (!isset($config->host_url)) + { $config->host_url = ''; } + if (empty($config->ldapencoding)) + { $config->ldapencoding = 'utf-8'; } + if (!isset($config->contexts)) + { $config->contexts = ''; } + if (!isset($config->user_type)) + { $config->user_type = 'default'; } + if (!isset($config->user_attribute)) + { $config->user_attribute = ''; } + if (!isset($config->search_sub)) + { $config->search_sub = ''; } + if (!isset($config->opt_deref)) + { $config->opt_deref = LDAP_DEREF_NEVER; } + if (!isset($config->bind_dn)) + {$config->bind_dn = ''; } + if (!isset($config->bind_pw)) + {$config->bind_pw = ''; } + if (!isset($config->version)) + {$config->version = '2'; } + if (!isset($config->objectclass)) + {$config->objectclass = ''; } + if (!isset($config->memberattribute)) + {$config->memberattribute = ''; } + if (!isset($config->memberattribute_isdn)) + {$config->memberattribute_isdn = ''; } + if (!isset($config->groupecreators)) + {$config->groupecreators = ''; } + if (!isset($config->attrcreators)) + {$config->attrcreators = ''; } + if (!isset($config->removeuser)) + {$config->removeuser = 0; } + + $yesno = array( get_string('no'), get_string('yes') ); + +if (!function_exists('ldap_connect')) { // Is php4-ldap really there? + notify(get_string('auth_ldap_noextension','auth')); +} + + +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +'; +$help .= get_string('auth_updateremote_ldap','auth'); + +print_auth_lock_options('cas', $user_fields, $help, true, true); + +?> +
+

+
: + use_cas, get_string('no'), '', ''); + + ?> +
: + + +
: + + +
: + + +
: + + +
: + language, ''); + + ?> +
: + proxycas, get_string('no'), '', ''); + ?> +
: + logoutcas, get_string('no'), '', ''); + ?> +
: + multiauth, get_string('no'), '', ''); + ?> +
+

+
+ + + + +
+ version, ''); + if (isset($err['version'])) formerr($err['version']); + ?> + + +
+ + +
+

+
+ + + + +
+ + + + +
+

+
+ ldap_suppported_usertypes(), 'user_type', $config->user_type, ''); ?> + + + +
+ + + + +
+ search_sub, ''); ?> + + +
+ opt_deref, LDAP_DEREF_NEVER, ''); + if (isset($err['opt_deref'])) formerr($err['opt_deref']); + ?> + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+

+
+ + + + +
+ + + + +
+

+
+ removeuser, ''); + ?> + + +
diff --git a/lang/en_utf8/auth.php b/lang/en_utf8/auth.php index 1a6b689fde3..c6bc0f28651 100644 --- a/lang/en_utf8/auth.php +++ b/lang/en_utf8/auth.php @@ -1,7 +1,15 @@ \'$a\' and return fields username and password.
Be careful not to enter an incorrect URL as you may lock yourself out of this site.
Leave this setting blank to use the default login page.'; $string['alternateloginurl'] = 'Alternate Login URL'; @@ -30,15 +38,6 @@ $string['auth_nologindescription'] = 'Auxiliary plugin that prevents user to log $string['auth_nologintitle'] = 'No login'; // CAS plugin -$string['auth_cas_proxycas_key'] = "Proxy mode"; -$string['auth_cas_logoutcas_key'] = "Logout CAS"; -$string['auth_cas_multiauth_key'] = "Multi-authentication"; -$string['auth_cas_proxycas'] = "Turn this to 'yes'' if you use CASin proxy-mode"; -$string['auth_cas_logoutcas'] = "Turn this to 'yes'' if tou want to logout from CAS when you deconnect from Moodle"; -$string['auth_cas_multiauth'] = "Turn this to 'yes'' if you want to have multi-authentication (CAS + other authentication)"; -$string['accesCAS'] = "CAS users"; -$string['accesNOCAS'] = "other users"; -$string['CASform'] = "Authentication choice"; $string['auth_cas_logincas'] = 'Secure connection access'; $string['auth_cas_invalidcaslogin'] = 'Sorry, your login has failed - you could not be authorised'; $string['auth_cas_server_settings'] = 'CAS server configuration'; @@ -253,7 +252,7 @@ $string['auth_nonedescription'] = 'Users can sign in and create valid accounts i $string['auth_nonetitle'] = 'No authentication'; // PAM plugin -$string['auth_pamdescription'] = 'This method uses PAM to access the native usernames on this server. You have to install PHP4 PAM Authentication in order to use this module.'; +$string['auth_pamdescription'] = 'This method uses PAM to access the native usernames on this server. You have to install PHP4 PAM Authentication in order to use this module.'; $string['auth_pamtitle'] = 'PAM (Pluggable Authentication Modules)'; $string['auth_passwordisexpired'] = 'Your password is expired. Do you want change your password now?'; @@ -275,7 +274,7 @@ $string['auth_pop3host_key'] = 'Host'; // RADIUS plugin $string['auth_radiustitle'] = 'RADIUS server'; -$string['auth_radiusdescription'] = 'This method uses a RADIUS server to check whether a given username and password is valid.'; +$string['auth_radiusdescription'] = 'This method uses a RADIUS server to check whether a given username and password is valid.'; $string['auth_radiushost'] = 'Address of the RADIUS server'; $string['auth_radiusnasport'] = 'Port to use to connect'; $string['auth_radiussecret'] = 'Shared secret'; @@ -285,7 +284,7 @@ $string['auth_radiushost_key'] = 'Host'; $string['auth_radiussecret_key'] = 'Secret'; // Shibboleth plugin -$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using Shibboleth.
Be sure to read the README for Shibboleth on how to set up your Moodle with Shibboleth'; +$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using Shibboleth.
Be sure to read the README for Shibboleth on how to set up your Moodle with Shibboleth'; $string['auth_shibbolethtitle'] = 'Shibboleth'; $string['auth_shibboleth_login'] = 'Shibboleth Login'; $string['auth_shibboleth_manual_login'] = 'Manual Login'; @@ -294,7 +293,7 @@ $string['auth_shib_only_description'] = 'Check this option if a Shibboleth authe $string['auth_shib_username_description'] = 'Name of the webserver Shibboleth environment variable that shall be used as Moodle username'; $string['auth_shib_instructions'] = 'Use the Shibboleth login to get access via Shibboleth, if your institution supports it.
Otherwise, use the normal login form shown here.'; $string['auth_shib_convert_data'] = 'Data modification API'; -$string['auth_shib_convert_data_description'] = 'You can use this API to further modify the data provided by Shibboleth. Read the README for further instructions.'; +$string['auth_shib_convert_data_description'] = 'You can use this API to further modify the data provided by Shibboleth. Read the README for further instructions.'; $string['auth_shib_instructions_help'] = 'Here you should provide custom instructions for your users to explain Shibboleth. It will be shown on the login page in the instructions section. The instructions must include a link to \"$a\" that users click when they want to log in.'; $string['auth_shib_convert_data_warning'] = 'The file does not exist or is not readable by the webserver process!'; $string['auth_shib_changepasswordurl'] = 'Password-change URL';