ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
Client.php
Go to the documentation of this file.
1 <?php
2 
52 {
53 
54  // ########################################################################
55  // HTML OUTPUT
56  // ########################################################################
75  private function _htmlFilterOutput($str)
76  {
77  $str = str_replace('__CAS_VERSION__', $this->getServerVersion(), $str);
78  $str = str_replace('__PHPCAS_VERSION__', phpCAS::getVersion(), $str);
79  $str = str_replace('__SERVER_BASE_URL__', $this->_getServerBaseURL(), $str);
80  echo $str;
81  }
82 
90  private $_output_header = '';
91 
101  public function printHTMLHeader($title)
102  {
103  $this->_htmlFilterOutput(
104  str_replace(
105  '__TITLE__', $title,
106  (empty($this->_output_header)
107  ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
108  : $this->_output_header)
109  )
110  );
111  }
112 
120  private $_output_footer = '';
121 
129  public function printHTMLFooter()
130  {
131  $lang = $this->getLangObj();
132  $this->_htmlFilterOutput(
133  empty($this->_output_footer)?
134  (phpcas::getVerbose())?
135  '<hr><address>phpCAS __PHPCAS_VERSION__ '
136  .$lang->getUsingServer()
137  .' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>'
138  :'</body></html>'
140  );
141  }
142 
150  public function setHTMLHeader($header)
151  {
152  // Argument Validation
153  if (gettype($header) != 'string')
154  throw new CAS_TypeMismatchException($header, '$header', 'string');
155 
156  $this->_output_header = $header;
157  }
158 
166  public function setHTMLFooter($footer)
167  {
168  // Argument Validation
169  if (gettype($footer) != 'string')
170  throw new CAS_TypeMismatchException($footer, '$footer', 'string');
171 
172  $this->_output_footer = $footer;
173  }
174 
175 
179  // ########################################################################
180  // INTERNATIONALIZATION
181  // ########################################################################
193 
201  public function setLang($lang)
202  {
203  // Argument Validation
204  if (gettype($lang) != 'string')
205  throw new CAS_TypeMismatchException($lang, '$lang', 'string');
206 
208  $obj = new $lang();
209  if (!($obj instanceof CAS_Languages_LanguageInterface)) {
211  '$className must implement the CAS_Languages_LanguageInterface'
212  );
213  }
214  $this->_lang = $lang;
216  }
222  public function getLangObj()
223  {
224  $classname = $this->_lang;
225  return new $classname();
226  }
227 
229  // ########################################################################
230  // CAS SERVER CONFIG
231  // ########################################################################
262  private $_server = array(
263  'version' => -1,
264  'hostname' => 'none',
265  'port' => -1,
266  'uri' => 'none');
267 
273  public function getServerVersion()
274  {
275  return $this->_server['version'];
276  }
277 
283  private function _getServerHostname()
284  {
285  return $this->_server['hostname'];
286  }
287 
293  private function _getServerPort()
294  {
295  return $this->_server['port'];
296  }
297 
303  private function _getServerURI()
304  {
305  return $this->_server['uri'];
306  }
307 
313  private function _getServerBaseURL()
314  {
315  // the URL is build only when needed
316  if ( empty($this->_server['base_url']) ) {
317  $this->_server['base_url'] = 'https://' . $this->_getServerHostname();
318  if ($this->_getServerPort()!=443) {
319  $this->_server['base_url'] .= ':'
320  .$this->_getServerPort();
321  }
322  $this->_server['base_url'] .= $this->_getServerURI();
323  }
324  return $this->_server['base_url'];
325  }
326 
337  public function getServerLoginURL($gateway=false,$renew=false)
338  {
340  // the URL is build only when needed
341  if ( empty($this->_server['login_url']) ) {
342  $this->_server['login_url'] = $this->_buildQueryUrl($this->_getServerBaseURL().'login','service='.urlencode($this->getURL()));
343  }
344  $url = $this->_server['login_url'];
345  if ($renew) {
346  // It is recommended that when the "renew" parameter is set, its
347  // value be "true"
348  $url = $this->_buildQueryUrl($url, 'renew=true');
349  } elseif ($gateway) {
350  // It is recommended that when the "gateway" parameter is set, its
351  // value be "true"
352  $url = $this->_buildQueryUrl($url, 'gateway=true');
353  }
355  return $url;
356  }
357 
365  public function setServerLoginURL($url)
366  {
367  // Argument Validation
368  if (gettype($url) != 'string')
369  throw new CAS_TypeMismatchException($url, '$url', 'string');
370 
371  return $this->_server['login_url'] = $url;
372  }
373 
374 
383  {
384  // Argument Validation
385  if (gettype($url) != 'string')
386  throw new CAS_TypeMismatchException($url, '$url', 'string');
387 
388  return $this->_server['service_validate_url'] = $url;
389  }
390 
391 
400  {
401  // Argument Validation
402  if (gettype($url) != 'string')
403  throw new CAS_TypeMismatchException($url, '$url', 'string');
404 
405  return $this->_server['proxy_validate_url'] = $url;
406  }
407 
408 
417  {
418  // Argument Validation
419  if (gettype($url) != 'string')
420  throw new CAS_TypeMismatchException($url, '$url', 'string');
421 
422  return $this->_server['saml_validate_url'] = $url;
423  }
424 
425 
431  public function getServerServiceValidateURL()
432  {
434  // the URL is build only when needed
435  if ( empty($this->_server['service_validate_url']) ) {
436  switch ($this->getServerVersion()) {
437  case CAS_VERSION_1_0:
438  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
439  .'validate';
440  break;
441  case CAS_VERSION_2_0:
442  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
443  .'serviceValidate';
444  break;
445  case CAS_VERSION_3_0:
446  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
447  .'p3/serviceValidate';
448  break;
449  }
450  }
451  $url = $this->_buildQueryUrl(
452  $this->_server['service_validate_url'],
453  'service='.urlencode($this->getURL())
454  );
456  return $url;
457  }
463  public function getServerSamlValidateURL()
464  {
466  // the URL is build only when needed
467  if ( empty($this->_server['saml_validate_url']) ) {
468  switch ($this->getServerVersion()) {
469  case SAML_VERSION_1_1:
470  $this->_server['saml_validate_url'] = $this->_getServerBaseURL().'samlValidate';
471  break;
472  }
473  }
474 
475  $url = $this->_buildQueryUrl(
476  $this->_server['saml_validate_url'],
477  'TARGET='.urlencode($this->getURL())
478  );
480  return $url;
481  }
482 
488  public function getServerProxyValidateURL()
489  {
491  // the URL is build only when needed
492  if ( empty($this->_server['proxy_validate_url']) ) {
493  switch ($this->getServerVersion()) {
494  case CAS_VERSION_1_0:
495  $this->_server['proxy_validate_url'] = '';
496  break;
497  case CAS_VERSION_2_0:
498  $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'proxyValidate';
499  break;
500  case CAS_VERSION_3_0:
501  $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'p3/proxyValidate';
502  break;
503  }
504  }
505  $url = $this->_buildQueryUrl(
506  $this->_server['proxy_validate_url'],
507  'service='.urlencode($this->getURL())
508  );
510  return $url;
511  }
512 
513 
519  public function getServerProxyURL()
520  {
521  // the URL is build only when needed
522  if ( empty($this->_server['proxy_url']) ) {
523  switch ($this->getServerVersion()) {
524  case CAS_VERSION_1_0:
525  $this->_server['proxy_url'] = '';
526  break;
527  case CAS_VERSION_2_0:
528  case CAS_VERSION_3_0:
529  $this->_server['proxy_url'] = $this->_getServerBaseURL().'proxy';
530  break;
531  }
532  }
533  return $this->_server['proxy_url'];
534  }
535 
541  public function getServerLogoutURL()
542  {
543  // the URL is build only when needed
544  if ( empty($this->_server['logout_url']) ) {
545  $this->_server['logout_url'] = $this->_getServerBaseURL().'logout';
546  }
547  return $this->_server['logout_url'];
548  }
549 
557  public function setServerLogoutURL($url)
558  {
559  // Argument Validation
560  if (gettype($url) != 'string')
561  throw new CAS_TypeMismatchException($url, '$url', 'string');
562 
563  return $this->_server['logout_url'] = $url;
564  }
565 
569  private $_curl_options = array();
570 
579  public function setExtraCurlOption($key, $value)
580  {
581  $this->_curl_options[$key] = $value;
582  }
583 
586  // ########################################################################
587  // Change the internal behaviour of phpcas
588  // ########################################################################
589 
601  private $_requestImplementation = 'CAS_Request_CurlRequest';
602 
611  public function setRequestImplementation ($className)
612  {
613  $obj = new $className;
614  if (!($obj instanceof CAS_Request_RequestInterface)) {
616  '$className must implement the CAS_Request_RequestInterface'
617  );
618  }
619  $this->_requestImplementation = $className;
620  }
621 
626  private $_clearTicketsFromUrl = true;
627 
638  public function setNoClearTicketsFromUrl ()
639  {
640  $this->_clearTicketsFromUrl = false;
641  }
642 
647 
652 
664  public function setCasAttributeParserCallback($function, array $additionalArgs = array())
665  {
666  $this->_casAttributeParserCallbackFunction = $function;
667  $this->_casAttributeParserCallbackArgs = $additionalArgs;
668  }
669 
673 
678 
698  public function setPostAuthenticateCallback ($function, array $additionalArgs = array())
699  {
700  $this->_postAuthenticateCallbackFunction = $function;
701  $this->_postAuthenticateCallbackArgs = $additionalArgs;
702  }
703 
708 
713 
728  public function setSingleSignoutCallback ($function, array $additionalArgs = array())
729  {
730  $this->_signoutCallbackFunction = $function;
731  $this->_signoutCallbackArgs = $additionalArgs;
732  }
733 
734  // ########################################################################
735  // Methods for supplying code-flow feedback to integrators.
736  // ########################################################################
737 
745  public function ensureIsProxy()
746  {
747  if (!$this->isProxy()) {
749  }
750  }
751 
761  public function markAuthenticationCall ($auth)
762  {
763  // store where the authentication has been checked and the result
764  $dbg = debug_backtrace();
765  $this->_authentication_caller = array (
766  'file' => $dbg[1]['file'],
767  'line' => $dbg[1]['line'],
768  'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'],
769  'result' => (boolean)$auth
770  );
771  }
773 
779  public function wasAuthenticationCalled ()
780  {
781  return !empty($this->_authentication_caller);
782  }
783 
792  private function _ensureAuthenticationCalled()
793  {
794  if (!$this->wasAuthenticationCalled()) {
796  }
797  }
798 
808  {
810  return $this->_authentication_caller['result'];
811  }
812 
813 
823  {
825  if (!$this->_authentication_caller['result']) {
826  throw new CAS_OutOfSequenceException(
827  'authentication was checked (by '
829  . '() at ' . $this->getAuthenticationCallerFile()
830  . ':' . $this->getAuthenticationCallerLine()
831  . ') but the method returned false'
832  );
833  }
834  }
835 
844  public function getAuthenticationCallerFile ()
845  {
847  return $this->_authentication_caller['file'];
848  }
849 
858  public function getAuthenticationCallerLine ()
859  {
861  return $this->_authentication_caller['line'];
862  }
863 
872  public function getAuthenticationCallerMethod ()
873  {
875  return $this->_authentication_caller['method'];
876  }
877 
880  // ########################################################################
881  // CONSTRUCTOR
882  // ########################################################################
902  public function __construct(
903  $server_version,
904  $proxy,
905  $server_hostname,
906  $server_port,
907  $server_uri,
908  $changeSessionID = true
909  ) {
910  // Argument validation
911  if (gettype($server_version) != 'string')
912  throw new CAS_TypeMismatchException($server_version, '$server_version', 'string');
913  if (gettype($proxy) != 'boolean')
914  throw new CAS_TypeMismatchException($proxy, '$proxy', 'boolean');
915  if (gettype($server_hostname) != 'string')
916  throw new CAS_TypeMismatchException($server_hostname, '$server_hostname', 'string');
917  if (gettype($server_port) != 'integer')
918  throw new CAS_TypeMismatchException($server_port, '$server_port', 'integer');
919  if (gettype($server_uri) != 'string')
920  throw new CAS_TypeMismatchException($server_uri, '$server_uri', 'string');
921  if (gettype($changeSessionID) != 'boolean')
922  throw new CAS_TypeMismatchException($changeSessionID, '$changeSessionID', 'boolean');
923 
925  // true : allow to change the session_id(), false session_id won't be
926  // change and logout won't be handle because of that
927  $this->_setChangeSessionID($changeSessionID);
928 
929  // skip Session Handling for logout requests and if don't want it'
930  if (session_id()=="" && !$this->_isLogoutRequest()) {
931  session_start();
932  phpCAS :: trace("Starting a new session " . session_id());
933  }
934  // Only for debug purposes
935  if ($this->isSessionAuthenticated()){
936  phpCAS :: trace("Session is authenticated as: " . $_SESSION['phpCAS']['user']);
937  } else {
938  phpCAS :: trace("Session is not authenticated");
939  }
940  // are we in proxy mode ?
941  $this->_proxy = $proxy;
942 
943  // Make cookie handling available.
944  if ($this->isProxy()) {
945  if (!isset($_SESSION['phpCAS'])) {
946  $_SESSION['phpCAS'] = array();
947  }
948  if (!isset($_SESSION['phpCAS']['service_cookies'])) {
949  $_SESSION['phpCAS']['service_cookies'] = array();
950  }
951  $this->_serviceCookieJar = new CAS_CookieJar(
952  $_SESSION['phpCAS']['service_cookies']
953  );
954  }
955 
956  //check version
957  switch ($server_version) {
958  case CAS_VERSION_1_0:
959  if ( $this->isProxy() ) {
961  'CAS proxies are not supported in CAS '.$server_version
962  );
963  }
964  break;
965  case CAS_VERSION_2_0:
966  case CAS_VERSION_3_0:
967  break;
968  case SAML_VERSION_1_1:
969  break;
970  default:
972  'this version of CAS (`'.$server_version
973  .'\') is not supported by phpCAS '.phpCAS::getVersion()
974  );
975  }
976  $this->_server['version'] = $server_version;
977 
978  // check hostname
979  if ( empty($server_hostname)
980  || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/', $server_hostname)
981  ) {
982  phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
983  }
984  $this->_server['hostname'] = $server_hostname;
985 
986  // check port
987  if ( $server_port == 0
988  || !is_int($server_port)
989  ) {
990  phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
991  }
992  $this->_server['port'] = $server_port;
993 
994  // check URI
995  if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/', $server_uri) ) {
996  phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
997  }
998  // add leading and trailing `/' and remove doubles
999  if(strstr($server_uri, '?') === false) $server_uri .= '/';
1000  $server_uri = preg_replace('/\/\//', '/', '/'.$server_uri);
1001  $this->_server['uri'] = $server_uri;
1002 
1003  // set to callback mode if PgtIou and PgtId CGI GET parameters are provided
1004  if ( $this->isProxy() ) {
1005  $this->_setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
1006  }
1007 
1008  if ( $this->_isCallbackMode() ) {
1009  //callback mode: check that phpCAS is secured
1010  if ( !$this->_isHttps() ) {
1011  phpCAS::error(
1012  'CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server'
1013  );
1014  }
1015  } else {
1016  //normal mode: get ticket and remove it from CGI parameters for
1017  // developers
1018  $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
1019  if (preg_match('/^[SP]T-/', $ticket) ) {
1020  phpCAS::trace('Ticket \''.$ticket.'\' found');
1021  $this->setTicket($ticket);
1022  unset($_GET['ticket']);
1023  } else if ( !empty($ticket) ) {
1024  //ill-formed ticket, halt
1025  phpCAS::error(
1026  'ill-formed ticket found in the URL (ticket=`'
1027  .htmlentities($ticket).'\')'
1028  );
1029  }
1030 
1031  }
1032  phpCAS::traceEnd();
1033  }
1034 
1037  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1038  // XX XX
1039  // XX Session Handling XX
1040  // XX XX
1041  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1042 
1053  private $_change_session_id = true;
1054 
1062  private function _setChangeSessionID($allowed)
1063  {
1064  $this->_change_session_id = $allowed;
1065  }
1066 
1072  public function getChangeSessionID()
1073  {
1075  }
1076 
1079  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1080  // XX XX
1081  // XX AUTHENTICATION XX
1082  // XX XX
1083  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1084 
1096  private $_user = '';
1097 
1105  private function _setUser($user)
1106  {
1107  $this->_user = $user;
1108  }
1109 
1118  public function getUser()
1119  {
1120  // Sequence validation
1122 
1123  return $this->_getUser();
1124  }
1125 
1134  private function _getUser()
1135  {
1136  // This is likely a duplicate check that could be removed....
1137  if ( empty($this->_user) ) {
1138  phpCAS::error(
1139  'this method should be used only after '.__CLASS__
1140  .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
1141  );
1142  }
1143  return $this->_user;
1144  }
1145 
1153  private $_attributes = array();
1154 
1162  public function setAttributes($attributes)
1163  {
1164  $this->_attributes = $attributes;
1165  }
1166 
1172  public function getAttributes()
1173  {
1174  // Sequence validation
1176  // This is likely a duplicate check that could be removed....
1177  if ( empty($this->_user) ) {
1178  // if no user is set, there shouldn't be any attributes also...
1179  phpCAS::error(
1180  'this method should be used only after '.__CLASS__
1181  .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
1182  );
1183  }
1184  return $this->_attributes;
1185  }
1186 
1192  public function hasAttributes()
1193  {
1194  // Sequence validation
1196 
1197  return !empty($this->_attributes);
1198  }
1206  public function hasAttribute($key)
1207  {
1208  // Sequence validation
1210 
1211  return $this->_hasAttribute($key);
1212  }
1213 
1221  private function _hasAttribute($key)
1222  {
1223  return (is_array($this->_attributes)
1224  && array_key_exists($key, $this->_attributes));
1225  }
1226 
1234  public function getAttribute($key)
1235  {
1236  // Sequence validation
1238 
1239  if ($this->_hasAttribute($key)) {
1240  return $this->_attributes[$key];
1241  }
1242  }
1243 
1251  public function renewAuthentication()
1252  {
1254  // Either way, the user is authenticated by CAS
1255  if (isset( $_SESSION['phpCAS']['auth_checked'])) {
1256  unset($_SESSION['phpCAS']['auth_checked']);
1257  }
1258  if ( $this->isAuthenticated(true) ) {
1259  phpCAS::trace('user already authenticated');
1260  $res = true;
1261  } else {
1262  $this->redirectToCas(false, true);
1263  // never reached
1264  $res = false;
1265  }
1266  phpCAS::traceEnd();
1267  return $res;
1268  }
1269 
1276  public function forceAuthentication()
1277  {
1279 
1280  if ( $this->isAuthenticated() ) {
1281  // the user is authenticated, nothing to be done.
1282  phpCAS::trace('no need to authenticate');
1283  $res = true;
1284  } else {
1285  // the user is not authenticated, redirect to the CAS server
1286  if (isset($_SESSION['phpCAS']['auth_checked'])) {
1287  unset($_SESSION['phpCAS']['auth_checked']);
1288  }
1289  $this->redirectToCas(false/* no gateway */);
1290  // never reached
1291  $res = false;
1292  }
1294  return $res;
1295  }
1296 
1304 
1313  {
1314  if (gettype($n) != 'integer')
1315  throw new CAS_TypeMismatchException($n, '$n', 'string');
1316 
1317  $this->_cache_times_for_auth_recheck = $n;
1318  }
1319 
1327  public function checkAuthentication()
1328  {
1330  $res = false;
1331  if ( $this->isAuthenticated() ) {
1332  phpCAS::trace('user is authenticated');
1333  /* The 'auth_checked' variable is removed just in case it's set. */
1334  unset($_SESSION['phpCAS']['auth_checked']);
1335  $res = true;
1336  } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
1337  // the previous request has redirected the client to the CAS server
1338  // with gateway=true
1339  unset($_SESSION['phpCAS']['auth_checked']);
1340  $res = false;
1341  } else {
1342  // avoid a check against CAS on every request
1343  if (!isset($_SESSION['phpCAS']['unauth_count'])) {
1344  $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized
1345  }
1346 
1347  if (($_SESSION['phpCAS']['unauth_count'] != -2
1348  && $this->_cache_times_for_auth_recheck == -1)
1349  || ($_SESSION['phpCAS']['unauth_count'] >= 0
1350  && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck)
1351  ) {
1352  $res = false;
1353 
1354  if ($this->_cache_times_for_auth_recheck != -1) {
1355  $_SESSION['phpCAS']['unauth_count']++;
1356  phpCAS::trace(
1357  'user is not authenticated (cached for '
1358  .$_SESSION['phpCAS']['unauth_count'].' times of '
1359  .$this->_cache_times_for_auth_recheck.')'
1360  );
1361  } else {
1362  phpCAS::trace(
1363  'user is not authenticated (cached for until login pressed)'
1364  );
1365  }
1366  } else {
1367  $_SESSION['phpCAS']['unauth_count'] = 0;
1368  $_SESSION['phpCAS']['auth_checked'] = true;
1369  phpCAS::trace('user is not authenticated (cache reset)');
1370  $this->redirectToCas(true/* gateway */);
1371  // never reached
1372  $res = false;
1373  }
1374  }
1376  return $res;
1377  }
1378 
1388  public function isAuthenticated($renew=false)
1389  {
1391  $res = false;
1392  $validate_url = '';
1393  if ( $this->_wasPreviouslyAuthenticated() ) {
1394  if ($this->hasTicket()) {
1395  // User has a additional ticket but was already authenticated
1396  phpCAS::trace(
1397  'ticket was present and will be discarded, use renewAuthenticate()'
1398  );
1399  if ($this->_clearTicketsFromUrl) {
1400  phpCAS::trace("Prepare redirect to : ".$this->getURL());
1401  session_write_close();
1402  header('Location: '.$this->getURL());
1403  flush();
1406  } else {
1407  phpCAS::trace(
1408  'Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.'
1409  );
1410  $res = true;
1411  }
1412  } else {
1413  // the user has already (previously during the session) been
1414  // authenticated, nothing to be done.
1415  phpCAS::trace(
1416  'user was already authenticated, no need to look for tickets'
1417  );
1418  $res = true;
1419  }
1420 
1421  // Mark the auth-check as complete to allow post-authentication
1422  // callbacks to make use of phpCAS::getUser() and similar methods
1423  $this->markAuthenticationCall($res);
1424  } else {
1425  if ($this->hasTicket()) {
1426  switch ($this->getServerVersion()) {
1427  case CAS_VERSION_1_0:
1428  // if a Service Ticket was given, validate it
1429  phpCAS::trace(
1430  'CAS 1.0 ticket `'.$this->getTicket().'\' is present'
1431  );
1432  $this->validateCAS10(
1433  $validate_url, $text_response, $tree_response, $renew
1434  ); // if it fails, it halts
1435  phpCAS::trace(
1436  'CAS 1.0 ticket `'.$this->getTicket().'\' was validated'
1437  );
1438  $_SESSION['phpCAS']['user'] = $this->_getUser();
1439  $res = true;
1440  $logoutTicket = $this->getTicket();
1441  break;
1442  case CAS_VERSION_2_0:
1443  case CAS_VERSION_3_0:
1444  // if a Proxy Ticket was given, validate it
1445  phpCAS::trace(
1446  'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' is present'
1447  );
1448  $this->validateCAS20(
1449  $validate_url, $text_response, $tree_response, $renew
1450  ); // note: if it fails, it halts
1451  phpCAS::trace(
1452  'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' was validated'
1453  );
1454  if ( $this->isProxy() ) {
1455  $this->_validatePGT(
1456  $validate_url, $text_response, $tree_response
1457  ); // idem
1458  phpCAS::trace('PGT `'.$this->_getPGT().'\' was validated');
1459  $_SESSION['phpCAS']['pgt'] = $this->_getPGT();
1460  }
1461  $_SESSION['phpCAS']['user'] = $this->_getUser();
1462  if (!empty($this->_attributes)) {
1463  $_SESSION['phpCAS']['attributes'] = $this->_attributes;
1464  }
1465  $proxies = $this->getProxies();
1466  if (!empty($proxies)) {
1467  $_SESSION['phpCAS']['proxies'] = $this->getProxies();
1468  }
1469  $res = true;
1470  $logoutTicket = $this->getTicket();
1471  break;
1472  case SAML_VERSION_1_1:
1473  // if we have a SAML ticket, validate it.
1474  phpCAS::trace(
1475  'SAML 1.1 ticket `'.$this->getTicket().'\' is present'
1476  );
1477  $this->validateSA(
1478  $validate_url, $text_response, $tree_response, $renew
1479  ); // if it fails, it halts
1480  phpCAS::trace(
1481  'SAML 1.1 ticket `'.$this->getTicket().'\' was validated'
1482  );
1483  $_SESSION['phpCAS']['user'] = $this->_getUser();
1484  $_SESSION['phpCAS']['attributes'] = $this->_attributes;
1485  $res = true;
1486  $logoutTicket = $this->getTicket();
1487  break;
1488  default:
1489  phpCAS::trace('Protocoll error');
1490  break;
1491  }
1492  } else {
1493  // no ticket given, not authenticated
1494  phpCAS::trace('no ticket found');
1495  }
1496 
1497  // Mark the auth-check as complete to allow post-authentication
1498  // callbacks to make use of phpCAS::getUser() and similar methods
1499  $this->markAuthenticationCall($res);
1500 
1501  if ($res) {
1502  // call the post-authenticate callback if registered.
1503  if ($this->_postAuthenticateCallbackFunction) {
1504  $args = $this->_postAuthenticateCallbackArgs;
1505  array_unshift($args, $logoutTicket);
1506  call_user_func_array(
1507  $this->_postAuthenticateCallbackFunction, $args
1508  );
1509  }
1510 
1511  // if called with a ticket parameter, we need to redirect to the
1512  // app without the ticket so that CAS-ification is transparent
1513  // to the browser (for later POSTS) most of the checks and
1514  // errors should have been made now, so we're safe for redirect
1515  // without masking error messages. remove the ticket as a
1516  // security precaution to prevent a ticket in the HTTP_REFERRER
1517  if ($this->_clearTicketsFromUrl) {
1518  phpCAS::trace("Prepare redirect to : ".$this->getURL());
1519  session_write_close();
1520  header('Location: '.$this->getURL());
1521  flush();
1524  }
1525  }
1526  }
1528  return $res;
1529  }
1530 
1536  public function isSessionAuthenticated ()
1537  {
1538  return !empty($_SESSION['phpCAS']['user']);
1539  }
1540 
1549  private function _wasPreviouslyAuthenticated()
1550  {
1552 
1553  if ( $this->_isCallbackMode() ) {
1554  // Rebroadcast the pgtIou and pgtId to all nodes
1555  if ($this->_rebroadcast&&!isset($_POST['rebroadcast'])) {
1556  $this->_rebroadcast(self::PGTIOU);
1557  }
1558  $this->_callback();
1559  }
1560 
1561  $auth = false;
1562 
1563  if ( $this->isProxy() ) {
1564  // CAS proxy: username and PGT must be present
1565  if ( $this->isSessionAuthenticated()
1566  && !empty($_SESSION['phpCAS']['pgt'])
1567  ) {
1568  // authentication already done
1569  $this->_setUser($_SESSION['phpCAS']['user']);
1570  if (isset($_SESSION['phpCAS']['attributes'])) {
1571  $this->setAttributes($_SESSION['phpCAS']['attributes']);
1572  }
1573  $this->_setPGT($_SESSION['phpCAS']['pgt']);
1574  phpCAS::trace(
1575  'user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'
1576  .$_SESSION['phpCAS']['pgt'].'\''
1577  );
1578 
1579  // Include the list of proxies
1580  if (isset($_SESSION['phpCAS']['proxies'])) {
1581  $this->_setProxies($_SESSION['phpCAS']['proxies']);
1582  phpCAS::trace(
1583  'proxies = "'
1584  .implode('", "', $_SESSION['phpCAS']['proxies']).'"'
1585  );
1586  }
1587 
1588  $auth = true;
1589  } elseif ( $this->isSessionAuthenticated()
1590  && empty($_SESSION['phpCAS']['pgt'])
1591  ) {
1592  // these two variables should be empty or not empty at the same time
1593  phpCAS::trace(
1594  'username found (`'.$_SESSION['phpCAS']['user']
1595  .'\') but PGT is empty'
1596  );
1597  // unset all tickets to enforce authentication
1598  unset($_SESSION['phpCAS']);
1599  $this->setTicket('');
1600  } elseif ( !$this->isSessionAuthenticated()
1601  && !empty($_SESSION['phpCAS']['pgt'])
1602  ) {
1603  // these two variables should be empty or not empty at the same time
1604  phpCAS::trace(
1605  'PGT found (`'.$_SESSION['phpCAS']['pgt']
1606  .'\') but username is empty'
1607  );
1608  // unset all tickets to enforce authentication
1609  unset($_SESSION['phpCAS']);
1610  $this->setTicket('');
1611  } else {
1612  phpCAS::trace('neither user nor PGT found');
1613  }
1614  } else {
1615  // `simple' CAS client (not a proxy): username must be present
1616  if ( $this->isSessionAuthenticated() ) {
1617  // authentication already done
1618  $this->_setUser($_SESSION['phpCAS']['user']);
1619  if (isset($_SESSION['phpCAS']['attributes'])) {
1620  $this->setAttributes($_SESSION['phpCAS']['attributes']);
1621  }
1622  phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\'');
1623 
1624  // Include the list of proxies
1625  if (isset($_SESSION['phpCAS']['proxies'])) {
1626  $this->_setProxies($_SESSION['phpCAS']['proxies']);
1627  phpCAS::trace(
1628  'proxies = "'
1629  .implode('", "', $_SESSION['phpCAS']['proxies']).'"'
1630  );
1631  }
1632 
1633  $auth = true;
1634  } else {
1635  phpCAS::trace('no user found');
1636  }
1637  }
1638 
1639  phpCAS::traceEnd($auth);
1640  return $auth;
1641  }
1642 
1653  public function redirectToCas($gateway=false,$renew=false)
1654  {
1656  $cas_url = $this->getServerLoginURL($gateway, $renew);
1657  session_write_close();
1658  if (php_sapi_name() === 'cli') {
1659  @header('Location: '.$cas_url);
1660  } else {
1661  header('Location: '.$cas_url);
1662  }
1663  phpCAS::trace("Redirect to : ".$cas_url);
1664  $lang = $this->getLangObj();
1665  $this->printHTMLHeader($lang->getAuthenticationWanted());
1666  printf('<p>'. $lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
1667  $this->printHTMLFooter();
1670  }
1671 
1672 
1681  public function logout($params)
1682  {
1684  $cas_url = $this->getServerLogoutURL();
1685  $paramSeparator = '?';
1686  if (isset($params['url'])) {
1687  $cas_url = $cas_url . $paramSeparator . "url="
1688  . urlencode($params['url']);
1689  $paramSeparator = '&';
1690  }
1691  if (isset($params['service'])) {
1692  $cas_url = $cas_url . $paramSeparator . "service="
1693  . urlencode($params['service']);
1694  }
1695  header('Location: '.$cas_url);
1696  phpCAS::trace("Prepare redirect to : ".$cas_url);
1697 
1698  phpCAS::trace("Destroying session : ".session_id());
1699  session_unset();
1700  session_destroy();
1701  if (session_status() === PHP_SESSION_NONE) {
1702  phpCAS::trace("Session terminated");
1703  } else {
1704  phpCAS::error("Session was not terminated");
1705  phpCAS::trace("Session was not terminated");
1706  }
1707  $lang = $this->getLangObj();
1708  $this->printHTMLHeader($lang->getLogout());
1709  printf('<p>'.$lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
1710  $this->printHTMLFooter();
1713  }
1714 
1720  private function _isLogoutRequest()
1721  {
1722  return !empty($_POST['logoutRequest']);
1723  }
1724 
1735  public function handleLogoutRequests($check_client=true, $allowed_clients=false)
1736  {
1738  if (!$this->_isLogoutRequest()) {
1739  phpCAS::trace("Not a logout request");
1740  phpCAS::traceEnd();
1741  return;
1742  }
1743  if (!$this->getChangeSessionID()
1744  && is_null($this->_signoutCallbackFunction)
1745  ) {
1746  phpCAS::trace(
1747  "phpCAS can't handle logout requests if it is not allowed to change session_id."
1748  );
1749  }
1750  phpCAS::trace("Logout requested");
1751  $decoded_logout_rq = urldecode($_POST['logoutRequest']);
1752  phpCAS::trace("SAML REQUEST: ".$decoded_logout_rq);
1753  $allowed = false;
1754  if ($check_client) {
1755  if (!$allowed_clients) {
1756  $allowed_clients = array( $this->_getServerHostname() );
1757  }
1758  $client_ip = $_SERVER['REMOTE_ADDR'];
1759  $client = gethostbyaddr($client_ip);
1760  phpCAS::trace("Client: ".$client."/".$client_ip);
1761  foreach ($allowed_clients as $allowed_client) {
1762  if (($client == $allowed_client)
1763  || ($client_ip == $allowed_client)
1764  ) {
1765  phpCAS::trace(
1766  "Allowed client '".$allowed_client
1767  ."' matches, logout request is allowed"
1768  );
1769  $allowed = true;
1770  break;
1771  } else {
1772  phpCAS::trace(
1773  "Allowed client '".$allowed_client."' does not match"
1774  );
1775  }
1776  }
1777  } else {
1778  phpCAS::trace("No access control set");
1779  $allowed = true;
1780  }
1781  // If Logout command is permitted proceed with the logout
1782  if ($allowed) {
1783  phpCAS::trace("Logout command allowed");
1784  // Rebroadcast the logout request
1785  if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) {
1786  $this->_rebroadcast(self::LOGOUT);
1787  }
1788  // Extract the ticket from the SAML Request
1789  preg_match(
1790  "|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|",
1791  $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3
1792  );
1793  $wrappedSamlSessionIndex = preg_replace(
1794  '|<samlp:SessionIndex>|', '', $tick[0][0]
1795  );
1796  $ticket2logout = preg_replace(
1797  '|</samlp:SessionIndex>|', '', $wrappedSamlSessionIndex
1798  );
1799  phpCAS::trace("Ticket to logout: ".$ticket2logout);
1800 
1801  // call the post-authenticate callback if registered.
1802  if ($this->_signoutCallbackFunction) {
1804  array_unshift($args, $ticket2logout);
1805  call_user_func_array($this->_signoutCallbackFunction, $args);
1806  }
1807 
1808  // If phpCAS is managing the session_id, destroy session thanks to
1809  // session_id.
1810  if ($this->getChangeSessionID()) {
1811  $session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket2logout);
1812  phpCAS::trace("Session id: ".$session_id);
1813 
1814  // destroy a possible application session created before phpcas
1815  if (session_id() !== "") {
1816  session_unset();
1817  session_destroy();
1818  }
1819  // fix session ID
1820  session_id($session_id);
1821  $_COOKIE[session_name()]=$session_id;
1822  $_GET[session_name()]=$session_id;
1823 
1824  // Overwrite session
1825  session_start();
1826  session_unset();
1827  session_destroy();
1828  phpCAS::trace("Session ". $session_id . " destroyed");
1829  }
1830  } else {
1831  phpCAS::error("Unauthorized logout request from client '".$client."'");
1832  phpCAS::trace("Unauthorized logout request from client '".$client."'");
1833  }
1834  flush();
1837 
1838  }
1839 
1842  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1843  // XX XX
1844  // XX BASIC CLIENT FEATURES (CAS 1.0) XX
1845  // XX XX
1846  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1847 
1848  // ########################################################################
1849  // ST
1850  // ########################################################################
1863  private $_ticket = '';
1864 
1870  public function getTicket()
1871  {
1872  return $this->_ticket;
1873  }
1874 
1882  public function setTicket($st)
1883  {
1884  $this->_ticket = $st;
1885  }
1886 
1892  public function hasTicket()
1893  {
1894  return !empty($this->_ticket);
1895  }
1896 
1899  // ########################################################################
1900  // ST VALIDATION
1901  // ########################################################################
1912  private $_cas_server_ca_cert = null;
1913 
1914 
1926 
1933 
1934 
1944  public function setCasServerCACert($cert, $validate_cn)
1945  {
1946  // Argument validation
1947  if (gettype($cert) != 'string') {
1948  throw new CAS_TypeMismatchException($cert, '$cert', 'string');
1949  }
1950  if (gettype($validate_cn) != 'boolean') {
1951  throw new CAS_TypeMismatchException($validate_cn, '$validate_cn', 'boolean');
1952  }
1953  if ( !file_exists($cert) && $this->_requestImplementation !== 'CAS_TestHarness_DummyRequest'){
1954  throw new CAS_InvalidArgumentException("Certificate file does not exist " . $this->_requestImplementation);
1955  }
1956  $this->_cas_server_ca_cert = $cert;
1957  $this->_cas_server_cn_validate = $validate_cn;
1958  }
1959 
1965  public function setNoCasServerValidation()
1966  {
1967  $this->_no_cas_server_validation = true;
1968  }
1969 
1985  public function validateCAS10(&$validate_url,&$text_response,&$tree_response,$renew=false)
1986  {
1988  $result = false;
1989  // build the URL to validate the ticket
1990  $validate_url = $this->getServerServiceValidateURL()
1991  .'&ticket='.urlencode($this->getTicket());
1992 
1993  if ( $renew ) {
1994  // pass the renew
1995  $validate_url .= '&renew=true';
1996  }
1997 
1998  // open and read the URL
1999  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
2000  phpCAS::trace(
2001  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
2002  );
2003  throw new CAS_AuthenticationException(
2004  $this, 'CAS 1.0 ticket not validated', $validate_url,
2005  true/*$no_response*/
2006  );
2007  $result = false;
2008  }
2009 
2010  if (preg_match('/^no\n/', $text_response)) {
2011  phpCAS::trace('Ticket has not been validated');
2012  throw new CAS_AuthenticationException(
2013  $this, 'ST not validated', $validate_url, false/*$no_response*/,
2014  false/*$bad_response*/, $text_response
2015  );
2016  $result = false;
2017  } else if (!preg_match('/^yes\n/', $text_response)) {
2018  phpCAS::trace('ill-formed response');
2019  throw new CAS_AuthenticationException(
2020  $this, 'Ticket not validated', $validate_url,
2021  false/*$no_response*/, true/*$bad_response*/, $text_response
2022  );
2023  $result = false;
2024  }
2025  // ticket has been validated, extract the user name
2026  $arr = preg_split('/\n/', $text_response);
2027  $this->_setUser(trim($arr[1]));
2028  $result = true;
2029 
2030  if ($result) {
2031  $this->_renameSession($this->getTicket());
2032  }
2033  // at this step, ticket has been validated and $this->_user has been set,
2034  phpCAS::traceEnd(true);
2035  return true;
2036  }
2037 
2041  // ########################################################################
2042  // SAML VALIDATION
2043  // ########################################################################
2065  public function validateSA(&$validate_url,&$text_response,&$tree_response,$renew=false)
2066  {
2067  phpCAS::traceBegin();
2068  $result = false;
2069  // build the URL to validate the ticket
2070  $validate_url = $this->getServerSamlValidateURL();
2071 
2072  if ( $renew ) {
2073  // pass the renew
2074  $validate_url .= '&renew=true';
2075  }
2076 
2077  // open and read the URL
2078  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
2079  phpCAS::trace(
2080  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
2081  );
2082  throw new CAS_AuthenticationException(
2083  $this, 'SA not validated', $validate_url, true/*$no_response*/
2084  );
2085  }
2086 
2087  phpCAS::trace('server version: '.$this->getServerVersion());
2088 
2089  // analyze the result depending on the version
2090  switch ($this->getServerVersion()) {
2091  case SAML_VERSION_1_1:
2092  // create new DOMDocument Object
2093  $dom = new DOMDocument();
2094  // Fix possible whitspace problems
2095  $dom->preserveWhiteSpace = false;
2096  // read the response of the CAS server into a DOM object
2097  if (!($dom->loadXML($text_response))) {
2098  phpCAS::trace('dom->loadXML() failed');
2099  throw new CAS_AuthenticationException(
2100  $this, 'SA not validated', $validate_url,
2101  false/*$no_response*/, true/*$bad_response*/,
2102  $text_response
2103  );
2104  $result = false;
2105  }
2106  // read the root node of the XML tree
2107  if (!($tree_response = $dom->documentElement)) {
2108  phpCAS::trace('documentElement() failed');
2109  throw new CAS_AuthenticationException(
2110  $this, 'SA not validated', $validate_url,
2111  false/*$no_response*/, true/*$bad_response*/,
2112  $text_response
2113  );
2114  $result = false;
2115  } else if ( $tree_response->localName != 'Envelope' ) {
2116  // insure that tag name is 'Envelope'
2117  phpCAS::trace(
2118  'bad XML root node (should be `Envelope\' instead of `'
2119  .$tree_response->localName.'\''
2120  );
2121  throw new CAS_AuthenticationException(
2122  $this, 'SA not validated', $validate_url,
2123  false/*$no_response*/, true/*$bad_response*/,
2124  $text_response
2125  );
2126  $result = false;
2127  } else if ($tree_response->getElementsByTagName("NameIdentifier")->length != 0) {
2128  // check for the NameIdentifier tag in the SAML response
2129  $success_elements = $tree_response->getElementsByTagName("NameIdentifier");
2130  phpCAS::trace('NameIdentifier found');
2131  $user = trim($success_elements->item(0)->nodeValue);
2132  phpCAS::trace('user = `'.$user.'`');
2133  $this->_setUser($user);
2134  $this->_setSessionAttributes($text_response);
2135  $result = true;
2136  } else {
2137  phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
2138  throw new CAS_AuthenticationException(
2139  $this, 'SA not validated', $validate_url,
2140  false/*$no_response*/, true/*$bad_response*/,
2141  $text_response
2142  );
2143  $result = false;
2144  }
2145  }
2146  if ($result) {
2147  $this->_renameSession($this->getTicket());
2148  }
2149  // at this step, ST has been validated and $this->_user has been set,
2151  return $result;
2152  }
2153 
2162  private function _setSessionAttributes($text_response)
2163  {
2165 
2166  $result = false;
2167 
2168  $attr_array = array();
2169 
2170  // create new DOMDocument Object
2171  $dom = new DOMDocument();
2172  // Fix possible whitspace problems
2173  $dom->preserveWhiteSpace = false;
2174  if (($dom->loadXML($text_response))) {
2175  $xPath = new DOMXpath($dom);
2176  $xPath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
2177  $xPath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
2178  $nodelist = $xPath->query("//saml:Attribute");
2179 
2180  if ($nodelist) {
2181  foreach ($nodelist as $node) {
2182  $xres = $xPath->query("saml:AttributeValue", $node);
2183  $name = $node->getAttribute("AttributeName");
2184  $value_array = array();
2185  foreach ($xres as $node2) {
2186  $value_array[] = $node2->nodeValue;
2187  }
2188  $attr_array[$name] = $value_array;
2189  }
2190  // UGent addition...
2191  foreach ($attr_array as $attr_key => $attr_value) {
2192  if (count($attr_value) > 1) {
2193  $this->_attributes[$attr_key] = $attr_value;
2194  phpCAS::trace("* " . $attr_key . "=" . print_r($attr_value, true));
2195  } else {
2196  $this->_attributes[$attr_key] = $attr_value[0];
2197  phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
2198  }
2199  }
2200  $result = true;
2201  } else {
2202  phpCAS::trace("SAML Attributes are empty");
2203  $result = false;
2204  }
2205  }
2207  return $result;
2208  }
2209 
2212  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2213  // XX XX
2214  // XX PROXY FEATURES (CAS 2.0) XX
2215  // XX XX
2216  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2217 
2218  // ########################################################################
2219  // PROXYING
2220  // ########################################################################
2230  private $_proxy;
2231 
2236 
2242  public function isProxy()
2243  {
2244  return $this->_proxy;
2245  }
2246 
2247 
2249  // ########################################################################
2250  // PGT
2251  // ########################################################################
2264  private $_pgt = '';
2265 
2271  private function _getPGT()
2272  {
2273  return $this->_pgt;
2274  }
2275 
2283  private function _setPGT($pgt)
2284  {
2285  $this->_pgt = $pgt;
2286  }
2287 
2293  private function _hasPGT()
2294  {
2295  return !empty($this->_pgt);
2296  }
2297 
2300  // ########################################################################
2301  // CALLBACK MODE
2302  // ########################################################################
2319  private $_callback_mode = false;
2320 
2328  private function _setCallbackMode($callback_mode)
2329  {
2330  $this->_callback_mode = $callback_mode;
2331  }
2332 
2339  private function _isCallbackMode()
2340  {
2341  return $this->_callback_mode;
2342  }
2343 
2351  private $_callback_url = '';
2352 
2360  private function _getCallbackURL()
2361  {
2362  // the URL is built when needed only
2363  if ( empty($this->_callback_url) ) {
2364  $final_uri = '';
2365  // remove the ticket if present in the URL
2366  $final_uri = 'https://';
2367  $final_uri .= $this->_getClientUrl();
2368  $request_uri = $_SERVER['REQUEST_URI'];
2369  $request_uri = preg_replace('/\?.*$/', '', $request_uri);
2370  $final_uri .= $request_uri;
2371  $this->_callback_url = $final_uri;
2372  }
2373  return $this->_callback_url;
2374  }
2375 
2383  public function setCallbackURL($url)
2384  {
2385  // Sequence validation
2386  $this->ensureIsProxy();
2387  // Argument Validation
2388  if (gettype($url) != 'string')
2389  throw new CAS_TypeMismatchException($url, '$url', 'string');
2390 
2391  return $this->_callback_url = $url;
2392  }
2393 
2400  private function _callback()
2401  {
2403  if (preg_match('/PGTIOU-[\.\-\w]/', $_GET['pgtIou'])) {
2404  if (preg_match('/[PT]GT-[\.\-\w]/', $_GET['pgtId'])) {
2405  $this->printHTMLHeader('phpCAS callback');
2406  $pgt_iou = $_GET['pgtIou'];
2407  $pgt = $_GET['pgtId'];
2408  phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
2409  echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
2410  $this->_storePGT($pgt, $pgt_iou);
2411  $this->printHTMLFooter();
2412  phpCAS::traceExit("Successfull Callback");
2413  } else {
2414  phpCAS::error('PGT format invalid' . $_GET['pgtId']);
2415  phpCAS::traceExit('PGT format invalid' . $_GET['pgtId']);
2416  }
2417  } else {
2418  phpCAS::error('PGTiou format invalid' . $_GET['pgtIou']);
2419  phpCAS::traceExit('PGTiou format invalid' . $_GET['pgtIou']);
2420  }
2421 
2422  // Flush the buffer to prevent from sending anything other then a 200
2423  // Success Status back to the CAS Server. The Exception would normally
2424  // report as a 500 error.
2425  flush();
2427  }
2428 
2429 
2432  // ########################################################################
2433  // PGT STORAGE
2434  // ########################################################################
2447  private $_pgt_storage = null;
2448 
2455  private function _initPGTStorage()
2456  {
2457  // if no SetPGTStorageXxx() has been used, default to file
2458  if ( !is_object($this->_pgt_storage) ) {
2459  $this->setPGTStorageFile();
2460  }
2461 
2462  // initializes the storage
2463  $this->_pgt_storage->init();
2464  }
2465 
2474  private function _storePGT($pgt,$pgt_iou)
2475  {
2476  // ensure that storage is initialized
2477  $this->_initPGTStorage();
2478  // writes the PGT
2479  $this->_pgt_storage->write($pgt, $pgt_iou);
2480  }
2481 
2490  private function _loadPGT($pgt_iou)
2491  {
2492  // ensure that storage is initialized
2493  $this->_initPGTStorage();
2494  // read the PGT
2495  return $this->_pgt_storage->read($pgt_iou);
2496  }
2497 
2506  public function setPGTStorage($storage)
2507  {
2508  // Sequence validation
2509  $this->ensureIsProxy();
2510 
2511  // check that the storage has not already been set
2512  if ( is_object($this->_pgt_storage) ) {
2513  phpCAS::error('PGT storage already defined');
2514  }
2515 
2516  // check to make sure a valid storage object was specified
2517  if ( !($storage instanceof CAS_PGTStorage_AbstractStorage) )
2518  throw new CAS_TypeMismatchException($storage, '$storage', 'CAS_PGTStorage_AbstractStorage object');
2519 
2520  // store the PGTStorage object
2521  $this->_pgt_storage = $storage;
2522  }
2523 
2541  public function setPGTStorageDb(
2542  $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null
2543  ) {
2544  // Sequence validation
2545  $this->ensureIsProxy();
2546 
2547  // Argument validation
2548  if ((is_object($dsn_or_pdo) && !($dsn_or_pdo instanceof PDO)) || gettype($dsn_or_pdo) != 'string')
2549  throw new CAS_TypeMismatchException($dsn_or_pdo, '$dsn_or_pdo', 'string or PDO object');
2550  if (gettype($username) != 'string')
2551  throw new CAS_TypeMismatchException($username, '$username', 'string');
2552  if (gettype($password) != 'string')
2553  throw new CAS_TypeMismatchException($password, '$password', 'string');
2554  if (gettype($table) != 'string')
2555  throw new CAS_TypeMismatchException($table, '$password', 'string');
2556 
2557  // create the storage object
2558  $this->setPGTStorage(
2559  new CAS_PGTStorage_Db(
2560  $this, $dsn_or_pdo, $username, $password, $table, $driver_options
2561  )
2562  );
2563  }
2564 
2573  public function setPGTStorageFile($path='')
2574  {
2575  // Sequence validation
2576  $this->ensureIsProxy();
2577 
2578  // Argument validation
2579  if (gettype($path) != 'string')
2580  throw new CAS_TypeMismatchException($path, '$path', 'string');
2581 
2582  // create the storage object
2583  $this->setPGTStorage(new CAS_PGTStorage_File($this, $path));
2584  }
2585 
2586 
2587  // ########################################################################
2588  // PGT VALIDATION
2589  // ########################################################################
2604  private function _validatePGT(&$validate_url,$text_response,$tree_response)
2605  {
2607  if ( $tree_response->getElementsByTagName("proxyGrantingTicket")->length == 0) {
2608  phpCAS::trace('<proxyGrantingTicket> not found');
2609  // authentication succeded, but no PGT Iou was transmitted
2610  throw new CAS_AuthenticationException(
2611  $this, 'Ticket validated but no PGT Iou transmitted',
2612  $validate_url, false/*$no_response*/, false/*$bad_response*/,
2613  $text_response
2614  );
2615  } else {
2616  // PGT Iou transmitted, extract it
2617  $pgt_iou = trim(
2618  $tree_response->getElementsByTagName("proxyGrantingTicket")->item(0)->nodeValue
2619  );
2620  if (preg_match('/PGTIOU-[\.\-\w]/', $pgt_iou)) {
2621  $pgt = $this->_loadPGT($pgt_iou);
2622  if ( $pgt == false ) {
2623  phpCAS::trace('could not load PGT');
2624  throw new CAS_AuthenticationException(
2625  $this,
2626  'PGT Iou was transmitted but PGT could not be retrieved',
2627  $validate_url, false/*$no_response*/,
2628  false/*$bad_response*/, $text_response
2629  );
2630  }
2631  $this->_setPGT($pgt);
2632  } else {
2633  phpCAS::trace('PGTiou format error');
2634  throw new CAS_AuthenticationException(
2635  $this, 'PGT Iou was transmitted but has wrong format',
2636  $validate_url, false/*$no_response*/, false/*$bad_response*/,
2637  $text_response
2638  );
2639  }
2640  }
2641  phpCAS::traceEnd(true);
2642  return true;
2643  }
2644 
2645  // ########################################################################
2646  // PGT VALIDATION
2647  // ########################################################################
2648 
2658  public function retrievePT($target_service,&$err_code,&$err_msg)
2659  {
2660  // Argument validation
2661  if (gettype($target_service) != 'string')
2662  throw new CAS_TypeMismatchException($target_service, '$target_service', 'string');
2663 
2665 
2666  // by default, $err_msg is set empty and $pt to true. On error, $pt is
2667  // set to false and $err_msg to an error message. At the end, if $pt is false
2668  // and $error_msg is still empty, it is set to 'invalid response' (the most
2669  // commonly encountered error).
2670  $err_msg = '';
2671 
2672  // build the URL to retrieve the PT
2673  $cas_url = $this->getServerProxyURL().'?targetService='
2674  .urlencode($target_service).'&pgt='.$this->_getPGT();
2675 
2676  // open and read the URL
2677  if ( !$this->_readURL($cas_url, $headers, $cas_response, $err_msg) ) {
2678  phpCAS::trace(
2679  'could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')'
2680  );
2681  $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
2682  $err_msg = 'could not retrieve PT (no response from the CAS server)';
2683  phpCAS::traceEnd(false);
2684  return false;
2685  }
2686 
2687  $bad_response = false;
2688 
2689  if ( !$bad_response ) {
2690  // create new DOMDocument object
2691  $dom = new DOMDocument();
2692  // Fix possible whitspace problems
2693  $dom->preserveWhiteSpace = false;
2694  // read the response of the CAS server into a DOM object
2695  if ( !($dom->loadXML($cas_response))) {
2696  phpCAS::trace('dom->loadXML() failed');
2697  // read failed
2698  $bad_response = true;
2699  }
2700  }
2701 
2702  if ( !$bad_response ) {
2703  // read the root node of the XML tree
2704  if ( !($root = $dom->documentElement) ) {
2705  phpCAS::trace('documentElement failed');
2706  // read failed
2707  $bad_response = true;
2708  }
2709  }
2710 
2711  if ( !$bad_response ) {
2712  // insure that tag name is 'serviceResponse'
2713  if ( $root->localName != 'serviceResponse' ) {
2714  phpCAS::trace('localName failed');
2715  // bad root node
2716  $bad_response = true;
2717  }
2718  }
2719 
2720  if ( !$bad_response ) {
2721  // look for a proxySuccess tag
2722  if ( $root->getElementsByTagName("proxySuccess")->length != 0) {
2723  $proxy_success_list = $root->getElementsByTagName("proxySuccess");
2724 
2725  // authentication succeded, look for a proxyTicket tag
2726  if ( $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->length != 0) {
2727  $err_code = PHPCAS_SERVICE_OK;
2728  $err_msg = '';
2729  $pt = trim(
2730  $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->item(0)->nodeValue
2731  );
2732  phpCAS::trace('original PT: '.trim($pt));
2733  phpCAS::traceEnd($pt);
2734  return $pt;
2735  } else {
2736  phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
2737  }
2738  } else if ($root->getElementsByTagName("proxyFailure")->length != 0) {
2739  // look for a proxyFailure tag
2740  $proxy_failure_list = $root->getElementsByTagName("proxyFailure");
2741 
2742  // authentication failed, extract the error
2743  $err_code = PHPCAS_SERVICE_PT_FAILURE;
2744  $err_msg = 'PT retrieving failed (code=`'
2745  .$proxy_failure_list->item(0)->getAttribute('code')
2746  .'\', message=`'
2747  .trim($proxy_failure_list->item(0)->nodeValue)
2748  .'\')';
2749  phpCAS::traceEnd(false);
2750  return false;
2751  } else {
2752  phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
2753  }
2754  }
2755 
2756  // at this step, we are sure that the response of the CAS server was
2757  // illformed
2758  $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
2759  $err_msg = 'Invalid response from the CAS server (response=`'
2760  .$cas_response.'\')';
2761 
2762  phpCAS::traceEnd(false);
2763  return false;
2764  }
2765 
2768  // ########################################################################
2769  // READ CAS SERVER ANSWERS
2770  // ########################################################################
2771 
2790  private function _readURL($url, &$headers, &$body, &$err_msg)
2791  {
2793  $className = $this->_requestImplementation;
2794  $request = new $className();
2795 
2796  if (count($this->_curl_options)) {
2797  $request->setCurlOptions($this->_curl_options);
2798  }
2799 
2800  $request->setUrl($url);
2801 
2802  if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) {
2803  phpCAS::error(
2804  'one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.'
2805  );
2806  }
2807  if ($this->_cas_server_ca_cert != '') {
2808  $request->setSslCaCert(
2809  $this->_cas_server_ca_cert, $this->_cas_server_cn_validate
2810  );
2811  }
2812 
2813  // add extra stuff if SAML
2814  if ($this->getServerVersion() == SAML_VERSION_1_1) {
2815  $request->addHeader("soapaction: http://www.oasis-open.org/committees/security");
2816  $request->addHeader("cache-control: no-cache");
2817  $request->addHeader("pragma: no-cache");
2818  $request->addHeader("accept: text/xml");
2819  $request->addHeader("connection: keep-alive");
2820  $request->addHeader("content-type: text/xml");
2821  $request->makePost();
2822  $request->setPostBody($this->_buildSAMLPayload());
2823  }
2824 
2825  if ($request->send()) {
2826  $headers = $request->getResponseHeaders();
2827  $body = $request->getResponseBody();
2828  $err_msg = '';
2829  phpCAS::traceEnd(true);
2830  return true;
2831  } else {
2832  $headers = '';
2833  $body = '';
2834  $err_msg = $request->getErrorMessage();
2835  phpCAS::traceEnd(false);
2836  return false;
2837  }
2838  }
2839 
2845  private function _buildSAMLPayload()
2846  {
2848 
2849  //get the ticket
2850  $sa = urlencode($this->getTicket());
2851 
2852  $body = SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST
2853  .SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE
2854  .SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
2855 
2856  phpCAS::traceEnd($body);
2857  return ($body);
2858  }
2859 
2862  // ########################################################################
2863  // ACCESS TO EXTERNAL SERVICES
2864  // ########################################################################
2865 
2882  public function getProxiedService ($type)
2883  {
2884  // Sequence validation
2885  $this->ensureIsProxy();
2887 
2888  // Argument validation
2889  if (gettype($type) != 'string')
2890  throw new CAS_TypeMismatchException($type, '$type', 'string');
2891 
2892  switch ($type) {
2895  $requestClass = $this->_requestImplementation;
2896  $request = new $requestClass();
2897  if (count($this->_curl_options)) {
2898  $request->setCurlOptions($this->_curl_options);
2899  }
2900  $proxiedService = new $type($request, $this->_serviceCookieJar);
2901  if ($proxiedService instanceof CAS_ProxiedService_Testable) {
2902  $proxiedService->setCasClient($this);
2903  }
2904  return $proxiedService;
2906  $proxiedService = new CAS_ProxiedService_Imap($this->_getUser());
2907  if ($proxiedService instanceof CAS_ProxiedService_Testable) {
2908  $proxiedService->setCasClient($this);
2909  }
2910  return $proxiedService;
2911  default:
2912  throw new CAS_InvalidArgumentException(
2913  "Unknown proxied-service type, $type."
2914  );
2915  }
2916  }
2917 
2933  public function initializeProxiedService (CAS_ProxiedService $proxiedService)
2934  {
2935  // Sequence validation
2936  $this->ensureIsProxy();
2938 
2939  $url = $proxiedService->getServiceUrl();
2940  if (!is_string($url)) {
2941  throw new CAS_ProxiedService_Exception(
2942  "Proxied Service ".get_class($proxiedService)
2943  ."->getServiceUrl() should have returned a string, returned a "
2944  .gettype($url)." instead."
2945  );
2946  }
2947  $pt = $this->retrievePT($url, $err_code, $err_msg);
2948  if (!$pt) {
2949  throw new CAS_ProxyTicketException($err_msg, $err_code);
2950  }
2951  $proxiedService->setProxyTicket($pt);
2952  }
2953 
2968  public function serviceWeb($url,&$err_code,&$output)
2969  {
2970  // Sequence validation
2971  $this->ensureIsProxy();
2973 
2974  // Argument validation
2975  if (gettype($url) != 'string')
2976  throw new CAS_TypeMismatchException($url, '$url', 'string');
2977 
2978  try {
2980  $service->setUrl($url);
2981  $service->send();
2982  $output = $service->getResponseBody();
2983  $err_code = PHPCAS_SERVICE_OK;
2984  return true;
2985  } catch (CAS_ProxyTicketException $e) {
2986  $err_code = $e->getCode();
2987  $output = $e->getMessage();
2988  return false;
2989  } catch (CAS_ProxiedService_Exception $e) {
2990  $lang = $this->getLangObj();
2991  $output = sprintf(
2992  $lang->getServiceUnavailable(), $url, $e->getMessage()
2993  );
2994  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
2995  return false;
2996  }
2997  }
2998 
3018  public function serviceMail($url,$serviceUrl,$flags,&$err_code,&$err_msg,&$pt)
3019  {
3020  // Sequence validation
3021  $this->ensureIsProxy();
3023 
3024  // Argument validation
3025  if (gettype($url) != 'string')
3026  throw new CAS_TypeMismatchException($url, '$url', 'string');
3027  if (gettype($serviceUrl) != 'string')
3028  throw new CAS_TypeMismatchException($serviceUrl, '$serviceUrl', 'string');
3029  if (gettype($flags) != 'integer')
3030  throw new CAS_TypeMismatchException($flags, '$flags', 'string');
3031 
3032  try {
3034  $service->setServiceUrl($serviceUrl);
3035  $service->setMailbox($url);
3036  $service->setOptions($flags);
3037 
3038  $stream = $service->open();
3039  $err_code = PHPCAS_SERVICE_OK;
3040  $pt = $service->getImapProxyTicket();
3041  return $stream;
3042  } catch (CAS_ProxyTicketException $e) {
3043  $err_msg = $e->getMessage();
3044  $err_code = $e->getCode();
3045  $pt = false;
3046  return false;
3047  } catch (CAS_ProxiedService_Exception $e) {
3048  $lang = $this->getLangObj();
3049  $err_msg = sprintf(
3050  $lang->getServiceUnavailable(),
3051  $url,
3052  $e->getMessage()
3053  );
3054  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
3055  $pt = false;
3056  return false;
3057  }
3058  }
3059 
3062  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3063  // XX XX
3064  // XX PROXIED CLIENT FEATURES (CAS 2.0) XX
3065  // XX XX
3066  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3067 
3068  // ########################################################################
3069  // PT
3070  // ########################################################################
3086  private $_proxies = array();
3087 
3097  public function getProxies()
3098  {
3099  return $this->_proxies;
3100  }
3101 
3110  private function _setProxies($proxies)
3111  {
3112  $this->_proxies = $proxies;
3113  if (!empty($proxies)) {
3114  // For proxy-authenticated requests people are not viewing the URL
3115  // directly since the client is another application making a
3116  // web-service call.
3117  // Because of this, stripping the ticket from the URL is unnecessary
3118  // and causes another web-service request to be performed. Additionally,
3119  // if session handling on either the client or the server malfunctions
3120  // then the subsequent request will not complete successfully.
3121  $this->setNoClearTicketsFromUrl();
3122  }
3123  }
3124 
3131 
3137  public function getAllowedProxyChains ()
3138  {
3139  if (empty($this->_allowed_proxy_chains)) {
3140  $this->_allowed_proxy_chains = new CAS_ProxyChain_AllowedList();
3141  }
3143  }
3144 
3146  // ########################################################################
3147  // PT VALIDATION
3148  // ########################################################################
3166  public function validateCAS20(&$validate_url,&$text_response,&$tree_response, $renew=false)
3167  {
3169  phpCAS::trace($text_response);
3170  $result = false;
3171  // build the URL to validate the ticket
3172  if ($this->getAllowedProxyChains()->isProxyingAllowed()) {
3173  $validate_url = $this->getServerProxyValidateURL().'&ticket='
3174  .urlencode($this->getTicket());
3175  } else {
3176  $validate_url = $this->getServerServiceValidateURL().'&ticket='
3177  .urlencode($this->getTicket());
3178  }
3179 
3180  if ( $this->isProxy() ) {
3181  // pass the callback url for CAS proxies
3182  $validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL());
3183  }
3184 
3185  if ( $renew ) {
3186  // pass the renew
3187  $validate_url .= '&renew=true';
3188  }
3189 
3190  // open and read the URL
3191  if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
3192  phpCAS::trace(
3193  'could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')'
3194  );
3195  throw new CAS_AuthenticationException(
3196  $this, 'Ticket not validated', $validate_url,
3197  true/*$no_response*/
3198  );
3199  $result = false;
3200  }
3201 
3202  // create new DOMDocument object
3203  $dom = new DOMDocument();
3204  // Fix possible whitspace problems
3205  $dom->preserveWhiteSpace = false;
3206  // CAS servers should only return data in utf-8
3207  $dom->encoding = "utf-8";
3208  // read the response of the CAS server into a DOMDocument object
3209  if ( !($dom->loadXML($text_response))) {
3210  // read failed
3211  throw new CAS_AuthenticationException(
3212  $this, 'Ticket not validated', $validate_url,
3213  false/*$no_response*/, true/*$bad_response*/, $text_response
3214  );
3215  $result = false;
3216  } else if ( !($tree_response = $dom->documentElement) ) {
3217  // read the root node of the XML tree
3218  // read failed
3219  throw new CAS_AuthenticationException(
3220  $this, 'Ticket not validated', $validate_url,
3221  false/*$no_response*/, true/*$bad_response*/, $text_response
3222  );
3223  $result = false;
3224  } else if ($tree_response->localName != 'serviceResponse') {
3225  // insure that tag name is 'serviceResponse'
3226  // bad root node
3227  throw new CAS_AuthenticationException(
3228  $this, 'Ticket not validated', $validate_url,
3229  false/*$no_response*/, true/*$bad_response*/, $text_response
3230  );
3231  $result = false;
3232  } else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
3233  // authentication failed, extract the error code and message and throw exception
3234  $auth_fail_list = $tree_response
3235  ->getElementsByTagName("authenticationFailure");
3236  throw new CAS_AuthenticationException(
3237  $this, 'Ticket not validated', $validate_url,
3238  false/*$no_response*/, false/*$bad_response*/,
3239  $text_response,
3240  $auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
3241  trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
3242  );
3243  $result = false;
3244  } else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) {
3245  // authentication succeded, extract the user name
3246  $success_elements = $tree_response
3247  ->getElementsByTagName("authenticationSuccess");
3248  if ( $success_elements->item(0)->getElementsByTagName("user")->length == 0) {
3249  // no user specified => error
3250  throw new CAS_AuthenticationException(
3251  $this, 'Ticket not validated', $validate_url,
3252  false/*$no_response*/, true/*$bad_response*/, $text_response
3253  );
3254  $result = false;
3255  } else {
3256  $this->_setUser(
3257  trim(
3258  $success_elements->item(0)->getElementsByTagName("user")->item(0)->nodeValue
3259  )
3260  );
3261  $this->_readExtraAttributesCas20($success_elements);
3262  // Store the proxies we are sitting behind for authorization checking
3263  $proxyList = array();
3264  if ( sizeof($arr = $success_elements->item(0)->getElementsByTagName("proxy")) > 0) {
3265  foreach ($arr as $proxyElem) {
3266  phpCAS::trace("Found Proxy: ".$proxyElem->nodeValue);
3267  $proxyList[] = trim($proxyElem->nodeValue);
3268  }
3269  $this->_setProxies($proxyList);
3270  phpCAS::trace("Storing Proxy List");
3271  }
3272  // Check if the proxies in front of us are allowed
3273  if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) {
3274  throw new CAS_AuthenticationException(
3275  $this, 'Proxy not allowed', $validate_url,
3276  false/*$no_response*/, true/*$bad_response*/,
3277  $text_response
3278  );
3279  $result = false;
3280  } else {
3281  $result = true;
3282  }
3283  }
3284  } else {
3285  throw new CAS_AuthenticationException(
3286  $this, 'Ticket not validated', $validate_url,
3287  false/*$no_response*/, true/*$bad_response*/,
3288  $text_response
3289  );
3290  $result = false;
3291  }
3292  if ($result) {
3293  $this->_renameSession($this->getTicket());
3294  }
3295  // at this step, Ticket has been validated and $this->_user has been set,
3296 
3297  phpCAS::traceEnd($result);
3298  return $result;
3299  }
3300 
3301 
3311  private function _readExtraAttributesCas20($success_elements)
3312  {
3313  phpCAS::traceBegin();
3314 
3315  $extra_attributes = array();
3316 
3317  // "Jasig Style" Attributes:
3318  //
3319  // <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
3320  // <cas:authenticationSuccess>
3321  // <cas:user>jsmith</cas:user>
3322  // <cas:attributes>
3323  // <cas:attraStyle>RubyCAS</cas:attraStyle>
3324  // <cas:surname>Smith</cas:surname>
3325  // <cas:givenName>John</cas:givenName>
3326  // <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
3327  // <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>
3328  // </cas:attributes>
3329  // <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
3330  // </cas:authenticationSuccess>
3331  // </cas:serviceResponse>
3332  //
3333  if ($this->_casAttributeParserCallbackFunction !== null
3334  && is_callable($this->_casAttributeParserCallbackFunction)
3335  ) {
3336  array_unshift($this->_casAttributeParserCallbackArgs, $success_elements->item(0));
3337  phpCas :: trace("Calling attritubeParser callback");
3338  $extra_attributes = call_user_func_array(
3339  $this->_casAttributeParserCallbackFunction,
3340  $this->_casAttributeParserCallbackArgs
3341  );
3342  } elseif ( $success_elements->item(0)->getElementsByTagName("attributes")->length != 0) {
3343  $attr_nodes = $success_elements->item(0)
3344  ->getElementsByTagName("attributes");
3345  phpCas :: trace("Found nested jasig style attributes");
3346  if ($attr_nodes->item(0)->hasChildNodes()) {
3347  // Nested Attributes
3348  foreach ($attr_nodes->item(0)->childNodes as $attr_child) {
3349  phpCas :: trace(
3350  "Attribute [".$attr_child->localName."] = "
3351  .$attr_child->nodeValue
3352  );
3353  $this->_addAttributeToArray(
3354  $extra_attributes, $attr_child->localName,
3355  $attr_child->nodeValue
3356  );
3357  }
3358  }
3359  } else {
3360  // "RubyCAS Style" attributes
3361  //
3362  // <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
3363  // <cas:authenticationSuccess>
3364  // <cas:user>jsmith</cas:user>
3365  //
3366  // <cas:attraStyle>RubyCAS</cas:attraStyle>
3367  // <cas:surname>Smith</cas:surname>
3368  // <cas:givenName>John</cas:givenName>
3369  // <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
3370  // <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>
3371  //
3372  // <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
3373  // </cas:authenticationSuccess>
3374  // </cas:serviceResponse>
3375  //
3376  phpCas :: trace("Testing for rubycas style attributes");
3377  $childnodes = $success_elements->item(0)->childNodes;
3378  foreach ($childnodes as $attr_node) {
3379  switch ($attr_node->localName) {
3380  case 'user':
3381  case 'proxies':
3382  case 'proxyGrantingTicket':
3383  continue;
3384  default:
3385  if (strlen(trim($attr_node->nodeValue))) {
3386  phpCas :: trace(
3387  "Attribute [".$attr_node->localName."] = ".$attr_node->nodeValue
3388  );
3389  $this->_addAttributeToArray(
3390  $extra_attributes, $attr_node->localName,
3391  $attr_node->nodeValue
3392  );
3393  }
3394  }
3395  }
3396  }
3397 
3398  // "Name-Value" attributes.
3399  //
3400  // Attribute format from these mailing list thread:
3401  // http://jasig.275507.n4.nabble.com/CAS-attributes-and-how-they-appear-in-the-CAS-response-td264272.html
3402  // Note: This is a less widely used format, but in use by at least two institutions.
3403  //
3404  // <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
3405  // <cas:authenticationSuccess>
3406  // <cas:user>jsmith</cas:user>
3407  //
3408  // <cas:attribute name='attraStyle' value='Name-Value' />
3409  // <cas:attribute name='surname' value='Smith' />
3410  // <cas:attribute name='givenName' value='John' />
3411  // <cas:attribute name='memberOf' value='CN=Staff,OU=Groups,DC=example,DC=edu' />
3412  // <cas:attribute name='memberOf' value='CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu' />
3413  //
3414  // <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
3415  // </cas:authenticationSuccess>
3416  // </cas:serviceResponse>
3417  //
3418  if (!count($extra_attributes)
3419  && $success_elements->item(0)->getElementsByTagName("attribute")->length != 0
3420  ) {
3421  $attr_nodes = $success_elements->item(0)
3422  ->getElementsByTagName("attribute");
3423  $firstAttr = $attr_nodes->item(0);
3424  if (!$firstAttr->hasChildNodes()
3425  && $firstAttr->hasAttribute('name')
3426  && $firstAttr->hasAttribute('value')
3427  ) {
3428  phpCas :: trace("Found Name-Value style attributes");
3429  // Nested Attributes
3430  foreach ($attr_nodes as $attr_node) {
3431  if ($attr_node->hasAttribute('name')
3432  && $attr_node->hasAttribute('value')
3433  ) {
3434  phpCas :: trace(
3435  "Attribute [".$attr_node->getAttribute('name')
3436  ."] = ".$attr_node->getAttribute('value')
3437  );
3438  $this->_addAttributeToArray(
3439  $extra_attributes, $attr_node->getAttribute('name'),
3440  $attr_node->getAttribute('value')
3441  );
3442  }
3443  }
3444  }
3445  }
3446 
3447  $this->setAttributes($extra_attributes);
3448  phpCAS::traceEnd();
3449  return true;
3450  }
3451 
3461  private function _addAttributeToArray(array &$attributeArray, $name, $value)
3462  {
3463  // If multiple attributes exist, add as an array value
3464  if (isset($attributeArray[$name])) {
3465  // Initialize the array with the existing value
3466  if (!is_array($attributeArray[$name])) {
3467  $existingValue = $attributeArray[$name];
3468  $attributeArray[$name] = array($existingValue);
3469  }
3470 
3471  $attributeArray[$name][] = trim($value);
3472  } else {
3473  $attributeArray[$name] = trim($value);
3474  }
3475  }
3476 
3479  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3480  // XX XX
3481  // XX MISC XX
3482  // XX XX
3483  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3484 
3490  // ########################################################################
3491  // URL
3492  // ########################################################################
3499  private $_url = '';
3500 
3501 
3509  public function setURL($url)
3510  {
3511  // Argument Validation
3512  if (gettype($url) != 'string')
3513  throw new CAS_TypeMismatchException($url, '$url', 'string');
3514 
3515  $this->_url = $url;
3516  }
3517 
3524  public function getURL()
3525  {
3527  // the URL is built when needed only
3528  if ( empty($this->_url) ) {
3529  $final_uri = '';
3530  // remove the ticket if present in the URL
3531  $final_uri = ($this->_isHttps()) ? 'https' : 'http';
3532  $final_uri .= '://';
3533 
3534  $final_uri .= $this->_getClientUrl();
3535  $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);
3536  $final_uri .= $request_uri[0];
3537 
3538  if (isset($request_uri[1]) && $request_uri[1]) {
3539  $query_string= $this->_removeParameterFromQueryString('ticket', $request_uri[1]);
3540 
3541  // If the query string still has anything left,
3542  // append it to the final URI
3543  if ($query_string !== '') {
3544  $final_uri .= "?$query_string";
3545  }
3546  }
3547 
3548  phpCAS::trace("Final URI: $final_uri");
3549  $this->setURL($final_uri);
3550  }
3551  phpCAS::traceEnd($this->_url);
3552  return $this->_url;
3553  }
3554 
3562  public function setBaseURL($url)
3563  {
3564  // Argument Validation
3565  if (gettype($url) != 'string')
3566  throw new CAS_TypeMismatchException($url, '$url', 'string');
3567 
3568  return $this->_server['base_url'] = $url;
3569  }
3570 
3571 
3577  private function _getClientUrl()
3578  {
3579  $server_url = '';
3580  if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
3581  // explode the host list separated by comma and use the first host
3582  $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
3583  // see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default
3584  return $hosts[0];
3585  } else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
3586  $server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];
3587  } else {
3588  if (empty($_SERVER['SERVER_NAME'])) {
3589  $server_url = $_SERVER['HTTP_HOST'];
3590  } else {
3591  $server_url = $_SERVER['SERVER_NAME'];
3592  }
3593  }
3594  if (!strpos($server_url, ':')) {
3595  if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
3596  $server_port = $_SERVER['SERVER_PORT'];
3597  } else {
3598  $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);
3599  $server_port = $ports[0];
3600  }
3601 
3602  if ( ($this->_isHttps() && $server_port!=443)
3603  || (!$this->_isHttps() && $server_port!=80)
3604  ) {
3605  $server_url .= ':';
3606  $server_url .= $server_port;
3607  }
3608  }
3609  return $server_url;
3610  }
3611 
3617  private function _isHttps()
3618  {
3619  if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
3620  return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
3621  } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {
3622  return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https');
3623  } elseif ( isset($_SERVER['HTTPS'])
3624  && !empty($_SERVER['HTTPS'])
3625  && strcasecmp($_SERVER['HTTPS'], 'off') !== 0
3626  ) {
3627  return true;
3628  }
3629  return false;
3630 
3631  }
3632 
3643  private function _removeParameterFromQueryString($parameterName, $queryString)
3644  {
3645  $parameterName = preg_quote($parameterName);
3646  return preg_replace(
3647  "/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/",
3648  '', $queryString
3649  );
3650  }
3651 
3662  private function _buildQueryUrl($url, $query)
3663  {
3664  $url .= (strstr($url, '?') === false) ? '?' : '&';
3665  $url .= $query;
3666  return $url;
3667  }
3668 
3676  private function _renameSession($ticket)
3677  {
3679  if ($this->getChangeSessionID()) {
3680  if (!empty($this->_user)) {
3681  $old_session = $_SESSION;
3682  phpCAS :: trace("Killing session: ". session_id());
3683  session_destroy();
3684  // set up a new session, of name based on the ticket
3685  $session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket);
3686  phpCAS :: trace("Starting session: ". $session_id);
3687  session_id($session_id);
3688  session_start();
3689  phpCAS :: trace("Restoring old session vars");
3690  $_SESSION = $old_session;
3691  } else {
3692  phpCAS :: trace (
3693  'Session should only be renamed after successfull authentication'
3694  );
3695  }
3696  } else {
3698  "Skipping session rename since phpCAS is not handling the session."
3699  );
3700  }
3701  phpCAS::traceEnd();
3702  }
3703 
3704 
3705  // ########################################################################
3706  // AUTHENTICATION ERROR HANDLING
3707  // ########################################################################
3724  private function _authError(
3725  $failure,
3726  $cas_url,
3727  $no_response,
3728  $bad_response='',
3729  $cas_response='',
3730  $err_code='',
3731  $err_msg=''
3732  ) {
3734  $lang = $this->getLangObj();
3735  $this->printHTMLHeader($lang->getAuthenticationFailed());
3736  printf(
3737  $lang->getYouWereNotAuthenticated(), htmlentities($this->getURL()),
3738  isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''
3739  );
3740  phpCAS::trace('CAS URL: '.$cas_url);
3741  phpCAS::trace('Authentication failure: '.$failure);
3742  if ( $no_response ) {
3743  phpCAS::trace('Reason: no response from the CAS server');
3744  } else {
3745  if ( $bad_response ) {
3746  phpCAS::trace('Reason: bad response from the CAS server');
3747  } else {
3748  switch ($this->getServerVersion()) {
3749  case CAS_VERSION_1_0:
3750  phpCAS::trace('Reason: CAS error');
3751  break;
3752  case CAS_VERSION_2_0:
3753  case CAS_VERSION_3_0:
3754  if ( empty($err_code) ) {
3755  phpCAS::trace('Reason: no CAS error');
3756  } else {
3757  phpCAS::trace(
3758  'Reason: ['.$err_code.'] CAS error: '.$err_msg
3759  );
3760  }
3761  break;
3762  }
3763  }
3764  phpCAS::trace('CAS response: '.$cas_response);
3765  }
3766  $this->printHTMLFooter();
3769  }
3770 
3771  // ########################################################################
3772  // PGTIOU/PGTID and logoutRequest rebroadcasting
3773  // ########################################################################
3774 
3779  private $_rebroadcast = false;
3781 
3785  const HOSTNAME = 0;
3786  const IP = 1;
3787 
3796  private function _getNodeType($nodeURL)
3797  {
3799  if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $nodeURL)) {
3800  phpCAS::traceEnd(self::IP);
3801  return self::IP;
3802  } else {
3803  phpCAS::traceEnd(self::HOSTNAME);
3804  return self::HOSTNAME;
3805  }
3806  }
3807 
3815  public function addRebroadcastNode($rebroadcastNodeUrl)
3816  {
3817  // Argument validation
3818  if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl))
3819  throw new CAS_TypeMismatchException($rebroadcastNodeUrl, '$rebroadcastNodeUrl', 'url');
3820 
3821  // Store the rebroadcast node and set flag
3822  $this->_rebroadcast = true;
3823  $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl;
3824  }
3825 
3830 
3840  {
3841  if (gettype($header) != 'string')
3842  throw new CAS_TypeMismatchException($header, '$header', 'string');
3843 
3844  $this->_rebroadcast_headers[] = $header;
3845  }
3846 
3850  const LOGOUT = 0;
3851  const PGTIOU = 1;
3852 
3860  private function _rebroadcast($type)
3861  {
3863 
3864  $rebroadcast_curl_options = array(
3865  CURLOPT_FAILONERROR => 1,
3866  CURLOPT_FOLLOWLOCATION => 1,
3867  CURLOPT_RETURNTRANSFER => 1,
3868  CURLOPT_CONNECTTIMEOUT => 1,
3869  CURLOPT_TIMEOUT => 4);
3870 
3871  // Try to determine the IP address of the server
3872  if (!empty($_SERVER['SERVER_ADDR'])) {
3873  $ip = $_SERVER['SERVER_ADDR'];
3874  } else if (!empty($_SERVER['LOCAL_ADDR'])) {
3875  // IIS 7
3876  $ip = $_SERVER['LOCAL_ADDR'];
3877  }
3878  // Try to determine the DNS name of the server
3879  if (!empty($ip)) {
3880  $dns = gethostbyaddr($ip);
3881  }
3882  $multiClassName = 'CAS_Request_CurlMultiRequest';
3883  $multiRequest = new $multiClassName();
3884 
3885  for ($i = 0; $i < sizeof($this->_rebroadcast_nodes); $i++) {
3886  if ((($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) === false))
3887  || (($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) === false))
3888  ) {
3889  phpCAS::trace(
3890  'Rebroadcast target URL: '.$this->_rebroadcast_nodes[$i]
3891  .$_SERVER['REQUEST_URI']
3892  );
3893  $className = $this->_requestImplementation;
3894  $request = new $className();
3895 
3896  $url = $this->_rebroadcast_nodes[$i].$_SERVER['REQUEST_URI'];
3897  $request->setUrl($url);
3898 
3899  if (count($this->_rebroadcast_headers)) {
3900  $request->addHeaders($this->_rebroadcast_headers);
3901  }
3902 
3903  $request->makePost();
3904  if ($type == self::LOGOUT) {
3905  // Logout request
3906  $request->setPostBody(
3907  'rebroadcast=false&logoutRequest='.$_POST['logoutRequest']
3908  );
3909  } else if ($type == self::PGTIOU) {
3910  // pgtIou/pgtId rebroadcast
3911  $request->setPostBody('rebroadcast=false');
3912  }
3913 
3914  $request->setCurlOptions($rebroadcast_curl_options);
3915 
3916  $multiRequest->addRequest($request);
3917  } else {
3918  phpCAS::trace(
3919  'Rebroadcast not sent to self: '
3920  .$this->_rebroadcast_nodes[$i].' == '.(!empty($ip)?$ip:'')
3921  .'/'.(!empty($dns)?$dns:'')
3922  );
3923  }
3924  }
3925  // We need at least 1 request
3926  if ($multiRequest->getNumRequests() > 0) {
3927  $multiRequest->send();
3928  }
3929  phpCAS::traceEnd();
3930  }
3931 
3933 }
3934 
3935 ?>
getAuthenticationCallerFile()
Answer information about the authentication caller.
Definition: Client.php:844
File written to
_setProxies($proxies)
Set the Proxy array, probably from persistant storage.
Definition: Client.php:3110
$_callback_mode
each PHP script using phpCAS in proxy mode is its own callback to get the PGT back from the CAS serve...
Definition: Client.php:2319
ProxyChain is a container for storing chains of valid proxies that can be used to validate proxied re...
Definition: AllowedList.php:43
if( $out) else
getLangObj()
Create the language.
Definition: Client.php:222
$_cache_times_for_auth_recheck
An integer that gives the number of times authentication will be cached before rechecked.
Definition: Client.php:1303
_rebroadcast($type)
This method rebroadcasts logout/pgtIou requests.
Definition: Client.php:3860
$path
Definition: aliased.php:25
setServerLoginURL($url)
This method sets the login URL of the CAS server.
Definition: Client.php:365
$failure
$_rebroadcast
Boolean of whether to rebroadcast pgtIou/pgtId and logoutRequest, and array of the nodes...
Definition: Client.php:3779
_getClientUrl()
Try to figure out the phpCas client URL with possible Proxys / Ports etc.
Definition: Client.php:3577
getUser()
This method returns the CAS user&#39;s login name.
Definition: Client.php:1118
setPGTStorageFile($path='')
This method is used to tell phpCAS to store the response of the CAS server to PGT requests onto the f...
Definition: Client.php:2573
$_cas_server_cn_validate
validate CN of the CAS server certificate
Definition: Client.php:1925
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
_loadPGT($pgt_iou)
This method reads a PGT from its Iou and deletes the corresponding storage entry. ...
Definition: Client.php:2490
setServerServiceValidateURL($url)
This method sets the serviceValidate URL of the CAS server.
Definition: Client.php:382
const PHPCAS_PROXIED_SERVICE_IMAP
phpCAS::getProxiedService() type for IMAP
Definition: CAS.php:203
Basic class for PGT database storage The CAS_PGTStorage_Db class is a class for PGT database storage...
Definition: Db.php:46
$_SESSION["AccountId"]
initializeProxiedService(CAS_ProxiedService $proxiedService)
Initialize a proxied-service handler with the proxy-ticket it should use.
Definition: Client.php:2933
const CAS_VERSION_1_0
CAS version 1.0.
Definition: CAS.php:74
The phpCAS class is a simple container for the phpCAS library.
Definition: CAS.php:278
$result
renewAuthentication()
This method is called to renew the authentication of the user If the user is authenticated, renew the connection If not, redirect to CAS.
Definition: Client.php:1251
getAttributes()
Get an key values arry of attributes.
Definition: Client.php:1172
static error($msg)
This method is used by interface methods to print an error and where the function was originally call...
Definition: CAS.php:543
printHTMLFooter()
This method prints the footer of the HTML output (after filtering).
Definition: Client.php:129
_ensureAuthenticationCalled()
Ensure that authentication was checked.
Definition: Client.php:792
static traceExit()
This method is used to indicate the end of the execution of the program.
Definition: CAS.php:661
$_GET["client_id"]
$_authentication_caller
Definition: Client.php:772
retrievePT($target_service, &$err_code, &$err_msg)
This method is used to retrieve PT&#39;s from the CAS server thanks to a PGT.
Definition: Client.php:2658
const SAML_VERSION_1_1
SAML protocol.
Definition: CAS.php:91
setCasAttributeParserCallback($function, array $additionalArgs=array())
Set a callback function to be run when parsing CAS attributes.
Definition: Client.php:664
_initPGTStorage()
This method is used to initialize the storage of PGT&#39;s.
Definition: Client.php:2455
_authError( $failure, $cas_url, $no_response, $bad_response='', $cas_response='', $err_code='', $err_msg='')
This method is used to print the HTML output when the user was not authenticated. ...
Definition: Client.php:3724
setPGTStorage($storage)
This method can be used to set a custom PGT storage object.
Definition: Client.php:2506
_getServerPort()
This method is used to retrieve the port of the CAS server.
Definition: Client.php:293
_getServerHostname()
This method is used to retrieve the hostname of the CAS server.
Definition: Client.php:283
setSingleSignoutCallback($function, array $additionalArgs=array())
Set a callback function to be run when a single-signout request is received.
Definition: Client.php:728
const CAS_VERSION_3_0
CAS version 3.0.
Definition: CAS.php:82
const SAML_SOAP_ENV
SOAP envelope for SAML POST.
Definition: CAS.php:101
const PGTIOU
Definition: Client.php:3851
hasAttributes()
Check whether attributes are available.
Definition: Client.php:1192
$_cas_server_ca_cert
the certificate of the CAS server CA.
Definition: Client.php:1912
addRebroadcastHeader($header)
This method is used to add header parameters when rebroadcasting pgtIou/pgtId or logoutRequest.
Definition: Client.php:3839
wasAuthenticationCalled()
Answer true if authentication has been checked.
Definition: Client.php:779
getAttribute($key)
Get a specific attribute by name.
Definition: Client.php:1234
const PHPCAS_SERVICE_OK
phpCAS::service() error code on success
Definition: CAS.php:168
getServerProxyURL()
This method is used to retrieve the proxy URL of the CAS server.
Definition: Client.php:519
$_serviceCookieJar
Handler for managing service cookies.
Definition: Client.php:2235
_removeParameterFromQueryString($parameterName, $queryString)
Removes a parameter from a query string.
Definition: Client.php:3643
if(! $in) print Initializing normalization quick check tables n
$_server
a record to store information about the CAS server.
Definition: Client.php:262
wasAuthenticationCallSuccessful()
Answer the result of the authentication call.
Definition: Client.php:807
$url
Definition: shib_logout.php:72
An Exception for problems communicating with a proxied service.
Definition: Exception.php:40
getServerProxyValidateURL()
This method is used to retrieve the proxy validating URL of the CAS server.
Definition: Client.php:488
This interface defines a class library for performing web requests.
This interface defines methods that allow proxy-authenticated service handlers to interact with phpCA...
_setChangeSessionID($allowed)
Set a parameter whether to allow phpCas to change session_id.
Definition: Client.php:1062
static traceEnd($res='')
This method is used to indicate the end of the execution of a function in debug mode.
Definition: CAS.php:638
setLang($lang)
This method is used to set the language used by phpCAS.
Definition: Client.php:201
_validatePGT(&$validate_url, $text_response, $tree_response)
This method is used to validate a PGT; halt on failure.
Definition: Client.php:2604
getTicket()
This method returns the Service Ticket provided in the URL of the request.
Definition: Client.php:1870
_getServerBaseURL()
This method is used to retrieve the base URL of the CAS server.
Definition: Client.php:313
const PHPCAS_LANG_DEFAULT
phpCAS default language (when phpCAS::setLang() is not used)
Definition: CAS.php:234
The CAS_PGTStorage_File class is a class for PGT file storage.
Definition: File.php:45
user()
Definition: user.php:4
static trace($str)
This method is used to log something in debug mode.
Definition: CAS.php:579
_isLogoutRequest()
Check of the current request is a logout request.
Definition: Client.php:1720
setRequestImplementation($className)
Override the default implementation used to make web requests in readUrl().
Definition: Client.php:611
This class defines Exceptions that should be thrown when the sequence of operations is invalid...
ensureIsProxy()
Ensure that this is actually a proxy object or fail with an exception.
Definition: Client.php:745
isAuthenticated($renew=false)
This method is called to check if the user is authenticated (previously or by tickets given in the UR...
Definition: Client.php:1388
_isHttps()
This method checks to see if the request is secured via HTTPS.
Definition: Client.php:3617
hasAttribute($key)
Check whether a specific attribute with a name is available.
Definition: Client.php:1206
_wasPreviouslyAuthenticated()
This method tells if the user has already been (previously) authenticated by looking into the session...
Definition: Client.php:1549
$_output_footer
A string used to print the footer of HTML pages.
Definition: Client.php:120
_hasPGT()
This method tells if a Proxy Granting Ticket was stored.
Definition: Client.php:2293
_htmlFilterOutput($str)
This method filters a string by replacing special tokens by appropriate values and prints it...
Definition: Client.php:75
getChangeSessionID()
Get whether phpCas is allowed to change session_id.
Definition: Client.php:1072
$client
setProxyTicket($proxyTicket)
Register a proxy ticket with the ProxiedService that it can use when making requests.
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\+" &#(? foreach( $entity_files as $file) $output
_getCallbackURL()
This method returns the URL that should be used for the PGT callback (in fact the URL of the current ...
Definition: Client.php:2360
$_clearTicketsFromUrl
Definition: Client.php:626
$_user
The Authenticated user.
Definition: Client.php:1096
setCallbackURL($url)
This method sets the callback url.
Definition: Client.php:2383
Provides access to a proxy-authenticated IMAP stream.
Definition: Imap.php:40
This class defines Exceptions that should be thrown when the sequence of operations is invalid...
_getNodeType($nodeURL)
Determine the node type from the URL.
Definition: Client.php:3796
_hasAttribute($key)
Check whether a specific attribute with a name is available.
Definition: Client.php:1221
$_rebroadcast_headers
An array to store extra rebroadcast curl options.
Definition: Client.php:3829
$_casAttributeParserCallbackArgs
Definition: Client.php:651
_buildQueryUrl($url, $query)
This method is used to append query parameters to an url.
Definition: Client.php:3662
logout($params)
This method is used to logout from CAS.
Definition: Client.php:1681
const IP
Definition: Client.php:3786
$_pgt_storage
an instance of a class inheriting of PGTStorage, used to deal with PGT storage.
Definition: Client.php:2447
_getUser()
This method returns the CAS user&#39;s login name.
Definition: Client.php:1134
_callback()
This method is called by CAS_Client::CAS_Client() when running in callback mode.
Definition: Client.php:2400
const PHPCAS_PROXIED_SERVICE_HTTP_POST
phpCAS::getProxiedService() type for HTTP POST
Definition: CAS.php:199
setBaseURL($url)
This method sets the base URL of the CAS server.
Definition: Client.php:3562
Basic class for PGT storage The CAS_PGTStorage_AbstractStorage class is a generic class for PGT stora...
$header
Exception that denotes invalid arguments were passed.
markAuthenticationCall($auth)
Mark the caller of authentication.
Definition: Client.php:761
getServerServiceValidateURL()
This method is used to retrieve the service validating URL of the CAS server.
Definition: Client.php:431
$_output_header
A string used to print the header of HTML pages.
Definition: Client.php:90
_setUser($user)
This method sets the CAS user&#39;s login name.
Definition: Client.php:1105
_readURL($url, &$headers, &$body, &$err_msg)
This method is used to acces a remote URL.
Definition: Client.php:2790
redirectToCas($gateway=false, $renew=false)
This method is used to redirect the client to the CAS server.
Definition: Client.php:1653
getServerLogoutURL()
This method is used to retrieve the logout URL of the CAS server.
Definition: Client.php:541
$_signoutCallbackArgs
Definition: Client.php:712
const PHPCAS_SERVICE_NOT_AVAILABLE
phpCAS::service() error code when the service was not available.
Definition: CAS.php:187
getServiceUrl()
Answer a service identifier (URL) for whom we should fetch a proxy ticket.
setServerProxyValidateURL($url)
This method sets the proxyValidate URL of the CAS server.
Definition: Client.php:399
_setCallbackMode($callback_mode)
This method sets/unsets callback mode.
Definition: Client.php:2328
setPostAuthenticateCallback($function, array $additionalArgs=array())
Set a callback function to be run when a user authenticates.
Definition: Client.php:698
const CAS_VERSION_2_0
Definition: CAS.php:78
getProxies()
Answer an array of proxies that are sitting in front of this application.
Definition: Client.php:3097
Add a drawing to the header
Definition: 04printing.php:69
$_rebroadcast_nodes
Definition: Client.php:3780
$n
Definition: RandomTest.php:80
_buildSAMLPayload()
This method is used to build the SAML POST body sent to /samlValidate URL.
Definition: Client.php:2845
static getVersion()
This method returns the phpCAS version.
Definition: CAS.php:714
_addAttributeToArray(array &$attributeArray, $name, $value)
Add an attribute value to an array of attributes.
Definition: Client.php:3461
$_allowed_proxy_chains
Definition: Client.php:3130
$_postAuthenticateCallbackArgs
Definition: Client.php:677
const LOGOUT
Constants used for determining rebroadcast type (logout or pgtIou/pgtId).
Definition: Client.php:3850
validateCAS20(&$validate_url, &$text_response, &$tree_response, $renew=false)
This method is used to validate a cas 2.0 ST or PT; halt on failure Used for all CAS 2...
Definition: Client.php:3166
setURL($url)
This method sets the URL of the current request.
Definition: Client.php:3509
$_url
the URL of the current request (without any ticket CGI parameter).
Definition: Client.php:3499
Create styles array
The data for the language used.
setAttributes($attributes)
Set an array of attributes.
Definition: Client.php:1162
printHTMLHeader($title)
This method prints the header of the HTML output (after filtering).
Definition: Client.php:101
ensureAuthenticationCallSuccessful()
Ensure that authentication was checked.
Definition: Client.php:822
setHTMLHeader($header)
This method set the HTML header used for all outputs.
Definition: Client.php:150
hasTicket()
This method tells if a Service Ticket was stored.
Definition: Client.php:1892
validateSA(&$validate_url, &$text_response, &$tree_response, $renew=false)
This method is used to validate a SAML TICKET; halt on failure, and sets $validate_url, $text_reponse and $tree_response on success.
Definition: Client.php:2065
setNoCasServerValidation()
Set no SSL validation for the CAS server.
Definition: Client.php:1965
setHTMLFooter($footer)
This method set the HTML footer used for all outputs.
Definition: Client.php:166
getURL()
This method returns the URL of the current request (without any ticket CGI parameter).
Definition: Client.php:3524
$_callback_url
the URL that should be used for the PGT callback (in fact the URL of the current request without any ...
Definition: Client.php:2351
Language Interface class for all internationalization files.
$_proxy
A boolean telling if the client is a CAS proxy or not.
Definition: Client.php:2230
getServerVersion()
This method is used to retrieve the version of the CAS server.
Definition: Client.php:273
Licensed to Jasig under one or more contributor license agreements.
$_ticket
The Ticket provided in the URL of the request if present (empty otherwise).
Definition: Client.php:1863
setServerLogoutURL($url)
This method sets the logout URL of the CAS server.
Definition: Client.php:557
isSessionAuthenticated()
This method tells if the current session is authenticated.
Definition: Client.php:1536
$_change_session_id
A variable to whether phpcas will use its own session handling.
Definition: Client.php:1053
static traceBegin()
This method is used to indicate the start of the execution of a function in debug mode...
Definition: CAS.php:591
getServerLoginURL($gateway=false, $renew=false)
This method is used to retrieve the login URL of the CAS server.
Definition: Client.php:337
$_no_cas_server_validation
Set to true not to validate the CAS server.
Definition: Client.php:1932
getAuthenticationCallerLine()
Answer information about the authentication caller.
Definition: Client.php:858
setNoClearTicketsFromUrl()
Configure the client to not send redirect headers and call exit() on authentication success...
Definition: Client.php:638
forceAuthentication()
This method is called to be sure that the user is authenticated.
Definition: Client.php:1276
$_COOKIE['ilClientId']
Definition: BPMN2Parser.php:15
isProxy()
Tells if a CAS client is a CAS proxy or not.
Definition: Client.php:2242
__construct( $server_version, $proxy, $server_hostname, $server_port, $server_uri, $changeSessionID=true)
CAS_Client constructor.
Definition: Client.php:902
_isCallbackMode()
This method returns true when the CAs client is running i callback mode, false otherwise.
Definition: Client.php:2339
for($i=1; $i<=count($kw_cases_sel); $i+=1) $lang
Definition: langwiz.php:349
setServerSamlValidateURL($url)
This method sets the samlValidate URL of the CAS server.
Definition: Client.php:416
The CAS_Client class is a client interface that provides CAS authentication to PHP applications...
Definition: Client.php:51
$_attributes
The Authenticated users attributes.
Definition: Client.php:1153
const HOSTNAME
Constants used for determining rebroadcast node type.
Definition: Client.php:3785
setCasServerCACert($cert, $validate_cn)
Set the CA certificate of the CAS server.
Definition: Client.php:1944
_setPGT($pgt)
This method stores the Proxy Granting Ticket.
Definition: Client.php:2283
getAuthenticationCallerMethod()
Answer information about the authentication caller.
Definition: Client.php:872
addRebroadcastNode($rebroadcastNodeUrl)
Store the rebroadcast node for pgtIou/pgtId and logout requests.
Definition: Client.php:3815
setCacheTimesForAuthRecheck($n)
Set the number of times authentication will be cached before rechecked.
Definition: Client.php:1312
This class defines Exceptions that should be thrown when the sequence of operations is invalid...
const PHPCAS_PROXIED_SERVICE_HTTP_GET
phpCAS::getProxiedService() type for HTTP GET
Definition: CAS.php:195
setExtraCurlOption($key, $value)
This method is used to set additional user curl options.
Definition: Client.php:579
checkAuthentication()
This method is called to check whether the user is authenticated or not.
Definition: Client.php:1327
_storePGT($pgt, $pgt_iou)
This method stores a PGT.
Definition: Client.php:2474
_renameSession($ticket)
Renaming the session.
Definition: Client.php:3676
_setSessionAttributes($text_response)
This method will parse the DOM and pull out the attributes from the SAML payload and put them into an...
Definition: Client.php:2162
setPGTStorageDb( $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null)
This method is used to tell phpCAS to store the response of the CAS server to PGT requests in a datab...
Definition: Client.php:2541
$_lang
A string corresponding to the language used by phpCAS.
Definition: Client.php:192
getAllowedProxyChains()
Answer the CAS_ProxyChain_AllowedList object for this client.
Definition: Client.php:3137
_getServerURI()
This method is used to retrieve the URI of the CAS server.
Definition: Client.php:303
$_requestImplementation
The class to instantiate for making web requests in readUrl().
Definition: Client.php:601
An Exception for errors related to fetching or validating proxy tickets.
serviceMail($url, $serviceUrl, $flags, &$err_code, &$err_msg, &$pt)
This method is used to access an IMAP/POP3/NNTP service.
Definition: Client.php:3018
$_POST["username"]
$params
Definition: example_049.php:96
$_casAttributeParserCallbackFunction
Definition: Client.php:646
handleLogoutRequests($check_client=true, $allowed_clients=false)
This method handles logout requests.
Definition: Client.php:1735
$_pgt
the Proxy Grnting Ticket given by the CAS server (empty otherwise).
Definition: Client.php:2264
$_proxies
This array will store a list of proxies in front of this application.
Definition: Client.php:3086
setTicket($st)
This method stores the Service Ticket.
Definition: Client.php:1882
getProxiedService($type)
Answer a proxy-authenticated service handler.
Definition: Client.php:2882
getServerSamlValidateURL()
This method is used to retrieve the SAML validating URL of the CAS server.
Definition: Client.php:463
This interface defines methods that allow proxy-authenticated service handlers to interact with phpCA...
$_curl_options
An array to store extra curl options.
Definition: Client.php:569
$_signoutCallbackFunction
Definition: Client.php:707
validateCAS10(&$validate_url, &$text_response, &$tree_response, $renew=false)
This method is used to validate a CAS 1,0 ticket; halt on failure, and sets $validate_url, $text_reponse and $tree_response on success.
Definition: Client.php:1985
$_postAuthenticateCallbackFunction
Definition: Client.php:672
This class provides access to service cookies and handles parsing of response headers to pull out coo...
Definition: CookieJar.php:41
serviceWeb($url, &$err_code, &$output)
This method is used to access an HTTP[S] service.
Definition: Client.php:2968
PHPExcel root directory.
Definition: Database.php:30
_getPGT()
This method returns the Proxy Granting Ticket given by the CAS server.
Definition: Client.php:2271