phpCAS  version 1.3.9
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  return session_set_save_handler($this->_sessionHandler, true);
1117  }
1118 
1127  protected function getSessionValue($key, $default = null)
1128  {
1129  $this->validateSession($key);
1130 
1131  if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {
1132  return $_SESSION[static::PHPCAS_SESSION_PREFIX][$key];
1133  }
1134 
1135  return $default;
1136  }
1137 
1148  protected function hasSessionValue($key)
1149  {
1150  $this->validateSession($key);
1151 
1152  return isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);
1153  }
1154 
1163  protected function setSessionValue($key, $value)
1164  {
1165  $this->validateSession($key);
1166 
1167  $_SESSION[static::PHPCAS_SESSION_PREFIX][$key] = $value;
1168  }
1169 
1175  protected function removeSessionValue($key)
1176  {
1177  $this->validateSession($key);
1178 
1179  if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {
1180  unset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);
1181  return true;
1182  }
1183 
1184  return false;
1185  }
1186 
1190  protected function clearSessionValues()
1191  {
1192  unset($_SESSION[static::PHPCAS_SESSION_PREFIX]);
1193  }
1194 
1202  protected function validateSession($key)
1203  {
1204  if (!is_string($key)) {
1205  throw new InvalidArgumentException('Session key must be a string.');
1206  }
1207 
1208  return true;
1209  }
1210 
1218  protected function _renameSession($ticket)
1219  {
1221  if ($this->getChangeSessionID()) {
1222  if (!empty($this->_user)) {
1223  $old_session = $_SESSION;
1224  phpCAS :: trace("Killing session: ". session_id());
1225  session_destroy();
1226  // set up a new session, of name based on the ticket
1227  $session_id = $this->_sessionIdForTicket($ticket);
1228  phpCAS :: trace("Starting session: ". $session_id);
1229  session_id($session_id);
1230  session_start();
1231  phpCAS :: trace("Restoring old session vars");
1232  $_SESSION = $old_session;
1233  } else {
1234  phpCAS :: trace (
1235  'Session should only be renamed after successfull authentication'
1236  );
1237  }
1238  } else {
1240  "Skipping session rename since phpCAS is not handling the session."
1241  );
1242  }
1243  phpCAS::traceEnd();
1244  }
1245 
1248  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1249  // XX XX
1250  // XX AUTHENTICATION XX
1251  // XX XX
1252  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1253 
1265  private $_user = '';
1266 
1274  private function _setUser($user)
1275  {
1276  $this->_user = $user;
1277  }
1278 
1287  public function getUser()
1288  {
1289  // Sequence validation
1291 
1292  return $this->_getUser();
1293  }
1294 
1303  private function _getUser()
1304  {
1305  // This is likely a duplicate check that could be removed....
1306  if ( empty($this->_user) ) {
1307  phpCAS::error(
1308  'this method should be used only after '.__CLASS__
1309  .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
1310  );
1311  }
1312  return $this->_user;
1313  }
1314 
1322  private $_attributes = array();
1323 
1331  public function setAttributes($attributes)
1332  {
1333  $this->_attributes = $attributes;
1334  }
1335 
1341  public function getAttributes()
1342  {
1343  // Sequence validation
1345  // This is likely a duplicate check that could be removed....
1346  if ( empty($this->_user) ) {
1347  // if no user is set, there shouldn't be any attributes also...
1348  phpCAS::error(
1349  'this method should be used only after '.__CLASS__
1350  .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
1351  );
1352  }
1353  return $this->_attributes;
1354  }
1355 
1361  public function hasAttributes()
1362  {
1363  // Sequence validation
1365 
1366  return !empty($this->_attributes);
1367  }
1375  public function hasAttribute($key)
1376  {
1377  // Sequence validation
1379 
1380  return $this->_hasAttribute($key);
1381  }
1382 
1390  private function _hasAttribute($key)
1391  {
1392  return (is_array($this->_attributes)
1393  && array_key_exists($key, $this->_attributes));
1394  }
1395 
1403  public function getAttribute($key)
1404  {
1405  // Sequence validation
1407 
1408  if ($this->_hasAttribute($key)) {
1409  return $this->_attributes[$key];
1410  }
1411  }
1412 
1420  public function renewAuthentication()
1421  {
1423  // Either way, the user is authenticated by CAS
1424  $this->removeSessionValue('auth_checked');
1425  if ( $this->isAuthenticated(true) ) {
1426  phpCAS::trace('user already authenticated');
1427  $res = true;
1428  } else {
1429  $this->redirectToCas(false, true);
1430  // never reached
1431  $res = false;
1432  }
1433  phpCAS::traceEnd();
1434  return $res;
1435  }
1436 
1443  public function forceAuthentication()
1444  {
1446 
1447  if ( $this->isAuthenticated() ) {
1448  // the user is authenticated, nothing to be done.
1449  phpCAS::trace('no need to authenticate');
1450  $res = true;
1451  } else {
1452  // the user is not authenticated, redirect to the CAS server
1453  $this->removeSessionValue('auth_checked');
1454  $this->redirectToCas(false/* no gateway */);
1455  // never reached
1456  $res = false;
1457  }
1458  phpCAS::traceEnd($res);
1459  return $res;
1460  }
1461 
1469 
1477  public function setCacheTimesForAuthRecheck($n)
1478  {
1479  if (gettype($n) != 'integer')
1480  throw new CAS_TypeMismatchException($n, '$n', 'string');
1481 
1482  $this->_cache_times_for_auth_recheck = $n;
1483  }
1484 
1492  public function checkAuthentication()
1493  {
1495  $res = false; // default
1496  if ( $this->isAuthenticated() ) {
1497  phpCAS::trace('user is authenticated');
1498  /* The 'auth_checked' variable is removed just in case it's set. */
1499  $this->removeSessionValue('auth_checked');
1500  $res = true;
1501  } else if ($this->getSessionValue('auth_checked')) {
1502  // the previous request has redirected the client to the CAS server
1503  // with gateway=true
1504  $this->removeSessionValue('auth_checked');
1505  } else {
1506  // avoid a check against CAS on every request
1507  // we need to write this back to session later
1508  $unauth_count = $this->getSessionValue('unauth_count', -2);
1509 
1510  if (($unauth_count != -2
1511  && $this->_cache_times_for_auth_recheck == -1)
1512  || ($unauth_count >= 0
1513  && $unauth_count < $this->_cache_times_for_auth_recheck)
1514  ) {
1515  if ($this->_cache_times_for_auth_recheck != -1) {
1516  $unauth_count++;
1517  phpCAS::trace(
1518  'user is not authenticated (cached for '
1519  .$unauth_count.' times of '
1520  .$this->_cache_times_for_auth_recheck.')'
1521  );
1522  } else {
1523  phpCAS::trace(
1524  'user is not authenticated (cached for until login pressed)'
1525  );
1526  }
1527  $this->setSessionValue('unauth_count', $unauth_count);
1528  } else {
1529  $this->setSessionValue('unauth_count', 0);
1530  $this->setSessionValue('auth_checked', true);
1531  phpCAS::trace('user is not authenticated (cache reset)');
1532  $this->redirectToCas(true/* gateway */);
1533  // never reached
1534  }
1535  }
1536  phpCAS::traceEnd($res);
1537  return $res;
1538  }
1539 
1549  public function isAuthenticated($renew=false)
1550  {
1552  $res = false;
1553  $validate_url = '';
1554  if ( $this->_wasPreviouslyAuthenticated() ) {
1555  if ($this->hasTicket()) {
1556  // User has a additional ticket but was already authenticated
1557  phpCAS::trace(
1558  'ticket was present and will be discarded, use renewAuthenticate()'
1559  );
1560  if ($this->_clearTicketsFromUrl) {
1561  phpCAS::trace("Prepare redirect to : ".$this->getURL());
1562  session_write_close();
1563  header('Location: '.$this->getURL());
1564  flush();
1567  } else {
1568  phpCAS::trace(
1569  'Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.'
1570  );
1571  $res = true;
1572  }
1573  } else {
1574  // the user has already (previously during the session) been
1575  // authenticated, nothing to be done.
1576  phpCAS::trace(
1577  'user was already authenticated, no need to look for tickets'
1578  );
1579  $res = true;
1580  }
1581 
1582  // Mark the auth-check as complete to allow post-authentication
1583  // callbacks to make use of phpCAS::getUser() and similar methods
1584  $this->markAuthenticationCall($res);
1585  } else {
1586  if ($this->hasTicket()) {
1587  switch ($this->getServerVersion()) {
1588  case CAS_VERSION_1_0:
1589  // if a Service Ticket was given, validate it
1590  phpCAS::trace(
1591  'CAS 1.0 ticket `'.$this->getTicket().'\' is present'
1592  );
1593  $this->validateCAS10(
1594  $validate_url, $text_response, $tree_response, $renew
1595  ); // if it fails, it halts
1596  phpCAS::trace(
1597  'CAS 1.0 ticket `'.$this->getTicket().'\' was validated'
1598  );
1599  $this->setSessionValue('user', $this->_getUser());
1600  $res = true;
1601  $logoutTicket = $this->getTicket();
1602  break;
1603  case CAS_VERSION_2_0:
1604  case CAS_VERSION_3_0:
1605  // if a Proxy Ticket was given, validate it
1606  phpCAS::trace(
1607  'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' is present'
1608  );
1609  $this->validateCAS20(
1610  $validate_url, $text_response, $tree_response, $renew
1611  ); // note: if it fails, it halts
1612  phpCAS::trace(
1613  'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' was validated'
1614  );
1615  if ( $this->isProxy() ) {
1616  $this->_validatePGT(
1617  $validate_url, $text_response, $tree_response
1618  ); // idem
1619  phpCAS::trace('PGT `'.$this->_getPGT().'\' was validated');
1620  $this->setSessionValue('pgt', $this->_getPGT());
1621  }
1622  $this->setSessionValue('user', $this->_getUser());
1623  if (!empty($this->_attributes)) {
1624  $this->setSessionValue('attributes', $this->_attributes);
1625  }
1626  $proxies = $this->getProxies();
1627  if (!empty($proxies)) {
1628  $this->setSessionValue('proxies', $this->getProxies());
1629  }
1630  $res = true;
1631  $logoutTicket = $this->getTicket();
1632  break;
1633  case SAML_VERSION_1_1:
1634  // if we have a SAML ticket, validate it.
1635  phpCAS::trace(
1636  'SAML 1.1 ticket `'.$this->getTicket().'\' is present'
1637  );
1638  $this->validateSA(
1639  $validate_url, $text_response, $tree_response, $renew
1640  ); // if it fails, it halts
1641  phpCAS::trace(
1642  'SAML 1.1 ticket `'.$this->getTicket().'\' was validated'
1643  );
1644  $this->setSessionValue('user', $this->_getUser());
1645  $this->setSessionValue('attributes', $this->_attributes);
1646  $res = true;
1647  $logoutTicket = $this->getTicket();
1648  break;
1649  default:
1650  phpCAS::trace('Protocoll error');
1651  break;
1652  }
1653  } else {
1654  // no ticket given, not authenticated
1655  phpCAS::trace('no ticket found');
1656  }
1657 
1658  // Mark the auth-check as complete to allow post-authentication
1659  // callbacks to make use of phpCAS::getUser() and similar methods
1660  $this->markAuthenticationCall($res);
1661 
1662  if ($res) {
1663  // call the post-authenticate callback if registered.
1664  if ($this->_postAuthenticateCallbackFunction) {
1665  $args = $this->_postAuthenticateCallbackArgs;
1666  array_unshift($args, $logoutTicket);
1667  call_user_func_array(
1668  $this->_postAuthenticateCallbackFunction, $args
1669  );
1670  }
1671 
1672  // if called with a ticket parameter, we need to redirect to the
1673  // app without the ticket so that CAS-ification is transparent
1674  // to the browser (for later POSTS) most of the checks and
1675  // errors should have been made now, so we're safe for redirect
1676  // without masking error messages. remove the ticket as a
1677  // security precaution to prevent a ticket in the HTTP_REFERRER
1678  if ($this->_clearTicketsFromUrl) {
1679  phpCAS::trace("Prepare redirect to : ".$this->getURL());
1680  session_write_close();
1681  header('Location: '.$this->getURL());
1682  flush();
1685  }
1686  }
1687  }
1688  phpCAS::traceEnd($res);
1689  return $res;
1690  }
1691 
1697  public function isSessionAuthenticated ()
1698  {
1699  return !!$this->getSessionValue('user');
1700  }
1701 
1710  private function _wasPreviouslyAuthenticated()
1711  {
1713 
1714  if ( $this->_isCallbackMode() ) {
1715  // Rebroadcast the pgtIou and pgtId to all nodes
1716  if ($this->_rebroadcast&&!isset($_POST['rebroadcast'])) {
1717  $this->_rebroadcast(self::PGTIOU);
1718  }
1719  $this->_callback();
1720  }
1721 
1722  $auth = false;
1723 
1724  if ( $this->isProxy() ) {
1725  // CAS proxy: username and PGT must be present
1726  if ( $this->isSessionAuthenticated()
1727  && $this->getSessionValue('pgt')
1728  ) {
1729  // authentication already done
1730  $this->_setUser($this->getSessionValue('user'));
1731  if ($this->hasSessionValue('attributes')) {
1732  $this->setAttributes($this->getSessionValue('attributes'));
1733  }
1734  $this->_setPGT($this->getSessionValue('pgt'));
1735  phpCAS::trace(
1736  'user = `'.$this->getSessionValue('user').'\', PGT = `'
1737  .$this->getSessionValue('pgt').'\''
1738  );
1739 
1740  // Include the list of proxies
1741  if ($this->hasSessionValue('proxies')) {
1742  $this->_setProxies($this->getSessionValue('proxies'));
1743  phpCAS::trace(
1744  'proxies = "'
1745  .implode('", "', $this->getSessionValue('proxies')).'"'
1746  );
1747  }
1748 
1749  $auth = true;
1750  } elseif ( $this->isSessionAuthenticated()
1751  && !$this->getSessionValue('pgt')
1752  ) {
1753  // these two variables should be empty or not empty at the same time
1754  phpCAS::trace(
1755  'username found (`'.$this->getSessionValue('user')
1756  .'\') but PGT is empty'
1757  );
1758  // unset all tickets to enforce authentication
1759  $this->clearSessionValues();
1760  $this->setTicket('');
1761  } elseif ( !$this->isSessionAuthenticated()
1762  && $this->getSessionValue('pgt')
1763  ) {
1764  // these two variables should be empty or not empty at the same time
1765  phpCAS::trace(
1766  'PGT found (`'.$this->getSessionValue('pgt')
1767  .'\') but username is empty'
1768  );
1769  // unset all tickets to enforce authentication
1770  $this->clearSessionValues();
1771  $this->setTicket('');
1772  } else {
1773  phpCAS::trace('neither user nor PGT found');
1774  }
1775  } else {
1776  // `simple' CAS client (not a proxy): username must be present
1777  if ( $this->isSessionAuthenticated() ) {
1778  // authentication already done
1779  $this->_setUser($this->getSessionValue('user'));
1780  if ($this->hasSessionValue('attributes')) {
1781  $this->setAttributes($this->getSessionValue('attributes'));
1782  }
1783  phpCAS::trace('user = `'.$this->getSessionValue('user').'\'');
1784 
1785  // Include the list of proxies
1786  if ($this->hasSessionValue('proxies')) {
1787  $this->_setProxies($this->getSessionValue('proxies'));
1788  phpCAS::trace(
1789  'proxies = "'
1790  .implode('", "', $this->getSessionValue('proxies')).'"'
1791  );
1792  }
1793 
1794  $auth = true;
1795  } else {
1796  phpCAS::trace('no user found');
1797  }
1798  }
1799 
1801  return $auth;
1802  }
1803 
1814  public function redirectToCas($gateway=false,$renew=false)
1815  {
1817  $cas_url = $this->getServerLoginURL($gateway, $renew);
1818  session_write_close();
1819  if (php_sapi_name() === 'cli') {
1820  @header('Location: '.$cas_url);
1821  } else {
1822  header('Location: '.$cas_url);
1823  }
1824  phpCAS::trace("Redirect to : ".$cas_url);
1825  $lang = $this->getLangObj();
1826  $this->printHTMLHeader($lang->getAuthenticationWanted());
1827  printf('<p>'. $lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
1828  $this->printHTMLFooter();
1831  }
1832 
1833 
1842  public function logout($params)
1843  {
1845  $cas_url = $this->getServerLogoutURL();
1846  $paramSeparator = '?';
1847  if (isset($params['url'])) {
1848  $cas_url = $cas_url . $paramSeparator . "url="
1849  . urlencode($params['url']);
1850  $paramSeparator = '&';
1851  }
1852  if (isset($params['service'])) {
1853  $cas_url = $cas_url . $paramSeparator . "service="
1854  . urlencode($params['service']);
1855  }
1856  header('Location: '.$cas_url);
1857  phpCAS::trace("Prepare redirect to : ".$cas_url);
1858 
1859  phpCAS::trace("Destroying session : ".session_id());
1860  session_unset();
1861  session_destroy();
1862  if (session_status() === PHP_SESSION_NONE) {
1863  phpCAS::trace("Session terminated");
1864  } else {
1865  phpCAS::error("Session was not terminated");
1866  phpCAS::trace("Session was not terminated");
1867  }
1868  $lang = $this->getLangObj();
1869  $this->printHTMLHeader($lang->getLogout());
1870  printf('<p>'.$lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
1871  $this->printHTMLFooter();
1874  }
1875 
1881  private function _isLogoutRequest()
1882  {
1883  return !empty($_POST['logoutRequest']);
1884  }
1885 
1896  public function handleLogoutRequests($check_client=true, $allowed_clients=array())
1897  {
1899  if (!$this->_isLogoutRequest()) {
1900  phpCAS::trace("Not a logout request");
1901  phpCAS::traceEnd();
1902  return;
1903  }
1904  if (!$this->getChangeSessionID()
1905  && is_null($this->_signoutCallbackFunction)
1906  ) {
1907  phpCAS::trace(
1908  "phpCAS can't handle logout requests if it is not allowed to change session_id."
1909  );
1910  }
1911  phpCAS::trace("Logout requested");
1912  $decoded_logout_rq = urldecode($_POST['logoutRequest']);
1913  phpCAS::trace("SAML REQUEST: ".$decoded_logout_rq);
1914  $allowed = false;
1915  if ($check_client) {
1916  if ($allowed_clients === array()) {
1917  $allowed_clients = array( $this->_getServerHostname() );
1918  }
1919  $client_ip = $_SERVER['REMOTE_ADDR'];
1920  $client = gethostbyaddr($client_ip);
1921  phpCAS::trace("Client: ".$client."/".$client_ip);
1922  foreach ($allowed_clients as $allowed_client) {
1923  if (($client == $allowed_client)
1924  || ($client_ip == $allowed_client)
1925  ) {
1926  phpCAS::trace(
1927  "Allowed client '".$allowed_client
1928  ."' matches, logout request is allowed"
1929  );
1930  $allowed = true;
1931  break;
1932  } else {
1933  phpCAS::trace(
1934  "Allowed client '".$allowed_client."' does not match"
1935  );
1936  }
1937  }
1938  } else {
1939  phpCAS::trace("No access control set");
1940  $allowed = true;
1941  }
1942  // If Logout command is permitted proceed with the logout
1943  if ($allowed) {
1944  phpCAS::trace("Logout command allowed");
1945  // Rebroadcast the logout request
1946  if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) {
1947  $this->_rebroadcast(self::LOGOUT);
1948  }
1949  // Extract the ticket from the SAML Request
1950  preg_match(
1951  "|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|",
1952  $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3
1953  );
1954  $wrappedSamlSessionIndex = preg_replace(
1955  '|<samlp:SessionIndex>|', '', $tick[0][0]
1956  );
1957  $ticket2logout = preg_replace(
1958  '|</samlp:SessionIndex>|', '', $wrappedSamlSessionIndex
1959  );
1960  phpCAS::trace("Ticket to logout: ".$ticket2logout);
1961 
1962  // call the post-authenticate callback if registered.
1963  if ($this->_signoutCallbackFunction) {
1965  array_unshift($args, $ticket2logout);
1966  call_user_func_array($this->_signoutCallbackFunction, $args);
1967  }
1968 
1969  // If phpCAS is managing the session_id, destroy session thanks to
1970  // session_id.
1971  if ($this->getChangeSessionID()) {
1972  $session_id = $this->_sessionIdForTicket($ticket2logout);
1973  phpCAS::trace("Session id: ".$session_id);
1974 
1975  // destroy a possible application session created before phpcas
1976  if (session_id() !== "") {
1977  session_unset();
1978  session_destroy();
1979  }
1980  // fix session ID
1981  session_id($session_id);
1982  $_COOKIE[session_name()]=$session_id;
1983  $_GET[session_name()]=$session_id;
1984 
1985  // Overwrite session
1986  session_start();
1987  session_unset();
1988  session_destroy();
1989  phpCAS::trace("Session ". $session_id . " destroyed");
1990  }
1991  } else {
1992  phpCAS::error("Unauthorized logout request from client '".$client."'");
1993  phpCAS::trace("Unauthorized logout request from client '".$client."'");
1994  }
1995  flush();
1998 
1999  }
2000 
2003  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2004  // XX XX
2005  // XX BASIC CLIENT FEATURES (CAS 1.0) XX
2006  // XX XX
2007  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2008 
2009  // ########################################################################
2010  // ST
2011  // ########################################################################
2024  private $_ticket = '';
2025 
2031  public function getTicket()
2032  {
2033  return $this->_ticket;
2034  }
2035 
2043  public function setTicket($st)
2044  {
2045  $this->_ticket = $st;
2046  }
2047 
2053  public function hasTicket()
2054  {
2055  return !empty($this->_ticket);
2056  }
2057 
2060  // ########################################################################
2061  // ST VALIDATION
2062  // ########################################################################
2073  private $_cas_server_ca_cert = null;
2074 
2075 
2087 
2094 
2095 
2105  public function setCasServerCACert($cert, $validate_cn)
2106  {
2107  // Argument validation
2108  if (gettype($cert) != 'string') {
2109  throw new CAS_TypeMismatchException($cert, '$cert', 'string');
2110  }
2111  if (gettype($validate_cn) != 'boolean') {
2112  throw new CAS_TypeMismatchException($validate_cn, '$validate_cn', 'boolean');
2113  }
2114  if (!file_exists($cert)) {
2115  throw new CAS_InvalidArgumentException("Certificate file does not exist " . $this->_requestImplementation);
2116  }
2117  $this->_cas_server_ca_cert = $cert;
2118  $this->_cas_server_cn_validate = $validate_cn;
2119  }
2120 
2126  public function setNoCasServerValidation()
2127  {
2128  $this->_no_cas_server_validation = true;
2129  }
2130 
2147  public function validateCAS10(&$validate_url,&$text_response,&$tree_response,$renew=false)
2148  {
2150  // build the URL to validate the ticket
2151  $validate_url = $this->getServerServiceValidateURL()
2152  .'&ticket='.urlencode($this->getTicket());
2153 
2154  if ( $renew ) {
2155  // pass the renew
2156  $validate_url .= '&renew=true';
2157  }
2158 
2159  // open and read the URL
2160  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
2161  phpCAS::trace(
2162  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
2163  );
2164  throw new CAS_AuthenticationException(
2165  $this, 'CAS 1.0 ticket not validated', $validate_url,
2166  true/*$no_response*/
2167  );
2168  }
2169 
2170  if (preg_match('/^no\n/', $text_response)) {
2171  phpCAS::trace('Ticket has not been validated');
2172  throw new CAS_AuthenticationException(
2173  $this, 'ST not validated', $validate_url, false/*$no_response*/,
2174  false/*$bad_response*/, $text_response
2175  );
2176  } else if (!preg_match('/^yes\n/', $text_response)) {
2177  phpCAS::trace('ill-formed response');
2178  throw new CAS_AuthenticationException(
2179  $this, 'Ticket not validated', $validate_url,
2180  false/*$no_response*/, true/*$bad_response*/, $text_response
2181  );
2182  }
2183  // ticket has been validated, extract the user name
2184  $arr = preg_split('/\n/', $text_response);
2185  $this->_setUser(trim($arr[1]));
2186 
2187  $this->_renameSession($this->getTicket());
2188 
2189  // at this step, ticket has been validated and $this->_user has been set,
2190  phpCAS::traceEnd(true);
2191  return true;
2192  }
2193 
2197  // ########################################################################
2198  // SAML VALIDATION
2199  // ########################################################################
2223  public function validateSA(&$validate_url,&$text_response,&$tree_response,$renew=false)
2224  {
2225  phpCAS::traceBegin();
2226  $result = false;
2227  // build the URL to validate the ticket
2228  $validate_url = $this->getServerSamlValidateURL();
2229 
2230  if ( $renew ) {
2231  // pass the renew
2232  $validate_url .= '&renew=true';
2233  }
2234 
2235  // open and read the URL
2236  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
2237  phpCAS::trace(
2238  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
2239  );
2240  throw new CAS_AuthenticationException(
2241  $this, 'SA not validated', $validate_url, true/*$no_response*/
2242  );
2243  }
2244 
2245  phpCAS::trace('server version: '.$this->getServerVersion());
2246 
2247  // analyze the result depending on the version
2248  switch ($this->getServerVersion()) {
2249  case SAML_VERSION_1_1:
2250  // create new DOMDocument Object
2251  $dom = new DOMDocument();
2252  // Fix possible whitspace problems
2253  $dom->preserveWhiteSpace = false;
2254  // read the response of the CAS server into a DOM object
2255  if (!($dom->loadXML($text_response))) {
2256  phpCAS::trace('dom->loadXML() failed');
2257  throw new CAS_AuthenticationException(
2258  $this, 'SA not validated', $validate_url,
2259  false/*$no_response*/, true/*$bad_response*/,
2260  $text_response
2261  );
2262  }
2263  // read the root node of the XML tree
2264  if (!($tree_response = $dom->documentElement)) {
2265  phpCAS::trace('documentElement() failed');
2266  throw new CAS_AuthenticationException(
2267  $this, 'SA not validated', $validate_url,
2268  false/*$no_response*/, true/*$bad_response*/,
2269  $text_response
2270  );
2271  } else if ( $tree_response->localName != 'Envelope' ) {
2272  // insure that tag name is 'Envelope'
2273  phpCAS::trace(
2274  'bad XML root node (should be `Envelope\' instead of `'
2275  .$tree_response->localName.'\''
2276  );
2277  throw new CAS_AuthenticationException(
2278  $this, 'SA not validated', $validate_url,
2279  false/*$no_response*/, true/*$bad_response*/,
2280  $text_response
2281  );
2282  } else if ($tree_response->getElementsByTagName("NameIdentifier")->length != 0) {
2283  // check for the NameIdentifier tag in the SAML response
2284  $success_elements = $tree_response->getElementsByTagName("NameIdentifier");
2285  phpCAS::trace('NameIdentifier found');
2286  $user = trim($success_elements->item(0)->nodeValue);
2287  phpCAS::trace('user = `'.$user.'`');
2288  $this->_setUser($user);
2289  $this->_setSessionAttributes($text_response);
2290  $result = true;
2291  } else {
2292  phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
2293  throw new CAS_AuthenticationException(
2294  $this, 'SA not validated', $validate_url,
2295  false/*$no_response*/, true/*$bad_response*/,
2296  $text_response
2297  );
2298  }
2299  }
2300  if ($result) {
2301  $this->_renameSession($this->getTicket());
2302  }
2303  // at this step, ST has been validated and $this->_user has been set,
2304  phpCAS::traceEnd($result);
2305  return $result;
2306  }
2307 
2316  private function _setSessionAttributes($text_response)
2317  {
2319 
2320  $result = false;
2321 
2322  $attr_array = array();
2323 
2324  // create new DOMDocument Object
2325  $dom = new DOMDocument();
2326  // Fix possible whitspace problems
2327  $dom->preserveWhiteSpace = false;
2328  if (($dom->loadXML($text_response))) {
2329  $xPath = new DOMXPath($dom);
2330  $xPath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
2331  $xPath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
2332  $nodelist = $xPath->query("//saml:Attribute");
2333 
2334  if ($nodelist) {
2335  foreach ($nodelist as $node) {
2336  $xres = $xPath->query("saml:AttributeValue", $node);
2337  $name = $node->getAttribute("AttributeName");
2338  $value_array = array();
2339  foreach ($xres as $node2) {
2340  $value_array[] = $node2->nodeValue;
2341  }
2342  $attr_array[$name] = $value_array;
2343  }
2344  // UGent addition...
2345  foreach ($attr_array as $attr_key => $attr_value) {
2346  if (count($attr_value) > 1) {
2347  $this->_attributes[$attr_key] = $attr_value;
2348  phpCAS::trace("* " . $attr_key . "=" . print_r($attr_value, true));
2349  } else {
2350  $this->_attributes[$attr_key] = $attr_value[0];
2351  phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
2352  }
2353  }
2354  $result = true;
2355  } else {
2356  phpCAS::trace("SAML Attributes are empty");
2357  $result = false;
2358  }
2359  }
2360  phpCAS::traceEnd($result);
2361  return $result;
2362  }
2363 
2366  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2367  // XX XX
2368  // XX PROXY FEATURES (CAS 2.0) XX
2369  // XX XX
2370  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2371 
2372  // ########################################################################
2373  // PROXYING
2374  // ########################################################################
2385  private $_proxy;
2386 
2391 
2397  public function isProxy()
2398  {
2399  return $this->_proxy;
2400  }
2401 
2402 
2404  // ########################################################################
2405  // PGT
2406  // ########################################################################
2419  private $_pgt = '';
2420 
2426  private function _getPGT()
2427  {
2428  return $this->_pgt;
2429  }
2430 
2438  private function _setPGT($pgt)
2439  {
2440  $this->_pgt = $pgt;
2441  }
2442 
2448  private function _hasPGT()
2449  {
2450  return !empty($this->_pgt);
2451  }
2452 
2455  // ########################################################################
2456  // CALLBACK MODE
2457  // ########################################################################
2474  private $_callback_mode = false;
2475 
2483  private function _setCallbackMode($callback_mode)
2484  {
2485  $this->_callback_mode = $callback_mode;
2486  }
2487 
2494  private function _isCallbackMode()
2495  {
2496  return $this->_callback_mode;
2497  }
2498 
2506 
2514  private function _setCallbackModeUsingPost($callback_mode_using_post)
2515  {
2516  $this->_callback_mode_using_post = $callback_mode_using_post;
2517  }
2518 
2524  private function _isCallbackModeUsingPost()
2525  {
2527  }
2528 
2536  private $_callback_url = '';
2537 
2545  private function _getCallbackURL()
2546  {
2547  // the URL is built when needed only
2548  if ( empty($this->_callback_url) ) {
2549  // remove the ticket if present in the URL
2550  $final_uri = 'https://';
2551  $final_uri .= $this->_getClientUrl();
2552  $request_uri = $_SERVER['REQUEST_URI'];
2553  $request_uri = preg_replace('/\?.*$/', '', $request_uri);
2554  $final_uri .= $request_uri;
2555  $this->_callback_url = $final_uri;
2556  }
2557  return $this->_callback_url;
2558  }
2559 
2567  public function setCallbackURL($url)
2568  {
2569  // Sequence validation
2570  $this->ensureIsProxy();
2571  // Argument Validation
2572  if (gettype($url) != 'string')
2573  throw new CAS_TypeMismatchException($url, '$url', 'string');
2574 
2575  return $this->_callback_url = $url;
2576  }
2577 
2584  private function _callback()
2585  {
2587  if ($this->_isCallbackModeUsingPost()) {
2588  $pgtId = $_POST['pgtId'];
2589  $pgtIou = $_POST['pgtIou'];
2590  } else {
2591  $pgtId = $_GET['pgtId'];
2592  $pgtIou = $_GET['pgtIou'];
2593  }
2594  if (preg_match('/^PGTIOU-[\.\-\w]+$/', $pgtIou)) {
2595  if (preg_match('/^[PT]GT-[\.\-\w]+$/', $pgtId)) {
2596  phpCAS::trace('Storing PGT `'.$pgtId.'\' (id=`'.$pgtIou.'\')');
2597  $this->_storePGT($pgtId, $pgtIou);
2598  if ($this->isXmlResponse()) {
2599  echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n";
2600  echo '<proxySuccess xmlns="http://www.yale.edu/tp/cas" />';
2601  phpCAS::traceExit("XML response sent");
2602  } else {
2603  $this->printHTMLHeader('phpCAS callback');
2604  echo '<p>Storing PGT `'.$pgtId.'\' (id=`'.$pgtIou.'\').</p>';
2605  $this->printHTMLFooter();
2606  phpCAS::traceExit("HTML response sent");
2607  }
2608  phpCAS::traceExit("Successfull Callback");
2609  } else {
2610  phpCAS::error('PGT format invalid' . $pgtId);
2611  phpCAS::traceExit('PGT format invalid' . $pgtId);
2612  }
2613  } else {
2614  phpCAS::error('PGTiou format invalid' . $pgtIou);
2615  phpCAS::traceExit('PGTiou format invalid' . $pgtIou);
2616  }
2617 
2618  // Flush the buffer to prevent from sending anything other then a 200
2619  // Success Status back to the CAS Server. The Exception would normally
2620  // report as a 500 error.
2621  flush();
2623  }
2624 
2631  private function isXmlResponse()
2632  {
2633  if (!array_key_exists('HTTP_ACCEPT', $_SERVER)) {
2634  return false;
2635  }
2636  if (strpos($_SERVER['HTTP_ACCEPT'], 'application/xml') === false && strpos($_SERVER['HTTP_ACCEPT'], 'text/xml') === false) {
2637  return false;
2638  }
2639 
2640  return true;
2641  }
2642 
2645  // ########################################################################
2646  // PGT STORAGE
2647  // ########################################################################
2661  private $_pgt_storage = null;
2662 
2669  private function _initPGTStorage()
2670  {
2671  // if no SetPGTStorageXxx() has been used, default to file
2672  if ( !is_object($this->_pgt_storage) ) {
2673  $this->setPGTStorageFile();
2674  }
2675 
2676  // initializes the storage
2677  $this->_pgt_storage->init();
2678  }
2679 
2688  private function _storePGT($pgt,$pgt_iou)
2689  {
2690  // ensure that storage is initialized
2691  $this->_initPGTStorage();
2692  // writes the PGT
2693  $this->_pgt_storage->write($pgt, $pgt_iou);
2694  }
2695 
2704  private function _loadPGT($pgt_iou)
2705  {
2706  // ensure that storage is initialized
2707  $this->_initPGTStorage();
2708  // read the PGT
2709  return $this->_pgt_storage->read($pgt_iou);
2710  }
2711 
2720  public function setPGTStorage($storage)
2721  {
2722  // Sequence validation
2723  $this->ensureIsProxy();
2724 
2725  // check that the storage has not already been set
2726  if ( is_object($this->_pgt_storage) ) {
2727  phpCAS::error('PGT storage already defined');
2728  }
2729 
2730  // check to make sure a valid storage object was specified
2731  if ( !($storage instanceof CAS_PGTStorage_AbstractStorage) )
2732  throw new CAS_TypeMismatchException($storage, '$storage', 'CAS_PGTStorage_AbstractStorage object');
2733 
2734  // store the PGTStorage object
2735  $this->_pgt_storage = $storage;
2736  }
2737 
2755  public function setPGTStorageDb(
2756  $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null
2757  ) {
2758  // Sequence validation
2759  $this->ensureIsProxy();
2760 
2761  // Argument validation
2762  if (!(is_object($dsn_or_pdo) && $dsn_or_pdo instanceof PDO) && !is_string($dsn_or_pdo))
2763  throw new CAS_TypeMismatchException($dsn_or_pdo, '$dsn_or_pdo', 'string or PDO object');
2764  if (gettype($username) != 'string')
2765  throw new CAS_TypeMismatchException($username, '$username', 'string');
2766  if (gettype($password) != 'string')
2767  throw new CAS_TypeMismatchException($password, '$password', 'string');
2768  if (gettype($table) != 'string')
2769  throw new CAS_TypeMismatchException($table, '$password', 'string');
2770 
2771  // create the storage object
2772  $this->setPGTStorage(
2773  new CAS_PGTStorage_Db(
2774  $this, $dsn_or_pdo, $username, $password, $table, $driver_options
2775  )
2776  );
2777  }
2778 
2787  public function setPGTStorageFile($path='')
2788  {
2789  // Sequence validation
2790  $this->ensureIsProxy();
2791 
2792  // Argument validation
2793  if (gettype($path) != 'string')
2794  throw new CAS_TypeMismatchException($path, '$path', 'string');
2795 
2796  // create the storage object
2797  $this->setPGTStorage(new CAS_PGTStorage_File($this, $path));
2798  }
2799 
2800 
2801  // ########################################################################
2802  // PGT VALIDATION
2803  // ########################################################################
2820  private function _validatePGT(&$validate_url,$text_response,$tree_response)
2821  {
2823  if ( $tree_response->getElementsByTagName("proxyGrantingTicket")->length == 0) {
2824  phpCAS::trace('<proxyGrantingTicket> not found');
2825  // authentication succeded, but no PGT Iou was transmitted
2826  throw new CAS_AuthenticationException(
2827  $this, 'Ticket validated but no PGT Iou transmitted',
2828  $validate_url, false/*$no_response*/, false/*$bad_response*/,
2829  $text_response
2830  );
2831  } else {
2832  // PGT Iou transmitted, extract it
2833  $pgt_iou = trim(
2834  $tree_response->getElementsByTagName("proxyGrantingTicket")->item(0)->nodeValue
2835  );
2836  if (preg_match('/^PGTIOU-[\.\-\w]+$/', $pgt_iou)) {
2837  $pgt = $this->_loadPGT($pgt_iou);
2838  if ( $pgt == false ) {
2839  phpCAS::trace('could not load PGT');
2840  throw new CAS_AuthenticationException(
2841  $this,
2842  'PGT Iou was transmitted but PGT could not be retrieved',
2843  $validate_url, false/*$no_response*/,
2844  false/*$bad_response*/, $text_response
2845  );
2846  }
2847  $this->_setPGT($pgt);
2848  } else {
2849  phpCAS::trace('PGTiou format error');
2850  throw new CAS_AuthenticationException(
2851  $this, 'PGT Iou was transmitted but has wrong format',
2852  $validate_url, false/*$no_response*/, false/*$bad_response*/,
2853  $text_response
2854  );
2855  }
2856  }
2857  phpCAS::traceEnd(true);
2858  return true;
2859  }
2860 
2861  // ########################################################################
2862  // PGT VALIDATION
2863  // ########################################################################
2864 
2874  public function retrievePT($target_service,&$err_code,&$err_msg)
2875  {
2876  // Argument validation
2877  if (gettype($target_service) != 'string')
2878  throw new CAS_TypeMismatchException($target_service, '$target_service', 'string');
2879 
2881 
2882  // by default, $err_msg is set empty and $pt to true. On error, $pt is
2883  // set to false and $err_msg to an error message. At the end, if $pt is false
2884  // and $error_msg is still empty, it is set to 'invalid response' (the most
2885  // commonly encountered error).
2886  $err_msg = '';
2887 
2888  // build the URL to retrieve the PT
2889  $cas_url = $this->getServerProxyURL().'?targetService='
2890  .urlencode($target_service).'&pgt='.$this->_getPGT();
2891 
2892  // open and read the URL
2893  if ( !$this->_readURL($cas_url, $headers, $cas_response, $err_msg) ) {
2894  phpCAS::trace(
2895  'could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')'
2896  );
2897  $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
2898  $err_msg = 'could not retrieve PT (no response from the CAS server)';
2899  phpCAS::traceEnd(false);
2900  return false;
2901  }
2902 
2903  $bad_response = false;
2904 
2905  // create new DOMDocument object
2906  $dom = new DOMDocument();
2907  // Fix possible whitspace problems
2908  $dom->preserveWhiteSpace = false;
2909  // read the response of the CAS server into a DOM object
2910  if ( !($dom->loadXML($cas_response))) {
2911  phpCAS::trace('dom->loadXML() failed');
2912  // read failed
2913  $bad_response = true;
2914  }
2915 
2916  if ( !$bad_response ) {
2917  // read the root node of the XML tree
2918  if ( !($root = $dom->documentElement) ) {
2919  phpCAS::trace('documentElement failed');
2920  // read failed
2921  $bad_response = true;
2922  }
2923  }
2924 
2925  if ( !$bad_response ) {
2926  // insure that tag name is 'serviceResponse'
2927  if ( $root->localName != 'serviceResponse' ) {
2928  phpCAS::trace('localName failed');
2929  // bad root node
2930  $bad_response = true;
2931  }
2932  }
2933 
2934  if ( !$bad_response ) {
2935  // look for a proxySuccess tag
2936  if ( $root->getElementsByTagName("proxySuccess")->length != 0) {
2937  $proxy_success_list = $root->getElementsByTagName("proxySuccess");
2938 
2939  // authentication succeded, look for a proxyTicket tag
2940  if ( $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->length != 0) {
2941  $err_code = PHPCAS_SERVICE_OK;
2942  $err_msg = '';
2943  $pt = trim(
2944  $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->item(0)->nodeValue
2945  );
2946  phpCAS::trace('original PT: '.trim($pt));
2947  phpCAS::traceEnd($pt);
2948  return $pt;
2949  } else {
2950  phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
2951  }
2952  } else if ($root->getElementsByTagName("proxyFailure")->length != 0) {
2953  // look for a proxyFailure tag
2954  $proxy_failure_list = $root->getElementsByTagName("proxyFailure");
2955 
2956  // authentication failed, extract the error
2957  $err_code = PHPCAS_SERVICE_PT_FAILURE;
2958  $err_msg = 'PT retrieving failed (code=`'
2959  .$proxy_failure_list->item(0)->getAttribute('code')
2960  .'\', message=`'
2961  .trim($proxy_failure_list->item(0)->nodeValue)
2962  .'\')';
2963  phpCAS::traceEnd(false);
2964  return false;
2965  } else {
2966  phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
2967  }
2968  }
2969 
2970  // at this step, we are sure that the response of the CAS server was
2971  // illformed
2972  $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
2973  $err_msg = 'Invalid response from the CAS server (response=`'
2974  .$cas_response.'\')';
2975 
2976  phpCAS::traceEnd(false);
2977  return false;
2978  }
2979 
2982  // ########################################################################
2983  // READ CAS SERVER ANSWERS
2984  // ########################################################################
2985 
3004  private function _readURL($url, &$headers, &$body, &$err_msg)
3005  {
3007  $className = $this->_requestImplementation;
3008  $request = new $className();
3009 
3010  if (count($this->_curl_options)) {
3011  $request->setCurlOptions($this->_curl_options);
3012  }
3013 
3014  $request->setUrl($url);
3015 
3016  if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) {
3017  phpCAS::error(
3018  'one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.'
3019  );
3020  }
3021  if ($this->_cas_server_ca_cert != '') {
3022  $request->setSslCaCert(
3023  $this->_cas_server_ca_cert, $this->_cas_server_cn_validate
3024  );
3025  }
3026 
3027  // add extra stuff if SAML
3028  if ($this->getServerVersion() == SAML_VERSION_1_1) {
3029  $request->addHeader("soapaction: http://www.oasis-open.org/committees/security");
3030  $request->addHeader("cache-control: no-cache");
3031  $request->addHeader("pragma: no-cache");
3032  $request->addHeader("accept: text/xml");
3033  $request->addHeader("connection: keep-alive");
3034  $request->addHeader("content-type: text/xml");
3035  $request->makePost();
3036  $request->setPostBody($this->_buildSAMLPayload());
3037  }
3038 
3039  if ($request->send()) {
3040  $headers = $request->getResponseHeaders();
3041  $body = $request->getResponseBody();
3042  $err_msg = '';
3043  phpCAS::traceEnd(true);
3044  return true;
3045  } else {
3046  $headers = '';
3047  $body = '';
3048  $err_msg = $request->getErrorMessage();
3049  phpCAS::traceEnd(false);
3050  return false;
3051  }
3052  }
3053 
3059  private function _buildSAMLPayload()
3060  {
3062 
3063  //get the ticket
3064  $sa = urlencode($this->getTicket());
3065 
3066  $body = SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST
3067  .SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE
3068  .SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
3069 
3070  phpCAS::traceEnd($body);
3071  return ($body);
3072  }
3073 
3076  // ########################################################################
3077  // ACCESS TO EXTERNAL SERVICES
3078  // ########################################################################
3079 
3096  public function getProxiedService ($type)
3097  {
3098  // Sequence validation
3099  $this->ensureIsProxy();
3101 
3102  // Argument validation
3103  if (gettype($type) != 'string')
3104  throw new CAS_TypeMismatchException($type, '$type', 'string');
3105 
3106  switch ($type) {
3109  $requestClass = $this->_requestImplementation;
3110  $request = new $requestClass();
3111  if (count($this->_curl_options)) {
3112  $request->setCurlOptions($this->_curl_options);
3113  }
3114  $proxiedService = new $type($request, $this->_serviceCookieJar);
3115  if ($proxiedService instanceof CAS_ProxiedService_Testable) {
3116  $proxiedService->setCasClient($this);
3117  }
3118  return $proxiedService;
3120  $proxiedService = new CAS_ProxiedService_Imap($this->_getUser());
3121  if ($proxiedService instanceof CAS_ProxiedService_Testable) {
3122  $proxiedService->setCasClient($this);
3123  }
3124  return $proxiedService;
3125  default:
3126  throw new CAS_InvalidArgumentException(
3127  "Unknown proxied-service type, $type."
3128  );
3129  }
3130  }
3131 
3147  public function initializeProxiedService (CAS_ProxiedService $proxiedService)
3148  {
3149  // Sequence validation
3150  $this->ensureIsProxy();
3152 
3153  $url = $proxiedService->getServiceUrl();
3154  if (!is_string($url)) {
3155  throw new CAS_ProxiedService_Exception(
3156  "Proxied Service ".get_class($proxiedService)
3157  ."->getServiceUrl() should have returned a string, returned a "
3158  .gettype($url)." instead."
3159  );
3160  }
3161  $pt = $this->retrievePT($url, $err_code, $err_msg);
3162  if (!$pt) {
3163  throw new CAS_ProxyTicketException($err_msg, $err_code);
3164  }
3165  $proxiedService->setProxyTicket($pt);
3166  }
3167 
3182  public function serviceWeb($url,&$err_code,&$output)
3183  {
3184  // Sequence validation
3185  $this->ensureIsProxy();
3187 
3188  // Argument validation
3189  if (gettype($url) != 'string')
3190  throw new CAS_TypeMismatchException($url, '$url', 'string');
3191 
3192  try {
3194  $service->setUrl($url);
3195  $service->send();
3196  $output = $service->getResponseBody();
3197  $err_code = PHPCAS_SERVICE_OK;
3198  return true;
3199  } catch (CAS_ProxyTicketException $e) {
3200  $err_code = $e->getCode();
3201  $output = $e->getMessage();
3202  return false;
3203  } catch (CAS_ProxiedService_Exception $e) {
3204  $lang = $this->getLangObj();
3205  $output = sprintf(
3206  $lang->getServiceUnavailable(), $url, $e->getMessage()
3207  );
3208  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
3209  return false;
3210  }
3211  }
3212 
3232  public function serviceMail($url,$serviceUrl,$flags,&$err_code,&$err_msg,&$pt)
3233  {
3234  // Sequence validation
3235  $this->ensureIsProxy();
3237 
3238  // Argument validation
3239  if (gettype($url) != 'string')
3240  throw new CAS_TypeMismatchException($url, '$url', 'string');
3241  if (gettype($serviceUrl) != 'string')
3242  throw new CAS_TypeMismatchException($serviceUrl, '$serviceUrl', 'string');
3243  if (gettype($flags) != 'integer')
3244  throw new CAS_TypeMismatchException($flags, '$flags', 'string');
3245 
3246  try {
3248  $service->setServiceUrl($serviceUrl);
3249  $service->setMailbox($url);
3250  $service->setOptions($flags);
3251 
3252  $stream = $service->open();
3253  $err_code = PHPCAS_SERVICE_OK;
3254  $pt = $service->getImapProxyTicket();
3255  return $stream;
3256  } catch (CAS_ProxyTicketException $e) {
3257  $err_msg = $e->getMessage();
3258  $err_code = $e->getCode();
3259  $pt = false;
3260  return false;
3261  } catch (CAS_ProxiedService_Exception $e) {
3262  $lang = $this->getLangObj();
3263  $err_msg = sprintf(
3264  $lang->getServiceUnavailable(),
3265  $url,
3266  $e->getMessage()
3267  );
3268  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
3269  $pt = false;
3270  return false;
3271  }
3272  }
3273 
3276  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3277  // XX XX
3278  // XX PROXIED CLIENT FEATURES (CAS 2.0) XX
3279  // XX XX
3280  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3281 
3282  // ########################################################################
3283  // PT
3284  // ########################################################################
3300  private $_proxies = array();
3301 
3311  public function getProxies()
3312  {
3313  return $this->_proxies;
3314  }
3315 
3324  private function _setProxies($proxies)
3325  {
3326  $this->_proxies = $proxies;
3327  if (!empty($proxies)) {
3328  // For proxy-authenticated requests people are not viewing the URL
3329  // directly since the client is another application making a
3330  // web-service call.
3331  // Because of this, stripping the ticket from the URL is unnecessary
3332  // and causes another web-service request to be performed. Additionally,
3333  // if session handling on either the client or the server malfunctions
3334  // then the subsequent request will not complete successfully.
3335  $this->setNoClearTicketsFromUrl();
3336  }
3337  }
3338 
3345 
3351  public function getAllowedProxyChains ()
3352  {
3353  if (empty($this->_allowed_proxy_chains)) {
3354  $this->_allowed_proxy_chains = new CAS_ProxyChain_AllowedList();
3355  }
3357  }
3358 
3360  // ########################################################################
3361  // PT VALIDATION
3362  // ########################################################################
3382  public function validateCAS20(&$validate_url,&$text_response,&$tree_response, $renew=false)
3383  {
3385  phpCAS::trace($text_response);
3386  // build the URL to validate the ticket
3387  if ($this->getAllowedProxyChains()->isProxyingAllowed()) {
3388  $validate_url = $this->getServerProxyValidateURL().'&ticket='
3389  .urlencode($this->getTicket());
3390  } else {
3391  $validate_url = $this->getServerServiceValidateURL().'&ticket='
3392  .urlencode($this->getTicket());
3393  }
3394 
3395  if ( $this->isProxy() ) {
3396  // pass the callback url for CAS proxies
3397  $validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL());
3398  }
3399 
3400  if ( $renew ) {
3401  // pass the renew
3402  $validate_url .= '&renew=true';
3403  }
3404 
3405  // open and read the URL
3406  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
3407  phpCAS::trace(
3408  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
3409  );
3410  throw new CAS_AuthenticationException(
3411  $this, 'Ticket not validated', $validate_url,
3412  true/*$no_response*/
3413  );
3414  }
3415 
3416  // create new DOMDocument object
3417  $dom = new DOMDocument();
3418  // Fix possible whitspace problems
3419  $dom->preserveWhiteSpace = false;
3420  // CAS servers should only return data in utf-8
3421  $dom->encoding = "utf-8";
3422  // read the response of the CAS server into a DOMDocument object
3423  if ( !($dom->loadXML($text_response))) {
3424  // read failed
3425  throw new CAS_AuthenticationException(
3426  $this, 'Ticket not validated', $validate_url,
3427  false/*$no_response*/, true/*$bad_response*/, $text_response
3428  );
3429  } else if ( !($tree_response = $dom->documentElement) ) {
3430  // read the root node of the XML tree
3431  // read failed
3432  throw new CAS_AuthenticationException(
3433  $this, 'Ticket not validated', $validate_url,
3434  false/*$no_response*/, true/*$bad_response*/, $text_response
3435  );
3436  } else if ($tree_response->localName != 'serviceResponse') {
3437  // insure that tag name is 'serviceResponse'
3438  // bad root node
3439  throw new CAS_AuthenticationException(
3440  $this, 'Ticket not validated', $validate_url,
3441  false/*$no_response*/, true/*$bad_response*/, $text_response
3442  );
3443  } else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
3444  // authentication failed, extract the error code and message and throw exception
3445  $auth_fail_list = $tree_response
3446  ->getElementsByTagName("authenticationFailure");
3447  throw new CAS_AuthenticationException(
3448  $this, 'Ticket not validated', $validate_url,
3449  false/*$no_response*/, false/*$bad_response*/,
3450  $text_response,
3451  $auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
3452  trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
3453  );
3454  } else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) {
3455  // authentication succeded, extract the user name
3456  $success_elements = $tree_response
3457  ->getElementsByTagName("authenticationSuccess");
3458  if ( $success_elements->item(0)->getElementsByTagName("user")->length == 0) {
3459  // no user specified => error
3460  throw new CAS_AuthenticationException(
3461  $this, 'Ticket not validated', $validate_url,
3462  false/*$no_response*/, true/*$bad_response*/, $text_response
3463  );
3464  } else {
3465  $this->_setUser(
3466  trim(
3467  $success_elements->item(0)->getElementsByTagName("user")->item(0)->nodeValue
3468  )
3469  );
3470  $this->_readExtraAttributesCas20($success_elements);
3471  // Store the proxies we are sitting behind for authorization checking
3472  $proxyList = array();
3473  if ( sizeof($arr = $success_elements->item(0)->getElementsByTagName("proxy")) > 0) {
3474  foreach ($arr as $proxyElem) {
3475  phpCAS::trace("Found Proxy: ".$proxyElem->nodeValue);
3476  $proxyList[] = trim($proxyElem->nodeValue);
3477  }
3478  $this->_setProxies($proxyList);
3479  phpCAS::trace("Storing Proxy List");
3480  }
3481  // Check if the proxies in front of us are allowed
3482  if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) {
3483  throw new CAS_AuthenticationException(
3484  $this, 'Proxy not allowed', $validate_url,
3485  false/*$no_response*/, true/*$bad_response*/,
3486  $text_response
3487  );
3488  } else {
3489  $result = true;
3490  }
3491  }
3492  } else {
3493  throw new CAS_AuthenticationException(
3494  $this, 'Ticket not validated', $validate_url,
3495  false/*$no_response*/, true/*$bad_response*/,
3496  $text_response
3497  );
3498  }
3499 
3500  $this->_renameSession($this->getTicket());
3501 
3502  // at this step, Ticket has been validated and $this->_user has been set,
3503 
3504  phpCAS::traceEnd($result);
3505  return $result;
3506  }
3507 
3607  private function _xml_to_array($root, $namespace = "cas")
3608  {
3609  $result = array();
3610  if ($root->hasAttributes()) {
3611  $attrs = $root->attributes;
3612  $pair = array();
3613  foreach ($attrs as $attr) {
3614  if ($attr->name === "name") {
3615  $pair['name'] = $attr->value;
3616  } elseif ($attr->name === "value") {
3617  $pair['value'] = $attr->value;
3618  } else {
3619  $result[$attr->name] = $attr->value;
3620  }
3621  if (array_key_exists('name', $pair) && array_key_exists('value', $pair)) {
3622  $result[$pair['name']] = $pair['value'];
3623  }
3624  }
3625  }
3626  if ($root->hasChildNodes()) {
3627  $children = $root->childNodes;
3628  if ($children->length == 1) {
3629  $child = $children->item(0);
3630  if ($child->nodeType == XML_TEXT_NODE) {
3631  $result['_value'] = $child->nodeValue;
3632  return (count($result) == 1) ? $result['_value'] : $result;
3633  }
3634  }
3635  $groups = array();
3636  foreach ($children as $child) {
3637  $child_nodeName = str_ireplace($namespace . ":", "", $child->nodeName);
3638  if (in_array($child_nodeName, array("user", "proxies", "proxyGrantingTicket"))) {
3639  continue;
3640  }
3641  if (!isset($result[$child_nodeName])) {
3642  $res = $this->_xml_to_array($child, $namespace);
3643  if (!empty($res)) {
3644  $result[$child_nodeName] = $this->_xml_to_array($child, $namespace);
3645  }
3646  } else {
3647  if (!isset($groups[$child_nodeName])) {
3648  $result[$child_nodeName] = array($result[$child_nodeName]);
3649  $groups[$child_nodeName] = 1;
3650  }
3651  $result[$child_nodeName][] = $this->_xml_to_array($child, $namespace);
3652  }
3653  }
3654  }
3655  return $result;
3656  }
3657 
3673  private function _parse_json_like_array_value($json_value)
3674  {
3675  $parts = explode(",", trim($json_value, "[]"));
3676  $out = array();
3677  $quote = '';
3678  foreach ($parts as $part) {
3679  $part = trim($part);
3680  if ($quote === '') {
3681  $value = "";
3682  if ($this->_startsWith($part, '\'')) {
3683  $quote = '\'';
3684  } elseif ($this->_startsWith($part, '"')) {
3685  $quote = '"';
3686  } else {
3687  $out[] = $part;
3688  }
3689  $part = ltrim($part, $quote);
3690  }
3691  if ($quote !== '') {
3692  $value .= $part;
3693  if ($this->_endsWith($part, $quote)) {
3694  $out[] = rtrim($value, $quote);
3695  $quote = '';
3696  } else {
3697  $value .= ", ";
3698  };
3699  }
3700  }
3701  return $out;
3702  }
3703 
3742  private function _flatten_array($arr)
3743  {
3744  if (!is_array($arr)) {
3745  if ($this->_startsWith($arr, '[') && $this->_endsWith($arr, ']')) {
3746  return $this->_parse_json_like_array_value($arr);
3747  } else {
3748  return $arr;
3749  }
3750  }
3751  $out = array();
3752  foreach ($arr as $key => $val) {
3753  if (!is_array($val)) {
3754  $out[$key] = $val;
3755  } else {
3756  switch (count($val)) {
3757  case 1 : {
3758  $key = key($val);
3759  if (array_key_exists($key, $out)) {
3760  $value = $out[$key];
3761  if (!is_array($value)) {
3762  $out[$key] = array();
3763  $out[$key][] = $value;
3764  }
3765  $out[$key][] = $this->_flatten_array($val[$key]);
3766  } else {
3767  $out[$key] = $this->_flatten_array($val[$key]);
3768  };
3769  break;
3770  };
3771  case 2 : {
3772  if (array_key_exists("name", $val) && array_key_exists("value", $val)) {
3773  $key = $val['name'];
3774  if (array_key_exists($key, $out)) {
3775  $value = $out[$key];
3776  if (!is_array($value)) {
3777  $out[$key] = array();
3778  $out[$key][] = $value;
3779  }
3780  $out[$key][] = $this->_flatten_array($val['value']);
3781  } else {
3782  $out[$key] = $this->_flatten_array($val['value']);
3783  };
3784  } else {
3785  $out[$key] = $this->_flatten_array($val);
3786  }
3787  break;
3788  };
3789  default: {
3790  $out[$key] = $this->_flatten_array($val);
3791  }
3792  }
3793  }
3794  }
3795  return $out;
3796  }
3797 
3807  private function _readExtraAttributesCas20($success_elements)
3808  {
3810 
3811  $extra_attributes = array();
3812  if ($this->_casAttributeParserCallbackFunction !== null
3813  && is_callable($this->_casAttributeParserCallbackFunction)
3814  ) {
3815  array_unshift($this->_casAttributeParserCallbackArgs, $success_elements->item(0));
3816  phpCAS :: trace("Calling attritubeParser callback");
3817  $extra_attributes = call_user_func_array(
3818  $this->_casAttributeParserCallbackFunction,
3819  $this->_casAttributeParserCallbackArgs
3820  );
3821  } else {
3822  phpCAS :: trace("Parse extra attributes: ");
3823  $attributes = $this->_xml_to_array($success_elements->item(0));
3824  phpCAS :: trace(print_r($attributes,true). "\nFLATTEN Array: ");
3825  $extra_attributes = $this->_flatten_array($attributes);
3826  phpCAS :: trace(print_r($extra_attributes, true)."\nFILTER : ");
3827  if (array_key_exists("attribute", $extra_attributes)) {
3828  $extra_attributes = $extra_attributes["attribute"];
3829  } elseif (array_key_exists("attributes", $extra_attributes)) {
3830  $extra_attributes = $extra_attributes["attributes"];
3831  };
3832  phpCAS :: trace(print_r($extra_attributes, true)."return");
3833  }
3834  $this->setAttributes($extra_attributes);
3835  phpCAS::traceEnd();
3836  return true;
3837  }
3838 
3848  private function _addAttributeToArray(array &$attributeArray, $name, $value)
3849  {
3850  // If multiple attributes exist, add as an array value
3851  if (isset($attributeArray[$name])) {
3852  // Initialize the array with the existing value
3853  if (!is_array($attributeArray[$name])) {
3854  $existingValue = $attributeArray[$name];
3855  $attributeArray[$name] = array($existingValue);
3856  }
3857 
3858  $attributeArray[$name][] = trim($value);
3859  } else {
3860  $attributeArray[$name] = trim($value);
3861  }
3862  }
3863 
3866  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3867  // XX XX
3868  // XX MISC XX
3869  // XX XX
3870  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3871 
3877  // ########################################################################
3878  // URL
3879  // ########################################################################
3886  private $_url = '';
3887 
3888 
3896  public function setURL($url)
3897  {
3898  // Argument Validation
3899  if (gettype($url) != 'string')
3900  throw new CAS_TypeMismatchException($url, '$url', 'string');
3901 
3902  $this->_url = $url;
3903  }
3904 
3911  public function getURL()
3912  {
3914  // the URL is built when needed only
3915  if ( empty($this->_url) ) {
3916  // remove the ticket if present in the URL
3917  $final_uri = ($this->_isHttps()) ? 'https' : 'http';
3918  $final_uri .= '://';
3919 
3920  $final_uri .= $this->_getClientUrl();
3921  $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);
3922  $final_uri .= $request_uri[0];
3923 
3924  if (isset($request_uri[1]) && $request_uri[1]) {
3925  $query_string= $this->_removeParameterFromQueryString('ticket', $request_uri[1]);
3926 
3927  // If the query string still has anything left,
3928  // append it to the final URI
3929  if ($query_string !== '') {
3930  $final_uri .= "?$query_string";
3931  }
3932  }
3933 
3934  phpCAS::trace("Final URI: $final_uri");
3935  $this->setURL($final_uri);
3936  }
3937  phpCAS::traceEnd($this->_url);
3938  return $this->_url;
3939  }
3940 
3948  public function setBaseURL($url)
3949  {
3950  // Argument Validation
3951  if (gettype($url) != 'string')
3952  throw new CAS_TypeMismatchException($url, '$url', 'string');
3953 
3954  return $this->_server['base_url'] = $url;
3955  }
3956 
3957 
3963  private function _getClientUrl()
3964  {
3965  if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
3966  // explode the host list separated by comma and use the first host
3967  $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
3968  // see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default
3969  return $hosts[0];
3970  } else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
3971  $server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];
3972  } else {
3973  if (empty($_SERVER['SERVER_NAME'])) {
3974  $server_url = $_SERVER['HTTP_HOST'];
3975  } else {
3976  $server_url = $_SERVER['SERVER_NAME'];
3977  }
3978  }
3979  if (!strpos($server_url, ':')) {
3980  if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
3981  $server_port = $_SERVER['SERVER_PORT'];
3982  } else {
3983  $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);
3984  $server_port = $ports[0];
3985  }
3986 
3987  if ( ($this->_isHttps() && $server_port!=443)
3988  || (!$this->_isHttps() && $server_port!=80)
3989  ) {
3990  $server_url .= ':';
3991  $server_url .= $server_port;
3992  }
3993  }
3994  return $server_url;
3995  }
3996 
4002  private function _isHttps()
4003  {
4004  if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
4005  return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
4006  } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {
4007  return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https');
4008  } elseif ( isset($_SERVER['HTTPS'])
4009  && !empty($_SERVER['HTTPS'])
4010  && strcasecmp($_SERVER['HTTPS'], 'off') !== 0
4011  ) {
4012  return true;
4013  }
4014  return false;
4015 
4016  }
4017 
4028  private function _removeParameterFromQueryString($parameterName, $queryString)
4029  {
4030  $parameterName = preg_quote($parameterName);
4031  return preg_replace(
4032  "/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/",
4033  '', $queryString
4034  );
4035  }
4036 
4047  private function _buildQueryUrl($url, $query)
4048  {
4049  $url .= (strstr($url, '?') === false) ? '?' : '&';
4050  $url .= $query;
4051  return $url;
4052  }
4053 
4062  private function _startsWith($text, $char)
4063  {
4064  return (strpos($text, $char) === 0);
4065  }
4066 
4075  private function _endsWith($text, $char)
4076  {
4077  return (strpos(strrev($text), $char) === 0);
4078  }
4079 
4091  private function _sessionIdForTicket($ticket)
4092  {
4093  // Hash the ticket to ensure that the value meets the PHP 7.1 requirement
4094  // that session-ids have a length between 22 and 256 characters.
4095  return hash('sha256', $this->_sessionIdSalt . $ticket);
4096  }
4097 
4103  private $_sessionIdSalt = '';
4104 
4112  public function setSessionIdSalt($salt) {
4113  $this->_sessionIdSalt = (string)$salt;
4114  }
4115 
4116  // ########################################################################
4117  // AUTHENTICATION ERROR HANDLING
4118  // ########################################################################
4135  private function _authError(
4136  $failure,
4137  $cas_url,
4138  $no_response=false,
4139  $bad_response=false,
4140  $cas_response='',
4141  $err_code=-1,
4142  $err_msg=''
4143  ) {
4145  $lang = $this->getLangObj();
4146  $this->printHTMLHeader($lang->getAuthenticationFailed());
4147  printf(
4148  $lang->getYouWereNotAuthenticated(), htmlentities($this->getURL()),
4149  isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''
4150  );
4151  phpCAS::trace('CAS URL: '.$cas_url);
4152  phpCAS::trace('Authentication failure: '.$failure);
4153  if ( $no_response ) {
4154  phpCAS::trace('Reason: no response from the CAS server');
4155  } else {
4156  if ( $bad_response ) {
4157  phpCAS::trace('Reason: bad response from the CAS server');
4158  } else {
4159  switch ($this->getServerVersion()) {
4160  case CAS_VERSION_1_0:
4161  phpCAS::trace('Reason: CAS error');
4162  break;
4163  case CAS_VERSION_2_0:
4164  case CAS_VERSION_3_0:
4165  if ( $err_code === -1 ) {
4166  phpCAS::trace('Reason: no CAS error');
4167  } else {
4168  phpCAS::trace(
4169  'Reason: ['.$err_code.'] CAS error: '.$err_msg
4170  );
4171  }
4172  break;
4173  }
4174  }
4175  phpCAS::trace('CAS response: '.$cas_response);
4176  }
4177  $this->printHTMLFooter();
4180  }
4181 
4182  // ########################################################################
4183  // PGTIOU/PGTID and logoutRequest rebroadcasting
4184  // ########################################################################
4185 
4190  private $_rebroadcast = false;
4191  private $_rebroadcast_nodes = array();
4192 
4196  const HOSTNAME = 0;
4197  const IP = 1;
4198 
4207  private function _getNodeType($nodeURL)
4208  {
4210  if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $nodeURL)) {
4211  phpCAS::traceEnd(self::IP);
4212  return self::IP;
4213  } else {
4214  phpCAS::traceEnd(self::HOSTNAME);
4215  return self::HOSTNAME;
4216  }
4217  }
4218 
4226  public function addRebroadcastNode($rebroadcastNodeUrl)
4227  {
4228  // Argument validation
4229  if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl))
4230  throw new CAS_TypeMismatchException($rebroadcastNodeUrl, '$rebroadcastNodeUrl', 'url');
4231 
4232  // Store the rebroadcast node and set flag
4233  $this->_rebroadcast = true;
4234  $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl;
4235  }
4236 
4240  private $_rebroadcast_headers = array();
4241 
4250  public function addRebroadcastHeader($header)
4251  {
4252  if (gettype($header) != 'string')
4253  throw new CAS_TypeMismatchException($header, '$header', 'string');
4254 
4255  $this->_rebroadcast_headers[] = $header;
4256  }
4257 
4261  const LOGOUT = 0;
4262  const PGTIOU = 1;
4263 
4271  private function _rebroadcast($type)
4272  {
4274 
4275  $rebroadcast_curl_options = array(
4276  CURLOPT_FAILONERROR => 1,
4277  CURLOPT_FOLLOWLOCATION => 1,
4278  CURLOPT_RETURNTRANSFER => 1,
4279  CURLOPT_CONNECTTIMEOUT => 1,
4280  CURLOPT_TIMEOUT => 4);
4281 
4282  // Try to determine the IP address of the server
4283  if (!empty($_SERVER['SERVER_ADDR'])) {
4284  $ip = $_SERVER['SERVER_ADDR'];
4285  } else if (!empty($_SERVER['LOCAL_ADDR'])) {
4286  // IIS 7
4287  $ip = $_SERVER['LOCAL_ADDR'];
4288  }
4289  // Try to determine the DNS name of the server
4290  if (!empty($ip)) {
4291  $dns = gethostbyaddr($ip);
4292  }
4293  $multiClassName = 'CAS_Request_CurlMultiRequest';
4294  $multiRequest = new $multiClassName();
4295 
4296  for ($i = 0; $i < sizeof($this->_rebroadcast_nodes); $i++) {
4297  if ((($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) === false))
4298  || (($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) === false))
4299  ) {
4300  phpCAS::trace(
4301  'Rebroadcast target URL: '.$this->_rebroadcast_nodes[$i]
4302  .$_SERVER['REQUEST_URI']
4303  );
4304  $className = $this->_requestImplementation;
4305  $request = new $className();
4306 
4307  $url = $this->_rebroadcast_nodes[$i].$_SERVER['REQUEST_URI'];
4308  $request->setUrl($url);
4309 
4310  if (count($this->_rebroadcast_headers)) {
4311  $request->addHeaders($this->_rebroadcast_headers);
4312  }
4313 
4314  $request->makePost();
4315  if ($type == self::LOGOUT) {
4316  // Logout request
4317  $request->setPostBody(
4318  'rebroadcast=false&logoutRequest='.$_POST['logoutRequest']
4319  );
4320  } else if ($type == self::PGTIOU) {
4321  // pgtIou/pgtId rebroadcast
4322  $request->setPostBody('rebroadcast=false');
4323  }
4324 
4325  $request->setCurlOptions($rebroadcast_curl_options);
4326 
4327  $multiRequest->addRequest($request);
4328  } else {
4329  phpCAS::trace(
4330  'Rebroadcast not sent to self: '
4331  .$this->_rebroadcast_nodes[$i].' == '.(!empty($ip)?$ip:'')
4332  .'/'.(!empty($dns)?$dns:'')
4333  );
4334  }
4335  }
4336  // We need at least 1 request
4337  if ($multiRequest->getNumRequests() > 0) {
4338  $multiRequest->send();
4339  }
4340  phpCAS::traceEnd();
4341  }
4342 
4344 }
getAuthenticationCallerFile()
Definition: Client.php:846
clearSessionValues()
Definition: Client.php:1190
_setProxies($proxies)
Definition: Client.php:3324
getLangObj()
Definition: Client.php:224
$_cache_times_for_auth_recheck
Definition: Client.php:1468
_rebroadcast($type)
Definition: Client.php:4271
setServerLoginURL($url)
Definition: Client.php:367
_getClientUrl()
Definition: Client.php:3963
setPGTStorageFile($path='')
Definition: Client.php:2787
$_cas_server_cn_validate
Definition: Client.php:2086
_loadPGT($pgt_iou)
Definition: Client.php:2704
const PHPCAS_SESSION_PREFIX
Definition: Client.php:1071
_xml_to_array($root, $namespace="cas")
Definition: Client.php:3607
setServerServiceValidateURL($url)
Definition: Client.php:384
const PHPCAS_PROXIED_SERVICE_IMAP
Definition: CAS.php:203
_setCallbackModeUsingPost($callback_mode_using_post)
Definition: Client.php:2514
initializeProxiedService(CAS_ProxiedService $proxiedService)
Definition: Client.php:3147
const CAS_VERSION_1_0
Definition: CAS.php:74
Definition: CAS.php:281
$cas_url
renewAuthentication()
Definition: Client.php:1420
getAttributes()
Definition: Client.php:1341
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:2874
const SAML_VERSION_1_1
Definition: CAS.php:91
setCasAttributeParserCallback($function, array $additionalArgs=array())
Definition: Client.php:666
_initPGTStorage()
Definition: Client.php:2669
setPGTStorage($storage)
Definition: Client.php:2720
_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:4262
hasAttributes()
Definition: Client.php:1361
$_cas_server_ca_cert
Definition: Client.php:2073
addRebroadcastHeader($header)
Definition: Client.php:4250
$_callback_mode_using_post
Definition: Client.php:2505
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:1403
const PHPCAS_SERVICE_OK
Definition: CAS.php:168
getServerProxyURL()
Definition: Client.php:521
$_serviceCookieJar
Definition: Client.php:2390
_startsWith($text, $char)
Definition: Client.php:4062
_removeParameterFromQueryString($parameterName, $queryString)
Definition: Client.php:4028
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:4075
setLang($lang)
Definition: Client.php:203
removeSessionValue($key)
Definition: Client.php:1175
_validatePGT(&$validate_url, $text_response, $tree_response)
Definition: Client.php:2820
_getServerBaseURL()
Definition: Client.php:315
const PHPCAS_LANG_DEFAULT
Definition: CAS.php:236
static trace($str)
Definition: CAS.php:616
_isLogoutRequest()
Definition: Client.php:1881
$_signoutCallbackFunction
Definition: Client.php:709
setRequestImplementation($className)
Definition: Client.php:613
ensureIsProxy()
Definition: Client.php:747
isAuthenticated($renew=false)
Definition: Client.php:1549
hasAttribute($key)
Definition: Client.php:1375
_wasPreviouslyAuthenticated()
Definition: Client.php:1710
$_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:2631
setProxyTicket($proxyTicket)
_getCallbackURL()
Definition: Client.php:2545
$_clearTicketsFromUrl
Definition: Client.php:628
if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']=='on') else
setCallbackURL($url)
Definition: Client.php:2567
_getNodeType($nodeURL)
Definition: Client.php:4207
_hasAttribute($key)
Definition: Client.php:1390
$_rebroadcast_headers
Definition: Client.php:4240
$_casAttributeParserCallbackArgs
Definition: Client.php:653
_buildQueryUrl($url, $query)
Definition: Client.php:4047
_flatten_array($arr)
Definition: Client.php:3742
logout($params)
Definition: Client.php:1842
const IP
Definition: Client.php:4197
const PHPCAS_PROXIED_SERVICE_HTTP_POST
Definition: CAS.php:199
setBaseURL($url)
Definition: Client.php:3948
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:1274
_readURL($url, &$headers, &$body, &$err_msg)
Definition: Client.php:3004
handleLogoutRequests($check_client=true, $allowed_clients=array())
Definition: Client.php:1896
redirectToCas($gateway=false, $renew=false)
Definition: Client.php:1814
getServerLogoutURL()
Definition: Client.php:543
$_signoutCallbackArgs
Definition: Client.php:714
setSessionIdSalt($salt)
Definition: Client.php:4112
const PHPCAS_SERVICE_NOT_AVAILABLE
Definition: CAS.php:187
setServerProxyValidateURL($url)
Definition: Client.php:401
_setCallbackMode($callback_mode)
Definition: Client.php:2483
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:3311
$_rebroadcast_nodes
Definition: Client.php:4191
validateSession($key)
Definition: Client.php:1202
_isCallbackModeUsingPost()
Definition: Client.php:2524
_buildSAMLPayload()
Definition: Client.php:3059
static getVersion()
Definition: CAS.php:750
_addAttributeToArray(array &$attributeArray, $name, $value)
Definition: Client.php:3848
$_allowed_proxy_chains
Definition: Client.php:3344
$_postAuthenticateCallbackArgs
Definition: Client.php:679
$_sessionHandler
Definition: Client.php:1082
const LOGOUT
Definition: Client.php:4261
validateCAS20(&$validate_url, &$text_response, &$tree_response, $renew=false)
Definition: Client.php:3382
setURL($url)
Definition: Client.php:3896
setAttributes($attributes)
Definition: Client.php:1331
printHTMLHeader($title)
Definition: Client.php:103
ensureAuthenticationCallSuccessful()
Definition: Client.php:824
setHTMLHeader($header)
Definition: Client.php:152
_sessionIdForTicket($ticket)
Definition: Client.php:4091
validateSA(&$validate_url, &$text_response, &$tree_response, $renew=false)
Definition: Client.php:2223
setNoCasServerValidation()
Definition: Client.php:2126
setHTMLFooter($footer)
Definition: Client.php:168
getServerVersion()
Definition: Client.php:275
setServerLogoutURL($url)
Definition: Client.php:559
isSessionAuthenticated()
Definition: Client.php:1697
$_change_session_id
Definition: Client.php:1077
_readExtraAttributesCas20($success_elements)
Definition: Client.php:3807
static traceBegin()
Definition: CAS.php:628
getServerLoginURL($gateway=false, $renew=false)
Definition: Client.php:339
$_no_cas_server_validation
Definition: Client.php:2093
$serviceUrl
getAuthenticationCallerLine()
Definition: Client.php:860
setNoClearTicketsFromUrl()
Definition: Client.php:640
forceAuthentication()
Definition: Client.php:1443
_isCallbackMode()
Definition: Client.php:2494
setServerSamlValidateURL($url)
Definition: Client.php:418
hasSessionValue($key)
Definition: Client.php:1148
const HOSTNAME
Definition: Client.php:4196
setCasServerCACert($cert, $validate_cn)
Definition: Client.php:2105
_setPGT($pgt)
Definition: Client.php:2438
getAuthenticationCallerMethod()
Definition: Client.php:874
if(isset($_REQUEST['logout'])) if(isset($_REQUEST['login'])) $auth
addRebroadcastNode($rebroadcastNodeUrl)
Definition: Client.php:4226
setCacheTimesForAuthRecheck($n)
Definition: Client.php:1477
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:4135
checkAuthentication()
Definition: Client.php:1492
_storePGT($pgt, $pgt_iou)
Definition: Client.php:2688
_setSessionAttributes($text_response)
Definition: Client.php:2316
getSessionValue($key, $default=null)
Definition: Client.php:1127
setPGTStorageDb( $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null)
Definition: Client.php:2755
getAllowedProxyChains()
Definition: Client.php:3351
_getServerURI()
Definition: Client.php:305
_parse_json_like_array_value($json_value)
Definition: Client.php:3673
$_requestImplementation
Definition: Client.php:603
serviceMail($url, $serviceUrl, $flags, &$err_code, &$err_msg, &$pt)
Definition: Client.php:3232
$_casAttributeParserCallbackFunction
Definition: Client.php:648
setTicket($st)
Definition: Client.php:2043
_renameSession($ticket)
Definition: Client.php:1218
getProxiedService($type)
Definition: Client.php:3096
getServerSamlValidateURL()
Definition: Client.php:465
$_curl_options
Definition: Client.php:571
validateCAS10(&$validate_url, &$text_response, &$tree_response, $renew=false)
Definition: Client.php:2147
serviceWeb($url, &$err_code, &$output)
Definition: Client.php:3182
setSessionValue($key, $value)
Definition: Client.php:1163