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