Skip to content
Snippets Groups Projects
Commit 6b78e865 authored by Jaime Perez Crespo's avatar Jaime Perez Crespo
Browse files

Reformat sspmod_discopower_PowerIdPDisco.

parent 822c08d5
No related branches found
No related tags found
No related merge requests found
<?php <?php
/** /**
* This class implements a generic IdP discovery service, for use in various IdP discovery service pages. This should * This class implements a generic IdP discovery service, for use in various IdP discovery service pages. This should
* reduce code duplication. * reduce code duplication.
...@@ -9,327 +10,354 @@ ...@@ -9,327 +10,354 @@
* @author Andreas Åkre Solberg <andreas@uninett.no>, UNINETT AS. * @author Andreas Åkre Solberg <andreas@uninett.no>, UNINETT AS.
* @package SimpleSAMLphp * @package SimpleSAMLphp
*/ */
class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco { class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
{
/**
* The configuration for this instance. /**
* * The configuration for this instance.
* @var SimpleSAML_Configuration *
*/ * @var SimpleSAML_Configuration
private $discoconfig; */
private $discoconfig;
/**
* The domain to use when saving common domain cookies. This is null if support for common domain cookies is /**
* disabled. * The domain to use when saving common domain cookies. This is null if support for common domain cookies is
* * disabled.
* @var string|null *
*/ * @var string|null
private $cdcDomain; */
private $cdcDomain;
/**
* The lifetime of the CDC cookie, in seconds. If set to null, it will only be valid until the browser is closed. /**
* * The lifetime of the CDC cookie, in seconds. If set to null, it will only be valid until the browser is closed.
* @var int|null *
*/ * @var int|null
private $cdcLifetime; */
private $cdcLifetime;
/**
* Initializes this discovery service. /**
* * Initializes this discovery service.
* The constructor does the parsing of the request. If this is an invalid request, it will throw an exception. *
* * The constructor does the parsing of the request. If this is an invalid request, it will throw an exception.
* @param array $metadataSets Array with metadata sets we find remote entities in. *
* @param string $instance The name of this instance of the discovery service. * @param array $metadataSets Array with metadata sets we find remote entities in.
*/ * @param string $instance The name of this instance of the discovery service.
public function __construct(array $metadataSets, $instance) { */
public function __construct(array $metadataSets, $instance)
parent::__construct($metadataSets, $instance); {
parent::__construct($metadataSets, $instance);
$this->discoconfig = SimpleSAML_Configuration::getConfig('module_discopower.php');
$this->discoconfig = SimpleSAML_Configuration::getConfig('module_discopower.php');
$this->cdcDomain = $this->discoconfig->getString('cdc.domain', NULL);
if ($this->cdcDomain !== NULL && $this->cdcDomain[0] !== '.') { $this->cdcDomain = $this->discoconfig->getString('cdc.domain', null);
/* Ensure that the CDC domain starts with a dot ('.') as required by the spec. */ if ($this->cdcDomain !== null && $this->cdcDomain[0] !== '.') {
$this->cdcDomain = '.' . $this->cdcDomain; // ensure that the CDC domain starts with a dot ('.') as required by the spec
} $this->cdcDomain = '.'.$this->cdcDomain;
}
$this->cdcLifetime = $this->discoconfig->getInteger('cdc.lifetime', NULL);
} $this->cdcLifetime = $this->discoconfig->getInteger('cdc.lifetime', null);
}
/**
* Log a message. /**
* * Log a message.
* This is an helper function for logging messages. It will prefix the messages with our discovery service type. *
* * This is an helper function for logging messages. It will prefix the messages with our discovery service type.
* @param string $message The message which should be logged. *
*/ * @param string $message The message which should be logged.
protected function log($message) { */
SimpleSAML_Logger::info('PowerIdPDisco.' . $this->instance . ': ' . $message); protected function log($message)
} {
SimpleSAML_Logger::info('PowerIdPDisco.'.$this->instance.': '.$message);
}
/**
* Compare two entities.
* /**
* This function is used to sort the entity list. It sorts based on english name, and will always put IdP's with * Compare two entities.
* names configured before those with only an entityID. *
* * This function is used to sort the entity list. It sorts based on english name, and will always put IdP's with
* @param array $a The metadata of the first entity. * names configured before those with only an entityID.
* @param array $b The metadata of the second entity. *
* @return int How $a compares to $b. * @param array $a The metadata of the first entity.
*/ * @param array $b The metadata of the second entity.
public static function mcmp(array $a, array $b) { *
if (isset($a['name']['en']) && isset($b['name']['en'])) { * @return int How $a compares to $b.
return strcasecmp($a['name']['en'], $b['name']['en']); */
} elseif (isset($a['name']['en'])) { public static function mcmp(array $a, array $b)
return -1; /* Place name before entity ID. */ {
} elseif (isset($b['name']['en'])) { if (isset($a['name']['en']) && isset($b['name']['en'])) {
return 1; /* Place entity ID after name. */ return strcasecmp($a['name']['en'], $b['name']['en']);
} else { } elseif (isset($a['name']['en'])) {
return strcasecmp($a['entityid'], $b['entityid']); return -1; // place name before entity ID
} } elseif (isset($b['name']['en'])) {
} return 1; // Place entity ID after name
} else {
return strcasecmp($a['entityid'], $b['entityid']);
/** }
* Structure the list of IdPs in a hierarchy based upon the tags. }
*
* @param array $list A list of IdPs.
* /**
* @return array The list of IdPs structured accordingly. * Structure the list of IdPs in a hierarchy based upon the tags.
*/ *
protected function idplistStructured($list) { * @param array $list A list of IdPs.
$slist = array(); *
* @return array The list of IdPs structured accordingly.
$order = $this->discoconfig->getValue('taborder'); */
if (is_array($order)) { protected function idplistStructured($list)
foreach($order AS $oe) { {
$slist[$oe] = array(); $slist = array();
}
} $order = $this->discoconfig->getValue('taborder');
if (is_array($order)) {
$enableTabs = $this->discoconfig->getValue('tabs', NULL); foreach ($order as $oe) {
$slist[$oe] = array();
foreach($list AS $key => $val) { }
$tags = array('misc'); }
if (array_key_exists('tags', $val)) {
$tags = $val['tags']; $enableTabs = $this->discoconfig->getValue('tabs', null);
}
foreach ($tags AS $tag) { foreach ($list as $key => $val) {
if (!empty($enableTabs) && !in_array($tag, $enableTabs)) continue; $tags = array('misc');
$slist[$tag][$key] = $val; if (array_key_exists('tags', $val)) {
} $tags = $val['tags'];
} }
foreach ($tags as $tag) {
foreach($slist AS $tab => $tbslist) { if (!empty($enableTabs) && !in_array($tag, $enableTabs)) {
uasort($slist[$tab], array('sspmod_discopower_PowerIdPDisco', 'mcmp')); continue;
} }
$slist[$tag][$key] = $val;
return $slist; }
} }
foreach ($slist as $tab => $tbslist) {
/** uasort($slist[$tab], array('sspmod_discopower_PowerIdPDisco', 'mcmp'));
* Do the actual filtering according the rules defined. }
*
* @param array $filter A set of rules regarding filtering. return $slist;
* @param array $entry An entry to be evaluated by the filters. }
* @param boolean $default What to do in case the entity does not match any rules. Defaults to true.
*
* @return boolean True if the entity should be kept, false if it should be discarded according to the filters. /**
*/ * Do the actual filtering according the rules defined.
private function processFilter($filter, $entry, $default = TRUE) { *
if (in_array($entry['entityid'], $filter['entities.include'] )) return TRUE; * @param array $filter A set of rules regarding filtering.
if (in_array($entry['entityid'], $filter['entities.exclude'] )) return FALSE; * @param array $entry An entry to be evaluated by the filters.
* @param boolean $default What to do in case the entity does not match any rules. Defaults to true.
if (array_key_exists('tags', $entry)) { *
foreach ($filter['tags.include'] AS $fe) { * @return boolean True if the entity should be kept, false if it should be discarded according to the filters.
if (in_array($fe, $entry['tags'])) return TRUE; */
} private function processFilter($filter, $entry, $default = true)
foreach ($filter['tags.exclude'] AS $fe) { {
if (in_array($fe, $entry['tags'])) return FALSE; if (in_array($entry['entityid'], $filter['entities.include'])) {
} return true;
} }
return $default; if (in_array($entry['entityid'], $filter['entities.exclude'])) {
} return false;
}
/** if (array_key_exists('tags', $entry)) {
* Filter a list of entities according to any filters defined in the parent class, plus discopower configuration foreach ($filter['tags.include'] as $fe) {
* options regarding filtering. if (in_array($fe, $entry['tags'])) {
* return true;
* @param array $list A list of entities to filter. }
* }
* @return array The list in $list after filtering entities. foreach ($filter['tags.exclude'] as $fe) {
*/ if (in_array($fe, $entry['tags'])) {
protected function filterList($list) { return false;
parent::filterList($list); }
}
try { }
$spmd = $this->metadata->getMetaData($this->spEntityId, 'saml20-sp-remote'); return $default;
} catch(Exception $e) { }
return $list;
}
/**
if (!isset($spmd)) return $list; * Filter a list of entities according to any filters defined in the parent class, plus discopower configuration
if (!array_key_exists('discopower.filter', $spmd)) return $list; * options regarding filtering.
$filter = $spmd['discopower.filter']; *
* @param array $list A list of entities to filter.
if (!array_key_exists('entities.include', $filter)) $filter['entities.include'] = array(); *
if (!array_key_exists('entities.exclude', $filter)) $filter['entities.exclude'] = array(); * @return array The list in $list after filtering entities.
if (!array_key_exists('tags.include', $filter)) $filter['tags.include'] = array(); */
if (!array_key_exists('tags.exclude', $filter)) $filter['tags.exclude'] = array(); protected function filterList($list)
{
$defaultrule = TRUE; parent::filterList($list);
if ( array_key_exists('entities.include', $spmd['discopower.filter'] ) ||
array_key_exists('tags.include', $spmd['discopower.filter'])) { try {
$spmd = $this->metadata->getMetaData($this->spEntityId, 'saml20-sp-remote');
$defaultrule = FALSE; } catch (Exception $e) {
} return $list;
}
$returnlist = array();
foreach ($list AS $key => $entry) { if (!isset($spmd)) {
if ($this->processFilter($filter, $entry, $defaultrule)) { return $list;
$returnlist[$key] = $entry; }
} if (!array_key_exists('discopower.filter', $spmd)) {
} return $list;
return $returnlist; }
$filter = $spmd['discopower.filter'];
}
if (!array_key_exists('entities.include', $filter)) {
$filter['entities.include'] = array();
/** }
* Handles a request to this discovery service. if (!array_key_exists('entities.exclude', $filter)) {
* $filter['entities.exclude'] = array();
* The IdP disco parameters should be set before calling this function. }
*/ if (!array_key_exists('tags.include', $filter)) {
public function handleRequest() { $filter['tags.include'] = array();
$this->start(); }
if (!array_key_exists('tags.exclude', $filter)) {
/* No choice made. Show discovery service page. */ $filter['tags.exclude'] = array();
$idpList = $this->getIdPList(); }
$idpList = $this->idplistStructured($this->filterList($idpList));
$preferredIdP = $this->getRecommendedIdP(); $defaultrule = true;
if (array_key_exists('entities.include', $spmd['discopower.filter']) ||
$t = new SimpleSAML_XHTML_Template($this->config, 'discopower:disco-tpl.php', 'disco'); array_key_exists('tags.include', $spmd['discopower.filter'])
$t->data['idplist'] = $idpList; ) {
$t->data['preferredidp'] = $preferredIdP;
$t->data['return'] = $this->returnURL; $defaultrule = false;
$t->data['returnIDParam'] = $this->returnIdParam; }
$t->data['entityID'] = $this->spEntityId;
$t->data['urlpattern'] = htmlspecialchars(\SimpleSAML\Utils\HTTP::getSelfURLNoQuery()); $returnlist = array();
$t->data['rememberenabled'] = $this->config->getBoolean('idpdisco.enableremember', FALSE); foreach ($list as $key => $entry) {
$t->data['rememberchecked'] = $this->config->getBoolean('idpdisco.rememberchecked', FALSE); if ($this->processFilter($filter, $entry, $defaultrule)) {
$t->data['defaulttab'] = $this->discoconfig->getValue('defaulttab', 0); $returnlist[$key] = $entry;
$t->data['score'] = $this->discoconfig->getValue('score', 'quicksilver'); }
$t->show(); }
} return $returnlist;
}
/**
* Get the IdP entities saved in the common domain cookie. /**
* * Handles a request to this discovery service.
* @return array List of IdP entities. *
*/ * The IdP disco parameters should be set before calling this function.
private function getCDC() { */
public function handleRequest()
if (!isset($_COOKIE['_saml_idp'])) { {
return array(); $this->start();
}
// no choice made. Show discovery service page
$ret = (string)$_COOKIE['_saml_idp']; $idpList = $this->getIdPList();
$ret = explode(' ', $ret); $idpList = $this->idplistStructured($this->filterList($idpList));
foreach ($ret as &$idp) { $preferredIdP = $this->getRecommendedIdP();
$idp = base64_decode($idp);
if ($idp === FALSE) { $t = new SimpleSAML_XHTML_Template($this->config, 'discopower:disco-tpl.php', 'disco');
/* Not properly base64 encoded. */ $t->data['idplist'] = $idpList;
return array(); $t->data['preferredidp'] = $preferredIdP;
} $t->data['return'] = $this->returnURL;
} $t->data['returnIDParam'] = $this->returnIdParam;
$t->data['entityID'] = $this->spEntityId;
return $ret; $t->data['urlpattern'] = htmlspecialchars(\SimpleSAML\Utils\HTTP::getSelfURLNoQuery());
} $t->data['rememberenabled'] = $this->config->getBoolean('idpdisco.enableremember', false);
$t->data['rememberchecked'] = $this->config->getBoolean('idpdisco.rememberchecked', false);
$t->data['defaulttab'] = $this->discoconfig->getValue('defaulttab', 0);
/** $t->data['score'] = $this->discoconfig->getValue('score', 'quicksilver');
* Save the current IdP choice to a cookie. $t->show();
* }
* This function overrides the corresponding function in the parent class, to add support for common domain cookie.
*
* @param string $idp The entityID of the IdP. /**
*/ * Get the IdP entities saved in the common domain cookie.
protected function setPreviousIdP($idp) { *
assert('is_string($idp)'); * @return array List of IdP entities.
*/
if ($this->cdcDomain === NULL) { private function getCDC()
parent::setPreviousIdP($idp); {
return; if (!isset($_COOKIE['_saml_idp'])) {
} return array();
}
$list = $this->getCDC();
$ret = (string) $_COOKIE['_saml_idp'];
$prevIndex = array_search($idp, $list, TRUE); $ret = explode(' ', $ret);
if ($prevIndex !== FALSE) { foreach ($ret as &$idp) {
unset($list[$prevIndex]); $idp = base64_decode($idp);
} if ($idp === false) {
$list[] = $idp; // not properly base64 encoded
return array();
foreach ($list as &$value) { }
$value = base64_encode($value); }
}
$newCookie = implode(' ', $list); return $ret;
}
while (strlen($newCookie) > 4000) {
/* The cookie is too long. Remove the oldest elements until it is short enough. */
$tmp = explode(' ', $newCookie, 2); /**
if (count($tmp) === 1) { * Save the current IdP choice to a cookie.
/* *
* We are left with a single entityID whose base64 * This function overrides the corresponding function in the parent class, to add support for common domain cookie.
* representation is too long to fit in a cookie. *
*/ * @param string $idp The entityID of the IdP.
break; */
} protected function setPreviousIdP($idp)
$newCookie = $tmp[1]; {
} assert('is_string($idp)');
$params = array( if ($this->cdcDomain === null) {
'lifetime' => $this->cdcLifetime, parent::setPreviousIdP($idp);
'domain' => $this->cdcDomain, return;
'secure' => TRUE, }
'httponly' => FALSE,
); $list = $this->getCDC();
\SimpleSAML\Utils\HTTP::setCookie('_saml_idp', $newCookie, $params, FALSE);
} $prevIndex = array_search($idp, $list, true);
if ($prevIndex !== false) {
unset($list[$prevIndex]);
/** }
* Retrieve the previous IdP the user used. $list[] = $idp;
*
* This function overrides the corresponding function in the parent class, to add support for common domain cookie. foreach ($list as &$value) {
* $value = base64_encode($value);
* @return string|null The entity id of the previous IdP the user used, or null if this is the first time. }
*/ $newCookie = implode(' ', $list);
protected function getPreviousIdP() {
while (strlen($newCookie) > 4000) {
if ($this->cdcDomain === NULL) { // the cookie is too long. Remove the oldest elements until it is short enough
return parent::getPreviousIdP(); $tmp = explode(' ', $newCookie, 2);
} if (count($tmp) === 1) {
// we are left with a single entityID whose base64 representation is too long to fit in a cookie.
$prevIdPs = $this->getCDC(); break;
while (count($prevIdPs) > 0) { }
$idp = array_pop($prevIdPs); $newCookie = $tmp[1];
$idp = $this->validateIdP($idp); }
if ($idp !== NULL) {
return $idp; $params = array(
} 'lifetime' => $this->cdcLifetime,
} 'domain' => $this->cdcDomain,
'secure' => true,
return NULL; 'httponly' => false,
} );
\SimpleSAML\Utils\HTTP::setCookie('_saml_idp', $newCookie, $params, false);
}
/**
* Retrieve the previous IdP the user used.
*
* This function overrides the corresponding function in the parent class, to add support for common domain cookie.
*
* @return string|null The entity id of the previous IdP the user used, or null if this is the first time.
*/
protected function getPreviousIdP()
{
if ($this->cdcDomain === null) {
return parent::getPreviousIdP();
}
$prevIdPs = $this->getCDC();
while (count($prevIdPs) > 0) {
$idp = array_pop($prevIdPs);
$idp = $this->validateIdP($idp);
if ($idp !== null) {
return $idp;
}
}
return null;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment