<?php /** * Authenticate using PAPI protocol. * * @author Jaime Perez, RedIRIS * @package simpleSAMLphp */ include("poa2/PoA.php"); class sspmod_papi_Auth_Source_PAPI extends SimpleSAML_Auth_Source { /** * The string used to identify our states. */ const STAGE_INIT = 'sspmod_papi_Auth_Source_PAPI.state'; /** * The key of the AuthId field in the state. */ const AUTHID = 'sspmod_papi_Auth_Source_PAPI.AuthId'; /** * @var the PoA to use. */ private $_poa; /** * @var the home locator interface to use. */ private $_hli; /** * @var the PAPIOPOA to use. */ private $_papiopoa; /** * @var the attributes of the user. */ private $_attrs; /** * @var the state ID to retrieve the original request later. */ private $_stateId; /** * Constructor for this authentication source. * * @param array $info Information about this authentication source. * @param array $config Configuration. */ public function __construct($info, $config) { assert('is_array($info)'); assert('is_array($config)'); /* Call the parent constructor first, as required by the interface. */ parent::__construct($info, $config); if (!array_key_exists('site', $config)) { throw new Exception('PAPI authentication source is not properly configured: missing [site]'); } $this->_poa = new PoA($config['site']); if (array_key_exists('hli', $config)) { $this->_hli = $config['hli']; } } /** * Hook that will set Home Locator Identifier, PAPIOPOA and/or State ID. * * @param The PAPI request parameters that will be modified/extended. */ public function modifyParams(&$params) { if (!empty($this->_hli)) { $params['PAPIHLI'] = $this->_hli; } if (!empty($this->_papiopoa)) { $params['PAPIOPOA'] = $this->_papiopoa; } $params['URL'] = $params['URL'].urlencode("&SSPStateID=".$this->_stateId); return false; } /** * Parse the attribute array in a format suitable for SSP. * * @param the original attribute array. */ protected function parseAttributes($attrs) { assert('is_array($attrs)'); foreach ($attrs as $name => $value) { if (!is_array($value)) { $attrs[$name] = array($value); } } return $attrs; } /** * Log-in using PAPI * * @param array &$state Information about the current authentication. */ public function authenticate(&$state) { assert('is_array($state)'); $this->_papiopoa = $state['SPMetadata']['entityid']; // check if we are returning back from PAPI authentication if (isset($_REQUEST['SSPStateID'])) { // yes! restore original request $this->_stateId = (string)$_REQUEST['SSPStateID']; // sanitize the input $sid = SimpleSAML_Utilities::parseStateID($this->_stateId); if (!is_null($sid['url'])) { SimpleSAML_Utilities::checkURLAllowed($sid['url']); } $state = SimpleSAML_Auth_State::loadState($this->_stateId, self::STAGE_INIT); } else if (!$this->_poa->isAuthenticated()) { // no! we have to save the request /* We are will need the authId in order to retrieve this authentication source later. */ $state[self::AUTHID] = $this->authId; $this->_stateId = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT); $this->_poa->addHook("PAPI_REDIRECT_URL_FINISH", new Hook(array($this, "modifyParams"))); } $this->_poa->authenticate(); $this->_attrs = $this->_poa->getAttributes(); $state['Attributes'] = $this->parseAttributes($this->_attrs); self::completeAuth($state); } /** * Log out from this authentication source. * * This function should be overridden if the authentication source requires special * steps to complete a logout operation. * * If the logout process requires a redirect, the state should be saved. Once the * logout operation is completed, the state should be restored, and completeLogout * should be called with the state. If this operation can be completed without * showing the user a page, or redirecting, this function should return. * * @param array &$state Information about the current logout operation. */ public function logout(&$state) { assert('is_array($state)'); // check first if we have a valid session if ($this->_poa->isAuthenticated()) { /* We are will need the authId in order to retrieve this authentication source later. */ $state[self::AUTHID] = $this->authId; $this->_stateId = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT); // TODO: pending on phpPoA adding PAPI_SLO_REDIRECT_URL_FINISH hook $this->_poa->addHook("PAPI_SLO_REDIRECT_URL_FINISH", new Hook(array($this, "modifyParams"))); // perform single logout, this won't return $this->_poa->logout(true); } else if (isset($_REQUEST['SSPStateID'])) { $this->_stateId = (string)$_REQUEST['SSPStateID']; // sanitize the input $sid = SimpleSAML_Utilities::parseStateID($this->_stateId); if (!is_null($sid['url'])) { SimpleSAML_Utilities::checkURLAllowed($sid['url']); } $state = SimpleSAML_Auth_State::loadState($this->_stateId, self::STAGE_INIT); } else { return; } self::completeLogout($state); } }