00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00037
00038 include_once(dirname(__FILE__).'/languages/languages.php');
00039
00040
00041 include_once(dirname(__FILE__).'/PGTStorage/pgt-main.php');
00042
00051 class CASClient
00052 {
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00081 function HTMLFilterOutput($str)
00082 {
00083 $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str);
00084 $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str);
00085 $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str);
00086 echo $str;
00087 }
00088
00097 var $_output_header = '';
00098
00108 function printHTMLHeader($title)
00109 {
00110 $this->HTMLFilterOutput(str_replace('__TITLE__',
00111 $title,
00112 (empty($this->_output_header)
00113 ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
00114 : $this->_output_header)
00115 )
00116 );
00117 }
00118
00127 var $_output_footer = '';
00128
00136 function printHTMLFooter()
00137 {
00138 $this->HTMLFilterOutput(empty($this->_output_footer)
00139 ?('<hr><address>phpCAS __PHPCAS_VERSION__ '.$this->getString(CAS_STR_USING_SERVER).' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>')
00140 :$this->_output_footer);
00141 }
00142
00150 function setHTMLHeader($header)
00151 {
00152 $this->_output_header = $header;
00153 }
00154
00162 function setHTMLFooter($footer)
00163 {
00164 $this->_output_footer = $footer;
00165 }
00166
00168
00169
00170
00185 var $_lang = '';
00186
00194 function getLang()
00195 {
00196 if ( empty($this->_lang) )
00197 $this->setLang(PHPCAS_LANG_DEFAULT);
00198 return $this->_lang;
00199 }
00200
00210 var $_strings;
00211
00221 function getString($str)
00222 {
00223
00224 $this->getLang();
00225
00226 if ( !isset($this->_strings[$str]) ) {
00227 trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR);
00228 }
00229 return $this->_strings[$str];
00230 }
00231
00241 function setLang($lang)
00242 {
00243
00244 include_once(dirname(__FILE__).'/languages/'.$lang.'.php');
00245
00246 if ( !is_array($this->_strings) ) {
00247 trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR);
00248 }
00249 $this->_lang = $lang;
00250 }
00251
00253 // ########################################################################
00254 // CAS SERVER CONFIG
00255 // ########################################################################
00285 var $_server = array(
00286 'version' => -1,
00287 'hostname' => 'none',
00288 'port' => -1,
00289 'uri' => 'none'
00290 );
00291
00297 function getServerVersion()
00298 {
00299 return $this->_server['version'];
00300 }
00301
00307 function getServerHostname()
00308 { return $this->_server['hostname']; }
00309
00315 function getServerPort()
00316 { return $this->_server['port']; }
00317
00323 function getServerURI()
00324 { return $this->_server['uri']; }
00325
00331 function getServerBaseURL()
00332 {
00333 // the URL is build only when needed
00334 if ( empty($this->_server['base_url']) ) {
00335 $this->_server['base_url'] = 'https:
00336 .$this->getServerHostname()
00337 .':'
00338 .$this->getServerPort()
00339 .$this->getServerURI();
00340 }
00341 return $this->_server['base_url'];
00342 }
00343
00353 function getServerLoginURL($gateway=false,$renew=false) {
00354 phpCAS::traceBegin();
00355
00356 if ( empty($this->_server['login_url']) ) {
00357 $this->_server['login_url'] = $this->getServerBaseURL();
00358 $this->_server['login_url'] .= 'login?service=';
00359
00360 $this->_server['login_url'] .= urlencode($this->getURL());
00361 if($renew) {
00362
00363 $this->_server['login_url'] .= '&renew=true';
00364 } elseif ($gateway) {
00365
00366 $this->_server['login_url'] .= '&gateway=true';
00367 }
00368 }
00369 phpCAS::traceEnd($this->_server['login_url']);
00370 return $this->_server['login_url'];
00371 }
00372
00379 function setServerLoginURL($url)
00380 {
00381 return $this->_server['login_url'] = $url;
00382 }
00383
00384
00391 function setServerServiceValidateURL($url)
00392 {
00393 return $this->_server['service_validate_url'] = $url;
00394 }
00395
00396
00403 function setServerProxyValidateURL($url)
00404 {
00405 return $this->_server['proxy_validate_url'] = $url;
00406 }
00407
00408
00415 function setServerSamlValidateURL($url)
00416 {
00417 return $this->_server['saml_validate_url'] = $url;
00418 }
00419
00420
00426 function getServerServiceValidateURL()
00427 {
00428
00429 if ( empty($this->_server['service_validate_url']) ) {
00430 switch ($this->getServerVersion()) {
00431 case CAS_VERSION_1_0:
00432 $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';
00433 break;
00434 case CAS_VERSION_2_0:
00435 $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';
00436 break;
00437 }
00438 }
00439
00440 return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL());
00441 }
00447 function getServerSamlValidateURL()
00448 {
00449 phpCAS::traceBegin();
00450
00451 if ( empty($this->_server['saml_validate_url']) ) {
00452 switch ($this->getServerVersion()) {
00453 case SAML_VERSION_1_1:
00454 $this->_server['saml_validate_url'] = $this->getServerBaseURL().'samlValidate';
00455 break;
00456 }
00457 }
00458 phpCAS::traceEnd($this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL()));
00459 return $this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL());
00460 }
00466 function getServerProxyValidateURL()
00467 {
00468
00469 if ( empty($this->_server['proxy_validate_url']) ) {
00470 switch ($this->getServerVersion()) {
00471 case CAS_VERSION_1_0:
00472 $this->_server['proxy_validate_url'] = '';
00473 break;
00474 case CAS_VERSION_2_0:
00475 $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate';
00476 break;
00477 }
00478 }
00479
00480 return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL());
00481 }
00482
00488 function getServerProxyURL()
00489 {
00490
00491 if ( empty($this->_server['proxy_url']) ) {
00492 switch ($this->getServerVersion()) {
00493 case CAS_VERSION_1_0:
00494 $this->_server['proxy_url'] = '';
00495 break;
00496 case CAS_VERSION_2_0:
00497 $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';
00498 break;
00499 }
00500 }
00501 return $this->_server['proxy_url'];
00502 }
00503
00509 function getServerLogoutURL()
00510 {
00511
00512 if ( empty($this->_server['logout_url']) ) {
00513 $this->_server['logout_url'] = $this->getServerBaseURL().'logout';
00514 }
00515 return $this->_server['logout_url'];
00516 }
00517
00524 function setServerLogoutURL($url)
00525 {
00526 return $this->_server['logout_url'] = $url;
00527 }
00528
00532 var $_curl_options = array();
00533
00537 function setExtraCurlOption($key, $value)
00538 {
00539 $this->_curl_options[$key] = $value;
00540 }
00541
00547 function isHttps() {
00548
00549
00550 if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
00551 return true;
00552 } else {
00553 return false;
00554 }
00555 }
00556
00557
00558
00559
00574 function CASClient(
00575 $server_version,
00576 $proxy,
00577 $server_hostname,
00578 $server_port,
00579 $server_uri,
00580 $start_session = true) {
00581
00582 phpCAS::traceBegin();
00583
00584
00585 if (version_compare(PHP_VERSION,'5','>=') && ini_get('zend.ze1_compatibility_mode')) {
00586 phpCAS::error('phpCAS cannot support zend.ze1_compatibility_mode. Sorry.');
00587 }
00588
00589 if ($start_session && !$this->isLogoutRequest()) {
00590 phpCAS::trace("Starting session handling");
00591
00592 if (empty($_GET['ticket'])){
00593 phpCAS::trace("No ticket found");
00594
00595 if (!session_id()) {
00596 phpCAS::trace("No session found, creating new session");
00597 session_start();
00598 }
00599 }else{
00600 phpCAS::trace("Ticket found");
00601
00602 if (session_id()) {
00603 phpCAS::trace("Old active session found, saving old data and destroying session");
00604 $old_session = $_SESSION;
00605 session_destroy();
00606 }else{
00607 session_start();
00608 phpCAS::trace("Starting possible old session to copy variables");
00609 $old_session = $_SESSION;
00610 session_destroy();
00611 }
00612
00613 $session_id = preg_replace('/[^\w]/','',$_GET['ticket']);
00614 phpCAS::LOG("Session ID: " . $session_id);
00615 session_id($session_id);
00616 session_start();
00617
00618 if(isset($old_session)){
00619 phpCAS::trace("Restoring old session vars");
00620 $_SESSION = $old_session;
00621 }
00622 }
00623 }else{
00624 phpCAS::trace("Skipping session creation");
00625 }
00626
00627
00628
00629 $this->_proxy = $proxy;
00630
00631
00632 switch ($server_version) {
00633 case CAS_VERSION_1_0:
00634 if ( $this->isProxy() )
00635 phpCAS::error('CAS proxies are not supported in CAS '
00636 .$server_version);
00637 break;
00638 case CAS_VERSION_2_0:
00639 break;
00640 case SAML_VERSION_1_1:
00641 break;
00642 default:
00643 phpCAS::error('this version of CAS (`'
00644 .$server_version
00645 .'\') is not supported by phpCAS '
00646 .phpCAS::getVersion());
00647 }
00648 $this->_server['version'] = $server_version;
00649
00650 // check hostname
00651 if ( empty($server_hostname)
00652 || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
00653 phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
00654 }
00655 $this->_server['hostname'] = $server_hostname;
00656
00657
00658 if ( $server_port == 0
00659 || !is_int($server_port) ) {
00660 phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
00661 }
00662 $this->_server['port'] = $server_port;
00663
00664 // check URI
00665 if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
00666 phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
00667 }
00668
00669 $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');
00670 $this->_server['uri'] = $server_uri;
00671
00672
00673 if ( $this->isProxy() ) {
00674 $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
00675 }
00676
00677 if ( $this->isCallbackMode() ) {
00678
00679 if ( !$this->isHttps() ) {
00680 phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
00681 }
00682 } else {
00683
00684 $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
00685 switch ($this->getServerVersion()) {
00686 case CAS_VERSION_1_0:
00687 if( preg_match('/^ST-/',$ticket) ) {
00688 phpCAS::trace('ST \''.$ticket.'\' found');
00689 //ST present
00690 $this->setST($ticket);
00691 //ticket has been taken into account, unset it to hide it to applications
00692 unset($_GET['ticket']);
00693 } else if ( !empty($ticket) ) {
00694 //ill-formed ticket, halt
00695 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00696 }
00697 break;
00698 case CAS_VERSION_2_0:
00699 if( preg_match('/^[SP]T-/',$ticket) ) {
00700 phpCAS::trace('ST or PT \''.$ticket.'\' found');
00701 $this->setPT($ticket);
00702 unset($_GET['ticket']);
00703 } else if ( !empty($ticket) ) {
00704 //ill-formed ticket, halt
00705 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00706 }
00707 break;
00708 case SAML_VERSION_1_1:
00709 if( preg_match('/^[SP]T-/',$ticket) ) {
00710 phpCAS::trace('SA \''.$ticket.'\' found');
00711 $this->setSA($ticket);
00712 unset($_GET['ticket']);
00713 } else if ( !empty($ticket) ) {
00714 //ill-formed ticket, halt
00715 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00716 }
00717 break;
00718 }
00719 }
00720 phpCAS::traceEnd();
00721 }
00722
00725
00726
00727
00728
00729
00730
00743 var $_user = '';
00744
00752 function setUser($user)
00753 {
00754 $this->_user = $user;
00755 }
00756
00764 function getUser()
00765 {
00766 if ( empty($this->_user) ) {
00767 phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00768 }
00769 return $this->_user;
00770 }
00771
00772
00773
00774
00775
00776
00777
00778
00779
00787 var $_attributes = array();
00788
00789 function setAttributes($attributes)
00790 { $this->_attributes = $attributes; }
00791
00792 function getAttributes() {
00793 if ( empty($this->_user) ) {
00794 phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00795 }
00796 return $this->_attributes;
00797 }
00798
00799 function hasAttributes()
00800 { return !empty($this->_attributes); }
00801
00802 function hasAttribute($key)
00803 { return (is_array($this->_attributes) && array_key_exists($key, $this->_attributes)); }
00804
00805 function getAttribute($key) {
00806 if($this->hasAttribute($key)) {
00807 return $this->_attributes[$key];
00808 }
00809 }
00810
00817 function renewAuthentication(){
00818 phpCAS::traceBegin();
00819
00820 if( isset( $_SESSION['phpCAS']['auth_checked'] ) )
00821 unset($_SESSION['phpCAS']['auth_checked']);
00822 if ( $this->isAuthenticated() ) {
00823 phpCAS::trace('user already authenticated; renew');
00824 $this->redirectToCas(false,true);
00825 } else {
00826 $this->redirectToCas();
00827 }
00828 phpCAS::traceEnd();
00829 }
00830
00837 function forceAuthentication()
00838 {
00839 phpCAS::traceBegin();
00840
00841 if ( $this->isAuthenticated() ) {
00842
00843 phpCAS::trace('no need to authenticate');
00844 $res = TRUE;
00845 } else {
00846
00847 if (isset($_SESSION['phpCAS']['auth_checked'])) {
00848 unset($_SESSION['phpCAS']['auth_checked']);
00849 }
00850 $this->redirectToCas(FALSE);
00851
00852 $res = FALSE;
00853 }
00854 phpCAS::traceEnd($res);
00855 return $res;
00856 }
00857
00864 var $_cache_times_for_auth_recheck = 0;
00865
00873 function setCacheTimesForAuthRecheck($n)
00874 {
00875 $this->_cache_times_for_auth_recheck = $n;
00876 }
00877
00883 function checkAuthentication()
00884 {
00885 phpCAS::traceBegin();
00886
00887 if ( $this->isAuthenticated() ) {
00888 phpCAS::trace('user is authenticated');
00889 $res = TRUE;
00890 } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
00891
00892 unset($_SESSION['phpCAS']['auth_checked']);
00893 $res = FALSE;
00894 } else {
00895
00896
00897
00898
00899
00900 if (! isset($_SESSION['phpCAS']['unauth_count']) )
00901 $_SESSION['phpCAS']['unauth_count'] = -2;
00902
00903 if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1)
00904 || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck))
00905 {
00906 $res = FALSE;
00907
00908 if ($this->_cache_times_for_auth_recheck != -1)
00909 {
00910 $_SESSION['phpCAS']['unauth_count']++;
00911 phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')');
00912 }
00913 else
00914 {
00915 phpCAS::trace('user is not authenticated (cached for until login pressed)');
00916 }
00917 }
00918 else
00919 {
00920 $_SESSION['phpCAS']['unauth_count'] = 0;
00921 $_SESSION['phpCAS']['auth_checked'] = true;
00922 phpCAS::trace('user is not authenticated (cache reset)');
00923 $this->redirectToCas(TRUE);
00924
00925 $res = FALSE;
00926 }
00927 }
00928 phpCAS::traceEnd($res);
00929 return $res;
00930 }
00931
00940 function isAuthenticated()
00941 {
00942 phpCAS::traceBegin();
00943 $res = FALSE;
00944 $validate_url = '';
00945
00946 if ( $this->wasPreviouslyAuthenticated() ) {
00947
00948
00949 phpCAS::trace('user was already authenticated, no need to look for tickets');
00950 $res = TRUE;
00951 }
00952 else {
00953 if ( $this->hasST() ) {
00954
00955 phpCAS::trace('ST `'.$this->getST().'\' is present');
00956 $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
00957 phpCAS::trace('ST `'.$this->getST().'\' was validated');
00958 if ( $this->isProxy() ) {
00959 $this->validatePGT($validate_url,$text_response,$tree_response);
00960 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00961 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00962 }
00963 $_SESSION['phpCAS']['user'] = $this->getUser();
00964 $res = TRUE;
00965 }
00966 elseif ( $this->hasPT() ) {
00967 // if a Proxy Ticket was given, validate it
00968 phpCAS::trace('PT `'.$this->getPT().'\' is present');
00969 $this->validatePT($validate_url,$text_response,$tree_response);
00970 phpCAS::trace('PT `'.$this->getPT().'\' was validated');
00971 if ( $this->isProxy() ) {
00972 $this->validatePGT($validate_url,$text_response,$tree_response); // idem
00973 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00974 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00975 }
00976 $_SESSION['phpCAS']['user'] = $this->getUser();
00977 $res = TRUE;
00978 }
00979 elseif ( $this->hasSA() ) {
00980
00981 phpCAS::trace('SA `'.$this->getSA().'\' is present');
00982 $this->validateSA($validate_url,$text_response,$tree_response); // if it fails, it halts
00983 phpCAS::trace('SA `'.$this->getSA().'\' was validated');
00984 $_SESSION['phpCAS']['user'] = $this->getUser();
00985 $_SESSION['phpCAS']['attributes'] = $this->getAttributes();
00986 $res = TRUE;
00987 }
00988 else {
00989
00990 phpCAS::trace('no ticket found');
00991 }
00992 if ($res) {
00993
00994
00995 header('Location: '.$this->getURL());
00996 phpCAS::log( "Prepare redirect to : ".$this->getURL() );
00997 }
00998 }
00999
01000 phpCAS::traceEnd($res);
01001 return $res;
01002 }
01003
01009 function isSessionAuthenticated ()
01010 {
01011 return !empty($_SESSION['phpCAS']['user']);
01012 }
01013
01024 function wasPreviouslyAuthenticated()
01025 {
01026 phpCAS::traceBegin();
01027
01028 if ( $this->isCallbackMode() ) {
01029 $this->callback();
01030 }
01031
01032 $auth = FALSE;
01033
01034 if ( $this->isProxy() ) {
01035
01036 if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
01037
01038 $this->setUser($_SESSION['phpCAS']['user']);
01039 $this->setPGT($_SESSION['phpCAS']['pgt']);
01040 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\'');
01041 $auth = TRUE;
01042 } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
01043
01044 phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
01045 // unset all tickets to enforce authentication
01046 unset($_SESSION['phpCAS']);
01047 $this->setST('');
01048 $this->setPT('');
01049 } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
01050 // these two variables should be empty or not empty at the same time
01051 phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty');
01052
01053 unset($_SESSION['phpCAS']);
01054 $this->setST('');
01055 $this->setPT('');
01056 } else {
01057 phpCAS::trace('neither user not PGT found');
01058 }
01059 } else {
01060
01061 if ( $this->isSessionAuthenticated() ) {
01062
01063 $this->setUser($_SESSION['phpCAS']['user']);
01064 if(isset($_SESSION['phpCAS']['attributes'])){
01065 $this->setAttributes($_SESSION['phpCAS']['attributes']);
01066 }
01067 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\'');
01068 $auth = TRUE;
01069 } else {
01070 phpCAS::trace('no user found');
01071 }
01072 }
01073
01074 phpCAS::traceEnd($auth);
01075 return $auth;
01076 }
01077
01085 function redirectToCas($gateway=false,$renew=false){
01086 phpCAS::traceBegin();
01087 $cas_url = $this->getServerLoginURL($gateway,$renew);
01088 header('Location: '.$cas_url);
01089 phpCAS::log( "Redirect to : ".$cas_url );
01090
01091 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
01092
01093 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
01094 $this->printHTMLFooter();
01095
01096 phpCAS::traceExit();
01097 exit();
01098 }
01099
01100
01106 function logout($params) {
01107 phpCAS::traceBegin();
01108 $cas_url = $this->getServerLogoutURL();
01109 $paramSeparator = '?';
01110 if (isset($params['url'])) {
01111 $cas_url = $cas_url . $paramSeparator . "url=" . urlencode($params['url']);
01112 $paramSeparator = '&';
01113 }
01114 if (isset($params['service'])) {
01115 $cas_url = $cas_url . $paramSeparator . "service=" . urlencode($params['service']);
01116 }
01117 header('Location: '.$cas_url);
01118 phpCAS::log( "Prepare redirect to : ".$cas_url );
01119
01120 session_unset();
01121 session_destroy();
01122
01123 $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
01124 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
01125 $this->printHTMLFooter();
01126
01127 phpCAS::traceExit();
01128 exit();
01129 }
01130
01135 function isLogoutRequest() {
01136 return !empty($_POST['logoutRequest']);
01137 }
01138
01143 function isLogoutRequestAllowed() {
01144 }
01145
01154 function handleLogoutRequests($check_client=true, $allowed_clients=false) {
01155 phpCAS::traceBegin();
01156 if (!$this->isLogoutRequest()) {
01157 phpCAS::log("Not a logout request");
01158 phpCAS::traceEnd();
01159 return;
01160 }
01161 phpCAS::log("Logout requested");
01162 phpCAS::log("SAML REQUEST: ".$_POST['logoutRequest']);
01163 if ($check_client) {
01164 if (!$allowed_clients) {
01165 $allowed_clients = array( $this->getServerHostname() );
01166 }
01167 $client_ip = $_SERVER['REMOTE_ADDR'];
01168 $client = gethostbyaddr($client_ip);
01169 phpCAS::log("Client: ".$client."/".$client_ip);
01170 $allowed = false;
01171 foreach ($allowed_clients as $allowed_client) {
01172 if (($client == $allowed_client) or ($client_ip == $allowed_client)) {
01173 phpCAS::log("Allowed client '".$allowed_client."' matches, logout request is allowed");
01174 $allowed = true;
01175 break;
01176 } else {
01177 phpCAS::log("Allowed client '".$allowed_client."' does not match");
01178 }
01179 }
01180 if (!$allowed) {
01181 phpCAS::error("Unauthorized logout request from client '".$client."'");
01182 printf("Unauthorized!");
01183 phpCAS::traceExit();
01184 exit();
01185 }
01186 } else {
01187 phpCAS::log("No access control set");
01188 }
01189
01190 preg_match("|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|", $_POST['logoutRequest'], $tick, PREG_OFFSET_CAPTURE, 3);
01191 $wrappedSamlSessionIndex = preg_replace('|<samlp:SessionIndex>|','',$tick[0][0]);
01192 $ticket2logout = preg_replace('|</samlp:SessionIndex>|','',$wrappedSamlSessionIndex);
01193 phpCAS::log("Ticket to logout: ".$ticket2logout);
01194 $session_id = preg_replace('/[^\w]/','',$ticket2logout);
01195 phpCAS::log("Session id: ".$session_id);
01196
01197
01198 if(session_id()){
01199 session_unset();
01200 session_destroy();
01201 }
01202
01203 session_id($session_id);
01204 $_COOKIE[session_name()]=$session_id;
01205 $_GET[session_name()]=$session_id;
01206
01207
01208 session_start();
01209 session_unset();
01210 session_destroy();
01211 printf("Disconnected!");
01212 phpCAS::traceExit();
01213 exit();
01214 }
01215
01218
01219
01220
01221
01222
01223
01224
01225
01226
01240 var $_st = '';
01241
01247 function getST()
01248 { return $this->_st; }
01249
01255 function setST($st)
01256 { $this->_st = $st; }
01257
01263 function hasST()
01264 { return !empty($this->_st); }
01265
01268
01269
01270
01282 var $_cas_server_cert = '';
01283
01290 var $_cas_server_ca_cert = '';
01291
01298 var $_no_cas_server_validation = false;
01299
01305 function setCasServerCert($cert)
01306 {
01307 $this->_cas_server_cert = $cert;
01308 }
01309
01315 function setCasServerCACert($cert)
01316 {
01317 $this->_cas_server_ca_cert = $cert;
01318 }
01319
01323 function setNoCasServerValidation()
01324 {
01325 $this->_no_cas_server_validation = true;
01326 }
01327
01341 function validateST($validate_url,&$text_response,&$tree_response)
01342 {
01343 phpCAS::traceBegin();
01344
01345 $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
01346 if ( $this->isProxy() ) {
01347
01348 $validate_url .= '&pgtUrl='.$this->getCallbackURL();
01349 }
01350
01351
01352 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
01353 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01354 $this->authError('ST not validated',
01355 $validate_url,
01356 TRUE/*$no_response*/);
01357 }
01358
01359 // analyze the result depending on the version
01360 switch ($this->getServerVersion()) {
01361 case CAS_VERSION_1_0:
01362 if (preg_match('/^no\n/',$text_response)) {
01363 phpCAS::trace('ST has not been validated');
01364 $this->authError('ST not validated',
01365 $validate_url,
01366 FALSE/*$no_response*/,
01367 FALSE/*$bad_response*/,
01368 $text_response);
01369 }
01370 if (!preg_match('/^yes\n/',$text_response)) {
01371 phpCAS::trace('ill-formed response');
01372 $this->authError('ST not validated',
01373 $validate_url,
01374 FALSE/*$no_response*/,
01375 TRUE/*$bad_response*/,
01376 $text_response);
01377 }
01378 // ST has been validated, extract the user name
01379 $arr = preg_split('/\n/',$text_response);
01380 $this->setUser(trim($arr[1]));
01381 break;
01382 case CAS_VERSION_2_0:
01383 // read the response of the CAS server into a DOM object
01384 if ( !($dom = domxml_open_mem($text_response))) {
01385 phpCAS::trace('domxml_open_mem() failed');
01386 $this->authError('ST not validated',
01387 $validate_url,
01388 FALSE/*$no_response*/,
01389 TRUE/*$bad_response*/,
01390 $text_response);
01391 }
01392 // read the root node of the XML tree
01393 if ( !($tree_response = $dom->document_element()) ) {
01394 phpCAS::trace('document_element() failed');
01395 $this->authError('ST not validated',
01396 $validate_url,
01397 FALSE/*$no_response*/,
01398 TRUE/*$bad_response*/,
01399 $text_response);
01400 }
01401 // insure that tag name is 'serviceResponse'
01402 if ( $tree_response->node_name() != 'serviceResponse' ) {
01403 phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');
01404 $this->authError('ST not validated',
01405 $validate_url,
01406 FALSE,
01407 TRUE,
01408 $text_response);
01409 }
01410 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
01411
01412 if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
01413 phpCAS::trace('<authenticationSuccess> found, but no <user>');
01414 $this->authError('ST not validated',
01415 $validate_url,
01416 FALSE,
01417 TRUE,
01418 $text_response);
01419 }
01420 $user = trim($user_elements[0]->get_content());
01421 phpCAS::trace('user = `'.$user);
01422 $this->setUser($user);
01423
01424 } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
01425 phpCAS::trace('<authenticationFailure> found');
01426
01427 $this->authError('ST not validated',
01428 $validate_url,
01429 FALSE,
01430 FALSE,
01431 $text_response,
01432 $failure_elements[0]->get_attribute('code'),
01433 trim($failure_elements[0]->get_content()));
01434 } else {
01435 phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
01436 $this->authError('ST not validated',
01437 $validate_url,
01438 FALSE,
01439 TRUE,
01440 $text_response);
01441 }
01442 break;
01443 }
01444
01445
01446 phpCAS::traceEnd(TRUE);
01447 return TRUE;
01448 }
01449
01450
01451
01452
01471 function validateSA($validate_url,&$text_response,&$tree_response)
01472 {
01473 phpCAS::traceBegin();
01474
01475
01476 $validate_url = $this->getServerSamlValidateURL();
01477
01478
01479 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
01480 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01481 $this->authError('SA not validated', $validate_url, TRUE/*$no_response*/);
01482 }
01483
01484 phpCAS::trace('server version: '.$this->getServerVersion());
01485
01486 // analyze the result depending on the version
01487 switch ($this->getServerVersion()) {
01488 case SAML_VERSION_1_1:
01489
01490 // read the response of the CAS server into a DOM object
01491 if ( !($dom = domxml_open_mem($text_response))) {
01492 phpCAS::trace('domxml_open_mem() failed');
01493 $this->authError('SA not validated',
01494 $validate_url,
01495 FALSE/*$no_response*/,
01496 TRUE/*$bad_response*/,
01497 $text_response);
01498 }
01499 // read the root node of the XML tree
01500 if ( !($tree_response = $dom->document_element()) ) {
01501 phpCAS::trace('document_element() failed');
01502 $this->authError('SA not validated',
01503 $validate_url,
01504 FALSE/*$no_response*/,
01505 TRUE/*$bad_response*/,
01506 $text_response);
01507 }
01508 // insure that tag name is 'Envelope'
01509 if ( $tree_response->node_name() != 'Envelope' ) {
01510 phpCAS::trace('bad XML root node (should be `Envelope\' instead of `'.$tree_response->node_name().'\'');
01511 $this->authError('SA not validated',
01512 $validate_url,
01513 FALSE,
01514 TRUE,
01515 $text_response);
01516 }
01517
01518 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("NameIdentifier")) != 0) {
01519 phpCAS::trace('NameIdentifier found');
01520 $user = trim($success_elements[0]->get_content());
01521 phpCAS::trace('user = `'.$user.'`');
01522 $this->setUser($user);
01523 $this->setSessionAttributes($text_response);
01524 } else {
01525 phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
01526 $this->authError('SA not validated',
01527 $validate_url,
01528 FALSE,
01529 TRUE,
01530 $text_response);
01531 }
01532 break;
01533 }
01534
01535
01536 phpCAS::traceEnd(TRUE);
01537 return TRUE;
01538 }
01539
01549 function setSessionAttributes($text_response)
01550 {
01551 phpCAS::traceBegin();
01552
01553 $result = FALSE;
01554
01555 if (isset($_SESSION[SAML_ATTRIBUTES])) {
01556 phpCAS::trace("session attrs already set.");
01557 }
01558
01559 $attr_array = array();
01560
01561 if (($dom = domxml_open_mem($text_response))) {
01562 $xPath = $dom->xpath_new_context();
01563 $xPath->xpath_register_ns('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
01564 $xPath->xpath_register_ns('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
01565 $nodelist = $xPath->xpath_eval("//saml:Attribute");
01566 $attrs = $nodelist->nodeset;
01567 phpCAS::trace($text_response);
01568 foreach($attrs as $attr){
01569 $xres = $xPath->xpath_eval("saml:AttributeValue", $attr);
01570 $name = $attr->get_attribute("AttributeName");
01571 $value_array = array();
01572 foreach($xres->nodeset as $node){
01573 $value_array[] = $node->get_content();
01574
01575 }
01576 phpCAS::trace("* " . $name . "=" . $value_array);
01577 $attr_array[$name] = $value_array;
01578 }
01579 $_SESSION[SAML_ATTRIBUTES] = $attr_array;
01580
01581 foreach($attr_array as $attr_key => $attr_value) {
01582 if(count($attr_value) > 1) {
01583 $this->_attributes[$attr_key] = $attr_value;
01584 }
01585 else {
01586 $this->_attributes[$attr_key] = $attr_value[0];
01587 }
01588 }
01589 $result = TRUE;
01590 }
01591 phpCAS::traceEnd($result);
01592 return $result;
01593 }
01594
01597
01598
01599
01600
01601
01602
01603
01604
01605
01617 var $_proxy;
01618
01626 function isProxy()
01627 {
01628 return $this->_proxy;
01629 }
01630
01632
01633
01634
01647 var $_pgt = '';
01648
01654 function getPGT()
01655 { return $this->_pgt; }
01656
01662 function setPGT($pgt)
01663 { $this->_pgt = $pgt; }
01664
01670 function hasPGT()
01671 { return !empty($this->_pgt); }
01672
01675
01676
01677
01695 var $_callback_mode = FALSE;
01696
01704 function setCallbackMode($callback_mode)
01705 {
01706 $this->_callback_mode = $callback_mode;
01707 }
01708
01717 function isCallbackMode()
01718 {
01719 return $this->_callback_mode;
01720 }
01721
01730 var $_callback_url = '';
01731
01741 function getCallbackURL()
01742 {
01743
01744 if ( empty($this->_callback_url) ) {
01745 $final_uri = '';
01746
01747 $final_uri = 'https://';
01748
01749
01750
01751 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01752
01753
01754
01755 if (empty($_SERVER['SERVER_NAME'])) {
01756 $final_uri .= $_SERVER['HTTP_HOST'];
01757 } else {
01758 $final_uri .= $_SERVER['SERVER_NAME'];
01759 }
01760 } else {
01761 $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
01762 }
01763 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
01764 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
01765 $final_uri .= ':';
01766 $final_uri .= $_SERVER['SERVER_PORT'];
01767 }
01768 $request_uri = $_SERVER['REQUEST_URI'];
01769 $request_uri = preg_replace('/\?.*$/','',$request_uri);
01770 $final_uri .= $request_uri;
01771 $this->setCallbackURL($final_uri);
01772 }
01773 return $this->_callback_url;
01774 }
01775
01783 function setCallbackURL($url)
01784 {
01785 return $this->_callback_url = $url;
01786 }
01787
01794 function callback()
01795 {
01796 phpCAS::traceBegin();
01797 $this->printHTMLHeader('phpCAS callback');
01798 $pgt_iou = $_GET['pgtIou'];
01799 $pgt = $_GET['pgtId'];
01800 phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
01801 echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
01802 $this->storePGT($pgt,$pgt_iou);
01803 $this->printHTMLFooter();
01804 phpCAS::traceExit();
01805 exit();
01806 }
01807
01810
01811
01812
01826 var $_pgt_storage = null;
01827
01834 function initPGTStorage()
01835 {
01836
01837 if ( !is_object($this->_pgt_storage) ) {
01838 $this->setPGTStorageFile();
01839 }
01840
01841
01842 $this->_pgt_storage->init();
01843 }
01844
01853 function storePGT($pgt,$pgt_iou)
01854 {
01855
01856 $this->initPGTStorage();
01857
01858 $this->_pgt_storage->write($pgt,$pgt_iou);
01859 }
01860
01870 function loadPGT($pgt_iou)
01871 {
01872
01873 $this->initPGTStorage();
01874
01875 return $this->_pgt_storage->read($pgt_iou);
01876 }
01877
01887 function setPGTStorageFile($format='',
01888 $path='')
01889 {
01890
01891 if ( is_object($this->_pgt_storage) ) {
01892 phpCAS::error('PGT storage already defined');
01893 }
01894
01895
01896 $this->_pgt_storage = new PGTStorageFile($this,$format,$path);
01897 }
01898
01916 function setPGTStorageDB($user,
01917 $password,
01918 $database_type,
01919 $hostname,
01920 $port,
01921 $database,
01922 $table)
01923 {
01924
01925 if ( is_object($this->_pgt_storage) ) {
01926 phpCAS::error('PGT storage already defined');
01927 }
01928
01929
01930 trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);
01931
01932
01933 $this->_pgt_storage = new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table);
01934 }
01935
01936
01937
01938
01952 function validatePGT(&$validate_url,$text_response,$tree_response)
01953 {
01954
01955 phpCAS::log('start validatePGT()');
01956 if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
01957 phpCAS::trace('<proxyGrantingTicket> not found');
01958
01959 $this->authError('Ticket validated but no PGT Iou transmitted',
01960 $validate_url,
01961 FALSE,
01962 FALSE,
01963 $text_response);
01964 } else {
01965
01966 $pgt_iou = trim($arr[0]->get_content());
01967 $pgt = $this->loadPGT($pgt_iou);
01968 if ( $pgt == FALSE ) {
01969 phpCAS::trace('could not load PGT');
01970 $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
01971 $validate_url,
01972 FALSE,
01973 FALSE,
01974 $text_response);
01975 }
01976 $this->setPGT($pgt);
01977 }
01978
01979 phpCAS::log('end validatePGT()');
01980 return TRUE;
01981 }
01982
01983
01984
01985
01986
01998 function retrievePT($target_service,&$err_code,&$err_msg)
01999 {
02000 phpCAS::traceBegin();
02001
02002
02003
02004
02005
02006 $err_msg = '';
02007
02008
02009
02010 $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT();
02011
02012
02013 if ( !$this->readURL($cas_url,'',$headers,$cas_response,$err_msg) ) {
02014 phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
02015 $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
02016 $err_msg = 'could not retrieve PT (no response from the CAS server)';
02017 phpCAS::traceEnd(FALSE);
02018 return FALSE;
02019 }
02020
02021 $bad_response = FALSE;
02022
02023 if ( !$bad_response ) {
02024 // read the response of the CAS server into a DOM object
02025 if ( !($dom = @domxml_open_mem($cas_response))) {
02026 phpCAS::trace('domxml_open_mem() failed');
02027 // read failed
02028 $bad_response = TRUE;
02029 }
02030 }
02031
02032 if ( !$bad_response ) {
02033 // read the root node of the XML tree
02034 if ( !($root = $dom->document_element()) ) {
02035 phpCAS::trace('document_element() failed');
02036 // read failed
02037 $bad_response = TRUE;
02038 }
02039 }
02040
02041 if ( !$bad_response ) {
02042 // insure that tag name is 'serviceResponse'
02043 if ( $root->node_name() != 'serviceResponse' ) {
02044 phpCAS::trace('node_name() failed');
02045 // bad root node
02046 $bad_response = TRUE;
02047 }
02048 }
02049
02050 if ( !$bad_response ) {
02051 // look for a proxySuccess tag
02052 if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
02053 // authentication succeded, look for a proxyTicket tag
02054 if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
02055 $err_code = PHPCAS_SERVICE_OK;
02056 $err_msg = '';
02057 phpCAS::trace('original PT: '.trim($arr[0]->get_content()));
02058 $pt = trim($arr[0]->get_content());
02059 phpCAS::traceEnd($pt);
02060 return $pt;
02061 } else {
02062 phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
02063 }
02064 }
02065 // look for a proxyFailure tag
02066 else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
02067 // authentication failed, extract the error
02068 $err_code = PHPCAS_SERVICE_PT_FAILURE;
02069 $err_msg = 'PT retrieving failed (code=`'
02070 .$arr[0]->get_attribute('code')
02071 .'\', message=`'
02072 .trim($arr[0]->get_content())
02073 .'\')';
02074 phpCAS::traceEnd(FALSE);
02075 return FALSE;
02076 } else {
02077 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
02078 }
02079 }
02080
02081 // at this step, we are sure that the response of the CAS server was ill-formed
02082 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
02083 $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
02084
02085 phpCAS::traceEnd(FALSE);
02086 return FALSE;
02087 }
02088
02089
02090
02091
02092
02108 function readURL($url,$cookies,&$headers,&$body,&$err_msg)
02109 {
02110 phpCAS::traceBegin();
02111 $headers = '';
02112 $body = '';
02113 $err_msg = '';
02114
02115 $res = TRUE;
02116
02117
02118 $ch = curl_init($url);
02119
02120 if (version_compare(PHP_VERSION,'5.1.3','>=')) {
02121
02122 curl_setopt_array($ch, $this->_curl_options);
02123 } else {
02124 foreach ($this->_curl_options as $key => $value) {
02125 curl_setopt($ch, $key, $value);
02126 }
02127 }
02128
02129 if ($this->_cas_server_cert == '' && $this->_cas_server_ca_cert == '' && !$this->_no_cas_server_validation) {
02130 phpCAS::error('one of the methods phpCAS::setCasServerCert(), phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.');
02131 }
02132 if ($this->_cas_server_cert != '' && $this->_cas_server_ca_cert != '') {
02133
02134 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02135 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
02136 curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
02137 curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
02138 curl_setopt($ch, CURLOPT_VERBOSE, '1');
02139 phpCAS::trace('CURL: Set all required opts for mutual authentication ------');
02140 } else if ($this->_cas_server_cert != '' ) {
02141 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02142 curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
02143 } else if ($this->_cas_server_ca_cert != '') {
02144 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02145 curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
02146 } else {
02147 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
02148 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
02149 }
02150
02151
02152 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
02153
02154 $this->_curl_headers = array();
02155 curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curl_read_headers'));
02156
02157 if ( is_array($cookies) ) {
02158 curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
02159 }
02160
02161 if ($this->hasSA()) {
02162 $more_headers = array ("soapaction: http://www.oasis-open.org/committees/security",
02163 "cache-control: no-cache",
02164 "pragma: no-cache",
02165 "accept: text/xml",
02166 "connection: keep-alive",
02167 "content-type: text/xml");
02168
02169 curl_setopt($ch, CURLOPT_HTTPHEADER, $more_headers);
02170 curl_setopt($ch, CURLOPT_POST, 1);
02171 $data = $this->buildSAMLPayload();
02172
02173 curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
02174 }
02175
02176 $buf = curl_exec ($ch);
02177
02178 if ( $buf === FALSE ) {
02179 phpCAS::trace('curl_exec() failed');
02180 $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
02181
02182
02183 curl_close ($ch);
02184 $res = FALSE;
02185 } else {
02186
02187 curl_close ($ch);
02188
02189 $headers = $this->_curl_headers;
02190 $body = $buf;
02191 }
02192
02193 phpCAS::traceEnd($res);
02194 return $res;
02195 }
02196
02204 function buildSAMLPayload()
02205 {
02206 phpCAS::traceBegin();
02207
02208
02209 $sa = $this->getSA();
02210
02211
02212 $body=SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST.SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE.SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
02213
02214 phpCAS::traceEnd($body);
02215 return ($body);
02216 }
02217
02221 var $_curl_headers = array();
02222 function _curl_read_headers($ch, $header)
02223 {
02224 $this->_curl_headers[] = $header;
02225 return strlen($header);
02226 }
02227
02243 function serviceWeb($url,&$err_code,&$output)
02244 {
02245 phpCAS::traceBegin();
02246
02247 $pt = $this->retrievePT($url,$err_code,$output);
02248
02249 $res = TRUE;
02250
02251
02252 if ( !$pt ) {
02253
02254 phpCAS::trace('PT was not retrieved correctly');
02255 $res = FALSE;
02256 } else {
02257
02258 if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
02259 foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) {
02260 $cookies[] = $name.'='.$val;
02261 }
02262 }
02263
02264
02265 if ( strstr($url,'?') === FALSE ) {
02266 $service_url = $url.'?ticket='.$pt;
02267 } else {
02268 $service_url = $url.'&ticket='.$pt;
02269 }
02270
02271 phpCAS::trace('reading URL`'.$service_url.'\'');
02272 if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
02273 phpCAS::trace('could not read URL`'.$service_url.'\'');
02274 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02275
02276 $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02277 $service_url,
02278 $err_msg);
02279 $res = FALSE;
02280 } else {
02281
02282 phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
02283 foreach ( $headers as $header ) {
02284 // test if the header is a cookie
02285 if ( preg_match('/^Set-Cookie:/',$header) ) {
02286 // the header is a cookie, remove the beginning
02287 $header_val = preg_replace('/^Set-Cookie: */','',$header);
02288 // extract interesting information
02289 $name_val = strtok($header_val,'; ');
02290 // extract the name and the value of the cookie
02291 $cookie_name = strtok($name_val,'=');
02292 $cookie_val = strtok('=');
02293 // store the cookie
02294 $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
02295 phpCAS::trace($cookie_name.' -> '.$cookie_val);
02296 }
02297 }
02298 }
02299 }
02300
02301 phpCAS::traceEnd($res);
02302 return $res;
02303 }
02304
02324 function serviceMail($url,$service,$flags,&$err_code,&$err_msg,&$pt)
02325 {
02326 phpCAS::traceBegin();
02327 // at first retrieve a PT
02328 $pt = $this->retrievePT($service,$err_code,$output);
02329
02330 $stream = FALSE;
02331
02332 // test if PT was retrieved correctly
02333 if ( !$pt ) {
02334 // note: $err_code and $err_msg are filled by CASClient::retrievePT()
02335 phpCAS::trace('PT was not retrieved correctly');
02336 } else {
02337 phpCAS::trace('opening IMAP URL `'.$url.'\'...');
02338 $stream = @imap_open($url,$this->getUser(),$pt,$flags);
02339 if ( !$stream ) {
02340 phpCAS::trace('could not open URL');
02341 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02342
02343 $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02344 $service_url,
02345 var_export(imap_errors(),TRUE));
02346 $pt = FALSE;
02347 $stream = FALSE;
02348 } else {
02349 phpCAS::trace('ok');
02350 }
02351 }
02352
02353 phpCAS::traceEnd($stream);
02354 return $stream;
02355 }
02356
02359
02360
02361
02362
02363
02364
02365
02366
02367
02381 var $_pt = '';
02382
02388 function getPT()
02389 {
02390
02391 return $this->_pt;
02392 }
02393
02399 function setPT($pt)
02400 { $this->_pt = $pt; }
02401
02407 function hasPT()
02408 { return !empty($this->_pt); }
02414 function getSA()
02415 { return 'ST'.substr($this->_sa, 2); }
02416
02422 function setSA($sa)
02423 { $this->_sa = $sa; }
02424
02430 function hasSA()
02431 { return !empty($this->_sa); }
02432
02434
02435
02436
02449 function validatePT(&$validate_url,&$text_response,&$tree_response)
02450 {
02451 phpCAS::traceBegin();
02452
02453 $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
02454
02455 if ( $this->isProxy() ) {
02456
02457 $validate_url .= '&pgtUrl='.$this->getCallbackURL();
02458 }
02459
02460
02461 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
02462 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
02463 $this->authError('PT not validated',
02464 $validate_url,
02465 TRUE/*$no_response*/);
02466 }
02467
02468 // read the response of the CAS server into a DOM object
02469 if ( !($dom = domxml_open_mem($text_response))) {
02470 // read failed
02471 $this->authError('PT not validated',
02472 $validate_url,
02473 FALSE/*$no_response*/,
02474 TRUE/*$bad_response*/,
02475 $text_response);
02476 }
02477 // read the root node of the XML tree
02478 if ( !($tree_response = $dom->document_element()) ) {
02479 // read failed
02480 $this->authError('PT not validated',
02481 $validate_url,
02482 FALSE/*$no_response*/,
02483 TRUE/*$bad_response*/,
02484 $text_response);
02485 }
02486 // insure that tag name is 'serviceResponse'
02487 if ( $tree_response->node_name() != 'serviceResponse' ) {
02488 // bad root node
02489 $this->authError('PT not validated',
02490 $validate_url,
02491 FALSE/*$no_response*/,
02492 TRUE/*$bad_response*/,
02493 $text_response);
02494 }
02495 if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
02496 // authentication succeded, extract the user name
02497 if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
02498 // no user specified => error
02499 $this->authError('PT not validated',
02500 $validate_url,
02501 FALSE/*$no_response*/,
02502 TRUE/*$bad_response*/,
02503 $text_response);
02504 }
02505 $this->setUser(trim($arr[0]->get_content()));
02506
02507 } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
02508 // authentication succeded, extract the error code and message
02509 $this->authError('PT not validated',
02510 $validate_url,
02511 FALSE/*$no_response*/,
02512 FALSE/*$bad_response*/,
02513 $text_response,
02514 $arr[0]->get_attribute('code')/*$err_code*/,
02515 trim($arr[0]->get_content())/*$err_msg*/);
02516 } else {
02517 $this->authError('PT not validated',
02518 $validate_url,
02519 FALSE/*$no_response*/,
02520 TRUE/*$bad_response*/,
02521 $text_response);
02522 }
02523
02524 // at this step, PT has been validated and $this->_user has been set,
02525
02526 phpCAS::traceEnd(TRUE);
02527 return TRUE;
02528 }
02529
02532 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02533 // XX XX
02534 // XX MISC XX
02535 // XX XX
02536 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02537
02543 // ########################################################################
02544 // URL
02545 // ########################################################################
02553 var $_url = '';
02554
02563 function getURL()
02564 {
02565 phpCAS::traceBegin();
02566 // the URL is built when needed only
02567 if ( empty($this->_url) ) {
02568 $final_uri = '';
02569 // remove the ticket if present in the URL
02570 $final_uri = ($this->isHttps()) ? 'https' : 'http';
02571 $final_uri .= ':
02572
02573
02574
02575 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
02576
02577
02578
02579 if (empty($_SERVER['SERVER_NAME'])) {
02580 $server_name = $_SERVER['HTTP_HOST'];
02581 } else {
02582 $server_name = $_SERVER['SERVER_NAME'];
02583 }
02584 } else {
02585 $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER'];
02586 }
02587 $final_uri .= $server_name;
02588 if (!strpos($server_name, ':')) {
02589 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
02590 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
02591 $final_uri .= ':';
02592 $final_uri .= $_SERVER['SERVER_PORT'];
02593 }
02594 }
02595
02596 $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);
02597 $final_uri .= $request_uri[0];
02598
02599 if (isset($request_uri[1]) && $request_uri[1])
02600 {
02601 $query_string = $this->removeParameterFromQueryString('ticket', $request_uri[1]);
02602
02603
02604 if ($query_string !== '')
02605 $final_uri .= "?$query_string";
02606
02607 }
02608
02609 phpCAS::trace("Final URI: $final_uri");
02610 $this->setURL($final_uri);
02611 }
02612 phpCAS::traceEnd($this->_url);
02613 return $this->_url;
02614 }
02615
02616
02617
02627 function removeParameterFromQueryString($parameterName, $queryString)
02628 {
02629 $parameterName = preg_quote($parameterName);
02630 return preg_replace("/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/", '', $queryString);
02631 }
02632
02633
02641 function setURL($url)
02642 {
02643 $this->_url = $url;
02644 }
02645
02646
02647
02648
02664 function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
02665 {
02666 phpCAS::traceBegin();
02667
02668 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
02669 printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),htmlentities($this->getURL()),$_SERVER['SERVER_ADMIN']);
02670 phpCAS::trace('CAS URL: '.$cas_url);
02671 phpCAS::trace('Authentication failure: '.$failure);
02672 if ( $no_response ) {
02673 phpCAS::trace('Reason: no response from the CAS server');
02674 } else {
02675 if ( $bad_response ) {
02676 phpCAS::trace('Reason: bad response from the CAS server');
02677 } else {
02678 switch ($this->getServerVersion()) {
02679 case CAS_VERSION_1_0:
02680 phpCAS::trace('Reason: CAS error');
02681 break;
02682 case CAS_VERSION_2_0:
02683 if ( empty($err_code) )
02684 phpCAS::trace('Reason: no CAS error');
02685 else
02686 phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
02687 break;
02688 }
02689 }
02690 phpCAS::trace('CAS response: '.$cas_response);
02691 }
02692 $this->printHTMLFooter();
02693 phpCAS::traceExit();
02694 exit();
02695 }
02696
02698 }
02699
02700 ?>