phpPoA2
[ class tree: phpPoA2 ] [ index: phpPoA2 ] [ all elements ]

Source for file PAPIAuthnEngine.php

Documentation is available at PAPIAuthnEngine.php

  1. <?php
  2. /**
  3.  * @copyright Copyright 2005-2010 RedIRIS, http://www.rediris.es/
  4.  *
  5.  *  This file is part of phpPoA2.
  6.  *
  7.  *  phpPoA2 is free software: you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation, either version 3 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  phpPoA2 is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with phpPoA2. If not, see <http://www.gnu.org/licenses/>.
  19.  *
  20.  * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
  21.  * @version 2.0
  22.  * @author Jaime Perez <jaime.perez@rediris.es>
  23.  * @filesource
  24.  */
  25.  
  26. /**
  27.  * Default assertion delimiters for standard PAPI 1.5 protocol.
  28.  */
  29. define("ATTR_SEPARATOR"",");
  30. define("VALUE_SEPARATOR""|");
  31. define("NAMEVALUE_SEPARATOR""=");
  32.  
  33. /**
  34.  * Supported database types.
  35.  */
  36. define('PAPI_DBA''PAPIDBADB');
  37. define('PAPI_MYSQL''PAPIMySQLDB');
  38. define('PAPI_SESSION''PAPISessionDB');
  39.  
  40. /**
  41.  * Supported namespaces for attributes.
  42.  */
  43. define('NS_PAPI_PROTOCOL''urn:mace:rediris.es:papi:protocol');
  44. define('NS_PAPI_ATTRIBUTES''urn:mace:rediris.es:papi:attributes');
  45.  
  46. /**
  47.  * Prefix for operational attributes inside the protocol and special
  48.  * attributes names.
  49.  */
  50. define('PROTO_ATTR_PREFIX''_papi_');
  51. define('PROTO_ATTR_AS_ID''__asid');
  52. define('PROTO_ATTR_KEY''__key');
  53. define('PROTO_ATTR_EXPIRE_TIME''__expiretime');
  54.  
  55. /**
  56.  * Default timeout for stored requests.
  57.  */
  58. define('REQUEST_LIFETIME'300)// 5 minutes
  59.  
  60. /**
  61.  * This hook is executed at the end of the method that returns the URL where to redirect a user.
  62.  * It can be used to alter parameters in the URL. The hook receives an array of parameters which
  63.  * should be directly modified. Functions for this hook must be defined like this:
  64.  *
  65.  * function redirectURLFinishHook(&$params);
  66.  *
  67.  * Please bear in mind that hooks must return TRUE or they'll keep other hooks from executing.
  68.  */
  69. define("PAPI_REDIRECT_URL_FINISH""PAPI_REDIRECT_URL_FINISH");
  70.  
  71. /**
  72.  * This hook is executed when a valid response is found from the AS/GPoA and the original request
  73.  * of the user is about to be restored. It receives an array with the main PHP global variables
  74.  * of the original context. Functions for this hook must be defined like this:
  75.  *
  76.  * function restoreOriginalRequestHook(&$env);
  77.  *
  78.  * Please bear in mind that hooks must return TRUE or they'll keep other hooks from executing.
  79.  */
  80. define("PAPI_RESTORE_ORIGINAL_REQUEST""PAPI_RESTORE_ORIGINAL_REQUEST");
  81.  
  82. /**
  83.  * This hook is executed when a valid response is found from the AS/GPoA and the engine is about
  84.  * to end the authentication result. It receives a boolean value that determines if the URL should
  85.  * be cleaned by means of a redirection to the initial URL. Functions for this hook must be
  86.  * defined like this:
  87.  *
  88.  * function cleanURLHook(&$clean);
  89.  *
  90.  * Please bear in mind that hooks must return TRUE or they'll keep other hooks from executing.
  91.  */
  92. define("PAPI_CLEAN_URL""PAPI_CLEAN_URL");
  93.  
  94. /**
  95.  * This hook is executed when returning the attributes found for a user with getAttributes()
  96.  * method. It receives a string with the attributes and the array that results of proccessing
  97.  * the string. Functions for this hook must be defined like this:
  98.  *
  99.  * function attributeParser($assertion, &$attributes);
  100.  *
  101.  * Please bear in mind that hooks must return TRUE or they'll keep other hooks from executing.
  102.  */
  103. define("PAPI_ATTRIBUTE_PARSER""PAPI_ATTRIBUTE_PARSER");
  104.  
  105. /**
  106.  * Authentication engine for the PAPI 1.5 protocol.
  107.  * PLEASE NOTE THAT THIS ENGINE WORKS ONLY FOR WEB-BASED APPLICATIONS.
  108.  * @package phpPoA2
  109.  * @subpackage PAPIAuthenticationEngine
  110.  */
  111.  
  112.     protected $assertion;
  113.     protected $status;
  114.     protected $expiration_time = false;
  115.     protected $attributes;
  116.     protected $as_id;
  117.     protected $key;
  118.     protected $lkey;
  119.     protected $pkey;
  120.     protected $global_expire_time;
  121.     protected $db;
  122.     protected $id;
  123.     protected $cfg;
  124.     protected $crypto;
  125.     protected $clean_url = true;
  126.     protected $skip_redirection = false;
  127.     protected $cookie_name = "PAPILcook_";
  128.     protected $enforcing = true;
  129.     protected $opoa = "http";
  130.     protected $valid_hooks = array(PAPI_REDIRECT_URL_FINISH,
  131.                                    PAPI_RESTORE_ORIGINAL_REQUEST,
  132.                                    PAPI_CLEAN_URL,
  133.                                    PAPI_ATTRIBUTE_PARSER);
  134.  
  135.     public function configure($file,$section{
  136.         parent::configure($file$section);
  137.  
  138.         // check requirements
  139.         // check mcrypt extension
  140.         if (!extension_loaded("mcrypt")) {
  141.             trigger_error(PoAUtils::msg('extension-required'array("mcrypt"))E_USER_ERROR);
  142.         }
  143.  
  144.         // set id
  145.         $this->id = $section;
  146.  
  147.         // set cookie name
  148.         $this->cookie_name .= $section;
  149.         if (strpos($this->cookie_name'.'!= false{
  150.             $this->cookie_name = str_replace '.''_' $this->cookie_name );
  151.         }
  152.  
  153.         // initialize cryptographic engine
  154.         $this->crypto = new PAPICrypt($this->cfg->getLKey()$this->cfg->getPubKeyFile());
  155.  
  156.         // set default OPOA
  157.         if (isset($_SERVER['HTTPS'])) $this->opoa .= "s";
  158.         $this->opoa .= "://".$_SERVER['SERVER_NAME'].$this->cfg->getLocation();
  159.  
  160.         // configure DB
  161.         $db_t $this->cfg->getDBType();
  162.         if (class_exists($db_ttrue)) {
  163.             $this->db = new $db_t($this->cfg);
  164.         }
  165.     }
  166.  
  167.     public function authenticate({
  168.         // PAPI authentication protocol v1.0
  169.  
  170.         $action @array_key_exists('ACTION'$_REQUEST$_REQUEST['ACTION'"";
  171.         $auth (isset($_COOKIE[$this->cookie_name])) $this->testCookie(false;
  172.  
  173.         // check if we have a cookie or coming back from AS/GPoA
  174.         if ($action === "CHECKED" && !$auth// GPoA/AS response
  175.             $data $_REQUEST['DATA'];
  176.             $key $this->testResponse($data$this->pkey);
  177.             if (!$key{
  178.                 $this->status = AUTHN_FAILED;
  179.                 $this->dirty false;
  180.                 return AUTHN_FAILED;
  181.             }
  182.             $request $this->loadRequest($key);
  183.             if (!$request{
  184.                 trigger_error(PoAUtils::msg('unknown-request'array())E_USER_WARNING);
  185.                 $this->status = AUTHN_FAILED;
  186.                 $this->dirty false;
  187.                 return AUTHN_FAILED;
  188.             }
  189.             $this->deleteRequest($key);
  190.             if ($key// the request was validated
  191.                 if ($this->skip_redirection{
  192.                     $this->status = AUTHN_SUCCESS;
  193.                     return AUTHN_SUCCESS;
  194.                 }
  195.  
  196.                 // set a new cookie
  197.                 $c $this->getNewCookie($this->assertion);
  198.                 if (setcookie($this->cookie_name$c0$this->cfg->getLocation()$this->cfg->getCookieDomain()0)) {
  199.                     $_COOKIE[$this->cookie_name$c;
  200.  
  201.                     // run hooks
  202.                     $arg array($this->clean_url);
  203.                     $this->runHooks(PAPI_CLEAN_URL$arg);
  204.                     $this->clean_url = $arg[0];
  205.  
  206.                     // finish it off
  207.                     if (!$this->clean_url{
  208.                         $this->status = AUTHN_SUCCESS;
  209.                         return AUTHN_SUCCESS;
  210.                     else {
  211.                         if ($_SERVER["REQUEST_METHOD"=== "POST"{
  212.                             $inputs "";
  213.  
  214.                             // build HTML with an input element for each element in the query string
  215.                             parse_str($_SERVER["QUERY_STRING"]$params);
  216.                             foreach ($params as $name => $value{
  217.                                 $inputs .= "<input name='".$name."' type='hidden' value='".$value."' />";
  218.                             }
  219.                             $inputs .= "<input type='submit' value='".PoAUtils::msg('continue'array())."' />";
  220.  
  221.                             // print a HTML form to continue
  222. ?>
  223. <html>
  224.  <head>
  225.   <title>phpPoA2 transaction in progress...</title>
  226.  </head>
  227.  <body onload="document.forms[0].submit();">
  228.   <form action="<?php echo $_SERVER['SCRIPT_NAME'];?>" method="post">
  229.    <?php echo $inputs?>
  230.   </form>
  231.  </body>
  232. </html>
  233. <?php
  234.                             die(0);
  235.                         else {
  236.                             // build redirect URL
  237.                             $protocol (!empty($_SERVER['HTTPS'])) "https://" "http://";
  238.                             $url $protocol.$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT'];
  239.                             $url .= substr($_SERVER['REQUEST_URI']0strpos($_SERVER['REQUEST_URI']"ACTION=CHECKED"-1);
  240.                             $this->redirect($url);
  241.                         }
  242.                     }
  243.                 else // can't set the cookie
  244.                     trigger_error(PoAUtils::msg('cannot-set-cookie'array())E_USER_WARNING);
  245.                 }
  246.             else // the request is invalid!
  247.                 trigger_error(PoAUtils::msg('authn-err'array())E_USER_WARNING);
  248.             }
  249.             $this->status = AUTHN_FAILED;
  250.             return AUTHN_FAILED;
  251.         else if (!$auth// first time browser access (w/o cookie)
  252.             if ($this->skip_redirection{
  253.                 $this->status = AUTHN_FAILED;
  254.                 throw new PoAException('cookie-not-found'E_USER_ERRORarray($this->cookie_name));
  255.             }
  256.             trigger_error(PoAUtils::msg('cookie-not-found'array($this->cookie_name))E_USER_WARNING);
  257.             $this->deleteCookie();
  258.             $this->redirect();
  259.         else // valid access with cookie, update it!
  260.             $c $this->getNewCookie($this->assertion);
  261.             if (setcookie($this->cookie_name$c0$this->cfg->getLocation()$this->cfg->getCookieDomain()0)) {
  262.                 $_COOKIE[$this->cookie_name$c;
  263.                 // if no request found, assume this is a visit to a previously stored URL
  264.                 // (reloaded by the user or in the browser favorites/history).
  265.                 // Rebuild the request without the ACTION and DATA parameters
  266.  
  267.                 // set protocol
  268.                 $protocol (!empty($_SERVER['HTTPS'])) "https://" "http://";                
  269.  
  270.                 // rebuild location
  271.                 $re["/ACTION=[^&]*&?/";
  272.                 $re["/DATA=[^&]*&?/";
  273.                 $location $protocol.$_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].
  274.                             rtrim(preg_replace($re,"",$_SERVER["REQUEST_URI"]),"&?");
  275.  
  276.                 // run hooks
  277.                 $arg array($this->clean_url);
  278.                 $this->runHooks(PAPI_CLEAN_URL$arg);
  279.                 $this->clean_url = $arg[0];
  280.  
  281.                 if ((isset($_REQUEST["ACTION"]|| isset ($_REQUEST["DATA"])) && !$this->skip_redirection && $this->clean_url{
  282.                     $this->redirect($location);
  283.                 }
  284.  
  285.             else // set cookie failed!
  286.                 trigger_error(PoAUtils::msg('cannot-set-cookie'array())E_USER_WARNING);
  287.             }
  288.  
  289.             $this->status = AUTHN_SUCCESS;
  290.             return AUTHN_SUCCESS;
  291.         }
  292.  
  293.         $this->status = AUTHN_FAILED;
  294.         return AUTHN_FAILED;
  295.     }
  296.  
  297.     public function isAuthenticated({
  298.         if ($this->isSafe()) {
  299.             return $this->status;
  300.         }
  301.  
  302.         $result (isset($_COOKIE[$this->cookie_name])) $this->testCookie(false;
  303.  
  304.         return $result;
  305.     }
  306.  
  307.     public function getAttributes({
  308.         // avoid parsing the assertion again and again
  309.         if (empty($this->attributes)) {
  310.             $attrs explode(ATTR_SEPARATOR$this->assertion);
  311.             foreach ($attrs as $attr{
  312.                 @list($name$valueexplode(NAMEVALUE_SEPARATOR$attr);
  313.  
  314.                 // discard operational attributes
  315.                 if (strpos($namePROTO_ATTR_PREFIX== 1continue;
  316.  
  317.                 if (!empty($value)) {
  318.                     $values explode(VALUE_SEPARATOR$value);
  319.                     if (count($values1{
  320.                         $this->attributes[$name$values;
  321.                     else {
  322.                         $this->attributes[$name$value;
  323.                     }
  324.                 }
  325.             }
  326.         }
  327.  
  328.         $arg array($this->assertion$this->attributes);
  329.         $this->runHooks(PAPI_ATTRIBUTE_PARSER$arg);
  330.         $this->attributes = $arg[1];
  331.  
  332.         return $this->attributes;
  333.     }
  334.  
  335.     public function getAttribute($name$namespace NS_PAPI_ATTRIBUTES{
  336.         switch ($namespace{
  337.             case NS_PAPI_ATTRIBUTES:
  338.                 if (empty($this->attributes)) {
  339.                     $this->getAttributes();
  340.                 }
  341.                 $attr $this->attributes[$name];
  342.                 if (!isset($this->attributes[$name])) {
  343.                     // attribute query
  344.                     $attr $this->attributeQuery($name);
  345.                 }
  346.                 break;
  347.             case NS_PAPI_PROTOCOL:
  348.                 switch ($name{
  349.                     case PROTO_ATTR_AS_ID:
  350.                         $attr $this->as_id;
  351.                         break;
  352.                     case PROTO_ATTR_KEY:
  353.                         $attr $this->key;
  354.                         break;
  355.                     case PROTO_ATTR_EXPIRE_TIME:
  356.                         $attr $this->expiration_time;
  357.                         break;
  358.                     default:
  359.                         $attr @$this->attributes['_papi_'.$name];
  360.                 }
  361.         }
  362.         return $attr;
  363.     }
  364.  
  365.     public function logout($slo false{
  366.         // first check if we really need to logout!
  367.         if (!$this->isAuthenticated()) {
  368.             trigger_error(PoAUtils::msg('already-logged-out'array())E_USER_NOTICE);
  369.             return true;
  370.         }
  371.  
  372.         // local logout only
  373.         if (!$slo{
  374.             $this->deleteCookie();
  375.             trigger_error(PoAUtils::msg('local-logout-success'array())E_USER_NOTICE);
  376.             return true;
  377.         }
  378.  
  379.         // check configuration
  380.         $rtype $this->cfg->getRedirectType();
  381.         if ($rtype === AS_T{
  382.             // configuration error, redirection type must be GPOA_T and the
  383.             throw new PoAException('slo-conf-error'E_USER_ERRORarray());
  384.         }
  385.  
  386.         // single logout
  387.         $action (array_key_exists('ACTION'$_REQUEST)) $_REQUEST['ACTION'"";
  388.         if ($action === "PAPILOGOUT"// single logout
  389.             // GPoA asks for logout!
  390.             $this->deleteCookie();
  391.             trigger_error(PoAUtils::msg('slo-logout'array())E_USER_NOTICE);
  392.             $location $this->getSingleLogoutResponseLocation();
  393.         else // logout is triggered from the application
  394.             trigger_error(PoAUtils::msg('slo-requested'array())E_USER_NOTICE);
  395.             $location $this->getSingleLogoutLocation();
  396.         }
  397.         $this->redirect($location);
  398.     }
  399.  
  400.     protected function attributeQuery($name{
  401.         // attribute query protocol
  402.         //TODO: define attr query protocol and implement!
  403.     }
  404.  
  405.     // PAPI SPECIFIC METHODS
  406.  
  407.     /**
  408.      * Check if a cookie is valid.
  409.      * @param cookie The cookie.
  410.      * @return boolean true if the cookie is valid, false otherwise.
  411.      */
  412.     protected function testCookie($name ""{
  413.         if (empty($name)) {
  414.             $name $this->cookie_name;
  415.         }
  416.         $cookie $_COOKIE[$name];
  417.  
  418.         if (empty($cookie)) {
  419.             trigger_error(PoAUtils::msg('empty-cookie-err'array($name))E_USER_WARNING);
  420.             return false;
  421.         }
  422.  
  423.         $now time();
  424.         // extract the contents from the cookie
  425.         $newsource $this->crypto->decryptAES($cookie);
  426.         list($timestamp$this->global_expire_time$location$id$this->as_id$this->assertionexplode(":"$newsource6);
  427.  
  428.         $this->expiration_time = ($this->global_expire_time < ($timestamp $this->cfg->getCookieTimeout()))
  429.                                  ? $this->global_expire_time : $timestamp $this->cfg->getCookieTimeout();
  430.  
  431.         // check the cookie
  432.         if ($location != $this->cfg->getLocation()) {
  433.             trigger_error(PoAUtils::msg('cookie-location-err'array($cookie))E_USER_WARNING);
  434.  
  435.             return false;
  436.         }
  437.         if ($id != $this->id{
  438.             trigger_error(PoAUtils::msg('cookie-service-err'array($cookie))E_USER_WARNING);
  439.  
  440.             return false;
  441.         }
  442.         if (($this->global_expire_time < $nowor ($timestamp $this->cfg->getCookieTimeout($now)) {
  443.             trigger_error(PoAUtils::msg('cookie-expired-err'array($cookie))E_USER_WARNING);
  444.             
  445.             return false;
  446.         }
  447.         trigger_error(PoAUtils::msg('valid-cookie'array())E_USER_NOTICE);
  448.         return true;
  449.     }
  450.  
  451.     /**
  452.      * Delete the current cookie, if any.
  453.      * @return true 
  454.      */
  455.     protected function deleteCookie({
  456.         /*
  457.          * This is a hack to make cookie deletion work with firefox browers.
  458.          * Firefox won't delete a cookie unless it is set with exactly the same
  459.          * way it was originally set, except the expiration time. So we have to
  460.          * set the contents, location and domain, and then set an expiration date
  461.          * in the past.
  462.          */
  463.         setcookie($this->cookie_name,
  464.                   @$_COOKIE[$this->cookie_name],
  465.                   time()-3600,
  466.                   $this->cfg->getLocation(),
  467.                   $this->cfg->getCookieDomain()0);
  468.         unset($_COOKIE[$this->cookie_name]);
  469.     }
  470.  
  471.     /**
  472.      * Check the response from the AS/GPoA.
  473.      * @param data The data received.
  474.      * @param key The public key of the AS/GPoA.
  475.      * @return boolean true if valid, false else.
  476.      */
  477.     protected function testResponse($data$pubkey{
  478.         // decrypt data
  479.         $newsource $this->crypto->decrypt($data);
  480.  
  481.         if ($newsource === false{
  482.             // Cannot decrypt!
  483.             trigger_error(PoAUtils::msg('cannot-decrypt'array())E_USER_WARNING);
  484.             return false;
  485.         }
  486.  
  487.         // check the assertion
  488.         if (empty($newsource)) // empty assertion
  489.             trigger_error(PoAUtils::msg('empty-response-err'array())E_USER_WARNING);
  490.             return false;
  491.         }
  492.  
  493.         // parse data
  494.         $response explode(":"$newsource);
  495.         $this->key = array_pop($response);
  496.         $current_time array_pop($response);
  497.         $this->global_expire_time = array_pop($response);
  498.         $rest implode(":"$response);
  499.         $rest_a explode("@"$rest);
  500.         $this->as_id = array_pop($rest_a);
  501.         $this->assertion = implode("@"$rest_a);
  502.  
  503.         $this->expiration_time = ($this->global_expire_time < ($current_time $this->cfg->getCookieTimeout()))
  504.                                  ? $this->global_expire_time : $current_time $this->cfg->getCookieTimeout();
  505.  
  506.  
  507.         if ($this->assertion === "ERROR"// AS/GPoA error response, authentication failed!
  508.             $this->deleteRequest($this->key);
  509.             trigger_error(PoAUtils::msg('authn-error'array())E_USER_WARNING);
  510.             return false;
  511.         }
  512.  
  513.         // check timestamps
  514.         if ($this->global_expire_time < time()) // globally expired
  515.             $this->deleteRequest($this->key);
  516.             trigger_error(PoAUtils::msg('expired-response'array())E_USER_WARNING);
  517.             return false;
  518.         }
  519.         if ($current_time $this->cfg->getCookieTimeout(time()) // expired
  520.             $this->deleteRequest($this->key);
  521.             trigger_error(PoAUtils::msg('expired-response'array())E_USER_WARNING);
  522.             return false;
  523.         }
  524.  
  525.         // the response is OK
  526.         trigger_error(PoAUtils::msg('valid-response'array($this->assertion))E_USER_WARNING);
  527.         return $this->key;
  528.     }
  529.  
  530.     /** 
  531.      * Redirect user browser to the appropriate URL for authentication.
  532.      * WARNING: This method ends execution.
  533.      * @param location If set, the location where to redirect the user. If not, defaults are used.
  534.      * @return void This method does not return!
  535.      */
  536.     protected function redirect($location ""{
  537.         if (!empty($location)) {
  538.             $l $location;
  539.         else {
  540.             $l $this->getRedirectLocation();
  541.         }
  542.  
  543.         if (!$l{
  544.             throw new PoAException('cannot-redirect'E_USER_ERRORarray());
  545.         }
  546.         header("HTTP/1.1 302 Found");
  547.         header("Location: ".$l);
  548.         trigger_error(PoAUtils::msg('redirecting'array($l))E_USER_WARNING);
  549.         die(0);
  550.     }
  551.  
  552.     /**
  553.      * Retrieve the URL where to redirect a user to perform a single logout.
  554.      * @return string The appropriate URL where to redirect the browser, false if error.
  555.      */
  556.     protected function getSingleLogoutLocation({
  557.         // set protocol
  558.         $protocol (!empty($_SERVER['HTTPS'])) "https://" "http://";
  559.  
  560.         // build URL
  561.         $url $protocol.$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT'].$_SERVER['REQUEST_URI'];
  562.         $c_url $this->cfg->getLogoutURL();
  563.         if (!empty($c_url)) {
  564.             $url $c_url;
  565.         }
  566.  
  567.         $params array('ACTION' => 'PAPISIGNOFFREQ',
  568.                         'DATA' => 'DUMMY',
  569.                         'POA' => $this->cfg->getID()// TODO
  570.                         'URL' => $url);
  571.  
  572.         $sep (strstr("?"$this->cfg->getRedirectURL())) "&" "?";
  573.         return $this->cfg->getRedirectURL().$sep.http_build_query($params);
  574.     }
  575.  
  576.     /**
  577.      * Retrieve the URL where to redirect a user once he has successfully logged out.
  578.      * @return string The appropriate URL where to redirect the browser, false if error.
  579.      */
  580.     protected function getSingleLogoutResponseLocation({
  581.         // set protocol
  582.         $protocol (!empty($_SERVER['HTTPS'])) "https://" "http://";
  583.  
  584.         $params array('ACTION' => 'PAPILOGGEDOUT',
  585.                         'DATA' => 'DUMMY',
  586.                         'POA' => $this->cfg->getID())// TODO
  587.  
  588.         $sep (strstr("?"$this->cfg->getRedirectURL())) "&" "?";
  589.         return $this->cfg->getRedirectURL().$sep.http_build_query($params);
  590.     }
  591.  
  592.     /**
  593.      * Retrieve the URL where to redirect a user and store his request.
  594.      * @return string The appropriate URL where to redirect the browser, false if error.
  595.      */
  596.     protected function getRedirectLocation({
  597.         // initialize key identifier
  598.         $key mt_rand();
  599.  
  600.         // set protocol
  601.         $protocol (!empty($_SERVER['HTTPS'])) "https://" "http://";
  602.  
  603.         // build URL
  604.         $url $protocol.$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT'].$_SERVER['REQUEST_URI'];
  605.  
  606.         // check if the request hast to be sent to a GPoA or an AS
  607.         if ($this->cfg->getRedirectType(=== AS_T// AS
  608.             $params array('ATTREQ' => 'poaid',
  609.                             'PAPIPOAREF' => $key,
  610.                             'PAPIPOAURL' => $url);
  611.         else // GPoA
  612.             $params array('ACTION' => 'CHECK',
  613.                             'DATA' => $key,
  614.                             'URL' => $url);
  615.             // check PAPIHLI
  616.             $hli $this->cfg->getHomeLocatorID();
  617.             if (!empty($hli)) {
  618.                 $params['PAPIHLI'$hli;
  619.             }
  620.  
  621.             // check PAPIOPOA
  622.             $params['POA'$this->opoa// TODO
  623.             $params['PAPIOPOA'$this->opoa;
  624.             $id $this->cfg->getID();
  625.             if (!empty($id)) {
  626.                 $params['POA'$id// TODO
  627.             }
  628.  
  629.             // check friendly name TODO
  630.             $fname $this->cfg->getFriendlyName();
  631.             if (!empty($fname)) {
  632.                 $params['POADISPLAYNAME'$fname;
  633.             }
  634.  
  635.             // check logout URL TODO
  636.             $logout $this->cfg->getLogoutURL();
  637.             if (!empty($logout)) {
  638.                 $params['LSOURL'base64_encode($logout);
  639.             }
  640.         }
  641.  
  642.         $arg array($params);
  643.         $this->runHooks(PAPI_REDIRECT_URL_FINISH$arg);
  644.         $params $arg[0];
  645.         $hli @$params['PAPIHLI'];
  646.  
  647.         // save the current request
  648.         $saved $this->saveRequest($key$hli);
  649.         if (!$saved{
  650.             trigger_error(PoAUtils::msg('cannot-save-request'array())E_USER_WARNING);
  651.             return false;
  652.         }
  653.  
  654.         $sep (strstr("?"$this->cfg->getRedirectURL())) "&" "?";
  655.         return $this->cfg->getRedirectURL().$sep.http_build_query($params);
  656.     }
  657.  
  658.     /**
  659.      * Save a request to the request database. The request includes: $_REQUEST, $_GET, $_POST,
  660.      * $_SERVER['QUERY_STRING'], $_SERVER['REQUEST_METHOD'] and php://input.
  661.      * @param key The key identifier for this request.
  662.      * @param hli The home locator identifier that should be used for this request.
  663.      * @return string|booleanThe key to retrieve later this request from the database, false if error.
  664.      */
  665.     protected function saveRequest($key$hli{
  666.         // open database
  667.         $id $this->db->open();
  668.         if (!$id{
  669.             trigger_error(PoAUtils::msg('cannot-open-req-db'array())E_USER_ERROR);
  670.             return false;
  671.         }
  672.  
  673.         // perform db maintenance
  674.         $purged $this->db->purge($this->cfg->getRequestLifetime());
  675.         if ($purged 0{
  676.             trigger_error(PoAUtils::msg('req-db-purged'array($purged))E_USER_NOTICE);
  677.         }
  678.  
  679.         // create/replace entry for random key
  680.         // marcoscm: Some clients don't rely *only* on $_REQUEST (2), but on $_GET (0), $_POST (1),
  681.         // $_SERVER["QUERY_STRING"] (3), $_SERVER["REQUEST_METHOD"] (4) or and php://input (5)
  682.         $ok $this->db->replaceContents($key$_GET$_POST$_REQUEST$_SERVER["QUERY_STRING"],
  683.                                          $_SERVER["REQUEST_METHOD"]file_get_contents("php://input")$hli);
  684.         $this->db->close();
  685.         return (!$okfalse $key;
  686.     }
  687.  
  688.     /**
  689.      * Load a request from the request database.
  690.      * @param key The key that identifies the request.
  691.      * @return hash The request associated with that key, false if error.
  692.      */
  693.     protected function loadRequest($key{
  694.         global $HTTP_RAW_POST_DATA;
  695.  
  696.         // open database
  697.         $id $this->db->open();
  698.         if (!$id{
  699.             trigger_error(PoAUtils::msg('cannot-open-db'array())E_USER_ERROR);
  700.             return false;
  701.         }
  702.  
  703.         // search for key
  704.         $request $this->db->fetch($key);
  705.         if (!$request{
  706.             $this->db->close();
  707.             trigger_error(PoAUtils::msg('cannot-fetch-key'array($key))E_USER_WARNING);
  708.         }
  709.         $this->db->close();
  710.  
  711.         // run hook
  712.         $arg array($request);
  713.         $this->runHooks(PAPI_RESTORE_ORIGINAL_REQUEST$arg);
  714.         $request $arg[0];
  715.  
  716.         // check if HLI matches with AS ID
  717.         if (!empty($request['HLI']&& $this->as_id != $request['HLI']{
  718.             trigger_error(PoAUtils::msg('as-id-error'array($this->as_id$request['HLI']))E_USER_ERROR);
  719.         }
  720.  
  721.         // reload original context
  722.         $_GET $request["GET"];
  723.         $_POST $request["POST"];
  724.         $_REQUEST $request["REQUEST"];
  725.         $_SERVER["QUERY_STRING"$request["QUERY_STRING"];
  726.         $_SERVER["REQUEST_METHOD"$request["REQUEST_METHOD"];
  727.         $HTTP_RAW_POST_DATA $request["PHP_INPUT"];
  728.  
  729.         return $request;
  730.     }
  731.  
  732.     /**
  733.      * Delete a request from the request database.
  734.      * @param key The key that identifies the request.
  735.      * @return boolean true if success, false in any other case.
  736.      */
  737.     protected function deleteRequest($key{
  738.         // open database
  739.         $id $this->db->open();
  740.         if (!$id{
  741.             trigger_error(PoAUtils::msg('cannot-open-db'array())E_USER_ERROR);
  742.             return false;
  743.         }
  744.  
  745.         // search and delete key
  746.         $request false;
  747.         if ($this->db->check($key)) {
  748.             $request $this->db->delete($key);
  749.         else {
  750.             $this->db->close();
  751.             trigger_error(PoAUtils::msg('cannot-del-key'array($key))E_USER_WARNING);
  752.         }
  753.         $this->db->close();
  754.  
  755.         return $request;
  756.     }
  757.  
  758.     /**
  759.      * Generate a new cookie for the current user.
  760.      * @return string The cookie conveniently encrypted with our own key.
  761.      */
  762.     protected function getNewCookie({
  763.         $expiration ((time($this->cfg->getCookieTimeout()) $this->global_expire_time)
  764.                       ? time($this->cfg->getCookieTimeout($this->global_expire_time;
  765.  
  766.         $content time().":".$expiration.":".$this->cfg->getLocation().":".$this->id.":".$this->as_id.":".$this->assertion;
  767.         return $this->crypto->encryptAES($content);
  768.     }
  769.  
  770.     /**
  771.      * Determines if it's safe to assume the user as authenticated.
  772.      * @return boolean true if the user still has a valid session, false otherwise.
  773.      */
  774.     protected function isSafe({
  775.         if (!$this->expiration_timereturn false;
  776.  
  777.         return $this->expiration_time > time();
  778.     }
  779.  
  780. }
  781.  
  782. ?>

Documentation generated on Fri, 11 Feb 2011 10:58:02 +0100 by phpDocumentor 1.4.3