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