phpCAS  version 1.4.0
Client.php
Go to the documentation of this file.
1 <?php
2 
54 {
55 
56  // ########################################################################
57  // HTML OUTPUT
58  // ########################################################################
77  private function _htmlFilterOutput($str)
78  {
79  $str = str_replace('__CAS_VERSION__', $this->getServerVersion(), $str);
80  $str = str_replace('__PHPCAS_VERSION__', phpCAS::getVersion(), $str);
81  $str = str_replace('__SERVER_BASE_URL__', $this->_getServerBaseURL(), $str);
82  echo $str;
83  }
84 
92  private $_output_header = '';
93 
103  public function printHTMLHeader($title)
104  {
105  $this->_htmlFilterOutput(
106  str_replace(
107  '__TITLE__', $title,
108  (empty($this->_output_header)
109  ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
110  : $this->_output_header)
111  )
112  );
113  }
114 
122  private $_output_footer = '';
123 
131  public function printHTMLFooter()
132  {
133  $lang = $this->getLangObj();
134  $this->_htmlFilterOutput(
135  empty($this->_output_footer)?
136  (phpCAS::getVerbose())?
137  '<hr><address>phpCAS __PHPCAS_VERSION__ '
138  .$lang->getUsingServer()
139  .' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>'
140  :'</body></html>'
142  );
143  }
144 
152  public function setHTMLHeader($header)
153  {
154  // Argument Validation
155  if (gettype($header) != 'string')
156  throw new CAS_TypeMismatchException($header, '$header', 'string');
157 
158  $this->_output_header = $header;
159  }
160 
168  public function setHTMLFooter($footer)
169  {
170  // Argument Validation
171  if (gettype($footer) != 'string')
172  throw new CAS_TypeMismatchException($footer, '$footer', 'string');
173 
174  $this->_output_footer = $footer;
175  }
176 
177 
181  // ########################################################################
182  // INTERNATIONALIZATION
183  // ########################################################################
195 
203  public function setLang($lang)
204  {
205  // Argument Validation
206  if (gettype($lang) != 'string')
207  throw new CAS_TypeMismatchException($lang, '$lang', 'string');
208 
210  $obj = new $lang();
211  if (!($obj instanceof CAS_Languages_LanguageInterface)) {
213  '$className must implement the CAS_Languages_LanguageInterface'
214  );
215  }
216  $this->_lang = $lang;
218  }
224  public function getLangObj()
225  {
226  $classname = $this->_lang;
227  return new $classname();
228  }
229 
231  // ########################################################################
232  // CAS SERVER CONFIG
233  // ########################################################################
264  private $_server = array(
265  'version' => '',
266  'hostname' => 'none',
267  'port' => -1,
268  'uri' => 'none');
269 
275  public function getServerVersion()
276  {
277  return $this->_server['version'];
278  }
279 
285  private function _getServerHostname()
286  {
287  return $this->_server['hostname'];
288  }
289 
295  private function _getServerPort()
296  {
297  return $this->_server['port'];
298  }
299 
305  private function _getServerURI()
306  {
307  return $this->_server['uri'];
308  }
309 
315  private function _getServerBaseURL()
316  {
317  // the URL is build only when needed
318  if ( empty($this->_server['base_url']) ) {
319  $this->_server['base_url'] = 'https://' . $this->_getServerHostname();
320  if ($this->_getServerPort()!=443) {
321  $this->_server['base_url'] .= ':'
322  .$this->_getServerPort();
323  }
324  $this->_server['base_url'] .= $this->_getServerURI();
325  }
326  return $this->_server['base_url'];
327  }
328 
339  public function getServerLoginURL($gateway=false,$renew=false)
340  {
342  // the URL is build only when needed
343  if ( empty($this->_server['login_url']) ) {
344  $this->_server['login_url'] = $this->_buildQueryUrl($this->_getServerBaseURL().'login','service='.urlencode($this->getURL()));
345  }
346  $url = $this->_server['login_url'];
347  if ($renew) {
348  // It is recommended that when the "renew" parameter is set, its
349  // value be "true"
350  $url = $this->_buildQueryUrl($url, 'renew=true');
351  } elseif ($gateway) {
352  // It is recommended that when the "gateway" parameter is set, its
353  // value be "true"
354  $url = $this->_buildQueryUrl($url, 'gateway=true');
355  }
356  phpCAS::traceEnd($url);
357  return $url;
358  }
359 
367  public function setServerLoginURL($url)
368  {
369  // Argument Validation
370  if (gettype($url) != 'string')
371  throw new CAS_TypeMismatchException($url, '$url', 'string');
372 
373  return $this->_server['login_url'] = $url;
374  }
375 
376 
384  public function setServerServiceValidateURL($url)
385  {
386  // Argument Validation
387  if (gettype($url) != 'string')
388  throw new CAS_TypeMismatchException($url, '$url', 'string');
389 
390  return $this->_server['service_validate_url'] = $url;
391  }
392 
393 
401  public function setServerProxyValidateURL($url)
402  {
403  // Argument Validation
404  if (gettype($url) != 'string')
405  throw new CAS_TypeMismatchException($url, '$url', 'string');
406 
407  return $this->_server['proxy_validate_url'] = $url;
408  }
409 
410 
418  public function setServerSamlValidateURL($url)
419  {
420  // Argument Validation
421  if (gettype($url) != 'string')
422  throw new CAS_TypeMismatchException($url, '$url', 'string');
423 
424  return $this->_server['saml_validate_url'] = $url;
425  }
426 
427 
433  public function getServerServiceValidateURL()
434  {
436  // the URL is build only when needed
437  if ( empty($this->_server['service_validate_url']) ) {
438  switch ($this->getServerVersion()) {
439  case CAS_VERSION_1_0:
440  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
441  .'validate';
442  break;
443  case CAS_VERSION_2_0:
444  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
445  .'serviceValidate';
446  break;
447  case CAS_VERSION_3_0:
448  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
449  .'p3/serviceValidate';
450  break;
451  }
452  }
453  $url = $this->_buildQueryUrl(
454  $this->_server['service_validate_url'],
455  'service='.urlencode($this->getURL())
456  );
457  phpCAS::traceEnd($url);
458  return $url;
459  }
465  public function getServerSamlValidateURL()
466  {
468  // the URL is build only when needed
469  if ( empty($this->_server['saml_validate_url']) ) {
470  switch ($this->getServerVersion()) {
471  case SAML_VERSION_1_1:
472  $this->_server['saml_validate_url'] = $this->_getServerBaseURL().'samlValidate';
473  break;
474  }
475  }
476 
477  $url = $this->_buildQueryUrl(
478  $this->_server['saml_validate_url'],
479  'TARGET='.urlencode($this->getURL())
480  );
481  phpCAS::traceEnd($url);
482  return $url;
483  }
484 
490  public function getServerProxyValidateURL()
491  {
493  // the URL is build only when needed
494  if ( empty($this->_server['proxy_validate_url']) ) {
495  switch ($this->getServerVersion()) {
496  case CAS_VERSION_1_0:
497  $this->_server['proxy_validate_url'] = '';
498  break;
499  case CAS_VERSION_2_0:
500  $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'proxyValidate';
501  break;
502  case CAS_VERSION_3_0:
503  $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'p3/proxyValidate';
504  break;
505  }
506  }
507  $url = $this->_buildQueryUrl(
508  $this->_server['proxy_validate_url'],
509  'service='.urlencode($this->getURL())
510  );
511  phpCAS::traceEnd($url);
512  return $url;
513  }
514 
515 
521  public function getServerProxyURL()
522  {
523  // the URL is build only when needed
524  if ( empty($this->_server['proxy_url']) ) {
525  switch ($this->getServerVersion()) {
526  case CAS_VERSION_1_0:
527  $this->_server['proxy_url'] = '';
528  break;
529  case CAS_VERSION_2_0:
530  case CAS_VERSION_3_0:
531  $this->_server['proxy_url'] = $this->_getServerBaseURL().'proxy';
532  break;
533  }
534  }
535  return $this->_server['proxy_url'];
536  }
537 
543  public function getServerLogoutURL()
544  {
545  // the URL is build only when needed
546  if ( empty($this->_server['logout_url']) ) {
547  $this->_server['logout_url'] = $this->_getServerBaseURL().'logout';
548  }
549  return $this->_server['logout_url'];
550  }
551 
559  public function setServerLogoutURL($url)
560  {
561  // Argument Validation
562  if (gettype($url) != 'string')
563  throw new CAS_TypeMismatchException($url, '$url', 'string');
564 
565  return $this->_server['logout_url'] = $url;
566  }
567 
571  private $_curl_options = array();
572 
581  public function setExtraCurlOption($key, $value)
582  {
583  $this->_curl_options[$key] = $value;
584  }
585 
588  // ########################################################################
589  // Change the internal behaviour of phpcas
590  // ########################################################################
591 
603  private $_requestImplementation = 'CAS_Request_CurlRequest';
604 
613  public function setRequestImplementation ($className)
614  {
615  $obj = new $className;
616  if (!($obj instanceof CAS_Request_RequestInterface)) {
618  '$className must implement the CAS_Request_RequestInterface'
619  );
620  }
621  $this->_requestImplementation = $className;
622  }
623 
628  private $_clearTicketsFromUrl = true;
629 
640  public function setNoClearTicketsFromUrl ()
641  {
642  $this->_clearTicketsFromUrl = false;
643  }
644 
649 
654 
666  public function setCasAttributeParserCallback($function, array $additionalArgs = array())
667  {
668  $this->_casAttributeParserCallbackFunction = $function;
669  $this->_casAttributeParserCallbackArgs = $additionalArgs;
670  }
671 
675 
680 
700  public function setPostAuthenticateCallback ($function, array $additionalArgs = array())
701  {
702  $this->_postAuthenticateCallbackFunction = $function;
703  $this->_postAuthenticateCallbackArgs = $additionalArgs;
704  }
705 
710 
714  private $_signoutCallbackArgs = array();
715 
730  public function setSingleSignoutCallback ($function, array $additionalArgs = array())
731  {
732  $this->_signoutCallbackFunction = $function;
733  $this->_signoutCallbackArgs = $additionalArgs;
734  }
735 
736  // ########################################################################
737  // Methods for supplying code-flow feedback to integrators.
738  // ########################################################################
739 
747  public function ensureIsProxy()
748  {
749  if (!$this->isProxy()) {
751  }
752  }
753 
763  public function markAuthenticationCall ($auth)
764  {
765  // store where the authentication has been checked and the result
766  $dbg = debug_backtrace();
767  $this->_authentication_caller = array (
768  'file' => $dbg[1]['file'],
769  'line' => $dbg[1]['line'],
770  'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'],
771  'result' => (boolean)$auth
772  );
773  }
775 
781  public function wasAuthenticationCalled ()
782  {
783  return !empty($this->_authentication_caller);
784  }
785 
794  private function _ensureAuthenticationCalled()
795  {
796  if (!$this->wasAuthenticationCalled()) {
798  }
799  }
800 
810  {
812  return $this->_authentication_caller['result'];
813  }
814 
815 
825  {
827  if (!$this->_authentication_caller['result']) {
828  throw new CAS_OutOfSequenceException(
829  'authentication was checked (by '
831  . '() at ' . $this->getAuthenticationCallerFile()
832  . ':' . $this->getAuthenticationCallerLine()
833  . ') but the method returned false'
834  );
835  }
836  }
837 
846  public function getAuthenticationCallerFile ()
847  {
849  return $this->_authentication_caller['file'];
850  }
851 
860  public function getAuthenticationCallerLine ()
861  {
863  return $this->_authentication_caller['line'];
864  }
865 
874  public function getAuthenticationCallerMethod ()
875  {
877  return $this->_authentication_caller['method'];
878  }
879 
882  // ########################################################################
883  // CONSTRUCTOR
884  // ########################################################################
905  public function __construct(
906  $server_version,
907  $proxy,
908  $server_hostname,
909  $server_port,
910  $server_uri,
911  $changeSessionID = true,
912  \SessionHandlerInterface $sessionHandler = null
913  ) {
914  // Argument validation
915  if (gettype($server_version) != 'string')
916  throw new CAS_TypeMismatchException($server_version, '$server_version', 'string');
917  if (gettype($proxy) != 'boolean')
918  throw new CAS_TypeMismatchException($proxy, '$proxy', 'boolean');
919  if (gettype($server_hostname) != 'string')
920  throw new CAS_TypeMismatchException($server_hostname, '$server_hostname', 'string');
921  if (gettype($server_port) != 'integer')
922  throw new CAS_TypeMismatchException($server_port, '$server_port', 'integer');
923  if (gettype($server_uri) != 'string')
924  throw new CAS_TypeMismatchException($server_uri, '$server_uri', 'string');
925  if (gettype($changeSessionID) != 'boolean')
926  throw new CAS_TypeMismatchException($changeSessionID, '$changeSessionID', 'boolean');
927 
928  if (empty($sessionHandler)) {
929  $sessionHandler = new CAS_Session_PhpSession;
930  }
931 
933  // true : allow to change the session_id(), false session_id won't be
934  // changed and logout won't be handled because of that
935  $this->_setChangeSessionID($changeSessionID);
936 
937  $this->setSessionHandler($sessionHandler);
938 
939  if (!$this->_isLogoutRequest()) {
940  if (session_id() === "") {
941  // skip Session Handling for logout requests and if don't want it
942  session_start();
943  phpCAS :: trace("Starting a new session " . session_id());
944  }
945  // init phpCAS session array
946  if (!isset($_SESSION[static::PHPCAS_SESSION_PREFIX])
947  || !is_array($_SESSION[static::PHPCAS_SESSION_PREFIX])) {
948  $_SESSION[static::PHPCAS_SESSION_PREFIX] = array();
949  }
950  }
951 
952  // Only for debug purposes
953  if ($this->isSessionAuthenticated()){
954  phpCAS :: trace("Session is authenticated as: " . $this->getSessionValue('user'));
955  } else {
956  phpCAS :: trace("Session is not authenticated");
957  }
958  // are we in proxy mode ?
959  $this->_proxy = $proxy;
960 
961  // Make cookie handling available.
962  if ($this->isProxy()) {
963  if (!$this->hasSessionValue('service_cookies')) {
964  $this->setSessionValue('service_cookies', array());
965  }
966  // TODO remove explicit call to $_SESSION
967  $this->_serviceCookieJar = new CAS_CookieJar(
968  $_SESSION[static::PHPCAS_SESSION_PREFIX]['service_cookies']
969  );
970  }
971 
972  // check version
973  $supportedProtocols = phpCAS::getSupportedProtocols();
974  if (isset($supportedProtocols[$server_version]) === false) {
976  'this version of CAS (`'.$server_version
977  .'\') is not supported by phpCAS '.phpCAS::getVersion()
978  );
979  }
980 
981  if ($server_version === CAS_VERSION_1_0 && $this->isProxy()) {
982  phpCAS::error(
983  'CAS proxies are not supported in CAS '.$server_version
984  );
985  }
986 
987  $this->_server['version'] = $server_version;
988 
989  // check hostname
990  if ( empty($server_hostname)
991  || !preg_match('/[\.\d\-a-z]*/', $server_hostname)
992  ) {
993  phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
994  }
995  $this->_server['hostname'] = $server_hostname;
996 
997  // check port
998  if ( $server_port == 0
999  || !is_int($server_port)
1000  ) {
1001  phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
1002  }
1003  $this->_server['port'] = $server_port;
1004 
1005  // check URI
1006  if ( !preg_match('/[\.\d\-_a-z\/]*/', $server_uri) ) {
1007  phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
1008  }
1009  // add leading and trailing `/' and remove doubles
1010  if(strstr($server_uri, '?') === false) $server_uri .= '/';
1011  $server_uri = preg_replace('/\/\//', '/', '/'.$server_uri);
1012  $this->_server['uri'] = $server_uri;
1013 
1014  // set to callback mode if PgtIou and PgtId CGI GET parameters are provided
1015  if ( $this->isProxy() ) {
1016  if(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId'])) {
1017  $this->_setCallbackMode(true);
1018  $this->_setCallbackModeUsingPost(false);
1019  } elseif (!empty($_POST['pgtIou'])&&!empty($_POST['pgtId'])) {
1020  $this->_setCallbackMode(true);
1021  $this->_setCallbackModeUsingPost(true);
1022  } else {
1023  $this->_setCallbackMode(false);
1024  $this->_setCallbackModeUsingPost(false);
1025  }
1026 
1027 
1028  }
1029 
1030  if ( $this->_isCallbackMode() ) {
1031  //callback mode: check that phpCAS is secured
1032  if ( !$this->_isHttps() ) {
1033  phpCAS::error(
1034  'CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server'
1035  );
1036  }
1037  } else {
1038  //normal mode: get ticket and remove it from CGI parameters for
1039  // developers
1040  $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
1041  if (preg_match('/^[SP]T-/', $ticket) ) {
1042  phpCAS::trace('Ticket \''.$ticket.'\' found');
1043  $this->setTicket($ticket);
1044  unset($_GET['ticket']);
1045  } else if ( !empty($ticket) ) {
1046  //ill-formed ticket, halt
1047  phpCAS::error(
1048  'ill-formed ticket found in the URL (ticket=`'
1049  .htmlentities($ticket).'\')'
1050  );
1051  }
1052 
1053  }
1054  phpCAS::traceEnd();
1055  }
1056 
1059  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1060  // XX XX
1061  // XX Session Handling XX
1062  // XX XX
1063  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1064 
1071  const PHPCAS_SESSION_PREFIX = 'phpCAS';
1072 
1077  private $_change_session_id = true;
1078 
1083 
1091  private function _setChangeSessionID($allowed)
1092  {
1093  $this->_change_session_id = $allowed;
1094  }
1095 
1101  public function getChangeSessionID()
1102  {
1104  }
1105 
1113  public function setSessionHandler(\SessionHandlerInterface $sessionHandler)
1114  {
1115  $this->_sessionHandler = $sessionHandler;
1116  if (session_status() !== PHP_SESSION_ACTIVE) {
1117  return session_set_save_handler($this->_sessionHandler, true);
1118  }
1119  return true;
1120  }
1121 
1130  protected function getSessionValue($key, $default = null)
1131  {
1132  $this->validateSession($key);
1133 
1134  if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {
1135  return $_SESSION[static::PHPCAS_SESSION_PREFIX][$key];
1136  }
1137 
1138  return $default;
1139  }
1140 
1151  protected function hasSessionValue($key)
1152  {
1153  $this->validateSession($key);
1154 
1155  return isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);
1156  }
1157 
1166  protected function setSessionValue($key, $value)
1167  {
1168  $this->validateSession($key);
1169 
1170  $_SESSION[static::PHPCAS_SESSION_PREFIX][$key] = $value;
1171  }
1172 
1178  protected function removeSessionValue($key)
1179  {
1180  $this->validateSession($key);
1181 
1182  if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {
1183  unset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);
1184  return true;
1185  }
1186 
1187  return false;
1188  }
1189 
1193  protected function clearSessionValues()
1194  {
1195  unset($_SESSION[static::PHPCAS_SESSION_PREFIX]);
1196  }
1197 
1205  protected function validateSession($key)
1206  {
1207  if (!is_string($key)) {
1208  throw new InvalidArgumentException('Session key must be a string.');
1209  }
1210 
1211  return true;
1212  }
1213 
1221  protected function _renameSession($ticket)
1222  {
1224  if ($this->getChangeSessionID()) {
1225  if (!empty($this->_user)) {
1226  $old_session = $_SESSION;
1227  phpCAS :: trace("Killing session: ". session_id());
1228  session_destroy();
1229  // set up a new session, of name based on the ticket
1230  $session_id = $this->_sessionIdForTicket($ticket);
1231  phpCAS :: trace("Starting session: ". $session_id);
1232  session_id($session_id);
1233  session_start();
1234  phpCAS :: trace("Restoring old session vars");
1235  $_SESSION = $old_session;
1236  } else {
1237  phpCAS :: trace (
1238  'Session should only be renamed after successfull authentication'
1239  );
1240  }
1241  } else {
1243  "Skipping session rename since phpCAS is not handling the session."
1244  );
1245  }
1246  phpCAS::traceEnd();
1247  }
1248 
1251  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1252  // XX XX
1253  // XX AUTHENTICATION XX
1254  // XX XX
1255  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1256 
1268  private $_user = '';
1269 
1277  private function _setUser($user)
1278  {
1279  $this->_user = $user;
1280  }
1281 
1290  public function getUser()
1291  {
1292  // Sequence validation
1294 
1295  return $this->_getUser();
1296  }
1297 
1306  private function _getUser()
1307  {
1308  // This is likely a duplicate check that could be removed....
1309  if ( empty($this->_user) ) {
1310  phpCAS::error(
1311  'this method should be used only after '.__CLASS__
1312  .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
1313  );
1314  }
1315  return $this->_user;
1316  }
1317 
1325  private $_attributes = array();
1326 
1334  public function setAttributes($attributes)
1335  {
1336  $this->_attributes = $attributes;
1337  }
1338 
1344  public function getAttributes()
1345  {
1346  // Sequence validation
1348  // This is likely a duplicate check that could be removed....
1349  if ( empty($this->_user) ) {
1350  // if no user is set, there shouldn't be any attributes also...
1351  phpCAS::error(
1352  'this method should be used only after '.__CLASS__
1353  .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
1354  );
1355  }
1356  return $this->_attributes;
1357  }
1358 
1364  public function hasAttributes()
1365  {
1366  // Sequence validation
1368 
1369  return !empty($this->_attributes);
1370  }
1378  public function hasAttribute($key)
1379  {
1380  // Sequence validation
1382 
1383  return $this->_hasAttribute($key);
1384  }
1385 
1393  private function _hasAttribute($key)
1394  {
1395  return (is_array($this->_attributes)
1396  && array_key_exists($key, $this->_attributes));
1397  }
1398 
1406  public function getAttribute($key)
1407  {
1408  // Sequence validation
1410 
1411  if ($this->_hasAttribute($key)) {
1412  return $this->_attributes[$key];
1413  }
1414  }
1415 
1423  public function renewAuthentication()
1424  {
1426  // Either way, the user is authenticated by CAS
1427  $this->removeSessionValue('auth_checked');
1428  if ( $this->isAuthenticated(true) ) {
1429  phpCAS::trace('user already authenticated');
1430  $res = true;
1431  } else {
1432  $this->redirectToCas(false, true);
1433  // never reached
1434  $res = false;
1435  }
1436  phpCAS::traceEnd();
1437  return $res;
1438  }
1439 
1446  public function forceAuthentication()
1447  {
1449 
1450  if ( $this->isAuthenticated() ) {
1451  // the user is authenticated, nothing to be done.
1452  phpCAS::trace('no need to authenticate');
1453  $res = true;
1454  } else {
1455  // the user is not authenticated, redirect to the CAS server
1456  $this->removeSessionValue('auth_checked');
1457  $this->redirectToCas(false/* no gateway */);
1458  // never reached
1459  $res = false;
1460  }
1461  phpCAS::traceEnd($res);
1462  return $res;
1463  }
1464 
1472 
1480  public function setCacheTimesForAuthRecheck($n)
1481  {
1482  if (gettype($n) != 'integer')
1483  throw new CAS_TypeMismatchException($n, '$n', 'string');
1484 
1485  $this->_cache_times_for_auth_recheck = $n;
1486  }
1487 
1495  public function checkAuthentication()
1496  {
1498  $res = false; // default
1499  if ( $this->isAuthenticated() ) {
1500  phpCAS::trace('user is authenticated');
1501  /* The 'auth_checked' variable is removed just in case it's set. */
1502  $this->removeSessionValue('auth_checked');
1503  $res = true;
1504  } else if ($this->getSessionValue('auth_checked')) {
1505  // the previous request has redirected the client to the CAS server
1506  // with gateway=true
1507  $this->removeSessionValue('auth_checked');
1508  } else {
1509  // avoid a check against CAS on every request
1510  // we need to write this back to session later
1511  $unauth_count = $this->getSessionValue('unauth_count', -2);
1512 
1513  if (($unauth_count != -2
1514  && $this->_cache_times_for_auth_recheck == -1)
1515  || ($unauth_count >= 0
1516  && $unauth_count < $this->_cache_times_for_auth_recheck)
1517  ) {
1518  if ($this->_cache_times_for_auth_recheck != -1) {
1519  $unauth_count++;
1520  phpCAS::trace(
1521  'user is not authenticated (cached for '
1522  .$unauth_count.' times of '
1523  .$this->_cache_times_for_auth_recheck.')'
1524  );
1525  } else {
1526  phpCAS::trace(
1527  'user is not authenticated (cached for until login pressed)'
1528  );
1529  }
1530  $this->setSessionValue('unauth_count', $unauth_count);
1531  } else {
1532  $this->setSessionValue('unauth_count', 0);
1533  $this->setSessionValue('auth_checked', true);
1534  phpCAS::trace('user is not authenticated (cache reset)');
1535  $this->redirectToCas(true/* gateway */);
1536  // never reached
1537  }
1538  }
1539  phpCAS::traceEnd($res);
1540  return $res;
1541  }
1542 
1552  public function isAuthenticated($renew=false)
1553  {
1555  $res = false;
1556  $validate_url = '';
1557  if ( $this->_wasPreviouslyAuthenticated() ) {
1558  if ($this->hasTicket()) {
1559  // User has a additional ticket but was already authenticated
1560  phpCAS::trace(
1561  'ticket was present and will be discarded, use renewAuthenticate()'
1562  );
1563  if ($this->_clearTicketsFromUrl) {
1564  phpCAS::trace("Prepare redirect to : ".$this->getURL());
1565  session_write_close();
1566  header('Location: '.$this->getURL());
1567  flush();
1570  } else {
1571  phpCAS::trace(
1572  'Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.'
1573  );
1574  $res = true;
1575  }
1576  } else {
1577  // the user has already (previously during the session) been
1578  // authenticated, nothing to be done.
1579  phpCAS::trace(
1580  'user was already authenticated, no need to look for tickets'
1581  );
1582  $res = true;
1583  }
1584 
1585  // Mark the auth-check as complete to allow post-authentication
1586  // callbacks to make use of phpCAS::getUser() and similar methods
1587  $this->markAuthenticationCall($res);
1588  } else {
1589  if ($this->hasTicket()) {
1590  switch ($this->getServerVersion()) {
1591  case CAS_VERSION_1_0:
1592  // if a Service Ticket was given, validate it
1593  phpCAS::trace(
1594  'CAS 1.0 ticket `'.$this->getTicket().'\' is present'
1595  );
1596  $this->validateCAS10(
1597  $validate_url, $text_response, $tree_response, $renew
1598  ); // if it fails, it halts
1599  phpCAS::trace(
1600  'CAS 1.0 ticket `'.$this->getTicket().'\' was validated'
1601  );
1602  $this->setSessionValue('user', $this->_getUser());
1603  $res = true;
1604  $logoutTicket = $this->getTicket();
1605  break;
1606  case CAS_VERSION_2_0:
1607  case CAS_VERSION_3_0:
1608  // if a Proxy Ticket was given, validate it
1609  phpCAS::trace(
1610  'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' is present'
1611  );
1612  $this->validateCAS20(
1613  $validate_url, $text_response, $tree_response, $renew
1614  ); // note: if it fails, it halts
1615  phpCAS::trace(
1616  'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' was validated'
1617  );
1618  if ( $this->isProxy() ) {
1619  $this->_validatePGT(
1620  $validate_url, $text_response, $tree_response
1621  ); // idem
1622  phpCAS::trace('PGT `'.$this->_getPGT().'\' was validated');
1623  $this->setSessionValue('pgt', $this->_getPGT());
1624  }
1625  $this->setSessionValue('user', $this->_getUser());
1626  if (!empty($this->_attributes)) {
1627  $this->setSessionValue('attributes', $this->_attributes);
1628  }
1629  $proxies = $this->getProxies();
1630  if (!empty($proxies)) {
1631  $this->setSessionValue('proxies', $this->getProxies());
1632  }
1633  $res = true;
1634  $logoutTicket = $this->getTicket();
1635  break;
1636  case SAML_VERSION_1_1:
1637  // if we have a SAML ticket, validate it.
1638  phpCAS::trace(
1639  'SAML 1.1 ticket `'.$this->getTicket().'\' is present'
1640  );
1641  $this->validateSA(
1642  $validate_url, $text_response, $tree_response, $renew
1643  ); // if it fails, it halts
1644  phpCAS::trace(
1645  'SAML 1.1 ticket `'.$this->getTicket().'\' was validated'
1646  );
1647  $this->setSessionValue('user', $this->_getUser());
1648  $this->setSessionValue('attributes', $this->_attributes);
1649  $res = true;
1650  $logoutTicket = $this->getTicket();
1651  break;
1652  default:
1653  phpCAS::trace('Protocoll error');
1654  break;
1655  }
1656  } else {
1657  // no ticket given, not authenticated
1658  phpCAS::trace('no ticket found');
1659  }
1660 
1661  // Mark the auth-check as complete to allow post-authentication
1662  // callbacks to make use of phpCAS::getUser() and similar methods
1663  $this->markAuthenticationCall($res);
1664 
1665  if ($res) {
1666  // call the post-authenticate callback if registered.
1667  if ($this->_postAuthenticateCallbackFunction) {
1668  $args = $this->_postAuthenticateCallbackArgs;
1669  array_unshift($args, $logoutTicket);
1670  call_user_func_array(
1671  $this->_postAuthenticateCallbackFunction, $args
1672  );
1673  }
1674 
1675  // if called with a ticket parameter, we need to redirect to the
1676  // app without the ticket so that CAS-ification is transparent
1677  // to the browser (for later POSTS) most of the checks and
1678  // errors should have been made now, so we're safe for redirect
1679  // without masking error messages. remove the ticket as a
1680  // security precaution to prevent a ticket in the HTTP_REFERRER
1681  if ($this->_clearTicketsFromUrl) {
1682  phpCAS::trace("Prepare redirect to : ".$this->getURL());
1683  session_write_close();
1684  header('Location: '.$this->getURL());
1685  flush();
1688  }
1689  }
1690  }
1691  phpCAS::traceEnd($res);
1692  return $res;
1693  }
1694 
1700  public function isSessionAuthenticated ()
1701  {
1702  return !!$this->getSessionValue('user');
1703  }
1704 
1713  private function _wasPreviouslyAuthenticated()
1714  {
1716 
1717  if ( $this->_isCallbackMode() ) {
1718  // Rebroadcast the pgtIou and pgtId to all nodes
1719  if ($this->_rebroadcast&&!isset($_POST['rebroadcast'])) {
1720  $this->_rebroadcast(self::PGTIOU);
1721  }
1722  $this->_callback();
1723  }
1724 
1725  $auth = false;
1726 
1727  if ( $this->isProxy() ) {
1728  // CAS proxy: username and PGT must be present
1729  if ( $this->isSessionAuthenticated()
1730  && $this->getSessionValue('pgt')
1731  ) {
1732  // authentication already done
1733  $this->_setUser($this->getSessionValue('user'));
1734  if ($this->hasSessionValue('attributes')) {
1735  $this->setAttributes($this->getSessionValue('attributes'));
1736  }
1737  $this->_setPGT($this->getSessionValue('pgt'));
1738  phpCAS::trace(
1739  'user = `'.$this->getSessionValue('user').'\', PGT = `'
1740  .$this->getSessionValue('pgt').'\''
1741  );
1742 
1743  // Include the list of proxies
1744  if ($this->hasSessionValue('proxies')) {
1745  $this->_setProxies($this->getSessionValue('proxies'));
1746  phpCAS::trace(
1747  'proxies = "'
1748  .implode('", "', $this->getSessionValue('proxies')).'"'
1749  );
1750  }
1751 
1752  $auth = true;
1753  } elseif ( $this->isSessionAuthenticated()
1754  && !$this->getSessionValue('pgt')
1755  ) {
1756  // these two variables should be empty or not empty at the same time
1757  phpCAS::trace(
1758  'username found (`'.$this->getSessionValue('user')
1759  .'\') but PGT is empty'
1760  );
1761  // unset all tickets to enforce authentication
1762  $this->clearSessionValues();
1763  $this->setTicket('');
1764  } elseif ( !$this->isSessionAuthenticated()
1765  && $this->getSessionValue('pgt')
1766  ) {
1767  // these two variables should be empty or not empty at the same time
1768  phpCAS::trace(
1769  'PGT found (`'.$this->getSessionValue('pgt')
1770  .'\') but username is empty'
1771  );
1772  // unset all tickets to enforce authentication
1773  $this->clearSessionValues();
1774  $this->setTicket('');
1775  } else {
1776  phpCAS::trace('neither user nor PGT found');
1777  }
1778  } else {
1779  // `simple' CAS client (not a proxy): username must be present
1780  if ( $this->isSessionAuthenticated() ) {
1781  // authentication already done
1782  $this->_setUser($this->getSessionValue('user'));
1783  if ($this->hasSessionValue('attributes')) {
1784  $this->setAttributes($this->getSessionValue('attributes'));
1785  }
1786  phpCAS::trace('user = `'.$this->getSessionValue('user').'\'');
1787 
1788  // Include the list of proxies
1789  if ($this->hasSessionValue('proxies')) {
1790  $this->_setProxies($this->getSessionValue('proxies'));
1791  phpCAS::trace(
1792  'proxies = "'
1793  .implode('", "', $this->getSessionValue('proxies')).'"'
1794  );
1795  }
1796 
1797  $auth = true;
1798  } else {
1799  phpCAS::trace('no user found');
1800  }
1801  }
1802 
1804  return $auth;
1805  }
1806 
1817  public function redirectToCas($gateway=false,$renew=false)
1818  {
1820  $cas_url = $this->getServerLoginURL($gateway, $renew);
1821  session_write_close();
1822  if (php_sapi_name() === 'cli') {
1823  @header('Location: '.$cas_url);
1824  } else {
1825  header('Location: '.$cas_url);
1826  }
1827  phpCAS::trace("Redirect to : ".$cas_url);
1828  $lang = $this->getLangObj();
1829  $this->printHTMLHeader($lang->getAuthenticationWanted());
1830  printf('<p>'. $lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
1831  $this->printHTMLFooter();
1834  }
1835 
1836 
1845  public function logout($params)
1846  {
1848  $cas_url = $this->getServerLogoutURL();
1849  $paramSeparator = '?';
1850  if (isset($params['url'])) {
1851  $cas_url = $cas_url . $paramSeparator . "url="
1852  . urlencode($params['url']);
1853  $paramSeparator = '&';
1854  }
1855  if (isset($params['service'])) {
1856  $cas_url = $cas_url . $paramSeparator . "service="
1857  . urlencode($params['service']);
1858  }
1859  header('Location: '.$cas_url);
1860  phpCAS::trace("Prepare redirect to : ".$cas_url);
1861 
1862  phpCAS::trace("Destroying session : ".session_id());
1863  session_unset();
1864  session_destroy();
1865  if (session_status() === PHP_SESSION_NONE) {
1866  phpCAS::trace("Session terminated");
1867  } else {
1868  phpCAS::error("Session was not terminated");
1869  phpCAS::trace("Session was not terminated");
1870  }
1871  $lang = $this->getLangObj();
1872  $this->printHTMLHeader($lang->getLogout());
1873  printf('<p>'.$lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
1874  $this->printHTMLFooter();
1877  }
1878 
1884  private function _isLogoutRequest()
1885  {
1886  return !empty($_POST['logoutRequest']);
1887  }
1888 
1899  public function handleLogoutRequests($check_client=true, $allowed_clients=array())
1900  {
1902  if (!$this->_isLogoutRequest()) {
1903  phpCAS::trace("Not a logout request");
1904  phpCAS::traceEnd();
1905  return;
1906  }
1907  if (!$this->getChangeSessionID()
1908  && is_null($this->_signoutCallbackFunction)
1909  ) {
1910  phpCAS::trace(
1911  "phpCAS can't handle logout requests if it is not allowed to change session_id."
1912  );
1913  }
1914  phpCAS::trace("Logout requested");
1915  $decoded_logout_rq = urldecode($_POST['logoutRequest']);
1916  phpCAS::trace("SAML REQUEST: ".$decoded_logout_rq);
1917  $allowed = false;
1918  if ($check_client) {
1919  if ($allowed_clients === array()) {
1920  $allowed_clients = array( $this->_getServerHostname() );
1921  }
1922  $client_ip = $_SERVER['REMOTE_ADDR'];
1923  $client = gethostbyaddr($client_ip);
1924  phpCAS::trace("Client: ".$client."/".$client_ip);
1925  foreach ($allowed_clients as $allowed_client) {
1926  if (($client == $allowed_client)
1927  || ($client_ip == $allowed_client)
1928  ) {
1929  phpCAS::trace(
1930  "Allowed client '".$allowed_client
1931  ."' matches, logout request is allowed"
1932  );
1933  $allowed = true;
1934  break;
1935  } else {
1936  phpCAS::trace(
1937  "Allowed client '".$allowed_client."' does not match"
1938  );
1939  }
1940  }
1941  } else {
1942  phpCAS::trace("No access control set");
1943  $allowed = true;
1944  }
1945  // If Logout command is permitted proceed with the logout
1946  if ($allowed) {
1947  phpCAS::trace("Logout command allowed");
1948  // Rebroadcast the logout request
1949  if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) {
1950  $this->_rebroadcast(self::LOGOUT);
1951  }
1952  // Extract the ticket from the SAML Request
1953  preg_match(
1954  "|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|",
1955  $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3
1956  );
1957  $wrappedSamlSessionIndex = preg_replace(
1958  '|<samlp:SessionIndex>|', '', $tick[0][0]
1959  );
1960  $ticket2logout = preg_replace(
1961  '|</samlp:SessionIndex>|', '', $wrappedSamlSessionIndex
1962  );
1963  phpCAS::trace("Ticket to logout: ".$ticket2logout);
1964 
1965  // call the post-authenticate callback if registered.
1966  if ($this->_signoutCallbackFunction) {
1968  array_unshift($args, $ticket2logout);
1969  call_user_func_array($this->_signoutCallbackFunction, $args);
1970  }
1971 
1972  // If phpCAS is managing the session_id, destroy session thanks to
1973  // session_id.
1974  if ($this->getChangeSessionID()) {
1975  $session_id = $this->_sessionIdForTicket($ticket2logout);
1976  phpCAS::trace("Session id: ".$session_id);
1977 
1978  // destroy a possible application session created before phpcas
1979  if (session_id() !== "") {
1980  session_unset();
1981  session_destroy();
1982  }
1983  // fix session ID
1984  session_id($session_id);
1985  $_COOKIE[session_name()]=$session_id;
1986  $_GET[session_name()]=$session_id;
1987 
1988  // Overwrite session
1989  session_start();
1990  session_unset();
1991  session_destroy();
1992  phpCAS::trace("Session ". $session_id . " destroyed");
1993  }
1994  } else {
1995  phpCAS::error("Unauthorized logout request from client '".$client."'");
1996  phpCAS::trace("Unauthorized logout request from client '".$client."'");
1997  }
1998  flush();
2001 
2002  }
2003 
2006  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2007  // XX XX
2008  // XX BASIC CLIENT FEATURES (CAS 1.0) XX
2009  // XX XX
2010  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2011 
2012  // ########################################################################
2013  // ST
2014  // ########################################################################
2027  private $_ticket = '';
2028 
2034  public function getTicket()
2035  {
2036  return $this->_ticket;
2037  }
2038 
2046  public function setTicket($st)
2047  {
2048  $this->_ticket = $st;
2049  }
2050 
2056  public function hasTicket()
2057  {
2058  return !empty($this->_ticket);
2059  }
2060 
2063  // ########################################################################
2064  // ST VALIDATION
2065  // ########################################################################
2076  private $_cas_server_ca_cert = null;
2077 
2078 
2090 
2097 
2098 
2108  public function setCasServerCACert($cert, $validate_cn)
2109  {
2110  // Argument validation
2111  if (gettype($cert) != 'string') {
2112  throw new CAS_TypeMismatchException($cert, '$cert', 'string');
2113  }
2114  if (gettype($validate_cn) != 'boolean') {
2115  throw new CAS_TypeMismatchException($validate_cn, '$validate_cn', 'boolean');
2116  }
2117  if (!file_exists($cert)) {
2118  throw new CAS_InvalidArgumentException("Certificate file does not exist " . $this->_requestImplementation);
2119  }
2120  $this->_cas_server_ca_cert = $cert;
2121  $this->_cas_server_cn_validate = $validate_cn;
2122  }
2123 
2129  public function setNoCasServerValidation()
2130  {
2131  $this->_no_cas_server_validation = true;
2132  }
2133 
2150  public function validateCAS10(&$validate_url,&$text_response,&$tree_response,$renew=false)
2151  {
2153  // build the URL to validate the ticket
2154  $validate_url = $this->getServerServiceValidateURL()
2155  .'&ticket='.urlencode($this->getTicket());
2156 
2157  if ( $renew ) {
2158  // pass the renew
2159  $validate_url .= '&renew=true';
2160  }
2161 
2162  // open and read the URL
2163  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
2164  phpCAS::trace(
2165  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
2166  );
2167  throw new CAS_AuthenticationException(
2168  $this, 'CAS 1.0 ticket not validated', $validate_url,
2169  true/*$no_response*/
2170  );
2171  }
2172 
2173  if (preg_match('/^no\n/', $text_response)) {
2174  phpCAS::trace('Ticket has not been validated');
2175  throw new CAS_AuthenticationException(
2176  $this, 'ST not validated', $validate_url, false/*$no_response*/,
2177  false/*$bad_response*/, $text_response
2178  );
2179  } else if (!preg_match('/^yes\n/', $text_response)) {
2180  phpCAS::trace('ill-formed response');
2181  throw new CAS_AuthenticationException(
2182  $this, 'Ticket not validated', $validate_url,
2183  false/*$no_response*/, true/*$bad_response*/, $text_response
2184  );
2185  }
2186  // ticket has been validated, extract the user name
2187  $arr = preg_split('/\n/', $text_response);
2188  $this->_setUser(trim($arr[1]));
2189 
2190  $this->_renameSession($this->getTicket());
2191 
2192  // at this step, ticket has been validated and $this->_user has been set,
2193  phpCAS::traceEnd(true);
2194  return true;
2195  }
2196 
2200  // ########################################################################
2201  // SAML VALIDATION
2202  // ########################################################################
2226  public function validateSA(&$validate_url,&$text_response,&$tree_response,$renew=false)
2227  {
2228  phpCAS::traceBegin();
2229  $result = false;
2230  // build the URL to validate the ticket
2231  $validate_url = $this->getServerSamlValidateURL();
2232 
2233  if ( $renew ) {
2234  // pass the renew
2235  $validate_url .= '&renew=true';
2236  }
2237 
2238  // open and read the URL
2239  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
2240  phpCAS::trace(
2241  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
2242  );
2243  throw new CAS_AuthenticationException(
2244  $this, 'SA not validated', $validate_url, true/*$no_response*/
2245  );
2246  }
2247 
2248  phpCAS::trace('server version: '.$this->getServerVersion());
2249 
2250  // analyze the result depending on the version
2251  switch ($this->getServerVersion()) {
2252  case SAML_VERSION_1_1:
2253  // create new DOMDocument Object
2254  $dom = new DOMDocument();
2255  // Fix possible whitspace problems
2256  $dom->preserveWhiteSpace = false;
2257  // read the response of the CAS server into a DOM object
2258  if (!($dom->loadXML($text_response))) {
2259  phpCAS::trace('dom->loadXML() failed');
2260  throw new CAS_AuthenticationException(
2261  $this, 'SA not validated', $validate_url,
2262  false/*$no_response*/, true/*$bad_response*/,
2263  $text_response
2264  );
2265  }
2266  // read the root node of the XML tree
2267  if (!($tree_response = $dom->documentElement)) {
2268  phpCAS::trace('documentElement() failed');
2269  throw new CAS_AuthenticationException(
2270  $this, 'SA not validated', $validate_url,
2271  false/*$no_response*/, true/*$bad_response*/,
2272  $text_response
2273  );
2274  } else if ( $tree_response->localName != 'Envelope' ) {
2275  // insure that tag name is 'Envelope'
2276  phpCAS::trace(
2277  'bad XML root node (should be `Envelope\' instead of `'
2278  .$tree_response->localName.'\''
2279  );
2280  throw new CAS_AuthenticationException(
2281  $this, 'SA not validated', $validate_url,
2282  false/*$no_response*/, true/*$bad_response*/,
2283  $text_response
2284  );
2285  } else if ($tree_response->getElementsByTagName("NameIdentifier")->length != 0) {
2286  // check for the NameIdentifier tag in the SAML response
2287  $success_elements = $tree_response->getElementsByTagName("NameIdentifier");
2288  phpCAS::trace('NameIdentifier found');
2289  $user = trim($success_elements->item(0)->nodeValue);
2290  phpCAS::trace('user = `'.$user.'`');
2291  $this->_setUser($user);
2292  $this->_setSessionAttributes($text_response);
2293  $result = true;
2294  } else {
2295  phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
2296  throw new CAS_AuthenticationException(
2297  $this, 'SA not validated', $validate_url,
2298  false/*$no_response*/, true/*$bad_response*/,
2299  $text_response
2300  );
2301  }
2302  }
2303  if ($result) {
2304  $this->_renameSession($this->getTicket());
2305  }
2306  // at this step, ST has been validated and $this->_user has been set,
2307  phpCAS::traceEnd($result);
2308  return $result;
2309  }
2310 
2319  private function _setSessionAttributes($text_response)
2320  {
2322 
2323  $result = false;
2324 
2325  $attr_array = array();
2326 
2327  // create new DOMDocument Object
2328  $dom = new DOMDocument();
2329  // Fix possible whitspace problems
2330  $dom->preserveWhiteSpace = false;
2331  if (($dom->loadXML($text_response))) {
2332  $xPath = new DOMXPath($dom);
2333  $xPath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
2334  $xPath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
2335  $nodelist = $xPath->query("//saml:Attribute");
2336 
2337  if ($nodelist) {
2338  foreach ($nodelist as $node) {
2339  $xres = $xPath->query("saml:AttributeValue", $node);
2340  $name = $node->getAttribute("AttributeName");
2341  $value_array = array();
2342  foreach ($xres as $node2) {
2343  $value_array[] = $node2->nodeValue;
2344  }
2345  $attr_array[$name] = $value_array;
2346  }
2347  // UGent addition...
2348  foreach ($attr_array as $attr_key => $attr_value) {
2349  if (count($attr_value) > 1) {
2350  $this->_attributes[$attr_key] = $attr_value;
2351  phpCAS::trace("* " . $attr_key . "=" . print_r($attr_value, true));
2352  } else {
2353  $this->_attributes[$attr_key] = $attr_value[0];
2354  phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
2355  }
2356  }
2357  $result = true;
2358  } else {
2359  phpCAS::trace("SAML Attributes are empty");
2360  $result = false;
2361  }
2362  }
2363  phpCAS::traceEnd($result);
2364  return $result;
2365  }
2366 
2369  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2370  // XX XX
2371  // XX PROXY FEATURES (CAS 2.0) XX
2372  // XX XX
2373  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2374 
2375  // ########################################################################
2376  // PROXYING
2377  // ########################################################################
2388  private $_proxy;
2389 
2394 
2400  public function isProxy()
2401  {
2402  return $this->_proxy;
2403  }
2404 
2405 
2407  // ########################################################################
2408  // PGT
2409  // ########################################################################
2422  private $_pgt = '';
2423 
2429  private function _getPGT()
2430  {
2431  return $this->_pgt;
2432  }
2433 
2441  private function _setPGT($pgt)
2442  {
2443  $this->_pgt = $pgt;
2444  }
2445 
2451  private function _hasPGT()
2452  {
2453  return !empty($this->_pgt);
2454  }
2455 
2458  // ########################################################################
2459  // CALLBACK MODE
2460  // ########################################################################
2477  private $_callback_mode = false;
2478 
2486  private function _setCallbackMode($callback_mode)
2487  {
2488  $this->_callback_mode = $callback_mode;
2489  }
2490 
2497  private function _isCallbackMode()
2498  {
2499  return $this->_callback_mode;
2500  }
2501 
2509 
2517  private function _setCallbackModeUsingPost($callback_mode_using_post)
2518  {
2519  $this->_callback_mode_using_post = $callback_mode_using_post;
2520  }
2521 
2527  private function _isCallbackModeUsingPost()
2528  {
2530  }
2531 
2539  private $_callback_url = '';
2540 
2548  private function _getCallbackURL()
2549  {
2550  // the URL is built when needed only
2551  if ( empty($this->_callback_url) ) {
2552  // remove the ticket if present in the URL
2553  $final_uri = 'https://';
2554  $final_uri .= $this->_getClientUrl();
2555  $request_uri = $_SERVER['REQUEST_URI'];
2556  $request_uri = preg_replace('/\?.*$/', '', $request_uri);
2557  $final_uri .= $request_uri;
2558  $this->_callback_url = $final_uri;
2559  }
2560  return $this->_callback_url;
2561  }
2562 
2570  public function setCallbackURL($url)
2571  {
2572  // Sequence validation
2573  $this->ensureIsProxy();
2574  // Argument Validation
2575  if (gettype($url) != 'string')
2576  throw new CAS_TypeMismatchException($url, '$url', 'string');
2577 
2578  return $this->_callback_url = $url;
2579  }
2580 
2587  private function _callback()
2588  {
2590  if ($this->_isCallbackModeUsingPost()) {
2591  $pgtId = $_POST['pgtId'];
2592  $pgtIou = $_POST['pgtIou'];
2593  } else {
2594  $pgtId = $_GET['pgtId'];
2595  $pgtIou = $_GET['pgtIou'];
2596  }
2597  if (preg_match('/^PGTIOU-[\.\-\w]+$/', $pgtIou)) {
2598  if (preg_match('/^[PT]GT-[\.\-\w]+$/', $pgtId)) {
2599  phpCAS::trace('Storing PGT `'.$pgtId.'\' (id=`'.$pgtIou.'\')');
2600  $this->_storePGT($pgtId, $pgtIou);
2601  if ($this->isXmlResponse()) {
2602  echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n";
2603  echo '<proxySuccess xmlns="http://www.yale.edu/tp/cas" />';
2604  phpCAS::traceExit("XML response sent");
2605  } else {
2606  $this->printHTMLHeader('phpCAS callback');
2607  echo '<p>Storing PGT `'.$pgtId.'\' (id=`'.$pgtIou.'\').</p>';
2608  $this->printHTMLFooter();
2609  phpCAS::traceExit("HTML response sent");
2610  }
2611  phpCAS::traceExit("Successfull Callback");
2612  } else {
2613  phpCAS::error('PGT format invalid' . $pgtId);
2614  phpCAS::traceExit('PGT format invalid' . $pgtId);
2615  }
2616  } else {
2617  phpCAS::error('PGTiou format invalid' . $pgtIou);
2618  phpCAS::traceExit('PGTiou format invalid' . $pgtIou);
2619  }
2620 
2621  // Flush the buffer to prevent from sending anything other then a 200
2622  // Success Status back to the CAS Server. The Exception would normally
2623  // report as a 500 error.
2624  flush();
2626  }
2627 
2634  private function isXmlResponse()
2635  {
2636  if (!array_key_exists('HTTP_ACCEPT', $_SERVER)) {
2637  return false;
2638  }
2639  if (strpos($_SERVER['HTTP_ACCEPT'], 'application/xml') === false && strpos($_SERVER['HTTP_ACCEPT'], 'text/xml') === false) {
2640  return false;
2641  }
2642 
2643  return true;
2644  }
2645 
2648  // ########################################################################
2649  // PGT STORAGE
2650  // ########################################################################
2664  private $_pgt_storage = null;
2665 
2672  private function _initPGTStorage()
2673  {
2674  // if no SetPGTStorageXxx() has been used, default to file
2675  if ( !is_object($this->_pgt_storage) ) {
2676  $this->setPGTStorageFile();
2677  }
2678 
2679  // initializes the storage
2680  $this->_pgt_storage->init();
2681  }
2682 
2691  private function _storePGT($pgt,$pgt_iou)
2692  {
2693  // ensure that storage is initialized
2694  $this->_initPGTStorage();
2695  // writes the PGT
2696  $this->_pgt_storage->write($pgt, $pgt_iou);
2697  }
2698 
2707  private function _loadPGT($pgt_iou)
2708  {
2709  // ensure that storage is initialized
2710  $this->_initPGTStorage();
2711  // read the PGT
2712  return $this->_pgt_storage->read($pgt_iou);
2713  }
2714 
2723  public function setPGTStorage($storage)
2724  {
2725  // Sequence validation
2726  $this->ensureIsProxy();
2727 
2728  // check that the storage has not already been set
2729  if ( is_object($this->_pgt_storage) ) {
2730  phpCAS::error('PGT storage already defined');
2731  }
2732 
2733  // check to make sure a valid storage object was specified
2734  if ( !($storage instanceof CAS_PGTStorage_AbstractStorage) )
2735  throw new CAS_TypeMismatchException($storage, '$storage', 'CAS_PGTStorage_AbstractStorage object');
2736 
2737  // store the PGTStorage object
2738  $this->_pgt_storage = $storage;
2739  }
2740 
2758  public function setPGTStorageDb(
2759  $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null
2760  ) {
2761  // Sequence validation
2762  $this->ensureIsProxy();
2763 
2764  // Argument validation
2765  if (!(is_object($dsn_or_pdo) && $dsn_or_pdo instanceof PDO) && !is_string($dsn_or_pdo))
2766  throw new CAS_TypeMismatchException($dsn_or_pdo, '$dsn_or_pdo', 'string or PDO object');
2767  if (gettype($username) != 'string')
2768  throw new CAS_TypeMismatchException($username, '$username', 'string');
2769  if (gettype($password) != 'string')
2770  throw new CAS_TypeMismatchException($password, '$password', 'string');
2771  if (gettype($table) != 'string')
2772  throw new CAS_TypeMismatchException($table, '$password', 'string');
2773 
2774  // create the storage object
2775  $this->setPGTStorage(
2776  new CAS_PGTStorage_Db(
2777  $this, $dsn_or_pdo, $username, $password, $table, $driver_options
2778  )
2779  );
2780  }
2781 
2790  public function setPGTStorageFile($path='')
2791  {
2792  // Sequence validation
2793  $this->ensureIsProxy();
2794 
2795  // Argument validation
2796  if (gettype($path) != 'string')
2797  throw new CAS_TypeMismatchException($path, '$path', 'string');
2798 
2799  // create the storage object
2800  $this->setPGTStorage(new CAS_PGTStorage_File($this, $path));
2801  }
2802 
2803 
2804  // ########################################################################
2805  // PGT VALIDATION
2806  // ########################################################################
2823  private function _validatePGT(&$validate_url,$text_response,$tree_response)
2824  {
2826  if ( $tree_response->getElementsByTagName("proxyGrantingTicket")->length == 0) {
2827  phpCAS::trace('<proxyGrantingTicket> not found');
2828  // authentication succeded, but no PGT Iou was transmitted
2829  throw new CAS_AuthenticationException(
2830  $this, 'Ticket validated but no PGT Iou transmitted',
2831  $validate_url, false/*$no_response*/, false/*$bad_response*/,
2832  $text_response
2833  );
2834  } else {
2835  // PGT Iou transmitted, extract it
2836  $pgt_iou = trim(
2837  $tree_response->getElementsByTagName("proxyGrantingTicket")->item(0)->nodeValue
2838  );
2839  if (preg_match('/^PGTIOU-[\.\-\w]+$/', $pgt_iou)) {
2840  $pgt = $this->_loadPGT($pgt_iou);
2841  if ( $pgt == false ) {
2842  phpCAS::trace('could not load PGT');
2843  throw new CAS_AuthenticationException(
2844  $this,
2845  'PGT Iou was transmitted but PGT could not be retrieved',
2846  $validate_url, false/*$no_response*/,
2847  false/*$bad_response*/, $text_response
2848  );
2849  }
2850  $this->_setPGT($pgt);
2851  } else {
2852  phpCAS::trace('PGTiou format error');
2853  throw new CAS_AuthenticationException(
2854  $this, 'PGT Iou was transmitted but has wrong format',
2855  $validate_url, false/*$no_response*/, false/*$bad_response*/,
2856  $text_response
2857  );
2858  }
2859  }
2860  phpCAS::traceEnd(true);
2861  return true;
2862  }
2863 
2864  // ########################################################################
2865  // PGT VALIDATION
2866  // ########################################################################
2867 
2877  public function retrievePT($target_service,&$err_code,&$err_msg)
2878  {
2879  // Argument validation
2880  if (gettype($target_service) != 'string')
2881  throw new CAS_TypeMismatchException($target_service, '$target_service', 'string');
2882 
2884 
2885  // by default, $err_msg is set empty and $pt to true. On error, $pt is
2886  // set to false and $err_msg to an error message. At the end, if $pt is false
2887  // and $error_msg is still empty, it is set to 'invalid response' (the most
2888  // commonly encountered error).
2889  $err_msg = '';
2890 
2891  // build the URL to retrieve the PT
2892  $cas_url = $this->getServerProxyURL().'?targetService='
2893  .urlencode($target_service).'&pgt='.$this->_getPGT();
2894 
2895  // open and read the URL
2896  if ( !$this->_readURL($cas_url, $headers, $cas_response, $err_msg) ) {
2897  phpCAS::trace(
2898  'could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')'
2899  );
2900  $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
2901  $err_msg = 'could not retrieve PT (no response from the CAS server)';
2902  phpCAS::traceEnd(false);
2903  return false;
2904  }
2905 
2906  $bad_response = false;
2907 
2908  // create new DOMDocument object
2909  $dom = new DOMDocument();
2910  // Fix possible whitspace problems
2911  $dom->preserveWhiteSpace = false;
2912  // read the response of the CAS server into a DOM object
2913  if ( !($dom->loadXML($cas_response))) {
2914  phpCAS::trace('dom->loadXML() failed');
2915  // read failed
2916  $bad_response = true;
2917  }
2918 
2919  if ( !$bad_response ) {
2920  // read the root node of the XML tree
2921  if ( !($root = $dom->documentElement) ) {
2922  phpCAS::trace('documentElement failed');
2923  // read failed
2924  $bad_response = true;
2925  }
2926  }
2927 
2928  if ( !$bad_response ) {
2929  // insure that tag name is 'serviceResponse'
2930  if ( $root->localName != 'serviceResponse' ) {
2931  phpCAS::trace('localName failed');
2932  // bad root node
2933  $bad_response = true;
2934  }
2935  }
2936 
2937  if ( !$bad_response ) {
2938  // look for a proxySuccess tag
2939  if ( $root->getElementsByTagName("proxySuccess")->length != 0) {
2940  $proxy_success_list = $root->getElementsByTagName("proxySuccess");
2941 
2942  // authentication succeded, look for a proxyTicket tag
2943  if ( $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->length != 0) {
2944  $err_code = PHPCAS_SERVICE_OK;
2945  $err_msg = '';
2946  $pt = trim(
2947  $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->item(0)->nodeValue
2948  );
2949  phpCAS::trace('original PT: '.trim($pt));
2950  phpCAS::traceEnd($pt);
2951  return $pt;
2952  } else {
2953  phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
2954  }
2955  } else if ($root->getElementsByTagName("proxyFailure")->length != 0) {
2956  // look for a proxyFailure tag
2957  $proxy_failure_list = $root->getElementsByTagName("proxyFailure");
2958 
2959  // authentication failed, extract the error
2960  $err_code = PHPCAS_SERVICE_PT_FAILURE;
2961  $err_msg = 'PT retrieving failed (code=`'
2962  .$proxy_failure_list->item(0)->getAttribute('code')
2963  .'\', message=`'
2964  .trim($proxy_failure_list->item(0)->nodeValue)
2965  .'\')';
2966  phpCAS::traceEnd(false);
2967  return false;
2968  } else {
2969  phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
2970  }
2971  }
2972 
2973  // at this step, we are sure that the response of the CAS server was
2974  // illformed
2975  $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
2976  $err_msg = 'Invalid response from the CAS server (response=`'
2977  .$cas_response.'\')';
2978 
2979  phpCAS::traceEnd(false);
2980  return false;
2981  }
2982 
2985  // ########################################################################
2986  // READ CAS SERVER ANSWERS
2987  // ########################################################################
2988 
3007  private function _readURL($url, &$headers, &$body, &$err_msg)
3008  {
3010  $className = $this->_requestImplementation;
3011  $request = new $className();
3012 
3013  if (count($this->_curl_options)) {
3014  $request->setCurlOptions($this->_curl_options);
3015  }
3016 
3017  $request->setUrl($url);
3018 
3019  if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) {
3020  phpCAS::error(
3021  'one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.'
3022  );
3023  }
3024  if ($this->_cas_server_ca_cert != '') {
3025  $request->setSslCaCert(
3026  $this->_cas_server_ca_cert, $this->_cas_server_cn_validate
3027  );
3028  }
3029 
3030  // add extra stuff if SAML
3031  if ($this->getServerVersion() == SAML_VERSION_1_1) {
3032  $request->addHeader("soapaction: http://www.oasis-open.org/committees/security");
3033  $request->addHeader("cache-control: no-cache");
3034  $request->addHeader("pragma: no-cache");
3035  $request->addHeader("accept: text/xml");
3036  $request->addHeader("connection: keep-alive");
3037  $request->addHeader("content-type: text/xml");
3038  $request->makePost();
3039  $request->setPostBody($this->_buildSAMLPayload());
3040  }
3041 
3042  if ($request->send()) {
3043  $headers = $request->getResponseHeaders();
3044  $body = $request->getResponseBody();
3045  $err_msg = '';
3046  phpCAS::traceEnd(true);
3047  return true;
3048  } else {
3049  $headers = '';
3050  $body = '';
3051  $err_msg = $request->getErrorMessage();
3052  phpCAS::traceEnd(false);
3053  return false;
3054  }
3055  }
3056 
3062  private function _buildSAMLPayload()
3063  {
3065 
3066  //get the ticket
3067  $sa = urlencode($this->getTicket());
3068 
3069  $body = SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST
3070  .SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE
3071  .SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
3072 
3073  phpCAS::traceEnd($body);
3074  return ($body);
3075  }
3076 
3079  // ########################################################################
3080  // ACCESS TO EXTERNAL SERVICES
3081  // ########################################################################
3082 
3099  public function getProxiedService ($type)
3100  {
3101  // Sequence validation
3102  $this->ensureIsProxy();
3104 
3105  // Argument validation
3106  if (gettype($type) != 'string')
3107  throw new CAS_TypeMismatchException($type, '$type', 'string');
3108 
3109  switch ($type) {
3112  $requestClass = $this->_requestImplementation;
3113  $request = new $requestClass();
3114  if (count($this->_curl_options)) {
3115  $request->setCurlOptions($this->_curl_options);
3116  }
3117  $proxiedService = new $type($request, $this->_serviceCookieJar);
3118  if ($proxiedService instanceof CAS_ProxiedService_Testable) {
3119  $proxiedService->setCasClient($this);
3120  }
3121  return $proxiedService;
3123  $proxiedService = new CAS_ProxiedService_Imap($this->_getUser());
3124  if ($proxiedService instanceof CAS_ProxiedService_Testable) {
3125  $proxiedService->setCasClient($this);
3126  }
3127  return $proxiedService;
3128  default:
3129  throw new CAS_InvalidArgumentException(
3130  "Unknown proxied-service type, $type."
3131  );
3132  }
3133  }
3134 
3150  public function initializeProxiedService (CAS_ProxiedService $proxiedService)
3151  {
3152  // Sequence validation
3153  $this->ensureIsProxy();
3155 
3156  $url = $proxiedService->getServiceUrl();
3157  if (!is_string($url)) {
3158  throw new CAS_ProxiedService_Exception(
3159  "Proxied Service ".get_class($proxiedService)
3160  ."->getServiceUrl() should have returned a string, returned a "
3161  .gettype($url)." instead."
3162  );
3163  }
3164  $pt = $this->retrievePT($url, $err_code, $err_msg);
3165  if (!$pt) {
3166  throw new CAS_ProxyTicketException($err_msg, $err_code);
3167  }
3168  $proxiedService->setProxyTicket($pt);
3169  }
3170 
3185  public function serviceWeb($url,&$err_code,&$output)
3186  {
3187  // Sequence validation
3188  $this->ensureIsProxy();
3190 
3191  // Argument validation
3192  if (gettype($url) != 'string')
3193  throw new CAS_TypeMismatchException($url, '$url', 'string');
3194 
3195  try {
3197  $service->setUrl($url);
3198  $service->send();
3199  $output = $service->getResponseBody();
3200  $err_code = PHPCAS_SERVICE_OK;
3201  return true;
3202  } catch (CAS_ProxyTicketException $e) {
3203  $err_code = $e->getCode();
3204  $output = $e->getMessage();
3205  return false;
3206  } catch (CAS_ProxiedService_Exception $e) {
3207  $lang = $this->getLangObj();
3208  $output = sprintf(
3209  $lang->getServiceUnavailable(), $url, $e->getMessage()
3210  );
3211  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
3212  return false;
3213  }
3214  }
3215 
3235  public function serviceMail($url,$serviceUrl,$flags,&$err_code,&$err_msg,&$pt)
3236  {
3237  // Sequence validation
3238  $this->ensureIsProxy();
3240 
3241  // Argument validation
3242  if (gettype($url) != 'string')
3243  throw new CAS_TypeMismatchException($url, '$url', 'string');
3244  if (gettype($serviceUrl) != 'string')
3245  throw new CAS_TypeMismatchException($serviceUrl, '$serviceUrl', 'string');
3246  if (gettype($flags) != 'integer')
3247  throw new CAS_TypeMismatchException($flags, '$flags', 'string');
3248 
3249  try {
3251  $service->setServiceUrl($serviceUrl);
3252  $service->setMailbox($url);
3253  $service->setOptions($flags);
3254 
3255  $stream = $service->open();
3256  $err_code = PHPCAS_SERVICE_OK;
3257  $pt = $service->getImapProxyTicket();
3258  return $stream;
3259  } catch (CAS_ProxyTicketException $e) {
3260  $err_msg = $e->getMessage();
3261  $err_code = $e->getCode();
3262  $pt = false;
3263  return false;
3264  } catch (CAS_ProxiedService_Exception $e) {
3265  $lang = $this->getLangObj();
3266  $err_msg = sprintf(
3267  $lang->getServiceUnavailable(),
3268  $url,
3269  $e->getMessage()
3270  );
3271  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
3272  $pt = false;
3273  return false;
3274  }
3275  }
3276 
3279  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3280  // XX XX
3281  // XX PROXIED CLIENT FEATURES (CAS 2.0) XX
3282  // XX XX
3283  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3284 
3285  // ########################################################################
3286  // PT
3287  // ########################################################################
3303  private $_proxies = array();
3304 
3314  public function getProxies()
3315  {
3316  return $this->_proxies;
3317  }
3318 
3327  private function _setProxies($proxies)
3328  {
3329  $this->_proxies = $proxies;
3330  if (!empty($proxies)) {
3331  // For proxy-authenticated requests people are not viewing the URL
3332  // directly since the client is another application making a
3333  // web-service call.
3334  // Because of this, stripping the ticket from the URL is unnecessary
3335  // and causes another web-service request to be performed. Additionally,
3336  // if session handling on either the client or the server malfunctions
3337  // then the subsequent request will not complete successfully.
3338  $this->setNoClearTicketsFromUrl();
3339  }
3340  }
3341 
3348 
3354  public function getAllowedProxyChains ()
3355  {
3356  if (empty($this->_allowed_proxy_chains)) {
3357  $this->_allowed_proxy_chains = new CAS_ProxyChain_AllowedList();
3358  }
3360  }
3361 
3363  // ########################################################################
3364  // PT VALIDATION
3365  // ########################################################################
3385  public function validateCAS20(&$validate_url,&$text_response,&$tree_response, $renew=false)
3386  {
3388  phpCAS::trace($text_response);
3389  // build the URL to validate the ticket
3390  if ($this->getAllowedProxyChains()->isProxyingAllowed()) {
3391  $validate_url = $this->getServerProxyValidateURL().'&ticket='
3392  .urlencode($this->getTicket());
3393  } else {
3394  $validate_url = $this->getServerServiceValidateURL().'&ticket='
3395  .urlencode($this->getTicket());
3396  }
3397 
3398  if ( $this->isProxy() ) {
3399  // pass the callback url for CAS proxies
3400  $validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL());
3401  }
3402 
3403  if ( $renew ) {
3404  // pass the renew
3405  $validate_url .= '&renew=true';
3406  }
3407 
3408  // open and read the URL
3409  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
3410  phpCAS::trace(
3411  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
3412  );
3413  throw new CAS_AuthenticationException(
3414  $this, 'Ticket not validated', $validate_url,
3415  true/*$no_response*/
3416  );
3417  }
3418 
3419  // create new DOMDocument object
3420  $dom = new DOMDocument();
3421  // Fix possible whitspace problems
3422  $dom->preserveWhiteSpace = false;
3423  // CAS servers should only return data in utf-8
3424  $dom->encoding = "utf-8";
3425  // read the response of the CAS server into a DOMDocument object
3426  if ( !($dom->loadXML($text_response))) {
3427  // read failed
3428  throw new CAS_AuthenticationException(
3429  $this, 'Ticket not validated', $validate_url,
3430  false/*$no_response*/, true/*$bad_response*/, $text_response
3431  );
3432  } else if ( !($tree_response = $dom->documentElement) ) {
3433  // read the root node of the XML tree
3434  // read failed
3435  throw new CAS_AuthenticationException(
3436  $this, 'Ticket not validated', $validate_url,
3437  false/*$no_response*/, true/*$bad_response*/, $text_response
3438  );
3439  } else if ($tree_response->localName != 'serviceResponse') {
3440  // insure that tag name is 'serviceResponse'
3441  // bad root node
3442  throw new CAS_AuthenticationException(
3443  $this, 'Ticket not validated', $validate_url,
3444  false/*$no_response*/, true/*$bad_response*/, $text_response
3445  );
3446  } else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
3447  // authentication failed, extract the error code and message and throw exception
3448  $auth_fail_list = $tree_response
3449  ->getElementsByTagName("authenticationFailure");
3450  throw new CAS_AuthenticationException(
3451  $this, 'Ticket not validated', $validate_url,
3452  false/*$no_response*/, false/*$bad_response*/,
3453  $text_response,
3454  $auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
3455  trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
3456  );
3457  } else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) {
3458  // authentication succeded, extract the user name
3459  $success_elements = $tree_response
3460  ->getElementsByTagName("authenticationSuccess");
3461  if ( $success_elements->item(0)->getElementsByTagName("user")->length == 0) {
3462  // no user specified => error
3463  throw new CAS_AuthenticationException(
3464  $this, 'Ticket not validated', $validate_url,
3465  false/*$no_response*/, true/*$bad_response*/, $text_response
3466  );
3467  } else {
3468  $this->_setUser(
3469  trim(
3470  $success_elements->item(0)->getElementsByTagName("user")->item(0)->nodeValue
3471  )
3472  );
3473  $this->_readExtraAttributesCas20($success_elements);
3474  // Store the proxies we are sitting behind for authorization checking
3475  $proxyList = array();
3476  if ( sizeof($arr = $success_elements->item(0)->getElementsByTagName("proxy")) > 0) {
3477  foreach ($arr as $proxyElem) {
3478  phpCAS::trace("Found Proxy: ".$proxyElem->nodeValue);
3479  $proxyList[] = trim($proxyElem->nodeValue);
3480  }
3481  $this->_setProxies($proxyList);
3482  phpCAS::trace("Storing Proxy List");
3483  }
3484  // Check if the proxies in front of us are allowed
3485  if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) {
3486  throw new CAS_AuthenticationException(
3487  $this, 'Proxy not allowed', $validate_url,
3488  false/*$no_response*/, true/*$bad_response*/,
3489  $text_response
3490  );
3491  } else {
3492  $result = true;
3493  }
3494  }
3495  } else {
3496  throw new CAS_AuthenticationException(
3497  $this, 'Ticket not validated', $validate_url,
3498  false/*$no_response*/, true/*$bad_response*/,
3499  $text_response
3500  );
3501  }
3502 
3503  $this->_renameSession($this->getTicket());
3504 
3505  // at this step, Ticket has been validated and $this->_user has been set,
3506 
3507  phpCAS::traceEnd($result);
3508  return $result;
3509  }
3510 
3610  private function _xml_to_array($root, $namespace = "cas")
3611  {
3612  $result = array();
3613  if ($root->hasAttributes()) {
3614  $attrs = $root->attributes;
3615  $pair = array();
3616  foreach ($attrs as $attr) {
3617  if ($attr->name === "name") {
3618  $pair['name'] = $attr->value;
3619  } elseif ($attr->name === "value") {
3620  $pair['value'] = $attr->value;
3621  } else {
3622  $result[$attr->name] = $attr->value;
3623  }
3624  if (array_key_exists('name', $pair) && array_key_exists('value', $pair)) {
3625  $result[$pair['name']] = $pair['value'];
3626  }
3627  }
3628  }
3629  if ($root->hasChildNodes()) {
3630  $children = $root->childNodes;
3631  if ($children->length == 1) {
3632  $child = $children->item(0);
3633  if ($child->nodeType == XML_TEXT_NODE) {
3634  $result['_value'] = $child->nodeValue;
3635  return (count($result) == 1) ? $result['_value'] : $result;
3636  }
3637  }
3638  $groups = array();
3639  foreach ($children as $child) {
3640  $child_nodeName = str_ireplace($namespace . ":", "", $child->nodeName);
3641  if (in_array($child_nodeName, array("user", "proxies", "proxyGrantingTicket"))) {
3642  continue;
3643  }
3644  if (!isset($result[$child_nodeName])) {
3645  $res = $this->_xml_to_array($child, $namespace);
3646  if (!empty($res)) {
3647  $result[$child_nodeName] = $this->_xml_to_array($child, $namespace);
3648  }
3649  } else {
3650  if (!isset($groups[$child_nodeName])) {
3651  $result[$child_nodeName] = array($result[$child_nodeName]);
3652  $groups[$child_nodeName] = 1;
3653  }
3654  $result[$child_nodeName][] = $this->_xml_to_array($child, $namespace);
3655  }
3656  }
3657  }
3658  return $result;
3659  }
3660 
3676  private function _parse_json_like_array_value($json_value)
3677  {
3678  $parts = explode(",", trim($json_value, "[]"));
3679  $out = array();
3680  $quote = '';
3681  foreach ($parts as $part) {
3682  $part = trim($part);
3683  if ($quote === '') {
3684  $value = "";
3685  if ($this->_startsWith($part, '\'')) {
3686  $quote = '\'';
3687  } elseif ($this->_startsWith($part, '"')) {
3688  $quote = '"';
3689  } else {
3690  $out[] = $part;
3691  }
3692  $part = ltrim($part, $quote);
3693  }
3694  if ($quote !== '') {
3695  $value .= $part;
3696  if ($this->_endsWith($part, $quote)) {
3697  $out[] = rtrim($value, $quote);
3698  $quote = '';
3699  } else {
3700  $value .= ", ";
3701  };
3702  }
3703  }
3704  return $out;
3705  }
3706 
3745  private function _flatten_array($arr)
3746  {
3747  if (!is_array($arr)) {
3748  if ($this->_startsWith($arr, '[') && $this->_endsWith($arr, ']')) {
3749  return $this->_parse_json_like_array_value($arr);
3750  } else {
3751  return $arr;
3752  }
3753  }
3754  $out = array();
3755  foreach ($arr as $key => $val) {
3756  if (!is_array($val)) {
3757  $out[$key] = $val;
3758  } else {
3759  switch (count($val)) {
3760  case 1 : {
3761  $key = key($val);
3762  if (array_key_exists($key, $out)) {
3763  $value = $out[$key];
3764  if (!is_array($value)) {
3765  $out[$key] = array();
3766  $out[$key][] = $value;
3767  }
3768  $out[$key][] = $this->_flatten_array($val[$key]);
3769  } else {
3770  $out[$key] = $this->_flatten_array($val[$key]);
3771  };
3772  break;
3773  };
3774  case 2 : {
3775  if (array_key_exists("name", $val) && array_key_exists("value", $val)) {
3776  $key = $val['name'];
3777  if (array_key_exists($key, $out)) {
3778  $value = $out[$key];
3779  if (!is_array($value)) {
3780  $out[$key] = array();
3781  $out[$key][] = $value;
3782  }
3783  $out[$key][] = $this->_flatten_array($val['value']);
3784  } else {
3785  $out[$key] = $this->_flatten_array($val['value']);
3786  };
3787  } else {
3788  $out[$key] = $this->_flatten_array($val);
3789  }
3790  break;
3791  };
3792  default: {
3793  $out[$key] = $this->_flatten_array($val);
3794  }
3795  }
3796  }
3797  }
3798  return $out;
3799  }
3800 
3810  private function _readExtraAttributesCas20($success_elements)
3811  {
3813 
3814  $extra_attributes = array();
3815  if ($this->_casAttributeParserCallbackFunction !== null
3816  && is_callable($this->_casAttributeParserCallbackFunction)
3817  ) {
3818  array_unshift($this->_casAttributeParserCallbackArgs, $success_elements->item(0));
3819  phpCAS :: trace("Calling attritubeParser callback");
3820  $extra_attributes = call_user_func_array(
3821  $this->_casAttributeParserCallbackFunction,
3822  $this->_casAttributeParserCallbackArgs
3823  );
3824  } else {
3825  phpCAS :: trace("Parse extra attributes: ");
3826  $attributes = $this->_xml_to_array($success_elements->item(0));
3827  phpCAS :: trace(print_r($attributes,true). "\nFLATTEN Array: ");
3828  $extra_attributes = $this->_flatten_array($attributes);
3829  phpCAS :: trace(print_r($extra_attributes, true)."\nFILTER : ");
3830  if (array_key_exists("attribute", $extra_attributes)) {
3831  $extra_attributes = $extra_attributes["attribute"];
3832  } elseif (array_key_exists("attributes", $extra_attributes)) {
3833  $extra_attributes = $extra_attributes["attributes"];
3834  };
3835  phpCAS :: trace(print_r($extra_attributes, true)."return");
3836  }
3837  $this->setAttributes($extra_attributes);
3838  phpCAS::traceEnd();
3839  return true;
3840  }
3841 
3851  private function _addAttributeToArray(array &$attributeArray, $name, $value)
3852  {
3853  // If multiple attributes exist, add as an array value
3854  if (isset($attributeArray[$name])) {
3855  // Initialize the array with the existing value
3856  if (!is_array($attributeArray[$name])) {
3857  $existingValue = $attributeArray[$name];
3858  $attributeArray[$name] = array($existingValue);
3859  }
3860 
3861  $attributeArray[$name][] = trim($value);
3862  } else {
3863  $attributeArray[$name] = trim($value);
3864  }
3865  }
3866 
3869  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3870  // XX XX
3871  // XX MISC XX
3872  // XX XX
3873  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3874 
3880  // ########################################################################
3881  // URL
3882  // ########################################################################
3889  private $_url = '';
3890 
3891 
3899  public function setURL($url)
3900  {
3901  // Argument Validation
3902  if (gettype($url) != 'string')
3903  throw new CAS_TypeMismatchException($url, '$url', 'string');
3904 
3905  $this->_url = $url;
3906  }
3907 
3914  public function getURL()
3915  {
3917  // the URL is built when needed only
3918  if ( empty($this->_url) ) {
3919  // remove the ticket if present in the URL
3920  $final_uri = ($this->_isHttps()) ? 'https' : 'http';
3921  $final_uri .= '://';
3922 
3923  $final_uri .= $this->_getClientUrl();
3924  $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);
3925  $final_uri .= $request_uri[0];
3926 
3927  if (isset($request_uri[1]) && $request_uri[1]) {
3928  $query_string= $this->_removeParameterFromQueryString('ticket', $request_uri[1]);
3929 
3930  // If the query string still has anything left,
3931  // append it to the final URI
3932  if ($query_string !== '') {
3933  $final_uri .= "?$query_string";
3934  }
3935  }
3936 
3937  phpCAS::trace("Final URI: $final_uri");
3938  $this->setURL($final_uri);
3939  }
3940  phpCAS::traceEnd($this->_url);
3941  return $this->_url;
3942  }
3943 
3951  public function setBaseURL($url)
3952  {
3953  // Argument Validation
3954  if (gettype($url) != 'string')
3955  throw new CAS_TypeMismatchException($url, '$url', 'string');
3956 
3957  return $this->_server['base_url'] = $url;
3958  }
3959 
3960 
3966  private function _getClientUrl()
3967  {
3968  if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
3969  // explode the host list separated by comma and use the first host
3970  $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
3971  // see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default
3972  return $hosts[0];
3973  } else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
3974  $server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];
3975  } else {
3976  if (empty($_SERVER['SERVER_NAME'])) {
3977  $server_url = $_SERVER['HTTP_HOST'];
3978  } else {
3979  $server_url = $_SERVER['SERVER_NAME'];
3980  }
3981  }
3982  if (!strpos($server_url, ':')) {
3983  if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
3984  $server_port = $_SERVER['SERVER_PORT'];
3985  } else {
3986  $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);
3987  $server_port = $ports[0];
3988  }
3989 
3990  if ( ($this->_isHttps() && $server_port!=443)
3991  || (!$this->_isHttps() && $server_port!=80)
3992  ) {
3993  $server_url .= ':';
3994  $server_url .= $server_port;
3995  }
3996  }
3997  return $server_url;
3998  }
3999 
4005  private function _isHttps()
4006  {
4007  if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
4008  return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
4009  } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {
4010  return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https');
4011  } elseif ( isset($_SERVER['HTTPS'])
4012  && !empty($_SERVER['HTTPS'])
4013  && strcasecmp($_SERVER['HTTPS'], 'off') !== 0
4014  ) {
4015  return true;
4016  }
4017  return false;
4018 
4019  }
4020 
4031  private function _removeParameterFromQueryString($parameterName, $queryString)
4032  {
4033  $parameterName = preg_quote($parameterName);
4034  return preg_replace(
4035  "/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/",
4036  '', $queryString
4037  );
4038  }
4039 
4050  private function _buildQueryUrl($url, $query)
4051  {
4052  $url .= (strstr($url, '?') === false) ? '?' : '&';
4053  $url .= $query;
4054  return $url;
4055  }
4056 
4065  private function _startsWith($text, $char)
4066  {
4067  return (strpos($text, $char) === 0);
4068  }
4069 
4078  private function _endsWith($text, $char)
4079  {
4080  return (strpos(strrev($text), $char) === 0);
4081  }
4082 
4094  private function _sessionIdForTicket($ticket)
4095  {
4096  // Hash the ticket to ensure that the value meets the PHP 7.1 requirement
4097  // that session-ids have a length between 22 and 256 characters.
4098  return hash('sha256', $this->_sessionIdSalt . $ticket);
4099  }
4100 
4106  private $_sessionIdSalt = '';
4107 
4115  public function setSessionIdSalt($salt) {
4116  $this->_sessionIdSalt = (string)$salt;
4117  }
4118 
4119  // ########################################################################
4120  // AUTHENTICATION ERROR HANDLING
4121  // ########################################################################
4138  private function _authError(
4139  $failure,
4140  $cas_url,
4141  $no_response=false,
4142  $bad_response=false,
4143  $cas_response='',
4144  $err_code=-1,
4145  $err_msg=''
4146  ) {
4148  $lang = $this->getLangObj();
4149  $this->printHTMLHeader($lang->getAuthenticationFailed());
4150  printf(
4151  $lang->getYouWereNotAuthenticated(), htmlentities($this->getURL()),
4152  isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''
4153  );
4154  phpCAS::trace('CAS URL: '.$cas_url);
4155  phpCAS::trace('Authentication failure: '.$failure);
4156  if ( $no_response ) {
4157  phpCAS::trace('Reason: no response from the CAS server');
4158  } else {
4159  if ( $bad_response ) {
4160  phpCAS::trace('Reason: bad response from the CAS server');
4161  } else {
4162  switch ($this->getServerVersion()) {
4163  case CAS_VERSION_1_0:
4164  phpCAS::trace('Reason: CAS error');
4165  break;
4166  case CAS_VERSION_2_0:
4167  case CAS_VERSION_3_0:
4168  if ( $err_code === -1 ) {
4169  phpCAS::trace('Reason: no CAS error');
4170  } else {
4171  phpCAS::trace(
4172  'Reason: ['.$err_code.'] CAS error: '.$err_msg
4173  );
4174  }
4175  break;
4176  }
4177  }
4178  phpCAS::trace('CAS response: '.$cas_response);
4179  }
4180  $this->printHTMLFooter();
4183  }
4184 
4185  // ########################################################################
4186  // PGTIOU/PGTID and logoutRequest rebroadcasting
4187  // ########################################################################
4188 
4193  private $_rebroadcast = false;
4194  private $_rebroadcast_nodes = array();
4195 
4199  const HOSTNAME = 0;
4200  const IP = 1;
4201 
4210  private function _getNodeType($nodeURL)
4211  {
4213  if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $nodeURL)) {
4214  phpCAS::traceEnd(self::IP);
4215  return self::IP;
4216  } else {
4217  phpCAS::traceEnd(self::HOSTNAME);
4218  return self::HOSTNAME;
4219  }
4220  }
4221 
4229  public function addRebroadcastNode($rebroadcastNodeUrl)
4230  {
4231  // Argument validation
4232  if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl))
4233  throw new CAS_TypeMismatchException($rebroadcastNodeUrl, '$rebroadcastNodeUrl', 'url');
4234 
4235  // Store the rebroadcast node and set flag
4236  $this->_rebroadcast = true;
4237  $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl;
4238  }
4239 
4243  private $_rebroadcast_headers = array();
4244 
4253  public function addRebroadcastHeader($header)
4254  {
4255  if (gettype($header) != 'string')
4256  throw new CAS_TypeMismatchException($header, '$header', 'string');
4257 
4258  $this->_rebroadcast_headers[] = $header;
4259  }
4260 
4264  const LOGOUT = 0;
4265  const PGTIOU = 1;
4266 
4274  private function _rebroadcast($type)
4275  {
4277 
4278  $rebroadcast_curl_options = array(
4279  CURLOPT_FAILONERROR => 1,
4280  CURLOPT_FOLLOWLOCATION => 1,
4281  CURLOPT_RETURNTRANSFER => 1,
4282  CURLOPT_CONNECTTIMEOUT => 1,
4283  CURLOPT_TIMEOUT => 4);
4284 
4285  // Try to determine the IP address of the server
4286  if (!empty($_SERVER['SERVER_ADDR'])) {
4287  $ip = $_SERVER['SERVER_ADDR'];
4288  } else if (!empty($_SERVER['LOCAL_ADDR'])) {
4289  // IIS 7
4290  $ip = $_SERVER['LOCAL_ADDR'];
4291  }
4292  // Try to determine the DNS name of the server
4293  if (!empty($ip)) {
4294  $dns = gethostbyaddr($ip);
4295  }
4296  $multiClassName = 'CAS_Request_CurlMultiRequest';
4297  $multiRequest = new $multiClassName();
4298 
4299  for ($i = 0; $i < sizeof($this->_rebroadcast_nodes); $i++) {
4300  if ((($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) === false))
4301  || (($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) === false))
4302  ) {
4303  phpCAS::trace(
4304  'Rebroadcast target URL: '.$this->_rebroadcast_nodes[$i]
4305  .$_SERVER['REQUEST_URI']
4306  );
4307  $className = $this->_requestImplementation;
4308  $request = new $className();
4309 
4310  $url = $this->_rebroadcast_nodes[$i].$_SERVER['REQUEST_URI'];
4311  $request->setUrl($url);
4312 
4313  if (count($this->_rebroadcast_headers)) {
4314  $request->addHeaders($this->_rebroadcast_headers);
4315  }
4316 
4317  $request->makePost();
4318  if ($type == self::LOGOUT) {
4319  // Logout request
4320  $request->setPostBody(
4321  'rebroadcast=false&logoutRequest='.$_POST['logoutRequest']
4322  );
4323  } else if ($type == self::PGTIOU) {
4324  // pgtIou/pgtId rebroadcast
4325  $request->setPostBody('rebroadcast=false');
4326  }
4327 
4328  $request->setCurlOptions($rebroadcast_curl_options);
4329 
4330  $multiRequest->addRequest($request);
4331  } else {
4332  phpCAS::trace(
4333  'Rebroadcast not sent to self: '
4334  .$this->_rebroadcast_nodes[$i].' == '.(!empty($ip)?$ip:'')
4335  .'/'.(!empty($dns)?$dns:'')
4336  );
4337  }
4338  }
4339  // We need at least 1 request
4340  if ($multiRequest->getNumRequests() > 0) {
4341  $multiRequest->send();
4342  }
4343  phpCAS::traceEnd();
4344  }
4345 
4347 }
getAuthenticationCallerFile()
Definition: Client.php:846
clearSessionValues()
Definition: Client.php:1193
_setProxies($proxies)
Definition: Client.php:3327
getLangObj()
Definition: Client.php:224
$_cache_times_for_auth_recheck
Definition: Client.php:1471
_rebroadcast($type)
Definition: Client.php:4274
setServerLoginURL($url)
Definition: Client.php:367
_getClientUrl()
Definition: Client.php:3966
setPGTStorageFile($path='')
Definition: Client.php:2790
$_cas_server_cn_validate
Definition: Client.php:2089
_loadPGT($pgt_iou)
Definition: Client.php:2707
const PHPCAS_SESSION_PREFIX
Definition: Client.php:1071
_xml_to_array($root, $namespace="cas")
Definition: Client.php:3610
setServerServiceValidateURL($url)
Definition: Client.php:384
const PHPCAS_PROXIED_SERVICE_IMAP
Definition: CAS.php:203
_setCallbackModeUsingPost($callback_mode_using_post)
Definition: Client.php:2517
initializeProxiedService(CAS_ProxiedService $proxiedService)
Definition: Client.php:3150
const CAS_VERSION_1_0
Definition: CAS.php:74
Definition: CAS.php:281
$cas_url
renewAuthentication()
Definition: Client.php:1423
getAttributes()
Definition: Client.php:1344
static error($msg)
Definition: CAS.php:580
printHTMLFooter()
Definition: Client.php:131
_ensureAuthenticationCalled()
Definition: Client.php:794
static traceExit()
Definition: CAS.php:697
$_authentication_caller
Definition: Client.php:774
retrievePT($target_service, &$err_code, &$err_msg)
Definition: Client.php:2877
const SAML_VERSION_1_1
Definition: CAS.php:91
setCasAttributeParserCallback($function, array $additionalArgs=array())
Definition: Client.php:666
_initPGTStorage()
Definition: Client.php:2672
setPGTStorage($storage)
Definition: Client.php:2723
_getServerPort()
Definition: Client.php:295
_getServerHostname()
Definition: Client.php:285
setSingleSignoutCallback($function, array $additionalArgs=array())
Definition: Client.php:730
const CAS_VERSION_3_0
Definition: CAS.php:82
const SAML_SOAP_ENV
Definition: CAS.php:101
if(isset( $_REQUEST[ 'logout']))
const PGTIOU
Definition: Client.php:4265
hasAttributes()
Definition: Client.php:1364
$_cas_server_ca_cert
Definition: Client.php:2076
addRebroadcastHeader($header)
Definition: Client.php:4253
$_callback_mode_using_post
Definition: Client.php:2508
wasAuthenticationCalled()
Definition: Client.php:781
__construct( $server_version, $proxy, $server_hostname, $server_port, $server_uri, $changeSessionID=true, \SessionHandlerInterface $sessionHandler=null)
Definition: Client.php:905
getAttribute($key)
Definition: Client.php:1406
const PHPCAS_SERVICE_OK
Definition: CAS.php:168
getServerProxyURL()
Definition: Client.php:521
$_serviceCookieJar
Definition: Client.php:2393
_startsWith($text, $char)
Definition: Client.php:4065
_removeParameterFromQueryString($parameterName, $queryString)
Definition: Client.php:4031
wasAuthenticationCallSuccessful()
Definition: Client.php:809
getServerProxyValidateURL()
Definition: Client.php:490
_setChangeSessionID($allowed)
Definition: Client.php:1091
static traceEnd($res='')
Definition: CAS.php:675
_endsWith($text, $char)
Definition: Client.php:4078
setLang($lang)
Definition: Client.php:203
removeSessionValue($key)
Definition: Client.php:1178
_validatePGT(&$validate_url, $text_response, $tree_response)
Definition: Client.php:2823
_getServerBaseURL()
Definition: Client.php:315
const PHPCAS_LANG_DEFAULT
Definition: CAS.php:236
static trace($str)
Definition: CAS.php:616
_isLogoutRequest()
Definition: Client.php:1884
$_signoutCallbackFunction
Definition: Client.php:709
setRequestImplementation($className)
Definition: Client.php:613
ensureIsProxy()
Definition: Client.php:747
isAuthenticated($renew=false)
Definition: Client.php:1552
hasAttribute($key)
Definition: Client.php:1378
_wasPreviouslyAuthenticated()
Definition: Client.php:1713
$_postAuthenticateCallbackFunction
Definition: Client.php:674
$_output_footer
Definition: Client.php:122
_htmlFilterOutput($str)
Definition: Client.php:77
getChangeSessionID()
Definition: Client.php:1101
isXmlResponse()
Definition: Client.php:2634
setProxyTicket($proxyTicket)
_getCallbackURL()
Definition: Client.php:2548
$_clearTicketsFromUrl
Definition: Client.php:628
if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']=='on') else
setCallbackURL($url)
Definition: Client.php:2570
_getNodeType($nodeURL)
Definition: Client.php:4210
_hasAttribute($key)
Definition: Client.php:1393
$_rebroadcast_headers
Definition: Client.php:4243
$_casAttributeParserCallbackArgs
Definition: Client.php:653
_buildQueryUrl($url, $query)
Definition: Client.php:4050
_flatten_array($arr)
Definition: Client.php:3745
logout($params)
Definition: Client.php:1845
const IP
Definition: Client.php:4200
const PHPCAS_PROXIED_SERVICE_HTTP_POST
Definition: CAS.php:199
setBaseURL($url)
Definition: Client.php:3951
static getSupportedProtocols()
Definition: CAS.php:760
markAuthenticationCall($auth)
Definition: Client.php:763
getServerServiceValidateURL()
Definition: Client.php:433
$_output_header
Definition: Client.php:92
_setUser($user)
Definition: Client.php:1277
_readURL($url, &$headers, &$body, &$err_msg)
Definition: Client.php:3007
handleLogoutRequests($check_client=true, $allowed_clients=array())
Definition: Client.php:1899
redirectToCas($gateway=false, $renew=false)
Definition: Client.php:1817
getServerLogoutURL()
Definition: Client.php:543
$_signoutCallbackArgs
Definition: Client.php:714
setSessionIdSalt($salt)
Definition: Client.php:4115
const PHPCAS_SERVICE_NOT_AVAILABLE
Definition: CAS.php:187
setServerProxyValidateURL($url)
Definition: Client.php:401
_setCallbackMode($callback_mode)
Definition: Client.php:2486
setSessionHandler(\SessionHandlerInterface $sessionHandler)
Definition: Client.php:1113
$driver_options
setPostAuthenticateCallback($function, array $additionalArgs=array())
Definition: Client.php:700
const CAS_VERSION_2_0
Definition: CAS.php:78
static getVerbose()
Definition: CAS.php:527
getProxies()
Definition: Client.php:3314
$_rebroadcast_nodes
Definition: Client.php:4194
validateSession($key)
Definition: Client.php:1205
_isCallbackModeUsingPost()
Definition: Client.php:2527
_buildSAMLPayload()
Definition: Client.php:3062
static getVersion()
Definition: CAS.php:750
_addAttributeToArray(array &$attributeArray, $name, $value)
Definition: Client.php:3851
$_allowed_proxy_chains
Definition: Client.php:3347
$_postAuthenticateCallbackArgs
Definition: Client.php:679
$_sessionHandler
Definition: Client.php:1082
const LOGOUT
Definition: Client.php:4264
validateCAS20(&$validate_url, &$text_response, &$tree_response, $renew=false)
Definition: Client.php:3385
setURL($url)
Definition: Client.php:3899
setAttributes($attributes)
Definition: Client.php:1334
printHTMLHeader($title)
Definition: Client.php:103
ensureAuthenticationCallSuccessful()
Definition: Client.php:824
setHTMLHeader($header)
Definition: Client.php:152
_sessionIdForTicket($ticket)
Definition: Client.php:4094
validateSA(&$validate_url, &$text_response, &$tree_response, $renew=false)
Definition: Client.php:2226
setNoCasServerValidation()
Definition: Client.php:2129
setHTMLFooter($footer)
Definition: Client.php:168
getServerVersion()
Definition: Client.php:275
setServerLogoutURL($url)
Definition: Client.php:559
isSessionAuthenticated()
Definition: Client.php:1700
$_change_session_id
Definition: Client.php:1077
_readExtraAttributesCas20($success_elements)
Definition: Client.php:3810
static traceBegin()
Definition: CAS.php:628
getServerLoginURL($gateway=false, $renew=false)
Definition: Client.php:339
$_no_cas_server_validation
Definition: Client.php:2096
$serviceUrl
getAuthenticationCallerLine()
Definition: Client.php:860
setNoClearTicketsFromUrl()
Definition: Client.php:640
forceAuthentication()
Definition: Client.php:1446
_isCallbackMode()
Definition: Client.php:2497
setServerSamlValidateURL($url)
Definition: Client.php:418
hasSessionValue($key)
Definition: Client.php:1151
const HOSTNAME
Definition: Client.php:4199
setCasServerCACert($cert, $validate_cn)
Definition: Client.php:2108
_setPGT($pgt)
Definition: Client.php:2441
getAuthenticationCallerMethod()
Definition: Client.php:874
if(isset($_REQUEST['logout'])) if(isset($_REQUEST['login'])) $auth
addRebroadcastNode($rebroadcastNodeUrl)
Definition: Client.php:4229
setCacheTimesForAuthRecheck($n)
Definition: Client.php:1480
const PHPCAS_PROXIED_SERVICE_HTTP_GET
Definition: CAS.php:195
setExtraCurlOption($key, $value)
Definition: Client.php:581
_authError( $failure, $cas_url, $no_response=false, $bad_response=false, $cas_response='', $err_code=-1, $err_msg='')
Definition: Client.php:4138
checkAuthentication()
Definition: Client.php:1495
_storePGT($pgt, $pgt_iou)
Definition: Client.php:2691
_setSessionAttributes($text_response)
Definition: Client.php:2319
getSessionValue($key, $default=null)
Definition: Client.php:1130
setPGTStorageDb( $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null)
Definition: Client.php:2758
getAllowedProxyChains()
Definition: Client.php:3354
_getServerURI()
Definition: Client.php:305
_parse_json_like_array_value($json_value)
Definition: Client.php:3676
$_requestImplementation
Definition: Client.php:603
serviceMail($url, $serviceUrl, $flags, &$err_code, &$err_msg, &$pt)
Definition: Client.php:3235
$_casAttributeParserCallbackFunction
Definition: Client.php:648
setTicket($st)
Definition: Client.php:2046
_renameSession($ticket)
Definition: Client.php:1221
getProxiedService($type)
Definition: Client.php:3099
getServerSamlValidateURL()
Definition: Client.php:465
$_curl_options
Definition: Client.php:571
validateCAS10(&$validate_url, &$text_response, &$tree_response, $renew=false)
Definition: Client.php:2150
serviceWeb($url, &$err_code, &$output)
Definition: Client.php:3185
setSessionValue($key, $value)
Definition: Client.php:1166