ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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__',
106  $title,
107  (empty($this->_output_header)
108  ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
109  : $this->_output_header)
110  )
111  );
112  }
113 
121  private $_output_footer = '';
122 
130  public function printHTMLFooter()
131  {
132  $lang = $this->getLangObj();
133  $this->_htmlFilterOutput(
134  empty($this->_output_footer)?
135  (phpcas::getVerbose())?
136  '<hr><address>phpCAS __PHPCAS_VERSION__ '
137  . $lang->getUsingServer()
138  . ' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>'
139  :'</body></html>'
141  );
142  }
143 
151  public function setHTMLHeader($header)
152  {
153  // Argument Validation
154  if (gettype($header) != 'string') {
155  throw new CAS_TypeMismatchException($header, '$header', 'string');
156  }
157 
158  $this->_output_header = $header;
159  }
160 
168  public function setHTMLFooter($footer)
169  {
170  // Argument Validation
171  if (gettype($footer) != 'string') {
172  throw new CAS_TypeMismatchException($footer, '$footer', 'string');
173  }
174 
175  $this->_output_footer = $footer;
176  }
177 
178 
182  // ########################################################################
183  // INTERNATIONALIZATION
184  // ########################################################################
196 
204  public function setLang($lang)
205  {
206  // Argument Validation
207  if (gettype($lang) != 'string') {
208  throw new CAS_TypeMismatchException($lang, '$lang', 'string');
209  }
210 
212  $obj = new $lang();
213  if (!($obj instanceof CAS_Languages_LanguageInterface)) {
215  '$className must implement the CAS_Languages_LanguageInterface'
216  );
217  }
218  $this->_lang = $lang;
220  }
226  public function getLangObj()
227  {
228  $classname = $this->_lang;
229  return new $classname();
230  }
231 
233  // ########################################################################
234  // CAS SERVER CONFIG
235  // ########################################################################
266  private $_server = array(
267  'version' => -1,
268  'hostname' => 'none',
269  'port' => -1,
270  'uri' => 'none');
271 
277  public function getServerVersion()
278  {
279  return $this->_server['version'];
280  }
281 
287  private function _getServerHostname()
288  {
289  return $this->_server['hostname'];
290  }
291 
297  private function _getServerPort()
298  {
299  return $this->_server['port'];
300  }
301 
307  private function _getServerURI()
308  {
309  return $this->_server['uri'];
310  }
311 
317  private function _getServerBaseURL()
318  {
319  // the URL is build only when needed
320  if (empty($this->_server['base_url'])) {
321  $this->_server['base_url'] = 'https://' . $this->_getServerHostname();
322  if ($this->_getServerPort() != 443) {
323  $this->_server['base_url'] .= ':'
324  . $this->_getServerPort();
325  }
326  $this->_server['base_url'] .= $this->_getServerURI();
327  }
328  return $this->_server['base_url'];
329  }
330 
341  public function getServerLoginURL($gateway = false, $renew = false)
342  {
344  // the URL is build only when needed
345  if (empty($this->_server['login_url'])) {
346  $this->_server['login_url'] = $this->_buildQueryUrl($this->_getServerBaseURL() . 'login', 'service=' . urlencode($this->getURL()));
347  }
348  $url = $this->_server['login_url'];
349  if ($renew) {
350  // It is recommended that when the "renew" parameter is set, its
351  // value be "true"
352  $url = $this->_buildQueryUrl($url, 'renew=true');
353  } elseif ($gateway) {
354  // It is recommended that when the "gateway" parameter is set, its
355  // value be "true"
356  $url = $this->_buildQueryUrl($url, 'gateway=true');
357  }
359  return $url;
360  }
361 
369  public function setServerLoginURL($url)
370  {
371  // Argument Validation
372  if (gettype($url) != 'string') {
373  throw new CAS_TypeMismatchException($url, '$url', 'string');
374  }
375 
376  return $this->_server['login_url'] = $url;
377  }
378 
379 
388  {
389  // Argument Validation
390  if (gettype($url) != 'string') {
391  throw new CAS_TypeMismatchException($url, '$url', 'string');
392  }
393 
394  return $this->_server['service_validate_url'] = $url;
395  }
396 
397 
406  {
407  // Argument Validation
408  if (gettype($url) != 'string') {
409  throw new CAS_TypeMismatchException($url, '$url', 'string');
410  }
411 
412  return $this->_server['proxy_validate_url'] = $url;
413  }
414 
415 
424  {
425  // Argument Validation
426  if (gettype($url) != 'string') {
427  throw new CAS_TypeMismatchException($url, '$url', 'string');
428  }
429 
430  return $this->_server['saml_validate_url'] = $url;
431  }
432 
433 
439  public function getServerServiceValidateURL()
440  {
442  // the URL is build only when needed
443  if (empty($this->_server['service_validate_url'])) {
444  switch ($this->getServerVersion()) {
445  case CAS_VERSION_1_0:
446  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
447  . 'validate';
448  break;
449  case CAS_VERSION_2_0:
450  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
451  . 'serviceValidate';
452  break;
453  case CAS_VERSION_3_0:
454  $this->_server['service_validate_url'] = $this->_getServerBaseURL()
455  . 'p3/serviceValidate';
456  break;
457  }
458  }
459  $url = $this->_buildQueryUrl(
460  $this->_server['service_validate_url'],
461  'service=' . urlencode($this->getURL())
462  );
464  return $url;
465  }
471  public function getServerSamlValidateURL()
472  {
474  // the URL is build only when needed
475  if (empty($this->_server['saml_validate_url'])) {
476  switch ($this->getServerVersion()) {
477  case SAML_VERSION_1_1:
478  $this->_server['saml_validate_url'] = $this->_getServerBaseURL() . 'samlValidate';
479  break;
480  }
481  }
482 
483  $url = $this->_buildQueryUrl(
484  $this->_server['saml_validate_url'],
485  'TARGET=' . urlencode($this->getURL())
486  );
488  return $url;
489  }
490 
496  public function getServerProxyValidateURL()
497  {
499  // the URL is build only when needed
500  if (empty($this->_server['proxy_validate_url'])) {
501  switch ($this->getServerVersion()) {
502  case CAS_VERSION_1_0:
503  $this->_server['proxy_validate_url'] = '';
504  break;
505  case CAS_VERSION_2_0:
506  $this->_server['proxy_validate_url'] = $this->_getServerBaseURL() . 'proxyValidate';
507  break;
508  case CAS_VERSION_3_0:
509  $this->_server['proxy_validate_url'] = $this->_getServerBaseURL() . 'p3/proxyValidate';
510  break;
511  }
512  }
513  $url = $this->_buildQueryUrl(
514  $this->_server['proxy_validate_url'],
515  'service=' . urlencode($this->getURL())
516  );
518  return $url;
519  }
520 
521 
527  public function getServerProxyURL()
528  {
529  // the URL is build only when needed
530  if (empty($this->_server['proxy_url'])) {
531  switch ($this->getServerVersion()) {
532  case CAS_VERSION_1_0:
533  $this->_server['proxy_url'] = '';
534  break;
535  case CAS_VERSION_2_0:
536  case CAS_VERSION_3_0:
537  $this->_server['proxy_url'] = $this->_getServerBaseURL() . 'proxy';
538  break;
539  }
540  }
541  return $this->_server['proxy_url'];
542  }
543 
549  public function getServerLogoutURL()
550  {
551  // the URL is build only when needed
552  if (empty($this->_server['logout_url'])) {
553  $this->_server['logout_url'] = $this->_getServerBaseURL() . 'logout';
554  }
555  return $this->_server['logout_url'];
556  }
557 
565  public function setServerLogoutURL($url)
566  {
567  // Argument Validation
568  if (gettype($url) != 'string') {
569  throw new CAS_TypeMismatchException($url, '$url', 'string');
570  }
571 
572  return $this->_server['logout_url'] = $url;
573  }
574 
578  private $_curl_options = array();
579 
588  public function setExtraCurlOption($key, $value)
589  {
590  $this->_curl_options[$key] = $value;
591  }
592 
595  // ########################################################################
596  // Change the internal behaviour of phpcas
597  // ########################################################################
598 
610  private $_requestImplementation = 'CAS_Request_CurlRequest';
611 
620  public function setRequestImplementation($className)
621  {
622  $obj = new $className;
623  if (!($obj instanceof CAS_Request_RequestInterface)) {
625  '$className must implement the CAS_Request_RequestInterface'
626  );
627  }
628  $this->_requestImplementation = $className;
629  }
630 
635  private $_clearTicketsFromUrl = true;
636 
647  public function setNoClearTicketsFromUrl()
648  {
649  $this->_clearTicketsFromUrl = false;
650  }
651 
656 
661 
673  public function setCasAttributeParserCallback($function, array $additionalArgs = array())
674  {
675  $this->_casAttributeParserCallbackFunction = $function;
676  $this->_casAttributeParserCallbackArgs = $additionalArgs;
677  }
678 
682 
687 
707  public function setPostAuthenticateCallback($function, array $additionalArgs = array())
708  {
709  $this->_postAuthenticateCallbackFunction = $function;
710  $this->_postAuthenticateCallbackArgs = $additionalArgs;
711  }
712 
717 
721  private $_signoutCallbackArgs = array();
722 
737  public function setSingleSignoutCallback($function, array $additionalArgs = array())
738  {
739  $this->_signoutCallbackFunction = $function;
740  $this->_signoutCallbackArgs = $additionalArgs;
741  }
742 
743  // ########################################################################
744  // Methods for supplying code-flow feedback to integrators.
745  // ########################################################################
746 
754  public function ensureIsProxy()
755  {
756  if (!$this->isProxy()) {
758  }
759  }
760 
770  public function markAuthenticationCall($auth)
771  {
772  // store where the authentication has been checked and the result
773  $dbg = debug_backtrace();
774  $this->_authentication_caller = array(
775  'file' => $dbg[1]['file'],
776  'line' => $dbg[1]['line'],
777  'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'],
778  'result' => (boolean) $auth
779  );
780  }
782 
788  public function wasAuthenticationCalled()
789  {
790  return !empty($this->_authentication_caller);
791  }
792 
801  private function _ensureAuthenticationCalled()
802  {
803  if (!$this->wasAuthenticationCalled()) {
805  }
806  }
807 
817  {
819  return $this->_authentication_caller['result'];
820  }
821 
822 
832  {
834  if (!$this->_authentication_caller['result']) {
835  throw new CAS_OutOfSequenceException(
836  'authentication was checked (by '
838  . '() at ' . $this->getAuthenticationCallerFile()
839  . ':' . $this->getAuthenticationCallerLine()
840  . ') but the method returned false'
841  );
842  }
843  }
844 
853  public function getAuthenticationCallerFile()
854  {
856  return $this->_authentication_caller['file'];
857  }
858 
867  public function getAuthenticationCallerLine()
868  {
870  return $this->_authentication_caller['line'];
871  }
872 
882  {
884  return $this->_authentication_caller['method'];
885  }
886 
889  // ########################################################################
890  // CONSTRUCTOR
891  // ########################################################################
911  public function __construct(
912  $server_version,
913  $proxy,
914  $server_hostname,
915  $server_port,
916  $server_uri,
917  $changeSessionID = true
918  ) {
919  // Argument validation
920  if (gettype($server_version) != 'string') {
921  throw new CAS_TypeMismatchException($server_version, '$server_version', 'string');
922  }
923  if (gettype($proxy) != 'boolean') {
924  throw new CAS_TypeMismatchException($proxy, '$proxy', 'boolean');
925  }
926  if (gettype($server_hostname) != 'string') {
927  throw new CAS_TypeMismatchException($server_hostname, '$server_hostname', 'string');
928  }
929  if (gettype($server_port) != 'integer') {
930  throw new CAS_TypeMismatchException($server_port, '$server_port', 'integer');
931  }
932  if (gettype($server_uri) != 'string') {
933  throw new CAS_TypeMismatchException($server_uri, '$server_uri', 'string');
934  }
935  if (gettype($changeSessionID) != 'boolean') {
936  throw new CAS_TypeMismatchException($changeSessionID, '$changeSessionID', 'boolean');
937  }
938 
940  // true : allow to change the session_id(), false session_id won't be
941  // change and logout won't be handle because of that
942  $this->_setChangeSessionID($changeSessionID);
943 
944  // skip Session Handling for logout requests and if don't want it'
945  if (session_id() == "" && !$this->_isLogoutRequest()) {
946  session_start();
947  phpCAS :: trace("Starting a new session " . session_id());
948  }
949  // Only for debug purposes
950  if ($this->isSessionAuthenticated()) {
951  phpCAS :: trace("Session is authenticated as: " . $_SESSION['phpCAS']['user']);
952  } else {
953  phpCAS :: trace("Session is not authenticated");
954  }
955  // are we in proxy mode ?
956  $this->_proxy = $proxy;
957 
958  // Make cookie handling available.
959  if ($this->isProxy()) {
960  if (!isset($_SESSION['phpCAS'])) {
961  $_SESSION['phpCAS'] = array();
962  }
963  if (!isset($_SESSION['phpCAS']['service_cookies'])) {
964  $_SESSION['phpCAS']['service_cookies'] = array();
965  }
966  $this->_serviceCookieJar = new CAS_CookieJar(
967  $_SESSION['phpCAS']['service_cookies']
968  );
969  }
970 
971  //check version
972  switch ($server_version) {
973  case CAS_VERSION_1_0:
974  if ($this->isProxy()) {
976  'CAS proxies are not supported in CAS ' . $server_version
977  );
978  }
979  break;
980  case CAS_VERSION_2_0:
981  case CAS_VERSION_3_0:
982  break;
983  case SAML_VERSION_1_1:
984  break;
985  default:
987  'this version of CAS (`' . $server_version
988  . '\') is not supported by phpCAS ' . phpCAS::getVersion()
989  );
990  }
991  $this->_server['version'] = $server_version;
992 
993  // check hostname
994  if (empty($server_hostname)
995  || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/', $server_hostname)
996  ) {
997  phpCAS::error('bad CAS server hostname (`' . $server_hostname . '\')');
998  }
999  $this->_server['hostname'] = $server_hostname;
1000 
1001  // check port
1002  if ($server_port == 0
1003  || !is_int($server_port)
1004  ) {
1005  phpCAS::error('bad CAS server port (`' . $server_hostname . '\')');
1006  }
1007  $this->_server['port'] = $server_port;
1008 
1009  // check URI
1010  if (!preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/', $server_uri)) {
1011  phpCAS::error('bad CAS server URI (`' . $server_uri . '\')');
1012  }
1013  // add leading and trailing `/' and remove doubles
1014  if (strstr($server_uri, '?') === false) {
1015  $server_uri .= '/';
1016  }
1017  $server_uri = preg_replace('/\/\//', '/', '/' . $server_uri);
1018  $this->_server['uri'] = $server_uri;
1019 
1020  // set to callback mode if PgtIou and PgtId CGI GET parameters are provided
1021  if ($this->isProxy()) {
1022  $this->_setCallbackMode(!empty($_GET['pgtIou']) && !empty($_GET['pgtId']));
1023  }
1024 
1025  if ($this->_isCallbackMode()) {
1026  //callback mode: check that phpCAS is secured
1027  if (!$this->_isHttps()) {
1028  phpCAS::error(
1029  'CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server'
1030  );
1031  }
1032  } else {
1033  //normal mode: get ticket and remove it from CGI parameters for
1034  // developers
1035  $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
1036  if (preg_match('/^[SP]T-/', $ticket)) {
1037  phpCAS::trace('Ticket \'' . $ticket . '\' found');
1038  $this->setTicket($ticket);
1039  unset($_GET['ticket']);
1040  } elseif (!empty($ticket)) {
1041  //ill-formed ticket, halt
1042  phpCAS::error(
1043  'ill-formed ticket found in the URL (ticket=`'
1044  . htmlentities($ticket) . '\')'
1045  );
1046  }
1047  }
1048  phpCAS::traceEnd();
1049  }
1050 
1053  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1054  // XX XX
1055  // XX Session Handling XX
1056  // XX XX
1057  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1058 
1069  private $_change_session_id = true;
1070 
1078  private function _setChangeSessionID($allowed)
1079  {
1080  $this->_change_session_id = $allowed;
1081  }
1082 
1088  public function getChangeSessionID()
1089  {
1091  }
1092 
1095  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1096  // XX XX
1097  // XX AUTHENTICATION XX
1098  // XX XX
1099  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1100 
1112  private $_user = '';
1113 
1121  private function _setUser($user)
1122  {
1123  $this->_user = $user;
1124  }
1125 
1134  public function getUser()
1135  {
1136  // Sequence validation
1138 
1139  return $this->_getUser();
1140  }
1141 
1150  private function _getUser()
1151  {
1152  // This is likely a duplicate check that could be removed....
1153  if (empty($this->_user)) {
1154  phpCAS::error(
1155  'this method should be used only after ' . __CLASS__
1156  . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()'
1157  );
1158  }
1159  return $this->_user;
1160  }
1161 
1169  private $_attributes = array();
1170 
1178  public function setAttributes($attributes)
1179  {
1180  $this->_attributes = $attributes;
1181  }
1182 
1188  public function getAttributes()
1189  {
1190  // Sequence validation
1192  // This is likely a duplicate check that could be removed....
1193  if (empty($this->_user)) {
1194  // if no user is set, there shouldn't be any attributes also...
1195  phpCAS::error(
1196  'this method should be used only after ' . __CLASS__
1197  . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()'
1198  );
1199  }
1200  return $this->_attributes;
1201  }
1202 
1208  public function hasAttributes()
1209  {
1210  // Sequence validation
1212 
1213  return !empty($this->_attributes);
1214  }
1222  public function hasAttribute($key)
1223  {
1224  // Sequence validation
1226 
1227  return $this->_hasAttribute($key);
1228  }
1229 
1237  private function _hasAttribute($key)
1238  {
1239  return (is_array($this->_attributes)
1240  && array_key_exists($key, $this->_attributes));
1241  }
1242 
1250  public function getAttribute($key)
1251  {
1252  // Sequence validation
1254 
1255  if ($this->_hasAttribute($key)) {
1256  return $this->_attributes[$key];
1257  }
1258  }
1259 
1267  public function renewAuthentication()
1268  {
1270  // Either way, the user is authenticated by CAS
1271  if (isset($_SESSION['phpCAS']['auth_checked'])) {
1272  unset($_SESSION['phpCAS']['auth_checked']);
1273  }
1274  if ($this->isAuthenticated(true)) {
1275  phpCAS::trace('user already authenticated');
1276  $res = true;
1277  } else {
1278  $this->redirectToCas(false, true);
1279  // never reached
1280  $res = false;
1281  }
1282  phpCAS::traceEnd();
1283  return $res;
1284  }
1285 
1292  public function forceAuthentication()
1293  {
1295 
1296  if ($this->isAuthenticated()) {
1297  // the user is authenticated, nothing to be done.
1298  phpCAS::trace('no need to authenticate');
1299  $res = true;
1300  } else {
1301  // the user is not authenticated, redirect to the CAS server
1302  if (isset($_SESSION['phpCAS']['auth_checked'])) {
1303  unset($_SESSION['phpCAS']['auth_checked']);
1304  }
1305  $this->redirectToCas(false/* no gateway */);
1306  // never reached
1307  $res = false;
1308  }
1310  return $res;
1311  }
1312 
1320 
1329  {
1330  if (gettype($n) != 'integer') {
1331  throw new CAS_TypeMismatchException($n, '$n', 'string');
1332  }
1333 
1334  $this->_cache_times_for_auth_recheck = $n;
1335  }
1336 
1344  public function checkAuthentication()
1345  {
1347  $res = false;
1348  if ($this->isAuthenticated()) {
1349  phpCAS::trace('user is authenticated');
1350  /* The 'auth_checked' variable is removed just in case it's set. */
1351  unset($_SESSION['phpCAS']['auth_checked']);
1352  $res = true;
1353  } elseif (isset($_SESSION['phpCAS']['auth_checked'])) {
1354  // the previous request has redirected the client to the CAS server
1355  // with gateway=true
1356  unset($_SESSION['phpCAS']['auth_checked']);
1357  $res = false;
1358  } else {
1359  // avoid a check against CAS on every request
1360  if (!isset($_SESSION['phpCAS']['unauth_count'])) {
1361  $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized
1362  }
1363 
1364  if (($_SESSION['phpCAS']['unauth_count'] != -2
1365  && $this->_cache_times_for_auth_recheck == -1)
1366  || ($_SESSION['phpCAS']['unauth_count'] >= 0
1367  && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck)
1368  ) {
1369  $res = false;
1370 
1371  if ($this->_cache_times_for_auth_recheck != -1) {
1372  $_SESSION['phpCAS']['unauth_count']++;
1373  phpCAS::trace(
1374  'user is not authenticated (cached for '
1375  . $_SESSION['phpCAS']['unauth_count'] . ' times of '
1376  . $this->_cache_times_for_auth_recheck . ')'
1377  );
1378  } else {
1379  phpCAS::trace(
1380  'user is not authenticated (cached for until login pressed)'
1381  );
1382  }
1383  } else {
1384  $_SESSION['phpCAS']['unauth_count'] = 0;
1385  $_SESSION['phpCAS']['auth_checked'] = true;
1386  phpCAS::trace('user is not authenticated (cache reset)');
1387  $this->redirectToCas(true/* gateway */);
1388  // never reached
1389  $res = false;
1390  }
1391  }
1393  return $res;
1394  }
1395 
1405  public function isAuthenticated($renew = false)
1406  {
1408  $res = false;
1409  $validate_url = '';
1410  if ($this->_wasPreviouslyAuthenticated()) {
1411  if ($this->hasTicket()) {
1412  // User has a additional ticket but was already authenticated
1413  phpCAS::trace(
1414  'ticket was present and will be discarded, use renewAuthenticate()'
1415  );
1416  if ($this->_clearTicketsFromUrl) {
1417  phpCAS::trace("Prepare redirect to : " . $this->getURL());
1418  session_write_close();
1419  header('Location: ' . $this->getURL());
1420  flush();
1423  } else {
1424  phpCAS::trace(
1425  'Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.'
1426  );
1427  $res = true;
1428  }
1429  } else {
1430  // the user has already (previously during the session) been
1431  // authenticated, nothing to be done.
1432  phpCAS::trace(
1433  'user was already authenticated, no need to look for tickets'
1434  );
1435  $res = true;
1436  }
1437 
1438  // Mark the auth-check as complete to allow post-authentication
1439  // callbacks to make use of phpCAS::getUser() and similar methods
1440  $this->markAuthenticationCall($res);
1441  } else {
1442  if ($this->hasTicket()) {
1443  switch ($this->getServerVersion()) {
1444  case CAS_VERSION_1_0:
1445  // if a Service Ticket was given, validate it
1446  phpCAS::trace(
1447  'CAS 1.0 ticket `' . $this->getTicket() . '\' is present'
1448  );
1449  $this->validateCAS10(
1450  $validate_url,
1451  $text_response,
1452  $tree_response,
1453  $renew
1454  ); // if it fails, it halts
1455  phpCAS::trace(
1456  'CAS 1.0 ticket `' . $this->getTicket() . '\' was validated'
1457  );
1458  $_SESSION['phpCAS']['user'] = $this->_getUser();
1459  $res = true;
1460  $logoutTicket = $this->getTicket();
1461  break;
1462  case CAS_VERSION_2_0:
1463  case CAS_VERSION_3_0:
1464  // if a Proxy Ticket was given, validate it
1465  phpCAS::trace(
1466  'CAS ' . $this->getServerVersion() . ' ticket `' . $this->getTicket() . '\' is present'
1467  );
1468  $this->validateCAS20(
1469  $validate_url,
1470  $text_response,
1471  $tree_response,
1472  $renew
1473  ); // note: if it fails, it halts
1474  phpCAS::trace(
1475  'CAS ' . $this->getServerVersion() . ' ticket `' . $this->getTicket() . '\' was validated'
1476  );
1477  if ($this->isProxy()) {
1478  $this->_validatePGT(
1479  $validate_url,
1480  $text_response,
1481  $tree_response
1482  ); // idem
1483  phpCAS::trace('PGT `' . $this->_getPGT() . '\' was validated');
1484  $_SESSION['phpCAS']['pgt'] = $this->_getPGT();
1485  }
1486  $_SESSION['phpCAS']['user'] = $this->_getUser();
1487  if (!empty($this->_attributes)) {
1488  $_SESSION['phpCAS']['attributes'] = $this->_attributes;
1489  }
1490  $proxies = $this->getProxies();
1491  if (!empty($proxies)) {
1492  $_SESSION['phpCAS']['proxies'] = $this->getProxies();
1493  }
1494  $res = true;
1495  $logoutTicket = $this->getTicket();
1496  break;
1497  case SAML_VERSION_1_1:
1498  // if we have a SAML ticket, validate it.
1499  phpCAS::trace(
1500  'SAML 1.1 ticket `' . $this->getTicket() . '\' is present'
1501  );
1502  $this->validateSA(
1503  $validate_url,
1504  $text_response,
1505  $tree_response,
1506  $renew
1507  ); // if it fails, it halts
1508  phpCAS::trace(
1509  'SAML 1.1 ticket `' . $this->getTicket() . '\' was validated'
1510  );
1511  $_SESSION['phpCAS']['user'] = $this->_getUser();
1512  $_SESSION['phpCAS']['attributes'] = $this->_attributes;
1513  $res = true;
1514  $logoutTicket = $this->getTicket();
1515  break;
1516  default:
1517  phpCAS::trace('Protocoll error');
1518  break;
1519  }
1520  } else {
1521  // no ticket given, not authenticated
1522  phpCAS::trace('no ticket found');
1523  }
1524 
1525  // Mark the auth-check as complete to allow post-authentication
1526  // callbacks to make use of phpCAS::getUser() and similar methods
1527  $this->markAuthenticationCall($res);
1528 
1529  if ($res) {
1530  // call the post-authenticate callback if registered.
1531  if ($this->_postAuthenticateCallbackFunction) {
1532  $args = $this->_postAuthenticateCallbackArgs;
1533  array_unshift($args, $logoutTicket);
1534  call_user_func_array(
1535  $this->_postAuthenticateCallbackFunction,
1536  $args
1537  );
1538  }
1539 
1540  // if called with a ticket parameter, we need to redirect to the
1541  // app without the ticket so that CAS-ification is transparent
1542  // to the browser (for later POSTS) most of the checks and
1543  // errors should have been made now, so we're safe for redirect
1544  // without masking error messages. remove the ticket as a
1545  // security precaution to prevent a ticket in the HTTP_REFERRER
1546  if ($this->_clearTicketsFromUrl) {
1547  phpCAS::trace("Prepare redirect to : " . $this->getURL());
1548  session_write_close();
1549  header('Location: ' . $this->getURL());
1550  flush();
1553  }
1554  }
1555  }
1557  return $res;
1558  }
1559 
1565  public function isSessionAuthenticated()
1566  {
1567  return !empty($_SESSION['phpCAS']['user']);
1568  }
1569 
1578  private function _wasPreviouslyAuthenticated()
1579  {
1581 
1582  if ($this->_isCallbackMode()) {
1583  // Rebroadcast the pgtIou and pgtId to all nodes
1584  if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) {
1585  $this->_rebroadcast(self::PGTIOU);
1586  }
1587  $this->_callback();
1588  }
1589 
1590  $auth = false;
1591 
1592  if ($this->isProxy()) {
1593  // CAS proxy: username and PGT must be present
1594  if ($this->isSessionAuthenticated()
1595  && !empty($_SESSION['phpCAS']['pgt'])
1596  ) {
1597  // authentication already done
1598  $this->_setUser($_SESSION['phpCAS']['user']);
1599  if (isset($_SESSION['phpCAS']['attributes'])) {
1600  $this->setAttributes($_SESSION['phpCAS']['attributes']);
1601  }
1602  $this->_setPGT($_SESSION['phpCAS']['pgt']);
1603  phpCAS::trace(
1604  'user = `' . $_SESSION['phpCAS']['user'] . '\', PGT = `'
1605  . $_SESSION['phpCAS']['pgt'] . '\''
1606  );
1607 
1608  // Include the list of proxies
1609  if (isset($_SESSION['phpCAS']['proxies'])) {
1610  $this->_setProxies($_SESSION['phpCAS']['proxies']);
1611  phpCAS::trace(
1612  'proxies = "'
1613  . implode('", "', $_SESSION['phpCAS']['proxies']) . '"'
1614  );
1615  }
1616 
1617  $auth = true;
1618  } elseif ($this->isSessionAuthenticated()
1619  && empty($_SESSION['phpCAS']['pgt'])
1620  ) {
1621  // these two variables should be empty or not empty at the same time
1622  phpCAS::trace(
1623  'username found (`' . $_SESSION['phpCAS']['user']
1624  . '\') but PGT is empty'
1625  );
1626  // unset all tickets to enforce authentication
1627  unset($_SESSION['phpCAS']);
1628  $this->setTicket('');
1629  } elseif (!$this->isSessionAuthenticated()
1630  && !empty($_SESSION['phpCAS']['pgt'])
1631  ) {
1632  // these two variables should be empty or not empty at the same time
1633  phpCAS::trace(
1634  'PGT found (`' . $_SESSION['phpCAS']['pgt']
1635  . '\') but username is empty'
1636  );
1637  // unset all tickets to enforce authentication
1638  unset($_SESSION['phpCAS']);
1639  $this->setTicket('');
1640  } else {
1641  phpCAS::trace('neither user nor PGT found');
1642  }
1643  } else {
1644  // `simple' CAS client (not a proxy): username must be present
1645  if ($this->isSessionAuthenticated()) {
1646  // authentication already done
1647  $this->_setUser($_SESSION['phpCAS']['user']);
1648  if (isset($_SESSION['phpCAS']['attributes'])) {
1649  $this->setAttributes($_SESSION['phpCAS']['attributes']);
1650  }
1651  phpCAS::trace('user = `' . $_SESSION['phpCAS']['user'] . '\'');
1652 
1653  // Include the list of proxies
1654  if (isset($_SESSION['phpCAS']['proxies'])) {
1655  $this->_setProxies($_SESSION['phpCAS']['proxies']);
1656  phpCAS::trace(
1657  'proxies = "'
1658  . implode('", "', $_SESSION['phpCAS']['proxies']) . '"'
1659  );
1660  }
1661 
1662  $auth = true;
1663  } else {
1664  phpCAS::trace('no user found');
1665  }
1666  }
1667 
1669  return $auth;
1670  }
1671 
1682  public function redirectToCas($gateway = false, $renew = false)
1683  {
1685  $cas_url = $this->getServerLoginURL($gateway, $renew);
1686  session_write_close();
1687  if (php_sapi_name() === 'cli') {
1688  @header('Location: ' . $cas_url);
1689  } else {
1690  header('Location: ' . $cas_url);
1691  }
1692  phpCAS::trace("Redirect to : " . $cas_url);
1693  $lang = $this->getLangObj();
1694  $this->printHTMLHeader($lang->getAuthenticationWanted());
1695  printf('<p>' . $lang->getShouldHaveBeenRedirected() . '</p>', $cas_url);
1696  $this->printHTMLFooter();
1699  }
1700 
1701 
1710  public function logout($params)
1711  {
1713  $cas_url = $this->getServerLogoutURL();
1714  $paramSeparator = '?';
1715  if (isset($params['url'])) {
1716  $cas_url = $cas_url . $paramSeparator . "url="
1717  . urlencode($params['url']);
1718  $paramSeparator = '&';
1719  }
1720  if (isset($params['service'])) {
1721  $cas_url = $cas_url . $paramSeparator . "service="
1722  . urlencode($params['service']);
1723  }
1724  header('Location: ' . $cas_url);
1725  phpCAS::trace("Prepare redirect to : " . $cas_url);
1726 
1727  phpCAS::trace("Destroying session : " . session_id());
1728  session_unset();
1729  session_destroy();
1730  if (session_status() === PHP_SESSION_NONE) {
1731  phpCAS::trace("Session terminated");
1732  } else {
1733  phpCAS::error("Session was not terminated");
1734  phpCAS::trace("Session was not terminated");
1735  }
1736  $lang = $this->getLangObj();
1737  $this->printHTMLHeader($lang->getLogout());
1738  printf('<p>' . $lang->getShouldHaveBeenRedirected() . '</p>', $cas_url);
1739  $this->printHTMLFooter();
1742  }
1743 
1749  private function _isLogoutRequest()
1750  {
1751  return !empty($_POST['logoutRequest']);
1752  }
1753 
1764  public function handleLogoutRequests($check_client = true, $allowed_clients = false)
1765  {
1767  if (!$this->_isLogoutRequest()) {
1768  phpCAS::trace("Not a logout request");
1769  phpCAS::traceEnd();
1770  return;
1771  }
1772  if (!$this->getChangeSessionID()
1773  && is_null($this->_signoutCallbackFunction)
1774  ) {
1775  phpCAS::trace(
1776  "phpCAS can't handle logout requests if it is not allowed to change session_id."
1777  );
1778  }
1779  phpCAS::trace("Logout requested");
1780  $decoded_logout_rq = urldecode($_POST['logoutRequest']);
1781  phpCAS::trace("SAML REQUEST: " . $decoded_logout_rq);
1782  $allowed = false;
1783  if ($check_client) {
1784  if (!$allowed_clients) {
1785  $allowed_clients = array( $this->_getServerHostname() );
1786  }
1787  $client_ip = $_SERVER['REMOTE_ADDR'];
1788  $client = gethostbyaddr($client_ip);
1789  phpCAS::trace("Client: " . $client . "/" . $client_ip);
1790  foreach ($allowed_clients as $allowed_client) {
1791  if (($client == $allowed_client)
1792  || ($client_ip == $allowed_client)
1793  ) {
1794  phpCAS::trace(
1795  "Allowed client '" . $allowed_client
1796  . "' matches, logout request is allowed"
1797  );
1798  $allowed = true;
1799  break;
1800  } else {
1801  phpCAS::trace(
1802  "Allowed client '" . $allowed_client . "' does not match"
1803  );
1804  }
1805  }
1806  } else {
1807  phpCAS::trace("No access control set");
1808  $allowed = true;
1809  }
1810  // If Logout command is permitted proceed with the logout
1811  if ($allowed) {
1812  phpCAS::trace("Logout command allowed");
1813  // Rebroadcast the logout request
1814  if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) {
1815  $this->_rebroadcast(self::LOGOUT);
1816  }
1817  // Extract the ticket from the SAML Request
1818  preg_match(
1819  "|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|",
1820  $decoded_logout_rq,
1821  $tick,
1822  PREG_OFFSET_CAPTURE,
1823  3
1824  );
1825  $wrappedSamlSessionIndex = preg_replace(
1826  '|<samlp:SessionIndex>|',
1827  '',
1828  $tick[0][0]
1829  );
1830  $ticket2logout = preg_replace(
1831  '|</samlp:SessionIndex>|',
1832  '',
1833  $wrappedSamlSessionIndex
1834  );
1835  phpCAS::trace("Ticket to logout: " . $ticket2logout);
1836 
1837  // call the post-authenticate callback if registered.
1838  if ($this->_signoutCallbackFunction) {
1840  array_unshift($args, $ticket2logout);
1841  call_user_func_array($this->_signoutCallbackFunction, $args);
1842  }
1843 
1844  // If phpCAS is managing the session_id, destroy session thanks to
1845  // session_id.
1846  if ($this->getChangeSessionID()) {
1847  $session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket2logout);
1848  phpCAS::trace("Session id: " . $session_id);
1849 
1850  // destroy a possible application session created before phpcas
1851  if (session_id() !== "") {
1852  session_unset();
1853  session_destroy();
1854  }
1855  // fix session ID
1856  session_id($session_id);
1857  $_COOKIE[session_name()] = $session_id;
1858  $_GET[session_name()] = $session_id;
1859 
1860  // Overwrite session
1861  session_start();
1862  session_unset();
1863  session_destroy();
1864  phpCAS::trace("Session " . $session_id . " destroyed");
1865  }
1866  } else {
1867  phpCAS::error("Unauthorized logout request from client '" . $client . "'");
1868  phpCAS::trace("Unauthorized logout request from client '" . $client . "'");
1869  }
1870  flush();
1873  }
1874 
1877  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1878  // XX XX
1879  // XX BASIC CLIENT FEATURES (CAS 1.0) XX
1880  // XX XX
1881  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1882 
1883  // ########################################################################
1884  // ST
1885  // ########################################################################
1898  private $_ticket = '';
1899 
1905  public function getTicket()
1906  {
1907  return $this->_ticket;
1908  }
1909 
1917  public function setTicket($st)
1918  {
1919  $this->_ticket = $st;
1920  }
1921 
1927  public function hasTicket()
1928  {
1929  return !empty($this->_ticket);
1930  }
1931 
1934  // ########################################################################
1935  // ST VALIDATION
1936  // ########################################################################
1947  private $_cas_server_ca_cert = null;
1948 
1949 
1961 
1968 
1969 
1979  public function setCasServerCACert($cert, $validate_cn)
1980  {
1981  // Argument validation
1982  if (gettype($cert) != 'string') {
1983  throw new CAS_TypeMismatchException($cert, '$cert', 'string');
1984  }
1985  if (gettype($validate_cn) != 'boolean') {
1986  throw new CAS_TypeMismatchException($validate_cn, '$validate_cn', 'boolean');
1987  }
1988  if (!file_exists($cert) && $this->_requestImplementation !== 'CAS_TestHarness_DummyRequest') {
1989  throw new CAS_InvalidArgumentException("Certificate file does not exist " . $this->_requestImplementation);
1990  }
1991  $this->_cas_server_ca_cert = $cert;
1992  $this->_cas_server_cn_validate = $validate_cn;
1993  }
1994 
2000  public function setNoCasServerValidation()
2001  {
2002  $this->_no_cas_server_validation = true;
2003  }
2004 
2020  public function validateCAS10(&$validate_url, &$text_response, &$tree_response, $renew = false)
2021  {
2023  $result = false;
2024  // build the URL to validate the ticket
2025  $validate_url = $this->getServerServiceValidateURL()
2026  . '&ticket=' . urlencode($this->getTicket());
2027 
2028  if ($renew) {
2029  // pass the renew
2030  $validate_url .= '&renew=true';
2031  }
2032 
2033  // open and read the URL
2034  if (!$this->_readURL($validate_url, $headers, $text_response, $err_msg)) {
2035  phpCAS::trace(
2036  'could not open URL \'' . $validate_url . '\' to validate (' . $err_msg . ')'
2037  );
2038  throw new CAS_AuthenticationException(
2039  $this,
2040  'CAS 1.0 ticket not validated',
2041  $validate_url,
2042  true/*$no_response*/
2043  );
2044  $result = false;
2045  }
2046 
2047  if (preg_match('/^no\n/', $text_response)) {
2048  phpCAS::trace('Ticket has not been validated');
2049  throw new CAS_AuthenticationException(
2050  $this,
2051  'ST not validated',
2052  $validate_url,
2053  false/*$no_response*/,
2054  false/*$bad_response*/,
2055  $text_response
2056  );
2057  $result = false;
2058  } elseif (!preg_match('/^yes\n/', $text_response)) {
2059  phpCAS::trace('ill-formed response');
2060  throw new CAS_AuthenticationException(
2061  $this,
2062  'Ticket not validated',
2063  $validate_url,
2064  false/*$no_response*/,
2065  true/*$bad_response*/,
2066  $text_response
2067  );
2068  $result = false;
2069  }
2070  // ticket has been validated, extract the user name
2071  $arr = preg_split('/\n/', $text_response);
2072  $this->_setUser(trim($arr[1]));
2073  $result = true;
2074 
2075  if ($result) {
2076  $this->_renameSession($this->getTicket());
2077  }
2078  // at this step, ticket has been validated and $this->_user has been set,
2079  phpCAS::traceEnd(true);
2080  return true;
2081  }
2082 
2086  // ########################################################################
2087  // SAML VALIDATION
2088  // ########################################################################
2110  public function validateSA(&$validate_url, &$text_response, &$tree_response, $renew = false)
2111  {
2112  phpCAS::traceBegin();
2113  $result = false;
2114  // build the URL to validate the ticket
2115  $validate_url = $this->getServerSamlValidateURL();
2116 
2117  if ($renew) {
2118  // pass the renew
2119  $validate_url .= '&renew=true';
2120  }
2121 
2122  // open and read the URL
2123  if (!$this->_readURL($validate_url, $headers, $text_response, $err_msg)) {
2124  phpCAS::trace(
2125  'could not open URL \'' . $validate_url . '\' to validate (' . $err_msg . ')'
2126  );
2127  throw new CAS_AuthenticationException(
2128  $this,
2129  'SA not validated',
2130  $validate_url,
2131  true/*$no_response*/
2132  );
2133  }
2134 
2135  phpCAS::trace('server version: ' . $this->getServerVersion());
2136 
2137  // analyze the result depending on the version
2138  switch ($this->getServerVersion()) {
2139  case SAML_VERSION_1_1:
2140  // create new DOMDocument Object
2141  $dom = new DOMDocument();
2142  // Fix possible whitspace problems
2143  $dom->preserveWhiteSpace = false;
2144  // read the response of the CAS server into a DOM object
2145  if (!($dom->loadXML($text_response))) {
2146  phpCAS::trace('dom->loadXML() failed');
2147  throw new CAS_AuthenticationException(
2148  $this,
2149  'SA not validated',
2150  $validate_url,
2151  false/*$no_response*/,
2152  true/*$bad_response*/,
2153  $text_response
2154  );
2155  $result = false;
2156  }
2157  // read the root node of the XML tree
2158  if (!($tree_response = $dom->documentElement)) {
2159  phpCAS::trace('documentElement() failed');
2160  throw new CAS_AuthenticationException(
2161  $this,
2162  'SA not validated',
2163  $validate_url,
2164  false/*$no_response*/,
2165  true/*$bad_response*/,
2166  $text_response
2167  );
2168  $result = false;
2169  } elseif ($tree_response->localName != 'Envelope') {
2170  // insure that tag name is 'Envelope'
2171  phpCAS::trace(
2172  'bad XML root node (should be `Envelope\' instead of `'
2173  . $tree_response->localName . '\''
2174  );
2175  throw new CAS_AuthenticationException(
2176  $this,
2177  'SA not validated',
2178  $validate_url,
2179  false/*$no_response*/,
2180  true/*$bad_response*/,
2181  $text_response
2182  );
2183  $result = false;
2184  } elseif ($tree_response->getElementsByTagName("NameIdentifier")->length != 0) {
2185  // check for the NameIdentifier tag in the SAML response
2186  $success_elements = $tree_response->getElementsByTagName("NameIdentifier");
2187  phpCAS::trace('NameIdentifier found');
2188  $user = trim($success_elements->item(0)->nodeValue);
2189  phpCAS::trace('user = `' . $user . '`');
2190  $this->_setUser($user);
2191  $this->_setSessionAttributes($text_response);
2192  $result = true;
2193  } else {
2194  phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
2195  throw new CAS_AuthenticationException(
2196  $this,
2197  'SA not validated',
2198  $validate_url,
2199  false/*$no_response*/,
2200  true/*$bad_response*/,
2201  $text_response
2202  );
2203  $result = false;
2204  }
2205  }
2206  if ($result) {
2207  $this->_renameSession($this->getTicket());
2208  }
2209  // at this step, ST has been validated and $this->_user has been set,
2211  return $result;
2212  }
2213 
2222  private function _setSessionAttributes($text_response)
2223  {
2225 
2226  $result = false;
2227 
2228  $attr_array = array();
2229 
2230  // create new DOMDocument Object
2231  $dom = new DOMDocument();
2232  // Fix possible whitspace problems
2233  $dom->preserveWhiteSpace = false;
2234  if (($dom->loadXML($text_response))) {
2235  $xPath = new DOMXpath($dom);
2236  $xPath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
2237  $xPath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
2238  $nodelist = $xPath->query("//saml:Attribute");
2239 
2240  if ($nodelist) {
2241  foreach ($nodelist as $node) {
2242  $xres = $xPath->query("saml:AttributeValue", $node);
2243  $name = $node->getAttribute("AttributeName");
2244  $value_array = array();
2245  foreach ($xres as $node2) {
2246  $value_array[] = $node2->nodeValue;
2247  }
2248  $attr_array[$name] = $value_array;
2249  }
2250  // UGent addition...
2251  foreach ($attr_array as $attr_key => $attr_value) {
2252  if (count($attr_value) > 1) {
2253  $this->_attributes[$attr_key] = $attr_value;
2254  phpCAS::trace("* " . $attr_key . "=" . print_r($attr_value, true));
2255  } else {
2256  $this->_attributes[$attr_key] = $attr_value[0];
2257  phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
2258  }
2259  }
2260  $result = true;
2261  } else {
2262  phpCAS::trace("SAML Attributes are empty");
2263  $result = false;
2264  }
2265  }
2267  return $result;
2268  }
2269 
2272  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2273  // XX XX
2274  // XX PROXY FEATURES (CAS 2.0) XX
2275  // XX XX
2276  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2277 
2278  // ########################################################################
2279  // PROXYING
2280  // ########################################################################
2290  private $_proxy;
2291 
2296 
2302  public function isProxy()
2303  {
2304  return $this->_proxy;
2305  }
2306 
2307 
2309  // ########################################################################
2310  // PGT
2311  // ########################################################################
2324  private $_pgt = '';
2325 
2331  private function _getPGT()
2332  {
2333  return $this->_pgt;
2334  }
2335 
2343  private function _setPGT($pgt)
2344  {
2345  $this->_pgt = $pgt;
2346  }
2347 
2353  private function _hasPGT()
2354  {
2355  return !empty($this->_pgt);
2356  }
2357 
2360  // ########################################################################
2361  // CALLBACK MODE
2362  // ########################################################################
2379  private $_callback_mode = false;
2380 
2388  private function _setCallbackMode($callback_mode)
2389  {
2390  $this->_callback_mode = $callback_mode;
2391  }
2392 
2399  private function _isCallbackMode()
2400  {
2401  return $this->_callback_mode;
2402  }
2403 
2411  private $_callback_url = '';
2412 
2420  private function _getCallbackURL()
2421  {
2422  // the URL is built when needed only
2423  if (empty($this->_callback_url)) {
2424  $final_uri = '';
2425  // remove the ticket if present in the URL
2426  $final_uri = 'https://';
2427  $final_uri .= $this->_getClientUrl();
2428  $request_uri = $_SERVER['REQUEST_URI'];
2429  $request_uri = preg_replace('/\?.*$/', '', $request_uri);
2430  $final_uri .= $request_uri;
2431  $this->_callback_url = $final_uri;
2432  }
2433  return $this->_callback_url;
2434  }
2435 
2443  public function setCallbackURL($url)
2444  {
2445  // Sequence validation
2446  $this->ensureIsProxy();
2447  // Argument Validation
2448  if (gettype($url) != 'string') {
2449  throw new CAS_TypeMismatchException($url, '$url', 'string');
2450  }
2451 
2452  return $this->_callback_url = $url;
2453  }
2454 
2461  private function _callback()
2462  {
2464  if (preg_match('/PGTIOU-[\.\-\w]/', $_GET['pgtIou'])) {
2465  if (preg_match('/[PT]GT-[\.\-\w]/', $_GET['pgtId'])) {
2466  $this->printHTMLHeader('phpCAS callback');
2467  $pgt_iou = $_GET['pgtIou'];
2468  $pgt = $_GET['pgtId'];
2469  phpCAS::trace('Storing PGT `' . $pgt . '\' (id=`' . $pgt_iou . '\')');
2470  echo '<p>Storing PGT `' . $pgt . '\' (id=`' . $pgt_iou . '\').</p>';
2471  $this->_storePGT($pgt, $pgt_iou);
2472  $this->printHTMLFooter();
2473  phpCAS::traceExit("Successfull Callback");
2474  } else {
2475  phpCAS::error('PGT format invalid' . $_GET['pgtId']);
2476  phpCAS::traceExit('PGT format invalid' . $_GET['pgtId']);
2477  }
2478  } else {
2479  phpCAS::error('PGTiou format invalid' . $_GET['pgtIou']);
2480  phpCAS::traceExit('PGTiou format invalid' . $_GET['pgtIou']);
2481  }
2482 
2483  // Flush the buffer to prevent from sending anything other then a 200
2484  // Success Status back to the CAS Server. The Exception would normally
2485  // report as a 500 error.
2486  flush();
2488  }
2489 
2490 
2493  // ########################################################################
2494  // PGT STORAGE
2495  // ########################################################################
2508  private $_pgt_storage = null;
2509 
2516  private function _initPGTStorage()
2517  {
2518  // if no SetPGTStorageXxx() has been used, default to file
2519  if (!is_object($this->_pgt_storage)) {
2520  $this->setPGTStorageFile();
2521  }
2522 
2523  // initializes the storage
2524  $this->_pgt_storage->init();
2525  }
2526 
2535  private function _storePGT($pgt, $pgt_iou)
2536  {
2537  // ensure that storage is initialized
2538  $this->_initPGTStorage();
2539  // writes the PGT
2540  $this->_pgt_storage->write($pgt, $pgt_iou);
2541  }
2542 
2551  private function _loadPGT($pgt_iou)
2552  {
2553  // ensure that storage is initialized
2554  $this->_initPGTStorage();
2555  // read the PGT
2556  return $this->_pgt_storage->read($pgt_iou);
2557  }
2558 
2567  public function setPGTStorage($storage)
2568  {
2569  // Sequence validation
2570  $this->ensureIsProxy();
2571 
2572  // check that the storage has not already been set
2573  if (is_object($this->_pgt_storage)) {
2574  phpCAS::error('PGT storage already defined');
2575  }
2576 
2577  // check to make sure a valid storage object was specified
2578  if (!($storage instanceof CAS_PGTStorage_AbstractStorage)) {
2579  throw new CAS_TypeMismatchException($storage, '$storage', 'CAS_PGTStorage_AbstractStorage object');
2580  }
2581 
2582  // store the PGTStorage object
2583  $this->_pgt_storage = $storage;
2584  }
2585 
2603  public function setPGTStorageDb(
2604  $dsn_or_pdo,
2605  $username = '',
2606  $password = '',
2607  $table = '',
2608  $driver_options = null
2609  ) {
2610  // Sequence validation
2611  $this->ensureIsProxy();
2612 
2613  // Argument validation
2614  if ((is_object($dsn_or_pdo) && !($dsn_or_pdo instanceof PDO)) || gettype($dsn_or_pdo) != 'string') {
2615  throw new CAS_TypeMismatchException($dsn_or_pdo, '$dsn_or_pdo', 'string or PDO object');
2616  }
2617  if (gettype($username) != 'string') {
2618  throw new CAS_TypeMismatchException($username, '$username', 'string');
2619  }
2620  if (gettype($password) != 'string') {
2621  throw new CAS_TypeMismatchException($password, '$password', 'string');
2622  }
2623  if (gettype($table) != 'string') {
2624  throw new CAS_TypeMismatchException($table, '$password', 'string');
2625  }
2626 
2627  // create the storage object
2628  $this->setPGTStorage(
2629  new CAS_PGTStorage_Db(
2630  $this,
2631  $dsn_or_pdo,
2632  $username,
2633  $password,
2634  $table,
2635  $driver_options
2636  )
2637  );
2638  }
2639 
2648  public function setPGTStorageFile($path = '')
2649  {
2650  // Sequence validation
2651  $this->ensureIsProxy();
2652 
2653  // Argument validation
2654  if (gettype($path) != 'string') {
2655  throw new CAS_TypeMismatchException($path, '$path', 'string');
2656  }
2657 
2658  // create the storage object
2659  $this->setPGTStorage(new CAS_PGTStorage_File($this, $path));
2660  }
2661 
2662 
2663  // ########################################################################
2664  // PGT VALIDATION
2665  // ########################################################################
2680  private function _validatePGT(&$validate_url, $text_response, $tree_response)
2681  {
2683  if ($tree_response->getElementsByTagName("proxyGrantingTicket")->length == 0) {
2684  phpCAS::trace('<proxyGrantingTicket> not found');
2685  // authentication succeded, but no PGT Iou was transmitted
2686  throw new CAS_AuthenticationException(
2687  $this,
2688  'Ticket validated but no PGT Iou transmitted',
2689  $validate_url,
2690  false/*$no_response*/,
2691  false/*$bad_response*/,
2692  $text_response
2693  );
2694  } else {
2695  // PGT Iou transmitted, extract it
2696  $pgt_iou = trim(
2697  $tree_response->getElementsByTagName("proxyGrantingTicket")->item(0)->nodeValue
2698  );
2699  if (preg_match('/PGTIOU-[\.\-\w]/', $pgt_iou)) {
2700  $pgt = $this->_loadPGT($pgt_iou);
2701  if ($pgt == false) {
2702  phpCAS::trace('could not load PGT');
2703  throw new CAS_AuthenticationException(
2704  $this,
2705  'PGT Iou was transmitted but PGT could not be retrieved',
2706  $validate_url,
2707  false/*$no_response*/,
2708  false/*$bad_response*/,
2709  $text_response
2710  );
2711  }
2712  $this->_setPGT($pgt);
2713  } else {
2714  phpCAS::trace('PGTiou format error');
2715  throw new CAS_AuthenticationException(
2716  $this,
2717  'PGT Iou was transmitted but has wrong format',
2718  $validate_url,
2719  false/*$no_response*/,
2720  false/*$bad_response*/,
2721  $text_response
2722  );
2723  }
2724  }
2725  phpCAS::traceEnd(true);
2726  return true;
2727  }
2728 
2729  // ########################################################################
2730  // PGT VALIDATION
2731  // ########################################################################
2732 
2742  public function retrievePT($target_service, &$err_code, &$err_msg)
2743  {
2744  // Argument validation
2745  if (gettype($target_service) != 'string') {
2746  throw new CAS_TypeMismatchException($target_service, '$target_service', 'string');
2747  }
2748 
2750 
2751  // by default, $err_msg is set empty and $pt to true. On error, $pt is
2752  // set to false and $err_msg to an error message. At the end, if $pt is false
2753  // and $error_msg is still empty, it is set to 'invalid response' (the most
2754  // commonly encountered error).
2755  $err_msg = '';
2756 
2757  // build the URL to retrieve the PT
2758  $cas_url = $this->getServerProxyURL() . '?targetService='
2759  . urlencode($target_service) . '&pgt=' . $this->_getPGT();
2760 
2761  // open and read the URL
2762  if (!$this->_readURL($cas_url, $headers, $cas_response, $err_msg)) {
2763  phpCAS::trace(
2764  'could not open URL \'' . $cas_url . '\' to validate (' . $err_msg . ')'
2765  );
2766  $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
2767  $err_msg = 'could not retrieve PT (no response from the CAS server)';
2768  phpCAS::traceEnd(false);
2769  return false;
2770  }
2771 
2772  $bad_response = false;
2773 
2774  if (!$bad_response) {
2775  // create new DOMDocument object
2776  $dom = new DOMDocument();
2777  // Fix possible whitspace problems
2778  $dom->preserveWhiteSpace = false;
2779  // read the response of the CAS server into a DOM object
2780  if (!($dom->loadXML($cas_response))) {
2781  phpCAS::trace('dom->loadXML() failed');
2782  // read failed
2783  $bad_response = true;
2784  }
2785  }
2786 
2787  if (!$bad_response) {
2788  // read the root node of the XML tree
2789  if (!($root = $dom->documentElement)) {
2790  phpCAS::trace('documentElement failed');
2791  // read failed
2792  $bad_response = true;
2793  }
2794  }
2795 
2796  if (!$bad_response) {
2797  // insure that tag name is 'serviceResponse'
2798  if ($root->localName != 'serviceResponse') {
2799  phpCAS::trace('localName failed');
2800  // bad root node
2801  $bad_response = true;
2802  }
2803  }
2804 
2805  if (!$bad_response) {
2806  // look for a proxySuccess tag
2807  if ($root->getElementsByTagName("proxySuccess")->length != 0) {
2808  $proxy_success_list = $root->getElementsByTagName("proxySuccess");
2809 
2810  // authentication succeded, look for a proxyTicket tag
2811  if ($proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->length != 0) {
2812  $err_code = PHPCAS_SERVICE_OK;
2813  $err_msg = '';
2814  $pt = trim(
2815  $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->item(0)->nodeValue
2816  );
2817  phpCAS::trace('original PT: ' . trim($pt));
2818  phpCAS::traceEnd($pt);
2819  return $pt;
2820  } else {
2821  phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
2822  }
2823  } elseif ($root->getElementsByTagName("proxyFailure")->length != 0) {
2824  // look for a proxyFailure tag
2825  $proxy_failure_list = $root->getElementsByTagName("proxyFailure");
2826 
2827  // authentication failed, extract the error
2828  $err_code = PHPCAS_SERVICE_PT_FAILURE;
2829  $err_msg = 'PT retrieving failed (code=`'
2830  . $proxy_failure_list->item(0)->getAttribute('code')
2831  . '\', message=`'
2832  . trim($proxy_failure_list->item(0)->nodeValue)
2833  . '\')';
2834  phpCAS::traceEnd(false);
2835  return false;
2836  } else {
2837  phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
2838  }
2839  }
2840 
2841  // at this step, we are sure that the response of the CAS server was
2842  // illformed
2843  $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
2844  $err_msg = 'Invalid response from the CAS server (response=`'
2845  . $cas_response . '\')';
2846 
2847  phpCAS::traceEnd(false);
2848  return false;
2849  }
2850 
2853  // ########################################################################
2854  // READ CAS SERVER ANSWERS
2855  // ########################################################################
2856 
2875  private function _readURL($url, &$headers, &$body, &$err_msg)
2876  {
2878  $className = $this->_requestImplementation;
2879  $request = new $className();
2880 
2881  if (count($this->_curl_options)) {
2882  $request->setCurlOptions($this->_curl_options);
2883  }
2884 
2885  $request->setUrl($url);
2886 
2887  if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) {
2888  phpCAS::error(
2889  'one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.'
2890  );
2891  }
2892  if ($this->_cas_server_ca_cert != '') {
2893  $request->setSslCaCert(
2894  $this->_cas_server_ca_cert,
2895  $this->_cas_server_cn_validate
2896  );
2897  }
2898 
2899  // add extra stuff if SAML
2900  if ($this->getServerVersion() == SAML_VERSION_1_1) {
2901  $request->addHeader("soapaction: http://www.oasis-open.org/committees/security");
2902  $request->addHeader("cache-control: no-cache");
2903  $request->addHeader("pragma: no-cache");
2904  $request->addHeader("accept: text/xml");
2905  $request->addHeader("connection: keep-alive");
2906  $request->addHeader("content-type: text/xml");
2907  $request->makePost();
2908  $request->setPostBody($this->_buildSAMLPayload());
2909  }
2910 
2911  if ($request->send()) {
2912  $headers = $request->getResponseHeaders();
2913  $body = $request->getResponseBody();
2914  $err_msg = '';
2915  phpCAS::traceEnd(true);
2916  return true;
2917  } else {
2918  $headers = '';
2919  $body = '';
2920  $err_msg = $request->getErrorMessage();
2921  phpCAS::traceEnd(false);
2922  return false;
2923  }
2924  }
2925 
2931  private function _buildSAMLPayload()
2932  {
2934 
2935  //get the ticket
2936  $sa = urlencode($this->getTicket());
2937 
2941 
2942  phpCAS::traceEnd($body);
2943  return ($body);
2944  }
2945 
2948  // ########################################################################
2949  // ACCESS TO EXTERNAL SERVICES
2950  // ########################################################################
2951 
2968  public function getProxiedService($type)
2969  {
2970  // Sequence validation
2971  $this->ensureIsProxy();
2973 
2974  // Argument validation
2975  if (gettype($type) != 'string') {
2976  throw new CAS_TypeMismatchException($type, '$type', 'string');
2977  }
2978 
2979  switch ($type) {
2982  $requestClass = $this->_requestImplementation;
2983  $request = new $requestClass();
2984  if (count($this->_curl_options)) {
2985  $request->setCurlOptions($this->_curl_options);
2986  }
2987  $proxiedService = new $type($request, $this->_serviceCookieJar);
2988  if ($proxiedService instanceof CAS_ProxiedService_Testable) {
2989  $proxiedService->setCasClient($this);
2990  }
2991  return $proxiedService;
2993  $proxiedService = new CAS_ProxiedService_Imap($this->_getUser());
2994  if ($proxiedService instanceof CAS_ProxiedService_Testable) {
2995  $proxiedService->setCasClient($this);
2996  }
2997  return $proxiedService;
2998  default:
2999  throw new CAS_InvalidArgumentException(
3000  "Unknown proxied-service type, $type."
3001  );
3002  }
3003  }
3004 
3020  public function initializeProxiedService(CAS_ProxiedService $proxiedService)
3021  {
3022  // Sequence validation
3023  $this->ensureIsProxy();
3025 
3026  $url = $proxiedService->getServiceUrl();
3027  if (!is_string($url)) {
3028  throw new CAS_ProxiedService_Exception(
3029  "Proxied Service " . get_class($proxiedService)
3030  . "->getServiceUrl() should have returned a string, returned a "
3031  . gettype($url) . " instead."
3032  );
3033  }
3034  $pt = $this->retrievePT($url, $err_code, $err_msg);
3035  if (!$pt) {
3036  throw new CAS_ProxyTicketException($err_msg, $err_code);
3037  }
3038  $proxiedService->setProxyTicket($pt);
3039  }
3040 
3055  public function serviceWeb($url, &$err_code, &$output)
3056  {
3057  // Sequence validation
3058  $this->ensureIsProxy();
3060 
3061  // Argument validation
3062  if (gettype($url) != 'string') {
3063  throw new CAS_TypeMismatchException($url, '$url', 'string');
3064  }
3065 
3066  try {
3068  $service->setUrl($url);
3069  $service->send();
3070  $output = $service->getResponseBody();
3071  $err_code = PHPCAS_SERVICE_OK;
3072  return true;
3073  } catch (CAS_ProxyTicketException $e) {
3074  $err_code = $e->getCode();
3075  $output = $e->getMessage();
3076  return false;
3077  } catch (CAS_ProxiedService_Exception $e) {
3078  $lang = $this->getLangObj();
3079  $output = sprintf(
3080  $lang->getServiceUnavailable(),
3081  $url,
3082  $e->getMessage()
3083  );
3084  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
3085  return false;
3086  }
3087  }
3088 
3108  public function serviceMail($url, $serviceUrl, $flags, &$err_code, &$err_msg, &$pt)
3109  {
3110  // Sequence validation
3111  $this->ensureIsProxy();
3113 
3114  // Argument validation
3115  if (gettype($url) != 'string') {
3116  throw new CAS_TypeMismatchException($url, '$url', 'string');
3117  }
3118  if (gettype($serviceUrl) != 'string') {
3119  throw new CAS_TypeMismatchException($serviceUrl, '$serviceUrl', 'string');
3120  }
3121  if (gettype($flags) != 'integer') {
3122  throw new CAS_TypeMismatchException($flags, '$flags', 'string');
3123  }
3124 
3125  try {
3127  $service->setServiceUrl($serviceUrl);
3128  $service->setMailbox($url);
3129  $service->setOptions($flags);
3130 
3131  $stream = $service->open();
3132  $err_code = PHPCAS_SERVICE_OK;
3133  $pt = $service->getImapProxyTicket();
3134  return $stream;
3135  } catch (CAS_ProxyTicketException $e) {
3136  $err_msg = $e->getMessage();
3137  $err_code = $e->getCode();
3138  $pt = false;
3139  return false;
3140  } catch (CAS_ProxiedService_Exception $e) {
3141  $lang = $this->getLangObj();
3142  $err_msg = sprintf(
3143  $lang->getServiceUnavailable(),
3144  $url,
3145  $e->getMessage()
3146  );
3147  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
3148  $pt = false;
3149  return false;
3150  }
3151  }
3152 
3155  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3156  // XX XX
3157  // XX PROXIED CLIENT FEATURES (CAS 2.0) XX
3158  // XX XX
3159  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3160 
3161  // ########################################################################
3162  // PT
3163  // ########################################################################
3179  private $_proxies = array();
3180 
3190  public function getProxies()
3191  {
3192  return $this->_proxies;
3193  }
3194 
3203  private function _setProxies($proxies)
3204  {
3205  $this->_proxies = $proxies;
3206  if (!empty($proxies)) {
3207  // For proxy-authenticated requests people are not viewing the URL
3208  // directly since the client is another application making a
3209  // web-service call.
3210  // Because of this, stripping the ticket from the URL is unnecessary
3211  // and causes another web-service request to be performed. Additionally,
3212  // if session handling on either the client or the server malfunctions
3213  // then the subsequent request will not complete successfully.
3214  $this->setNoClearTicketsFromUrl();
3215  }
3216  }
3217 
3224 
3230  public function getAllowedProxyChains()
3231  {
3232  if (empty($this->_allowed_proxy_chains)) {
3233  $this->_allowed_proxy_chains = new CAS_ProxyChain_AllowedList();
3234  }
3236  }
3237 
3239  // ########################################################################
3240  // PT VALIDATION
3241  // ########################################################################
3259  public function validateCAS20(&$validate_url, &$text_response, &$tree_response, $renew = false)
3260  {
3262  phpCAS::trace($text_response);
3263  $result = false;
3264  // build the URL to validate the ticket
3265  if ($this->getAllowedProxyChains()->isProxyingAllowed()) {
3266  $validate_url = $this->getServerProxyValidateURL() . '&ticket='
3267  . urlencode($this->getTicket());
3268  } else {
3269  $validate_url = $this->getServerServiceValidateURL() . '&ticket='
3270  . urlencode($this->getTicket());
3271  }
3272 
3273  if ($this->isProxy()) {
3274  // pass the callback url for CAS proxies
3275  $validate_url .= '&pgtUrl=' . urlencode($this->_getCallbackURL());
3276  }
3277 
3278  if ($renew) {
3279  // pass the renew
3280  $validate_url .= '&renew=true';
3281  }
3282 
3283  // open and read the URL
3284  if (!$this->_readURL($validate_url, $headers, $text_response, $err_msg)) {
3285  phpCAS::trace(
3286  'could not open URL \'' . $validate_url . '\' to validate (' . $err_msg . ')'
3287  );
3288  throw new CAS_AuthenticationException(
3289  $this,
3290  'Ticket not validated',
3291  $validate_url,
3292  true/*$no_response*/
3293  );
3294  $result = false;
3295  }
3296 
3297  // create new DOMDocument object
3298  $dom = new DOMDocument();
3299  // Fix possible whitspace problems
3300  $dom->preserveWhiteSpace = false;
3301  // CAS servers should only return data in utf-8
3302  $dom->encoding = "utf-8";
3303  // read the response of the CAS server into a DOMDocument object
3304  if (!($dom->loadXML($text_response))) {
3305  // read failed
3306  throw new CAS_AuthenticationException(
3307  $this,
3308  'Ticket not validated',
3309  $validate_url,
3310  false/*$no_response*/,
3311  true/*$bad_response*/,
3312  $text_response
3313  );
3314  $result = false;
3315  } elseif (!($tree_response = $dom->documentElement)) {
3316  // read the root node of the XML tree
3317  // read failed
3318  throw new CAS_AuthenticationException(
3319  $this,
3320  'Ticket not validated',
3321  $validate_url,
3322  false/*$no_response*/,
3323  true/*$bad_response*/,
3324  $text_response
3325  );
3326  $result = false;
3327  } elseif ($tree_response->localName != 'serviceResponse') {
3328  // insure that tag name is 'serviceResponse'
3329  // bad root node
3330  throw new CAS_AuthenticationException(
3331  $this,
3332  'Ticket not validated',
3333  $validate_url,
3334  false/*$no_response*/,
3335  true/*$bad_response*/,
3336  $text_response
3337  );
3338  $result = false;
3339  } elseif ($tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
3340  // authentication failed, extract the error code and message and throw exception
3341  $auth_fail_list = $tree_response
3342  ->getElementsByTagName("authenticationFailure");
3343  throw new CAS_AuthenticationException(
3344  $this,
3345  'Ticket not validated',
3346  $validate_url,
3347  false/*$no_response*/,
3348  false/*$bad_response*/,
3349  $text_response,
3350  $auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
3351  trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
3352  );
3353  $result = false;
3354  } elseif ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) {
3355  // authentication succeded, extract the user name
3356  $success_elements = $tree_response
3357  ->getElementsByTagName("authenticationSuccess");
3358  if ($success_elements->item(0)->getElementsByTagName("user")->length == 0) {
3359  // no user specified => error
3360  throw new CAS_AuthenticationException(
3361  $this,
3362  'Ticket not validated',
3363  $validate_url,
3364  false/*$no_response*/,
3365  true/*$bad_response*/,
3366  $text_response
3367  );
3368  $result = false;
3369  } else {
3370  $this->_setUser(
3371  trim(
3372  $success_elements->item(0)->getElementsByTagName("user")->item(0)->nodeValue
3373  )
3374  );
3375  $this->_readExtraAttributesCas20($success_elements);
3376  // Store the proxies we are sitting behind for authorization checking
3377  $proxyList = array();
3378  if (sizeof($arr = $success_elements->item(0)->getElementsByTagName("proxy")) > 0) {
3379  foreach ($arr as $proxyElem) {
3380  phpCAS::trace("Found Proxy: " . $proxyElem->nodeValue);
3381  $proxyList[] = trim($proxyElem->nodeValue);
3382  }
3383  $this->_setProxies($proxyList);
3384  phpCAS::trace("Storing Proxy List");
3385  }
3386  // Check if the proxies in front of us are allowed
3387  if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) {
3388  throw new CAS_AuthenticationException(
3389  $this,
3390  'Proxy not allowed',
3391  $validate_url,
3392  false/*$no_response*/,
3393  true/*$bad_response*/,
3394  $text_response
3395  );
3396  $result = false;
3397  } else {
3398  $result = true;
3399  }
3400  }
3401  } else {
3402  throw new CAS_AuthenticationException(
3403  $this,
3404  'Ticket not validated',
3405  $validate_url,
3406  false/*$no_response*/,
3407  true/*$bad_response*/,
3408  $text_response
3409  );
3410  $result = false;
3411  }
3412  if ($result) {
3413  $this->_renameSession($this->getTicket());
3414  }
3415  // at this step, Ticket has been validated and $this->_user has been set,
3416 
3417  phpCAS::traceEnd($result);
3418  return $result;
3419  }
3420 
3421 
3431  private function _readExtraAttributesCas20($success_elements)
3432  {
3433  phpCAS::traceBegin();
3434 
3435  $extra_attributes = array();
3436 
3437  // "Jasig Style" Attributes:
3438  //
3439  // <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
3440  // <cas:authenticationSuccess>
3441  // <cas:user>jsmith</cas:user>
3442  // <cas:attributes>
3443  // <cas:attraStyle>RubyCAS</cas:attraStyle>
3444  // <cas:surname>Smith</cas:surname>
3445  // <cas:givenName>John</cas:givenName>
3446  // <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
3447  // <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>
3448  // </cas:attributes>
3449  // <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
3450  // </cas:authenticationSuccess>
3451  // </cas:serviceResponse>
3452  //
3453  if ($this->_casAttributeParserCallbackFunction !== null
3454  && is_callable($this->_casAttributeParserCallbackFunction)
3455  ) {
3456  array_unshift($this->_casAttributeParserCallbackArgs, $success_elements->item(0));
3457  phpCas :: trace("Calling attritubeParser callback");
3458  $extra_attributes = call_user_func_array(
3459  $this->_casAttributeParserCallbackFunction,
3460  $this->_casAttributeParserCallbackArgs
3461  );
3462  } elseif ($success_elements->item(0)->getElementsByTagName("attributes")->length != 0) {
3463  $attr_nodes = $success_elements->item(0)
3464  ->getElementsByTagName("attributes");
3465  phpCas :: trace("Found nested jasig style attributes");
3466  if ($attr_nodes->item(0)->hasChildNodes()) {
3467  // Nested Attributes
3468  foreach ($attr_nodes->item(0)->childNodes as $attr_child) {
3469  phpCas :: trace(
3470  "Attribute [" . $attr_child->localName . "] = "
3471  . $attr_child->nodeValue
3472  );
3473  $this->_addAttributeToArray(
3474  $extra_attributes,
3475  $attr_child->localName,
3476  $attr_child->nodeValue
3477  );
3478  }
3479  }
3480  } else {
3481  // "RubyCAS Style" attributes
3482  //
3483  // <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
3484  // <cas:authenticationSuccess>
3485  // <cas:user>jsmith</cas:user>
3486  //
3487  // <cas:attraStyle>RubyCAS</cas:attraStyle>
3488  // <cas:surname>Smith</cas:surname>
3489  // <cas:givenName>John</cas:givenName>
3490  // <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
3491  // <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>
3492  //
3493  // <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
3494  // </cas:authenticationSuccess>
3495  // </cas:serviceResponse>
3496  //
3497  phpCas :: trace("Testing for rubycas style attributes");
3498  $childnodes = $success_elements->item(0)->childNodes;
3499  foreach ($childnodes as $attr_node) {
3500  switch ($attr_node->localName) {
3501  case 'user':
3502  case 'proxies':
3503  case 'proxyGrantingTicket':
3504  continue;
3505  default:
3506  if (strlen(trim($attr_node->nodeValue))) {
3507  phpCas :: trace(
3508  "Attribute [" . $attr_node->localName . "] = " . $attr_node->nodeValue
3509  );
3510  $this->_addAttributeToArray(
3511  $extra_attributes,
3512  $attr_node->localName,
3513  $attr_node->nodeValue
3514  );
3515  }
3516  }
3517  }
3518  }
3519 
3520  // "Name-Value" attributes.
3521  //
3522  // Attribute format from these mailing list thread:
3523  // http://jasig.275507.n4.nabble.com/CAS-attributes-and-how-they-appear-in-the-CAS-response-td264272.html
3524  // Note: This is a less widely used format, but in use by at least two institutions.
3525  //
3526  // <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
3527  // <cas:authenticationSuccess>
3528  // <cas:user>jsmith</cas:user>
3529  //
3530  // <cas:attribute name='attraStyle' value='Name-Value' />
3531  // <cas:attribute name='surname' value='Smith' />
3532  // <cas:attribute name='givenName' value='John' />
3533  // <cas:attribute name='memberOf' value='CN=Staff,OU=Groups,DC=example,DC=edu' />
3534  // <cas:attribute name='memberOf' value='CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu' />
3535  //
3536  // <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
3537  // </cas:authenticationSuccess>
3538  // </cas:serviceResponse>
3539  //
3540  if (!count($extra_attributes)
3541  && $success_elements->item(0)->getElementsByTagName("attribute")->length != 0
3542  ) {
3543  $attr_nodes = $success_elements->item(0)
3544  ->getElementsByTagName("attribute");
3545  $firstAttr = $attr_nodes->item(0);
3546  if (!$firstAttr->hasChildNodes()
3547  && $firstAttr->hasAttribute('name')
3548  && $firstAttr->hasAttribute('value')
3549  ) {
3550  phpCas :: trace("Found Name-Value style attributes");
3551  // Nested Attributes
3552  foreach ($attr_nodes as $attr_node) {
3553  if ($attr_node->hasAttribute('name')
3554  && $attr_node->hasAttribute('value')
3555  ) {
3556  phpCas :: trace(
3557  "Attribute [" . $attr_node->getAttribute('name')
3558  . "] = " . $attr_node->getAttribute('value')
3559  );
3560  $this->_addAttributeToArray(
3561  $extra_attributes,
3562  $attr_node->getAttribute('name'),
3563  $attr_node->getAttribute('value')
3564  );
3565  }
3566  }
3567  }
3568  }
3569 
3570  $this->setAttributes($extra_attributes);
3571  phpCAS::traceEnd();
3572  return true;
3573  }
3574 
3584  private function _addAttributeToArray(array &$attributeArray, $name, $value)
3585  {
3586  // If multiple attributes exist, add as an array value
3587  if (isset($attributeArray[$name])) {
3588  // Initialize the array with the existing value
3589  if (!is_array($attributeArray[$name])) {
3590  $existingValue = $attributeArray[$name];
3591  $attributeArray[$name] = array($existingValue);
3592  }
3593 
3594  $attributeArray[$name][] = trim($value);
3595  } else {
3596  $attributeArray[$name] = trim($value);
3597  }
3598  }
3599 
3602  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3603  // XX XX
3604  // XX MISC XX
3605  // XX XX
3606  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3607 
3613  // ########################################################################
3614  // URL
3615  // ########################################################################
3622  private $_url = '';
3623 
3624 
3632  public function setURL($url)
3633  {
3634  // Argument Validation
3635  if (gettype($url) != 'string') {
3636  throw new CAS_TypeMismatchException($url, '$url', 'string');
3637  }
3638 
3639  $this->_url = $url;
3640  }
3641 
3648  public function getURL()
3649  {
3651  // the URL is built when needed only
3652  if (empty($this->_url)) {
3653  $final_uri = '';
3654  // remove the ticket if present in the URL
3655  $final_uri = ($this->_isHttps()) ? 'https' : 'http';
3656  $final_uri .= '://';
3657 
3658  $final_uri .= $this->_getClientUrl();
3659  $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);
3660  $final_uri .= $request_uri[0];
3661 
3662  if (isset($request_uri[1]) && $request_uri[1]) {
3663  $query_string = $this->_removeParameterFromQueryString('ticket', $request_uri[1]);
3664 
3665  // If the query string still has anything left,
3666  // append it to the final URI
3667  if ($query_string !== '') {
3668  $final_uri .= "?$query_string";
3669  }
3670  }
3671 
3672  phpCAS::trace("Final URI: $final_uri");
3673  $this->setURL($final_uri);
3674  }
3675  phpCAS::traceEnd($this->_url);
3676  return $this->_url;
3677  }
3678 
3686  public function setBaseURL($url)
3687  {
3688  // Argument Validation
3689  if (gettype($url) != 'string') {
3690  throw new CAS_TypeMismatchException($url, '$url', 'string');
3691  }
3692 
3693  return $this->_server['base_url'] = $url;
3694  }
3695 
3696 
3702  private function _getClientUrl()
3703  {
3704  $server_url = '';
3705  if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
3706  // explode the host list separated by comma and use the first host
3707  $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
3708  // see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default
3709  return $hosts[0];
3710  } elseif (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
3711  $server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];
3712  } else {
3713  if (empty($_SERVER['SERVER_NAME'])) {
3714  $server_url = $_SERVER['HTTP_HOST'];
3715  } else {
3716  $server_url = $_SERVER['SERVER_NAME'];
3717  }
3718  }
3719  if (!strpos($server_url, ':')) {
3720  if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
3721  $server_port = $_SERVER['SERVER_PORT'];
3722  } else {
3723  $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);
3724  $server_port = $ports[0];
3725  }
3726 
3727  if (($this->_isHttps() && $server_port != 443)
3728  || (!$this->_isHttps() && $server_port != 80)
3729  ) {
3730  $server_url .= ':';
3731  $server_url .= $server_port;
3732  }
3733  }
3734  return $server_url;
3735  }
3736 
3742  private function _isHttps()
3743  {
3744  if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
3745  return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
3746  } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {
3747  return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https');
3748  } elseif (isset($_SERVER['HTTPS'])
3749  && !empty($_SERVER['HTTPS'])
3750  && strcasecmp($_SERVER['HTTPS'], 'off') !== 0
3751  ) {
3752  return true;
3753  }
3754  return false;
3755  }
3756 
3767  private function _removeParameterFromQueryString($parameterName, $queryString)
3768  {
3769  $parameterName = preg_quote($parameterName);
3770  return preg_replace(
3771  "/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/",
3772  '',
3773  $queryString
3774  );
3775  }
3776 
3787  private function _buildQueryUrl($url, $query)
3788  {
3789  $url .= (strstr($url, '?') === false) ? '?' : '&';
3790  $url .= $query;
3791  return $url;
3792  }
3793 
3801  private function _renameSession($ticket)
3802  {
3804  if ($this->getChangeSessionID()) {
3805  if (!empty($this->_user)) {
3806  $old_session = $_SESSION;
3807  phpCAS :: trace("Killing session: " . session_id());
3808  session_destroy();
3809  // set up a new session, of name based on the ticket
3810  $session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket);
3811  phpCAS :: trace("Starting session: " . $session_id);
3812  session_id($session_id);
3813  session_start();
3814  phpCAS :: trace("Restoring old session vars");
3815  $_SESSION = $old_session;
3816  } else {
3818  'Session should only be renamed after successfull authentication'
3819  );
3820  }
3821  } else {
3823  "Skipping session rename since phpCAS is not handling the session."
3824  );
3825  }
3826  phpCAS::traceEnd();
3827  }
3828 
3829 
3830  // ########################################################################
3831  // AUTHENTICATION ERROR HANDLING
3832  // ########################################################################
3849  private function _authError(
3850  $failure,
3851  $cas_url,
3852  $no_response,
3853  $bad_response = '',
3854  $cas_response = '',
3855  $err_code = '',
3856  $err_msg = ''
3857  ) {
3859  $lang = $this->getLangObj();
3860  $this->printHTMLHeader($lang->getAuthenticationFailed());
3861  printf(
3862  $lang->getYouWereNotAuthenticated(),
3863  htmlentities($this->getURL()),
3864  isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''
3865  );
3866  phpCAS::trace('CAS URL: ' . $cas_url);
3867  phpCAS::trace('Authentication failure: ' . $failure);
3868  if ($no_response) {
3869  phpCAS::trace('Reason: no response from the CAS server');
3870  } else {
3871  if ($bad_response) {
3872  phpCAS::trace('Reason: bad response from the CAS server');
3873  } else {
3874  switch ($this->getServerVersion()) {
3875  case CAS_VERSION_1_0:
3876  phpCAS::trace('Reason: CAS error');
3877  break;
3878  case CAS_VERSION_2_0:
3879  case CAS_VERSION_3_0:
3880  if (empty($err_code)) {
3881  phpCAS::trace('Reason: no CAS error');
3882  } else {
3883  phpCAS::trace(
3884  'Reason: [' . $err_code . '] CAS error: ' . $err_msg
3885  );
3886  }
3887  break;
3888  }
3889  }
3890  phpCAS::trace('CAS response: ' . $cas_response);
3891  }
3892  $this->printHTMLFooter();
3895  }
3896 
3897  // ########################################################################
3898  // PGTIOU/PGTID and logoutRequest rebroadcasting
3899  // ########################################################################
3900 
3905  private $_rebroadcast = false;
3906  private $_rebroadcast_nodes = array();
3907 
3911  const HOSTNAME = 0;
3912  const IP = 1;
3913 
3922  private function _getNodeType($nodeURL)
3923  {
3925  if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $nodeURL)) {
3926  phpCAS::traceEnd(self::IP);
3927  return self::IP;
3928  } else {
3929  phpCAS::traceEnd(self::HOSTNAME);
3930  return self::HOSTNAME;
3931  }
3932  }
3933 
3941  public function addRebroadcastNode($rebroadcastNodeUrl)
3942  {
3943  // Argument validation
3944  if (!(bool) preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl)) {
3945  throw new CAS_TypeMismatchException($rebroadcastNodeUrl, '$rebroadcastNodeUrl', 'url');
3946  }
3947 
3948  // Store the rebroadcast node and set flag
3949  $this->_rebroadcast = true;
3950  $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl;
3951  }
3952 
3956  private $_rebroadcast_headers = array();
3957 
3967  {
3968  if (gettype($header) != 'string') {
3969  throw new CAS_TypeMismatchException($header, '$header', 'string');
3970  }
3971 
3972  $this->_rebroadcast_headers[] = $header;
3973  }
3974 
3978  const LOGOUT = 0;
3979  const PGTIOU = 1;
3980 
3988  private function _rebroadcast($type)
3989  {
3991 
3992  $rebroadcast_curl_options = array(
3993  CURLOPT_FAILONERROR => 1,
3994  CURLOPT_FOLLOWLOCATION => 1,
3995  CURLOPT_RETURNTRANSFER => 1,
3996  CURLOPT_CONNECTTIMEOUT => 1,
3997  CURLOPT_TIMEOUT => 4);
3998 
3999  // Try to determine the IP address of the server
4000  if (!empty($_SERVER['SERVER_ADDR'])) {
4001  $ip = $_SERVER['SERVER_ADDR'];
4002  } elseif (!empty($_SERVER['LOCAL_ADDR'])) {
4003  // IIS 7
4004  $ip = $_SERVER['LOCAL_ADDR'];
4005  }
4006  // Try to determine the DNS name of the server
4007  if (!empty($ip)) {
4008  $dns = gethostbyaddr($ip);
4009  }
4010  $multiClassName = 'CAS_Request_CurlMultiRequest';
4011  $multiRequest = new $multiClassName();
4012 
4013  for ($i = 0; $i < sizeof($this->_rebroadcast_nodes); $i++) {
4014  if ((($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) === false))
4015  || (($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) === false))
4016  ) {
4017  phpCAS::trace(
4018  'Rebroadcast target URL: ' . $this->_rebroadcast_nodes[$i]
4019  . $_SERVER['REQUEST_URI']
4020  );
4021  $className = $this->_requestImplementation;
4022  $request = new $className();
4023 
4024  $url = $this->_rebroadcast_nodes[$i] . $_SERVER['REQUEST_URI'];
4025  $request->setUrl($url);
4026 
4027  if (count($this->_rebroadcast_headers)) {
4028  $request->addHeaders($this->_rebroadcast_headers);
4029  }
4030 
4031  $request->makePost();
4032  if ($type == self::LOGOUT) {
4033  // Logout request
4034  $request->setPostBody(
4035  'rebroadcast=false&logoutRequest=' . $_POST['logoutRequest']
4036  );
4037  } elseif ($type == self::PGTIOU) {
4038  // pgtIou/pgtId rebroadcast
4039  $request->setPostBody('rebroadcast=false');
4040  }
4041 
4042  $request->setCurlOptions($rebroadcast_curl_options);
4043 
4044  $multiRequest->addRequest($request);
4045  } else {
4046  phpCAS::trace(
4047  'Rebroadcast not sent to self: '
4048  . $this->_rebroadcast_nodes[$i] . ' == ' . (!empty($ip)?$ip:'')
4049  . '/' . (!empty($dns)?$dns:'')
4050  );
4051  }
4052  }
4053  // We need at least 1 request
4054  if ($multiRequest->getNumRequests() > 0) {
4055  $multiRequest->send();
4056  }
4057  phpCAS::traceEnd();
4058  }
4059 
4061 }
getAuthenticationCallerFile()
Answer information about the authentication caller.
Definition: Client.php:853
_setProxies($proxies)
Set the Proxy array, probably from persistant storage.
Definition: Client.php:3203
const SAML_SOAP_BODY_CLOSE
SOAP body close.
Definition: CAS.php:127
$_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:2379
ProxyChain is a container for storing chains of valid proxies that can be used to validate proxied re...
Definition: AllowedList.php:43
getLangObj()
Create the language.
Definition: Client.php:226
$_cache_times_for_auth_recheck
An integer that gives the number of times authentication will be cached before rechecked.
Definition: Client.php:1319
_rebroadcast($type)
This method rebroadcasts logout/pgtIou requests.
Definition: Client.php:3988
$path
Definition: aliased.php:25
setServerLoginURL($url)
This method sets the login URL of the CAS server.
Definition: Client.php:369
$_COOKIE['client_id']
Definition: server.php:9
$failure
$_rebroadcast
Boolean of whether to rebroadcast pgtIou/pgtId and logoutRequest, and array of the nodes...
Definition: Client.php:3905
_getClientUrl()
Try to figure out the phpCas client URL with possible Proxys / Ports etc.
Definition: Client.php:3702
getUser()
This method returns the CAS user&#39;s login name.
Definition: Client.php:1134
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:2648
$_cas_server_cn_validate
validate CN of the CAS server certificate
Definition: Client.php:1960
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:2551
setServerServiceValidateURL($url)
This method sets the serviceValidate URL of the CAS server.
Definition: Client.php:387
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:3020
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:285
$result
foreach($paths as $path) $request
Definition: asyncclient.php:32
$type
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:1267
getAttributes()
Get an key values arry of attributes.
Definition: Client.php:1188
static error($msg)
This method is used by interface methods to print an error and where the function was originally call...
Definition: CAS.php:563
printHTMLFooter()
This method prints the footer of the HTML output (after filtering).
Definition: Client.php:130
_ensureAuthenticationCalled()
Ensure that authentication was checked.
Definition: Client.php:801
static traceExit()
This method is used to indicate the end of the execution of the program.
Definition: CAS.php:681
$_GET["client_id"]
$_authentication_caller
Definition: Client.php:781
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:2742
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:673
_initPGTStorage()
This method is used to initialize the storage of PGT&#39;s.
Definition: Client.php:2516
_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:3849
setPGTStorage($storage)
This method can be used to set a custom PGT storage object.
Definition: Client.php:2567
_getServerPort()
This method is used to retrieve the port of the CAS server.
Definition: Client.php:297
_getServerHostname()
This method is used to retrieve the hostname of the CAS server.
Definition: Client.php:287
setSingleSignoutCallback($function, array $additionalArgs=array())
Set a callback function to be run when a single-signout request is received.
Definition: Client.php:737
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:3979
hasAttributes()
Check whether attributes are available.
Definition: Client.php:1208
$_cas_server_ca_cert
the certificate of the CAS server CA.
Definition: Client.php:1947
addRebroadcastHeader($header)
This method is used to add header parameters when rebroadcasting pgtIou/pgtId or logoutRequest.
Definition: Client.php:3966
wasAuthenticationCalled()
Answer true if authentication has been checked.
Definition: Client.php:788
getAttribute($key)
Get a specific attribute by name.
Definition: Client.php:1250
const SAML_SOAP_ENV_CLOSE
SOAP envelope close.
Definition: CAS.php:132
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:527
$_serviceCookieJar
Handler for managing service cookies.
Definition: Client.php:2295
const SAML_ASSERTION_ARTIFACT_CLOSE
SAMLP close.
Definition: CAS.php:122
_removeParameterFromQueryString($parameterName, $queryString)
Removes a parameter from a query string.
Definition: Client.php:3767
if(! $in) print Initializing normalization quick check tables n
$_server
a record to store information about the CAS server.
Definition: Client.php:266
wasAuthenticationCallSuccessful()
Answer the result of the authentication call.
Definition: Client.php:816
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:496
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:1078
if($_SERVER['argc']< 4) $client
Definition: cron.php:12
static traceEnd($res='')
This method is used to indicate the end of the execution of a function in debug mode.
Definition: CAS.php:658
setLang($lang)
This method is used to set the language used by phpCAS.
Definition: Client.php:204
_validatePGT(&$validate_url, $text_response, $tree_response)
This method is used to validate a PGT; halt on failure.
Definition: Client.php:2680
$stream
PHP stream implementation.
getTicket()
This method returns the Service Ticket provided in the URL of the request.
Definition: Client.php:1905
_getServerBaseURL()
This method is used to retrieve the base URL of the CAS server.
Definition: Client.php:317
const PHPCAS_LANG_DEFAULT
phpCAS default language (when phpCAS::setLang() is not used)
Definition: CAS.php:234
$auth
Definition: fileserver.php:48
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:599
_isLogoutRequest()
Check of the current request is a logout request.
Definition: Client.php:1749
setRequestImplementation($className)
Override the default implementation used to make web requests in readUrl().
Definition: Client.php:620
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:754
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:1405
_isHttps()
This method checks to see if the request is secured via HTTPS.
Definition: Client.php:3742
hasAttribute($key)
Check whether a specific attribute with a name is available.
Definition: Client.php:1222
_wasPreviouslyAuthenticated()
This method tells if the user has already been (previously) authenticated by looking into the session...
Definition: Client.php:1578
$_output_footer
A string used to print the footer of HTML pages.
Definition: Client.php:121
_hasPGT()
This method tells if a Proxy Granting Ticket was stored.
Definition: Client.php:2353
_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:1088
setProxyTicket($proxyTicket)
Register a proxy ticket with the ProxiedService that it can use when making requests.
_getCallbackURL()
This method returns the URL that should be used for the PGT callback (in fact the URL of the current ...
Definition: Client.php:2420
$_clearTicketsFromUrl
Definition: Client.php:635
const SAML_ASSERTION_ARTIFACT
SAMLP artifact tag (for the ticket)
Definition: CAS.php:117
$_user
The Authenticated user.
Definition: Client.php:1112
setCallbackURL($url)
This method sets the callback url.
Definition: Client.php:2443
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:3922
_hasAttribute($key)
Check whether a specific attribute with a name is available.
Definition: Client.php:1237
static http()
Fetches the global http state from ILIAS.
$_rebroadcast_headers
An array to store extra rebroadcast curl options.
Definition: Client.php:3956
$_casAttributeParserCallbackArgs
Definition: Client.php:660
_buildQueryUrl($url, $query)
This method is used to append query parameters to an url.
Definition: Client.php:3787
foreach($_POST as $key=> $value) $res
logout($params)
This method is used to logout from CAS.
Definition: Client.php:1710
const IP
Definition: Client.php:3912
$_pgt_storage
an instance of a class inheriting of PGTStorage, used to deal with PGT storage.
Definition: Client.php:2508
_getUser()
This method returns the CAS user&#39;s login name.
Definition: Client.php:1150
_callback()
This method is called by CAS_Client::CAS_Client() when running in callback mode.
Definition: Client.php:2461
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:3686
Basic class for PGT storage The CAS_PGTStorage_AbstractStorage class is a generic class for PGT stora...
Exception that denotes invalid arguments were passed.
markAuthenticationCall($auth)
Mark the caller of authentication.
Definition: Client.php:770
getServerServiceValidateURL()
This method is used to retrieve the service validating URL of the CAS server.
Definition: Client.php:439
$_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:1121
_readURL($url, &$headers, &$body, &$err_msg)
This method is used to acces a remote URL.
Definition: Client.php:2875
redirectToCas($gateway=false, $renew=false)
This method is used to redirect the client to the CAS server.
Definition: Client.php:1682
getServerLogoutURL()
This method is used to retrieve the logout URL of the CAS server.
Definition: Client.php:549
$_signoutCallbackArgs
Definition: Client.php:721
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:405
_setCallbackMode($callback_mode)
This method sets/unsets callback mode.
Definition: Client.php:2388
const SAMLP_REQUEST
SAMLP request.
Definition: CAS.php:111
setPostAuthenticateCallback($function, array $additionalArgs=array())
Set a callback function to be run when a user authenticates.
Definition: Client.php:707
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:3190
$query
$_rebroadcast_nodes
Definition: Client.php:3906
$n
Definition: RandomTest.php:85
_buildSAMLPayload()
This method is used to build the SAML POST body sent to /samlValidate URL.
Definition: Client.php:2931
$user
Definition: migrateto20.php:57
if(array_key_exists('yes', $_REQUEST)) $attributes
Definition: getconsent.php:85
static getVersion()
This method returns the phpCAS version.
Definition: CAS.php:734
_addAttributeToArray(array &$attributeArray, $name, $value)
Add an attribute value to an array of attributes.
Definition: Client.php:3584
$_allowed_proxy_chains
Definition: Client.php:3223
$_postAuthenticateCallbackArgs
Definition: Client.php:686
const LOGOUT
Constants used for determining rebroadcast type (logout or pgtIou/pgtId).
Definition: Client.php:3978
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:3259
setURL($url)
This method sets the URL of the current request.
Definition: Client.php:3632
$_url
the URL of the current request (without any ticket CGI parameter).
Definition: Client.php:3622
setAttributes($attributes)
Set an array of attributes.
Definition: Client.php:1178
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:831
setHTMLHeader($header)
This method set the HTML header used for all outputs.
Definition: Client.php:151
hasTicket()
This method tells if a Service Ticket was stored.
Definition: Client.php:1927
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:2110
setNoCasServerValidation()
Set no SSL validation for the CAS server.
Definition: Client.php:2000
setHTMLFooter($footer)
This method set the HTML footer used for all outputs.
Definition: Client.php:168
getURL()
This method returns the URL of the current request (without any ticket CGI parameter).
Definition: Client.php:3648
$_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:2411
Language Interface class for all internationalization files.
$_proxy
A boolean telling if the client is a CAS proxy or not.
Definition: Client.php:2290
getServerVersion()
This method is used to retrieve the version of the CAS server.
Definition: Client.php:277
Licensed to Jasig under one or more contributor license agreements.
$password
Definition: cron.php:14
$_ticket
The Ticket provided in the URL of the request if present (empty otherwise).
Definition: Client.php:1898
const SAMLP_REQUEST_CLOSE
Definition: CAS.php:112
setServerLogoutURL($url)
This method sets the logout URL of the CAS server.
Definition: Client.php:565
isSessionAuthenticated()
This method tells if the current session is authenticated.
Definition: Client.php:1565
$_change_session_id
A variable to whether phpcas will use its own session handling.
Definition: Client.php:1069
static traceBegin()
This method is used to indicate the start of the execution of a function in debug mode...
Definition: CAS.php:611
getServerLoginURL($gateway=false, $renew=false)
This method is used to retrieve the login URL of the CAS server.
Definition: Client.php:341
$_no_cas_server_validation
Set to true not to validate the CAS server.
Definition: Client.php:1967
getAuthenticationCallerLine()
Answer information about the authentication caller.
Definition: Client.php:867
setNoClearTicketsFromUrl()
Configure the client to not send redirect headers and call exit() on authentication success...
Definition: Client.php:647
forceAuthentication()
This method is called to be sure that the user is authenticated.
Definition: Client.php:1292
isProxy()
Tells if a CAS client is a CAS proxy or not.
Definition: Client.php:2302
__construct( $server_version, $proxy, $server_hostname, $server_port, $server_uri, $changeSessionID=true)
CAS_Client constructor.
Definition: Client.php:911
_isCallbackMode()
This method returns true when the CAs client is running i callback mode, false otherwise.
Definition: Client.php:2399
for($i=1; $i<=count($kw_cases_sel); $i+=1) $lang
Definition: langwiz.php:349
$i
Definition: disco.tpl.php:19
setServerSamlValidateURL($url)
This method sets the samlValidate URL of the CAS server.
Definition: Client.php:423
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:1169
const HOSTNAME
Constants used for determining rebroadcast node type.
Definition: Client.php:3911
setCasServerCACert($cert, $validate_cn)
Set the CA certificate of the CAS server.
Definition: Client.php:1979
const SAML_SOAP_BODY
SOAP body for SAML POST.
Definition: CAS.php:106
_setPGT($pgt)
This method stores the Proxy Granting Ticket.
Definition: Client.php:2343
getAuthenticationCallerMethod()
Answer information about the authentication caller.
Definition: Client.php:881
$url
addRebroadcastNode($rebroadcastNodeUrl)
Store the rebroadcast node for pgtIou/pgtId and logout requests.
Definition: Client.php:3941
setCacheTimesForAuthRecheck($n)
Set the number of times authentication will be cached before rechecked.
Definition: Client.php:1328
if(empty($password)) $table
Definition: pwgen.php:24
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:588
checkAuthentication()
This method is called to check whether the user is authenticated or not.
Definition: Client.php:1344
_storePGT($pgt, $pgt_iou)
This method stores a PGT.
Definition: Client.php:2535
_renameSession($ticket)
Renaming the session.
Definition: Client.php:3801
_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:2222
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:2603
$_lang
A string corresponding to the language used by phpCAS.
Definition: Client.php:195
getAllowedProxyChains()
Answer the CAS_ProxyChain_AllowedList object for this client.
Definition: Client.php:3230
_getServerURI()
This method is used to retrieve the URI of the CAS server.
Definition: Client.php:307
$_requestImplementation
The class to instantiate for making web requests in readUrl().
Definition: Client.php:610
$key
Definition: croninfo.php:18
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:3108
$_POST["username"]
$_casAttributeParserCallbackFunction
Definition: Client.php:655
handleLogoutRequests($check_client=true, $allowed_clients=false)
This method handles logout requests.
Definition: Client.php:1764
$_pgt
the Proxy Grnting Ticket given by the CAS server (empty otherwise).
Definition: Client.php:2324
$_proxies
This array will store a list of proxies in front of this application.
Definition: Client.php:3179
setTicket($st)
This method stores the Service Ticket.
Definition: Client.php:1917
getProxiedService($type)
Answer a proxy-authenticated service handler.
Definition: Client.php:2968
getServerSamlValidateURL()
This method is used to retrieve the SAML validating URL of the CAS server.
Definition: Client.php:471
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:578
$_signoutCallbackFunction
Definition: Client.php:716
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:2020
$_postAuthenticateCallbackFunction
Definition: Client.php:681
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:3055
_getPGT()
This method returns the Proxy Granting Ticket given by the CAS server.
Definition: Client.php:2331