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 $this->_start_session = $start_session;
00589
00590 if ($this->_start_session && session_id())
00591 {
00592 phpCAS :: error("Another session was started before phpcas. Either disable the session" .
00593 " handling for phpcas in the client() call or modify your application to leave" .
00594 " session handling to phpcas");
00595 }
00596
00597 if ($start_session && !$this->isLogoutRequest())
00598 {
00599 phpCAS :: trace("Starting a new session");
00600 session_start();
00601 }
00602
00603
00604
00605 $this->_proxy = $proxy;
00606
00607
00608 switch ($server_version) {
00609 case CAS_VERSION_1_0:
00610 if ( $this->isProxy() )
00611 phpCAS::error('CAS proxies are not supported in CAS '
00612 .$server_version);
00613 break;
00614 case CAS_VERSION_2_0:
00615 break;
00616 case SAML_VERSION_1_1:
00617 break;
00618 default:
00619 phpCAS::error('this version of CAS (`'
00620 .$server_version
00621 .'\') is not supported by phpCAS '
00622 .phpCAS::getVersion());
00623 }
00624 $this->_server['version'] = $server_version;
00625
00626 // check hostname
00627 if ( empty($server_hostname)
00628 || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
00629 phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
00630 }
00631 $this->_server['hostname'] = $server_hostname;
00632
00633
00634 if ( $server_port == 0
00635 || !is_int($server_port) ) {
00636 phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
00637 }
00638 $this->_server['port'] = $server_port;
00639
00640 // check URI
00641 if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
00642 phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
00643 }
00644
00645 $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');
00646 $this->_server['uri'] = $server_uri;
00647
00648
00649 if ( $this->isProxy() ) {
00650 $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
00651 }
00652
00653 if ( $this->isCallbackMode() ) {
00654
00655 if ( !$this->isHttps() ) {
00656 phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
00657 }
00658 } else {
00659
00660 $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
00661 switch ($this->getServerVersion()) {
00662 case CAS_VERSION_1_0:
00663 if( preg_match('/^ST-/',$ticket) ) {
00664 phpCAS::trace('ST \''.$ticket.'\' found');
00665 //ST present
00666 $this->setST($ticket);
00667 //ticket has been taken into account, unset it to hide it to applications
00668 unset($_GET['ticket']);
00669 } else if ( !empty($ticket) ) {
00670 //ill-formed ticket, halt
00671 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00672 }
00673 break;
00674 case CAS_VERSION_2_0:
00675 if( preg_match('/^[SP]T-/',$ticket) ) {
00676 phpCAS::trace('ST or PT \''.$ticket.'\' found');
00677 $this->setPT($ticket);
00678 unset($_GET['ticket']);
00679 } else if ( !empty($ticket) ) {
00680 //ill-formed ticket, halt
00681 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00682 }
00683 break;
00684 case SAML_VERSION_1_1:
00685 if( preg_match('/^[SP]T-/',$ticket) ) {
00686 phpCAS::trace('SA \''.$ticket.'\' found');
00687 $this->setSA($ticket);
00688 unset($_GET['ticket']);
00689 } else if ( !empty($ticket) ) {
00690 //ill-formed ticket, halt
00691 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00692 }
00693 break;
00694 }
00695 }
00696 phpCAS::traceEnd();
00697 }
00698
00701
00702
00703
00704
00705
00706
00712 var $_start_session = true;
00713
00714 function setStartSession($session)
00715 {
00716 $this->_start_session = session;
00717 }
00718
00719 function getStartSession($session)
00720 {
00721 $this->_start_session = session;
00722 }
00723
00727 function renameSession($ticket)
00728 {
00729 phpCAS::traceBegin();
00730 if($this->_start_session){
00731 if (!empty ($this->_user))
00732 {
00733 $old_session = $_SESSION;
00734 session_destroy();
00735
00736 $session_id = preg_replace('/[^\w]/', '', $ticket);
00737 phpCAS :: trace("Session ID: ".$session_id);
00738 session_id($session_id);
00739 session_start();
00740 phpCAS :: trace("Restoring old session vars");
00741 $_SESSION = $old_session;
00742 } else
00743 {
00744 phpCAS :: error('Session should only be renamed after successfull authentication');
00745 }
00746 }else{
00747 phpCAS :: trace("Skipping session rename since phpCAS is not handling the session.");
00748 }
00749 phpCAS::traceEnd();
00750 }
00751
00752
00753
00754
00755
00756
00757
00770 var $_user = '';
00771
00779 function setUser($user)
00780 {
00781 $this->_user = $user;
00782 }
00783
00791 function getUser()
00792 {
00793 if ( empty($this->_user) ) {
00794 phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00795 }
00796 return $this->_user;
00797 }
00798
00799
00800
00801
00802
00803
00804
00805
00806
00814 var $_attributes = array();
00815
00816 function setAttributes($attributes)
00817 { $this->_attributes = $attributes; }
00818
00819 function getAttributes() {
00820 if ( empty($this->_user) ) {
00821 phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00822 }
00823 return $this->_attributes;
00824 }
00825
00826 function hasAttributes()
00827 { return !empty($this->_attributes); }
00828
00829 function hasAttribute($key)
00830 { return (is_array($this->_attributes) && array_key_exists($key, $this->_attributes)); }
00831
00832 function getAttribute($key) {
00833 if($this->hasAttribute($key)) {
00834 return $this->_attributes[$key];
00835 }
00836 }
00837
00844 function renewAuthentication(){
00845 phpCAS::traceBegin();
00846
00847 if( isset( $_SESSION['phpCAS']['auth_checked'] ) )
00848 unset($_SESSION['phpCAS']['auth_checked']);
00849 if ( $this->isAuthenticated() ) {
00850 phpCAS::trace('user already authenticated; renew');
00851 $this->redirectToCas(false,true);
00852 } else {
00853 $this->redirectToCas();
00854 }
00855 phpCAS::traceEnd();
00856 }
00857
00864 function forceAuthentication()
00865 {
00866 phpCAS::traceBegin();
00867
00868 if ( $this->isAuthenticated() ) {
00869
00870 phpCAS::trace('no need to authenticate');
00871 $res = TRUE;
00872 } else {
00873
00874 if (isset($_SESSION['phpCAS']['auth_checked'])) {
00875 unset($_SESSION['phpCAS']['auth_checked']);
00876 }
00877 $this->redirectToCas(FALSE);
00878
00879 $res = FALSE;
00880 }
00881 phpCAS::traceEnd($res);
00882 return $res;
00883 }
00884
00891 var $_cache_times_for_auth_recheck = 0;
00892
00900 function setCacheTimesForAuthRecheck($n)
00901 {
00902 $this->_cache_times_for_auth_recheck = $n;
00903 }
00904
00910 function checkAuthentication()
00911 {
00912 phpCAS::traceBegin();
00913
00914 if ( $this->isAuthenticated() ) {
00915 phpCAS::trace('user is authenticated');
00916 $res = TRUE;
00917 } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
00918
00919 unset($_SESSION['phpCAS']['auth_checked']);
00920 $res = FALSE;
00921 } else {
00922
00923
00924
00925
00926
00927 if (! isset($_SESSION['phpCAS']['unauth_count']) )
00928 $_SESSION['phpCAS']['unauth_count'] = -2;
00929
00930 if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1)
00931 || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck))
00932 {
00933 $res = FALSE;
00934
00935 if ($this->_cache_times_for_auth_recheck != -1)
00936 {
00937 $_SESSION['phpCAS']['unauth_count']++;
00938 phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')');
00939 }
00940 else
00941 {
00942 phpCAS::trace('user is not authenticated (cached for until login pressed)');
00943 }
00944 }
00945 else
00946 {
00947 $_SESSION['phpCAS']['unauth_count'] = 0;
00948 $_SESSION['phpCAS']['auth_checked'] = true;
00949 phpCAS::trace('user is not authenticated (cache reset)');
00950 $this->redirectToCas(TRUE);
00951
00952 $res = FALSE;
00953 }
00954 }
00955 phpCAS::traceEnd($res);
00956 return $res;
00957 }
00958
00967 function isAuthenticated()
00968 {
00969 phpCAS::traceBegin();
00970 $res = FALSE;
00971 $validate_url = '';
00972
00973 if ( $this->wasPreviouslyAuthenticated() ) {
00974 if($this->hasST() || $this->hasPT() || $this->hasSA()){
00975
00976 phpCAS::trace('ticket was present and will be discarded, use renewAuthenticate()');
00977 header('Location: '.$this->getURL());
00978 phpCAS::log( "Prepare redirect to remove ticket: ".$this->getURL() );
00979 }else{
00980
00981
00982 phpCAS::trace('user was already authenticated, no need to look for tickets');
00983 }
00984 $res = TRUE;
00985 }
00986 else {
00987 if ( $this->hasST() ) {
00988
00989 phpCAS::trace('ST `'.$this->getST().'\' is present');
00990 $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
00991 phpCAS::trace('ST `'.$this->getST().'\' was validated');
00992 if ( $this->isProxy() ) {
00993 $this->validatePGT($validate_url,$text_response,$tree_response);
00994 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00995 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00996 }
00997 $_SESSION['phpCAS']['user'] = $this->getUser();
00998 $res = TRUE;
00999 }
01000 elseif ( $this->hasPT() ) {
01001 // if a Proxy Ticket was given, validate it
01002 phpCAS::trace('PT `'.$this->getPT().'\' is present');
01003 $this->validatePT($validate_url,$text_response,$tree_response);
01004 phpCAS::trace('PT `'.$this->getPT().'\' was validated');
01005 if ( $this->isProxy() ) {
01006 $this->validatePGT($validate_url,$text_response,$tree_response); // idem
01007 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
01008 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
01009 }
01010 $_SESSION['phpCAS']['user'] = $this->getUser();
01011 $res = TRUE;
01012 }
01013 elseif ( $this->hasSA() ) {
01014
01015 phpCAS::trace('SA `'.$this->getSA().'\' is present');
01016 $this->validateSA($validate_url,$text_response,$tree_response); // if it fails, it halts
01017 phpCAS::trace('SA `'.$this->getSA().'\' was validated');
01018 $_SESSION['phpCAS']['user'] = $this->getUser();
01019 $_SESSION['phpCAS']['attributes'] = $this->getAttributes();
01020 $res = TRUE;
01021 }
01022 else {
01023
01024 phpCAS::trace('no ticket found');
01025 }
01026 if ($res) {
01027
01028
01029 header('Location: '.$this->getURL());
01030 phpCAS::log( "Prepare redirect to : ".$this->getURL() );
01031 }
01032 }
01033
01034 phpCAS::traceEnd($res);
01035 return $res;
01036 }
01037
01043 function isSessionAuthenticated ()
01044 {
01045 return !empty($_SESSION['phpCAS']['user']);
01046 }
01047
01058 function wasPreviouslyAuthenticated()
01059 {
01060 phpCAS::traceBegin();
01061
01062 if ( $this->isCallbackMode() ) {
01063 $this->callback();
01064 }
01065
01066 $auth = FALSE;
01067
01068 if ( $this->isProxy() ) {
01069
01070 if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
01071
01072 $this->setUser($_SESSION['phpCAS']['user']);
01073 $this->setPGT($_SESSION['phpCAS']['pgt']);
01074 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\'');
01075 $auth = TRUE;
01076 } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
01077
01078 phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
01079 // unset all tickets to enforce authentication
01080 unset($_SESSION['phpCAS']);
01081 $this->setST('');
01082 $this->setPT('');
01083 } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
01084 // these two variables should be empty or not empty at the same time
01085 phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty');
01086
01087 unset($_SESSION['phpCAS']);
01088 $this->setST('');
01089 $this->setPT('');
01090 } else {
01091 phpCAS::trace('neither user not PGT found');
01092 }
01093 } else {
01094
01095 if ( $this->isSessionAuthenticated() ) {
01096
01097 $this->setUser($_SESSION['phpCAS']['user']);
01098 if(isset($_SESSION['phpCAS']['attributes'])){
01099 $this->setAttributes($_SESSION['phpCAS']['attributes']);
01100 }
01101 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\'');
01102 $auth = TRUE;
01103 } else {
01104 phpCAS::trace('no user found');
01105 }
01106 }
01107
01108 phpCAS::traceEnd($auth);
01109 return $auth;
01110 }
01111
01119 function redirectToCas($gateway=false,$renew=false){
01120 phpCAS::traceBegin();
01121 $cas_url = $this->getServerLoginURL($gateway,$renew);
01122 header('Location: '.$cas_url);
01123 phpCAS::log( "Redirect to : ".$cas_url );
01124
01125 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
01126
01127 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
01128 $this->printHTMLFooter();
01129
01130 phpCAS::traceExit();
01131 exit();
01132 }
01133
01134
01140 function logout($params) {
01141 phpCAS::traceBegin();
01142 $cas_url = $this->getServerLogoutURL();
01143 $paramSeparator = '?';
01144 if (isset($params['url'])) {
01145 $cas_url = $cas_url . $paramSeparator . "url=" . urlencode($params['url']);
01146 $paramSeparator = '&';
01147 }
01148 if (isset($params['service'])) {
01149 $cas_url = $cas_url . $paramSeparator . "service=" . urlencode($params['service']);
01150 }
01151 header('Location: '.$cas_url);
01152 phpCAS::log( "Prepare redirect to : ".$cas_url );
01153
01154 session_unset();
01155 session_destroy();
01156
01157 $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
01158 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
01159 $this->printHTMLFooter();
01160
01161 phpCAS::traceExit();
01162 exit();
01163 }
01164
01169 function isLogoutRequest() {
01170 return !empty($_POST['logoutRequest']);
01171 }
01172
01177 function isLogoutRequestAllowed() {
01178 }
01179
01188 function handleLogoutRequests($check_client=true, $allowed_clients=false) {
01189 phpCAS::traceBegin();
01190 if (!$this->isLogoutRequest()) {
01191 phpCAS::log("Not a logout request");
01192 phpCAS::traceEnd();
01193 return;
01194 }
01195 if(!$this->_start_session){
01196 phpCAS::log("phpCAS can't handle logout requests if it does not manage the session.");
01197 }
01198 phpCAS::log("Logout requested");
01199 phpCAS::log("SAML REQUEST: ".$_POST['logoutRequest']);
01200 if ($check_client) {
01201 if (!$allowed_clients) {
01202 $allowed_clients = array( $this->getServerHostname() );
01203 }
01204 $client_ip = $_SERVER['REMOTE_ADDR'];
01205 $client = gethostbyaddr($client_ip);
01206 phpCAS::log("Client: ".$client."/".$client_ip);
01207 $allowed = false;
01208 foreach ($allowed_clients as $allowed_client) {
01209 if (($client == $allowed_client) or ($client_ip == $allowed_client)) {
01210 phpCAS::log("Allowed client '".$allowed_client."' matches, logout request is allowed");
01211 $allowed = true;
01212 break;
01213 } else {
01214 phpCAS::log("Allowed client '".$allowed_client."' does not match");
01215 }
01216 }
01217 if (!$allowed) {
01218 phpCAS::error("Unauthorized logout request from client '".$client."'");
01219 printf("Unauthorized!");
01220 phpCAS::traceExit();
01221 exit();
01222 }
01223 } else {
01224 phpCAS::log("No access control set");
01225 }
01226
01227 preg_match("|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|", $_POST['logoutRequest'], $tick, PREG_OFFSET_CAPTURE, 3);
01228 $wrappedSamlSessionIndex = preg_replace('|<samlp:SessionIndex>|','',$tick[0][0]);
01229 $ticket2logout = preg_replace('|</samlp:SessionIndex>|','',$wrappedSamlSessionIndex);
01230 phpCAS::log("Ticket to logout: ".$ticket2logout);
01231 $session_id = preg_replace('/[^\w]/','',$ticket2logout);
01232 phpCAS::log("Session id: ".$session_id);
01233
01234
01235 if(session_id()){
01236 session_unset();
01237 session_destroy();
01238 }
01239
01240 session_id($session_id);
01241 $_COOKIE[session_name()]=$session_id;
01242 $_GET[session_name()]=$session_id;
01243
01244
01245 session_start();
01246 session_unset();
01247 session_destroy();
01248 printf("Disconnected!");
01249 phpCAS::traceExit();
01250 exit();
01251 }
01252
01255
01256
01257
01258
01259
01260
01261
01262
01263
01277 var $_st = '';
01278
01284 function getST()
01285 { return $this->_st; }
01286
01292 function setST($st)
01293 { $this->_st = $st; }
01294
01300 function hasST()
01301 { return !empty($this->_st); }
01302
01305
01306
01307
01319 var $_cas_server_cert = '';
01320
01327 var $_cas_server_ca_cert = '';
01328
01335 var $_no_cas_server_validation = false;
01336
01342 function setCasServerCert($cert)
01343 {
01344 $this->_cas_server_cert = $cert;
01345 }
01346
01352 function setCasServerCACert($cert)
01353 {
01354 $this->_cas_server_ca_cert = $cert;
01355 }
01356
01360 function setNoCasServerValidation()
01361 {
01362 $this->_no_cas_server_validation = true;
01363 }
01364
01378 function validateST($validate_url,&$text_response,&$tree_response)
01379 {
01380 phpCAS::traceBegin();
01381
01382 $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
01383 if ( $this->isProxy() ) {
01384
01385 $validate_url .= '&pgtUrl='.urlencode($this->getCallbackURL());
01386 }
01387
01388
01389 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
01390 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01391 $this->authError('ST not validated',
01392 $validate_url,
01393 TRUE/*$no_response*/);
01394 }
01395
01396 // analyze the result depending on the version
01397 switch ($this->getServerVersion()) {
01398 case CAS_VERSION_1_0:
01399 if (preg_match('/^no\n/',$text_response)) {
01400 phpCAS::trace('ST has not been validated');
01401 $this->authError('ST not validated',
01402 $validate_url,
01403 FALSE/*$no_response*/,
01404 FALSE/*$bad_response*/,
01405 $text_response);
01406 }
01407 if (!preg_match('/^yes\n/',$text_response)) {
01408 phpCAS::trace('ill-formed response');
01409 $this->authError('ST not validated',
01410 $validate_url,
01411 FALSE/*$no_response*/,
01412 TRUE/*$bad_response*/,
01413 $text_response);
01414 }
01415 // ST has been validated, extract the user name
01416 $arr = preg_split('/\n/',$text_response);
01417 $this->setUser(trim($arr[1]));
01418 break;
01419 case CAS_VERSION_2_0:
01420 // read the response of the CAS server into a DOM object
01421 if ( !($dom = domxml_open_mem($text_response))) {
01422 phpCAS::trace('domxml_open_mem() failed');
01423 $this->authError('ST not validated',
01424 $validate_url,
01425 FALSE/*$no_response*/,
01426 TRUE/*$bad_response*/,
01427 $text_response);
01428 }
01429 // read the root node of the XML tree
01430 if ( !($tree_response = $dom->document_element()) ) {
01431 phpCAS::trace('document_element() failed');
01432 $this->authError('ST not validated',
01433 $validate_url,
01434 FALSE/*$no_response*/,
01435 TRUE/*$bad_response*/,
01436 $text_response);
01437 }
01438 // insure that tag name is 'serviceResponse'
01439 if ( $tree_response->node_name() != 'serviceResponse' ) {
01440 phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');
01441 $this->authError('ST not validated',
01442 $validate_url,
01443 FALSE,
01444 TRUE,
01445 $text_response);
01446 }
01447 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
01448
01449 if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
01450 phpCAS::trace('<authenticationSuccess> found, but no <user>');
01451 $this->authError('ST not validated',
01452 $validate_url,
01453 FALSE,
01454 TRUE,
01455 $text_response);
01456 }
01457 $user = trim($user_elements[0]->get_content());
01458 phpCAS::trace('user = `'.$user);
01459 $this->setUser($user);
01460
01461 } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
01462 phpCAS::trace('<authenticationFailure> found');
01463
01464 $this->authError('ST not validated',
01465 $validate_url,
01466 FALSE,
01467 FALSE,
01468 $text_response,
01469 $failure_elements[0]->get_attribute('code'),
01470 trim($failure_elements[0]->get_content()));
01471 } else {
01472 phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
01473 $this->authError('ST not validated',
01474 $validate_url,
01475 FALSE,
01476 TRUE,
01477 $text_response);
01478 }
01479 break;
01480 }
01481 $this->renameSession($this->getST());
01482
01483 phpCAS::traceEnd(TRUE);
01484 return TRUE;
01485 }
01486
01487
01488
01489
01508 function validateSA($validate_url,&$text_response,&$tree_response)
01509 {
01510 phpCAS::traceBegin();
01511
01512
01513 $validate_url = $this->getServerSamlValidateURL();
01514
01515
01516 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
01517 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01518 $this->authError('SA not validated', $validate_url, TRUE/*$no_response*/);
01519 }
01520
01521 phpCAS::trace('server version: '.$this->getServerVersion());
01522
01523 // analyze the result depending on the version
01524 switch ($this->getServerVersion()) {
01525 case SAML_VERSION_1_1:
01526
01527 // read the response of the CAS server into a DOM object
01528 if ( !($dom = domxml_open_mem($text_response))) {
01529 phpCAS::trace('domxml_open_mem() failed');
01530 $this->authError('SA not validated',
01531 $validate_url,
01532 FALSE/*$no_response*/,
01533 TRUE/*$bad_response*/,
01534 $text_response);
01535 }
01536 // read the root node of the XML tree
01537 if ( !($tree_response = $dom->document_element()) ) {
01538 phpCAS::trace('document_element() failed');
01539 $this->authError('SA not validated',
01540 $validate_url,
01541 FALSE/*$no_response*/,
01542 TRUE/*$bad_response*/,
01543 $text_response);
01544 }
01545 // insure that tag name is 'Envelope'
01546 if ( $tree_response->node_name() != 'Envelope' ) {
01547 phpCAS::trace('bad XML root node (should be `Envelope\' instead of `'.$tree_response->node_name().'\'');
01548 $this->authError('SA not validated',
01549 $validate_url,
01550 FALSE,
01551 TRUE,
01552 $text_response);
01553 }
01554
01555 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("NameIdentifier")) != 0) {
01556 phpCAS::trace('NameIdentifier found');
01557 $user = trim($success_elements[0]->get_content());
01558 phpCAS::trace('user = `'.$user.'`');
01559 $this->setUser($user);
01560 $this->setSessionAttributes($text_response);
01561 } else {
01562 phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
01563 $this->authError('SA not validated',
01564 $validate_url,
01565 FALSE,
01566 TRUE,
01567 $text_response);
01568 }
01569 break;
01570 }
01571 $this->renameSession($this->getSA());
01572
01573 phpCAS::traceEnd(TRUE);
01574 return TRUE;
01575 }
01576
01586 function setSessionAttributes($text_response)
01587 {
01588 phpCAS::traceBegin();
01589
01590 $result = FALSE;
01591
01592 if (isset($_SESSION[SAML_ATTRIBUTES])) {
01593 phpCAS::trace("session attrs already set.");
01594 }
01595
01596 $attr_array = array();
01597
01598 if (($dom = domxml_open_mem($text_response))) {
01599 $xPath = $dom->xpath_new_context();
01600 $xPath->xpath_register_ns('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
01601 $xPath->xpath_register_ns('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
01602 $nodelist = $xPath->xpath_eval("//saml:Attribute");
01603 if($nodelist){
01604 $attrs = $nodelist->nodeset;
01605 foreach($attrs as $attr){
01606 $xres = $xPath->xpath_eval("saml:AttributeValue", $attr);
01607 $name = $attr->get_attribute("AttributeName");
01608 $value_array = array();
01609 foreach($xres->nodeset as $node){
01610 $value_array[] = $node->get_content();
01611 }
01612 $attr_array[$name] = $value_array;
01613 }
01614 $_SESSION[SAML_ATTRIBUTES] = $attr_array;
01615
01616 foreach($attr_array as $attr_key => $attr_value) {
01617 if(count($attr_value) > 1) {
01618 $this->_attributes[$attr_key] = $attr_value;
01619 phpCAS::trace("* " . $attr_key . "=" . $attr_value);
01620 }
01621 else {
01622 $this->_attributes[$attr_key] = $attr_value[0];
01623 phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
01624 }
01625 }
01626 $result = TRUE;
01627 }else{
01628 phpCAS::trace("SAML Attributes are empty");
01629 $result = FALSE;
01630 }
01631 }
01632 phpCAS::traceEnd($result);
01633 return $result;
01634 }
01635
01638
01639
01640
01641
01642
01643
01644
01645
01646
01658 var $_proxy;
01659
01667 function isProxy()
01668 {
01669 return $this->_proxy;
01670 }
01671
01673
01674
01675
01688 var $_pgt = '';
01689
01695 function getPGT()
01696 { return $this->_pgt; }
01697
01703 function setPGT($pgt)
01704 { $this->_pgt = $pgt; }
01705
01711 function hasPGT()
01712 { return !empty($this->_pgt); }
01713
01716
01717
01718
01736 var $_callback_mode = FALSE;
01737
01745 function setCallbackMode($callback_mode)
01746 {
01747 $this->_callback_mode = $callback_mode;
01748 }
01749
01758 function isCallbackMode()
01759 {
01760 return $this->_callback_mode;
01761 }
01762
01771 var $_callback_url = '';
01772
01782 function getCallbackURL()
01783 {
01784
01785 if ( empty($this->_callback_url) ) {
01786 $final_uri = '';
01787
01788 $final_uri = 'https://';
01789
01790
01791
01792 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01793
01794
01795
01796 if (empty($_SERVER['SERVER_NAME'])) {
01797 $final_uri .= $_SERVER['HTTP_HOST'];
01798 } else {
01799 $final_uri .= $_SERVER['SERVER_NAME'];
01800 }
01801 } else {
01802 $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
01803 }
01804 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
01805 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
01806 $final_uri .= ':';
01807 $final_uri .= $_SERVER['SERVER_PORT'];
01808 }
01809 $request_uri = $_SERVER['REQUEST_URI'];
01810 $request_uri = preg_replace('/\?.*$/','',$request_uri);
01811 $final_uri .= $request_uri;
01812 $this->setCallbackURL($final_uri);
01813 }
01814 return $this->_callback_url;
01815 }
01816
01824 function setCallbackURL($url)
01825 {
01826 return $this->_callback_url = $url;
01827 }
01828
01835 function callback()
01836 {
01837 phpCAS::traceBegin();
01838 $this->printHTMLHeader('phpCAS callback');
01839 $pgt_iou = $_GET['pgtIou'];
01840 $pgt = $_GET['pgtId'];
01841 phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
01842 echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
01843 $this->storePGT($pgt,$pgt_iou);
01844 $this->printHTMLFooter();
01845 phpCAS::traceExit();
01846 exit();
01847 }
01848
01851
01852
01853
01867 var $_pgt_storage = null;
01868
01875 function initPGTStorage()
01876 {
01877
01878 if ( !is_object($this->_pgt_storage) ) {
01879 $this->setPGTStorageFile();
01880 }
01881
01882
01883 $this->_pgt_storage->init();
01884 }
01885
01894 function storePGT($pgt,$pgt_iou)
01895 {
01896
01897 $this->initPGTStorage();
01898
01899 $this->_pgt_storage->write($pgt,$pgt_iou);
01900 }
01901
01911 function loadPGT($pgt_iou)
01912 {
01913
01914 $this->initPGTStorage();
01915
01916 return $this->_pgt_storage->read($pgt_iou);
01917 }
01918
01928 function setPGTStorageFile($format='',
01929 $path='')
01930 {
01931
01932 if ( is_object($this->_pgt_storage) ) {
01933 phpCAS::error('PGT storage already defined');
01934 }
01935
01936
01937 $this->_pgt_storage = new PGTStorageFile($this,$format,$path);
01938 }
01939
01957 function setPGTStorageDB($user,
01958 $password,
01959 $database_type,
01960 $hostname,
01961 $port,
01962 $database,
01963 $table)
01964 {
01965
01966 if ( is_object($this->_pgt_storage) ) {
01967 phpCAS::error('PGT storage already defined');
01968 }
01969
01970
01971 trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);
01972
01973
01974 $this->_pgt_storage = new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table);
01975 }
01976
01977
01978
01979
01993 function validatePGT(&$validate_url,$text_response,$tree_response)
01994 {
01995
01996 phpCAS::log('start validatePGT()');
01997 if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
01998 phpCAS::trace('<proxyGrantingTicket> not found');
01999
02000 $this->authError('Ticket validated but no PGT Iou transmitted',
02001 $validate_url,
02002 FALSE,
02003 FALSE,
02004 $text_response);
02005 } else {
02006
02007 $pgt_iou = trim($arr[0]->get_content());
02008 $pgt = $this->loadPGT($pgt_iou);
02009 if ( $pgt == FALSE ) {
02010 phpCAS::trace('could not load PGT');
02011 $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
02012 $validate_url,
02013 FALSE,
02014 FALSE,
02015 $text_response);
02016 }
02017 $this->setPGT($pgt);
02018 }
02019
02020 phpCAS::log('end validatePGT()');
02021 return TRUE;
02022 }
02023
02024
02025
02026
02027
02039 function retrievePT($target_service,&$err_code,&$err_msg)
02040 {
02041 phpCAS::traceBegin();
02042
02043
02044
02045
02046
02047 $err_msg = '';
02048
02049
02050
02051 $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT();
02052
02053
02054 if ( !$this->readURL($cas_url,'',$headers,$cas_response,$err_msg) ) {
02055 phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
02056 $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
02057 $err_msg = 'could not retrieve PT (no response from the CAS server)';
02058 phpCAS::traceEnd(FALSE);
02059 return FALSE;
02060 }
02061
02062 $bad_response = FALSE;
02063
02064 if ( !$bad_response ) {
02065 // read the response of the CAS server into a DOM object
02066 if ( !($dom = @domxml_open_mem($cas_response))) {
02067 phpCAS::trace('domxml_open_mem() failed');
02068 // read failed
02069 $bad_response = TRUE;
02070 }
02071 }
02072
02073 if ( !$bad_response ) {
02074 // read the root node of the XML tree
02075 if ( !($root = $dom->document_element()) ) {
02076 phpCAS::trace('document_element() failed');
02077 // read failed
02078 $bad_response = TRUE;
02079 }
02080 }
02081
02082 if ( !$bad_response ) {
02083 // insure that tag name is 'serviceResponse'
02084 if ( $root->node_name() != 'serviceResponse' ) {
02085 phpCAS::trace('node_name() failed');
02086 // bad root node
02087 $bad_response = TRUE;
02088 }
02089 }
02090
02091 if ( !$bad_response ) {
02092 // look for a proxySuccess tag
02093 if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
02094 // authentication succeded, look for a proxyTicket tag
02095 if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
02096 $err_code = PHPCAS_SERVICE_OK;
02097 $err_msg = '';
02098 phpCAS::trace('original PT: '.trim($arr[0]->get_content()));
02099 $pt = trim($arr[0]->get_content());
02100 phpCAS::traceEnd($pt);
02101 return $pt;
02102 } else {
02103 phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
02104 }
02105 }
02106 // look for a proxyFailure tag
02107 else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
02108 // authentication failed, extract the error
02109 $err_code = PHPCAS_SERVICE_PT_FAILURE;
02110 $err_msg = 'PT retrieving failed (code=`'
02111 .$arr[0]->get_attribute('code')
02112 .'\', message=`'
02113 .trim($arr[0]->get_content())
02114 .'\')';
02115 phpCAS::traceEnd(FALSE);
02116 return FALSE;
02117 } else {
02118 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
02119 }
02120 }
02121
02122 // at this step, we are sure that the response of the CAS server was ill-formed
02123 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
02124 $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
02125
02126 phpCAS::traceEnd(FALSE);
02127 return FALSE;
02128 }
02129
02130
02131
02132
02133
02149 function readURL($url,$cookies,&$headers,&$body,&$err_msg)
02150 {
02151 phpCAS::traceBegin();
02152 $headers = '';
02153 $body = '';
02154 $err_msg = '';
02155
02156 $res = TRUE;
02157
02158
02159 $ch = curl_init($url);
02160
02161 if (version_compare(PHP_VERSION,'5.1.3','>=')) {
02162
02163 curl_setopt_array($ch, $this->_curl_options);
02164 } else {
02165 foreach ($this->_curl_options as $key => $value) {
02166 curl_setopt($ch, $key, $value);
02167 }
02168 }
02169
02170 if ($this->_cas_server_cert == '' && $this->_cas_server_ca_cert == '' && !$this->_no_cas_server_validation) {
02171 phpCAS::error('one of the methods phpCAS::setCasServerCert(), phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.');
02172 }
02173 if ($this->_cas_server_cert != '' && $this->_cas_server_ca_cert != '') {
02174
02175 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02176 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
02177 curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
02178 curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
02179 curl_setopt($ch, CURLOPT_VERBOSE, '1');
02180 phpCAS::trace('CURL: Set all required opts for mutual authentication ------');
02181 } else if ($this->_cas_server_cert != '' ) {
02182 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02183 curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
02184 } else if ($this->_cas_server_ca_cert != '') {
02185 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02186 curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
02187 } else {
02188 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
02189 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
02190 }
02191
02192
02193 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
02194
02195 $this->_curl_headers = array();
02196 curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curl_read_headers'));
02197
02198 if ( is_array($cookies) ) {
02199 curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
02200 }
02201
02202 if ($this->hasSA()) {
02203 $more_headers = array ("soapaction: http://www.oasis-open.org/committees/security",
02204 "cache-control: no-cache",
02205 "pragma: no-cache",
02206 "accept: text/xml",
02207 "connection: keep-alive",
02208 "content-type: text/xml");
02209
02210 curl_setopt($ch, CURLOPT_HTTPHEADER, $more_headers);
02211 curl_setopt($ch, CURLOPT_POST, 1);
02212 $data = $this->buildSAMLPayload();
02213
02214 curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
02215 }
02216
02217 $buf = curl_exec ($ch);
02218
02219 if ( $buf === FALSE ) {
02220 phpCAS::trace('curl_exec() failed');
02221 $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
02222
02223
02224 curl_close ($ch);
02225 $res = FALSE;
02226 } else {
02227
02228 curl_close ($ch);
02229
02230 $headers = $this->_curl_headers;
02231 $body = $buf;
02232 }
02233
02234 phpCAS::traceEnd($res);
02235 return $res;
02236 }
02237
02245 function buildSAMLPayload()
02246 {
02247 phpCAS::traceBegin();
02248
02249
02250 $sa = $this->getSA();
02251
02252
02253 $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;
02254
02255 phpCAS::traceEnd($body);
02256 return ($body);
02257 }
02258
02262 var $_curl_headers = array();
02263 function _curl_read_headers($ch, $header)
02264 {
02265 $this->_curl_headers[] = $header;
02266 return strlen($header);
02267 }
02268
02284 function serviceWeb($url,&$err_code,&$output)
02285 {
02286 phpCAS::traceBegin();
02287 $cookies = array();
02288
02289 $pt = $this->retrievePT($url,$err_code,$output);
02290
02291 $res = TRUE;
02292
02293
02294 if ( !$pt ) {
02295
02296 phpCAS::trace('PT was not retrieved correctly');
02297 $res = FALSE;
02298 } else {
02299
02300 if ( isset($_SESSION['phpCAS']['services'][$url]['cookies']) &&
02301 is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
02302 foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) {
02303 $cookies[] = $name.'='.$val;
02304 }
02305 }
02306
02307
02308 if ( strstr($url,'?') === FALSE ) {
02309 $service_url = $url.'?ticket='.$pt;
02310 } else {
02311 $service_url = $url.'&ticket='.$pt;
02312 }
02313
02314 phpCAS::trace('reading URL`'.$service_url.'\'');
02315 if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
02316 phpCAS::trace('could not read URL`'.$service_url.'\'');
02317 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02318
02319 $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02320 $service_url,
02321 $err_msg);
02322 $res = FALSE;
02323 } else {
02324
02325 phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
02326 foreach ( $headers as $header ) {
02327 // test if the header is a cookie
02328 if ( preg_match('/^Set-Cookie:/',$header) ) {
02329 // the header is a cookie, remove the beginning
02330 $header_val = preg_replace('/^Set-Cookie: */','',$header);
02331 // extract interesting information
02332 $name_val = strtok($header_val,'; ');
02333 // extract the name and the value of the cookie
02334 $cookie_name = strtok($name_val,'=');
02335 $cookie_val = strtok('=');
02336 // store the cookie
02337 $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
02338 phpCAS::trace($cookie_name.' -> '.$cookie_val);
02339 }
02340 }
02341 }
02342 }
02343
02344 phpCAS::traceEnd($res);
02345 return $res;
02346 }
02347
02367 function serviceMail($url,$service,$flags,&$err_code,&$err_msg,&$pt)
02368 {
02369 phpCAS::traceBegin();
02370 // at first retrieve a PT
02371 $pt = $this->retrievePT($service,$err_code,$output);
02372
02373 $stream = FALSE;
02374
02375 // test if PT was retrieved correctly
02376 if ( !$pt ) {
02377 // note: $err_code and $err_msg are filled by CASClient::retrievePT()
02378 phpCAS::trace('PT was not retrieved correctly');
02379 } else {
02380 phpCAS::trace('opening IMAP URL `'.$url.'\'...');
02381 $stream = @imap_open($url,$this->getUser(),$pt,$flags);
02382 if ( !$stream ) {
02383 phpCAS::trace('could not open URL');
02384 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02385
02386 $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02387 $service_url,
02388 var_export(imap_errors(),TRUE));
02389 $pt = FALSE;
02390 $stream = FALSE;
02391 } else {
02392 phpCAS::trace('ok');
02393 }
02394 }
02395
02396 phpCAS::traceEnd($stream);
02397 return $stream;
02398 }
02399
02402
02403
02404
02405
02406
02407
02408
02409
02410
02424 var $_pt = '';
02425
02431 function getPT()
02432 {
02433
02434 return $this->_pt;
02435 }
02436
02442 function setPT($pt)
02443 { $this->_pt = $pt; }
02444
02450 function hasPT()
02451 { return !empty($this->_pt); }
02457 function getSA()
02458 { return 'ST'.substr($this->_sa, 2); }
02459
02465 function setSA($sa)
02466 { $this->_sa = $sa; }
02467
02473 function hasSA()
02474 { return !empty($this->_sa); }
02475
02477
02478
02479
02492 function validatePT(&$validate_url,&$text_response,&$tree_response)
02493 {
02494 phpCAS::traceBegin();
02495
02496 $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
02497
02498 if ( $this->isProxy() ) {
02499
02500 $validate_url .= '&pgtUrl='.urlencode($this->getCallbackURL());
02501 }
02502
02503
02504 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
02505 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
02506 $this->authError('PT not validated',
02507 $validate_url,
02508 TRUE/*$no_response*/);
02509 }
02510
02511 // read the response of the CAS server into a DOM object
02512 if ( !($dom = domxml_open_mem($text_response))) {
02513 // read failed
02514 $this->authError('PT not validated',
02515 $validate_url,
02516 FALSE/*$no_response*/,
02517 TRUE/*$bad_response*/,
02518 $text_response);
02519 }
02520 // read the root node of the XML tree
02521 if ( !($tree_response = $dom->document_element()) ) {
02522 // read failed
02523 $this->authError('PT not validated',
02524 $validate_url,
02525 FALSE/*$no_response*/,
02526 TRUE/*$bad_response*/,
02527 $text_response);
02528 }
02529 // insure that tag name is 'serviceResponse'
02530 if ( $tree_response->node_name() != 'serviceResponse' ) {
02531 // bad root node
02532 $this->authError('PT not validated',
02533 $validate_url,
02534 FALSE/*$no_response*/,
02535 TRUE/*$bad_response*/,
02536 $text_response);
02537 }
02538 if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
02539 // authentication succeded, extract the user name
02540 if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
02541 // no user specified => error
02542 $this->authError('PT not validated',
02543 $validate_url,
02544 FALSE/*$no_response*/,
02545 TRUE/*$bad_response*/,
02546 $text_response);
02547 }
02548 $this->setUser(trim($arr[0]->get_content()));
02549
02550 } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
02551 // authentication succeded, extract the error code and message
02552 $this->authError('PT not validated',
02553 $validate_url,
02554 FALSE/*$no_response*/,
02555 FALSE/*$bad_response*/,
02556 $text_response,
02557 $arr[0]->get_attribute('code')/*$err_code*/,
02558 trim($arr[0]->get_content())/*$err_msg*/);
02559 } else {
02560 $this->authError('PT not validated',
02561 $validate_url,
02562 FALSE/*$no_response*/,
02563 TRUE/*$bad_response*/,
02564 $text_response);
02565 }
02566
02567 $this->renameSession($this->getPT());
02568 // at this step, PT has been validated and $this->_user has been set,
02569
02570 phpCAS::traceEnd(TRUE);
02571 return TRUE;
02572 }
02573
02576 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02577 // XX XX
02578 // XX MISC XX
02579 // XX XX
02580 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02581
02587 // ########################################################################
02588 // URL
02589 // ########################################################################
02597 var $_url = '';
02598
02607 function getURL()
02608 {
02609 phpCAS::traceBegin();
02610 // the URL is built when needed only
02611 if ( empty($this->_url) ) {
02612 $final_uri = '';
02613 // remove the ticket if present in the URL
02614 $final_uri = ($this->isHttps()) ? 'https' : 'http';
02615 $final_uri .= ':
02616
02617
02618
02619 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
02620
02621
02622
02623 if (empty($_SERVER['SERVER_NAME'])) {
02624 $server_name = $_SERVER['HTTP_HOST'];
02625 } else {
02626 $server_name = $_SERVER['SERVER_NAME'];
02627 }
02628 } else {
02629 $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER'];
02630 }
02631 $final_uri .= $server_name;
02632 if (!strpos($server_name, ':')) {
02633 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
02634 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
02635 $final_uri .= ':';
02636 $final_uri .= $_SERVER['SERVER_PORT'];
02637 }
02638 }
02639
02640 $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);
02641 $final_uri .= $request_uri[0];
02642
02643 if (isset($request_uri[1]) && $request_uri[1])
02644 {
02645 $query_string = $this->removeParameterFromQueryString('ticket', $request_uri[1]);
02646
02647
02648 if ($query_string !== '')
02649 $final_uri .= "?$query_string";
02650
02651 }
02652
02653 phpCAS::trace("Final URI: $final_uri");
02654 $this->setURL($final_uri);
02655 }
02656 phpCAS::traceEnd($this->_url);
02657 return $this->_url;
02658 }
02659
02660
02661
02671 function removeParameterFromQueryString($parameterName, $queryString)
02672 {
02673 $parameterName = preg_quote($parameterName);
02674 return preg_replace("/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/", '', $queryString);
02675 }
02676
02677
02685 function setURL($url)
02686 {
02687 $this->_url = $url;
02688 }
02689
02690
02691
02692
02708 function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
02709 {
02710 phpCAS::traceBegin();
02711
02712 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
02713 printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),htmlentities($this->getURL()),$_SERVER['SERVER_ADMIN']);
02714 phpCAS::trace('CAS URL: '.$cas_url);
02715 phpCAS::trace('Authentication failure: '.$failure);
02716 if ( $no_response ) {
02717 phpCAS::trace('Reason: no response from the CAS server');
02718 } else {
02719 if ( $bad_response ) {
02720 phpCAS::trace('Reason: bad response from the CAS server');
02721 } else {
02722 switch ($this->getServerVersion()) {
02723 case CAS_VERSION_1_0:
02724 phpCAS::trace('Reason: CAS error');
02725 break;
02726 case CAS_VERSION_2_0:
02727 if ( empty($err_code) )
02728 phpCAS::trace('Reason: no CAS error');
02729 else
02730 phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
02731 break;
02732 }
02733 }
02734 phpCAS::trace('CAS response: '.$cas_response);
02735 }
02736 $this->printHTMLFooter();
02737 phpCAS::traceExit();
02738 exit();
02739 }
02740
02742 }
02743
02744 ?>