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

Documentation generated on Mon, 20 Feb 2012 12:07:12 +0100 by phpDocumentor 1.4.3