ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
PowerIdPDisco.php
Go to the documentation of this file.
1 <?php
2 
3 
14 {
15 
16 
22  private $discoconfig;
23 
24 
31  private $cdcDomain;
32 
33 
39  private $cdcLifetime;
40 
41 
50  public function __construct(array $metadataSets, $instance)
51  {
52  parent::__construct($metadataSets, $instance);
53 
54  $this->discoconfig = SimpleSAML_Configuration::getConfig('module_discopower.php');
55 
56  $this->cdcDomain = $this->discoconfig->getString('cdc.domain', null);
57  if ($this->cdcDomain !== null && $this->cdcDomain[0] !== '.') {
58  // ensure that the CDC domain starts with a dot ('.') as required by the spec
59  $this->cdcDomain = '.'.$this->cdcDomain;
60  }
61 
62  $this->cdcLifetime = $this->discoconfig->getInteger('cdc.lifetime', null);
63  }
64 
65 
73  protected function log($message)
74  {
75  SimpleSAML\Logger::info('PowerIdPDisco.'.$this->instance.': '.$message);
76  }
77 
78 
90  public static function mcmp(array $a, array $b)
91  {
92  if (isset($a['name']['en']) && isset($b['name']['en'])) {
93  return strcasecmp($a['name']['en'], $b['name']['en']);
94  } elseif (isset($a['name']['en'])) {
95  return -1; // place name before entity ID
96  } elseif (isset($b['name']['en'])) {
97  return 1; // Place entity ID after name
98  } else {
99  return strcasecmp($a['entityid'], $b['entityid']);
100  }
101  }
102 
103 
111  protected function idplistStructured($list)
112  {
113  $slist = array();
114 
115  $order = $this->discoconfig->getValue('taborder');
116  if (is_array($order)) {
117  foreach ($order as $oe) {
118  $slist[$oe] = array();
119  }
120  }
121 
122  $enableTabs = $this->discoconfig->getValue('tabs', null);
123 
124  foreach ($list as $key => $val) {
125  $tags = array('misc');
126  if (array_key_exists('tags', $val)) {
127  $tags = $val['tags'];
128  }
129  foreach ($tags as $tag) {
130  if (!empty($enableTabs) && !in_array($tag, $enableTabs, true)) {
131  continue;
132  }
133  $slist[$tag][$key] = $val;
134  }
135  }
136 
137  foreach ($slist as $tab => $tbslist) {
138  uasort($slist[$tab], array('sspmod_discopower_PowerIdPDisco', 'mcmp'));
139  }
140 
141  return $slist;
142  }
143 
144 
154  private function processFilter($filter, $entry, $default = true)
155  {
156  if (in_array($entry['entityid'], $filter['entities.include'], true)) {
157  return true;
158  }
159  if (in_array($entry['entityid'], $filter['entities.exclude'], true)) {
160  return false;
161  }
162 
163  if (array_key_exists('tags', $entry)) {
164  foreach ($filter['tags.include'] as $fe) {
165  if (in_array($fe, $entry['tags'], true)) {
166  return true;
167  }
168  }
169  foreach ($filter['tags.exclude'] as $fe) {
170  if (in_array($fe, $entry['tags'], true)) {
171  return false;
172  }
173  }
174  }
175  return $default;
176  }
177 
178 
187  protected function filterList($list)
188  {
189  $list = parent::filterList($list);
190 
191  try {
192  $spmd = $this->metadata->getMetaData($this->spEntityId, 'saml20-sp-remote');
193  } catch (Exception $e) {
194  return $list;
195  }
196 
197  if (!isset($spmd)) {
198  return $list;
199  }
200  if (!array_key_exists('discopower.filter', $spmd)) {
201  return $list;
202  }
203  $filter = $spmd['discopower.filter'];
204 
205  if (!array_key_exists('entities.include', $filter)) {
206  $filter['entities.include'] = array();
207  }
208  if (!array_key_exists('entities.exclude', $filter)) {
209  $filter['entities.exclude'] = array();
210  }
211  if (!array_key_exists('tags.include', $filter)) {
212  $filter['tags.include'] = array();
213  }
214  if (!array_key_exists('tags.exclude', $filter)) {
215  $filter['tags.exclude'] = array();
216  }
217 
218  $defaultrule = true;
219  if (array_key_exists('entities.include', $spmd['discopower.filter']) ||
220  array_key_exists('tags.include', $spmd['discopower.filter'])
221  ) {
222 
223  $defaultrule = false;
224  }
225 
226  $returnlist = array();
227  foreach ($list as $key => $entry) {
228  if ($this->processFilter($filter, $entry, $defaultrule)) {
229  $returnlist[$key] = $entry;
230  }
231  }
232  return $returnlist;
233  }
234 
235 
241  public function handleRequest()
242  {
243  $this->start();
244 
245  // no choice made. Show discovery service page
246  $idpList = $this->getIdPList();
247  $idpList = $this->idplistStructured($this->filterList($idpList));
248  $preferredIdP = $this->getRecommendedIdP();
249  $faventry = NULL;
250  foreach ($idpList AS $tab => $slist) {
251  if (!empty($preferredIdP) && array_key_exists($preferredIdP, $slist)) {
252  $faventry = $slist[$preferredIdP];
253  }
254  }
255 
256  $t = new SimpleSAML_XHTML_Template($this->config, 'discopower:disco.tpl.php', 'disco');
257  $discoPowerTabs = array(
258  'denmark' => $t->noop('{discopower:tabs:denmark}'),
259  'edugain' => $t->noop('{discopower:tabs:edugain}'),
260  'finland' => $t->noop('{discopower:tabs:finland}'),
261  'greece' => $t->noop('{discopower:tabs:greece}'),
262  'southafrica' => $t->noop('{discopower:tabs:southafrica}'),
263  'iceland' => $t->noop('{discopower:tabs:iceland}'),
264  'incommon' => $t->noop('{discopower:tabs:incommon}'),
265  'kalmar' => $t->noop('{discopower:tabs:kalmar}'),
266  'misc' => $t->noop('{discopower:tabs:misc}'),
267  'norway' => $t->noop('{discopower:tabs:norway}'),
268  'sweden' => $t->noop('{discopower:tabs:sweden}'),
269  'switzerland' => $t->noop('{discopower:tabs:switzerland}'),
270  'ukacessfederation' => $t->noop('{discopower:tabs:ukacessfederation}'),
271  );
272  $t->data['faventry'] = $faventry;
273  $t->data['tabNames'] = $discoPowerTabs;
274  $t->data['idplist'] = $idpList;
275  $t->data['preferredidp'] = $preferredIdP;
276  $t->data['return'] = $this->returnURL;
277  $t->data['returnIDParam'] = $this->returnIdParam;
278  $t->data['entityID'] = $this->spEntityId;
279  $t->data['urlpattern'] = htmlspecialchars(\SimpleSAML\Utils\HTTP::getSelfURLNoQuery());
280  $t->data['rememberenabled'] = $this->config->getBoolean('idpdisco.enableremember', false);
281  $t->data['rememberchecked'] = $this->config->getBoolean('idpdisco.rememberchecked', false);
282  $t->data['defaulttab'] = $this->discoconfig->getValue('defaulttab', 0);
283  $t->data['score'] = $this->discoconfig->getValue('score', 'quicksilver');
284  $t->show();
285  }
286 
287 
293  private function getCDC()
294  {
295  if (!isset($_COOKIE['_saml_idp'])) {
296  return array();
297  }
298 
299  $ret = (string) $_COOKIE['_saml_idp'];
300  $ret = explode(' ', $ret);
301  foreach ($ret as &$idp) {
302  $idp = base64_decode($idp);
303  if ($idp === false) {
304  // not properly base64 encoded
305  return array();
306  }
307  }
308 
309  return $ret;
310  }
311 
312 
320  protected function setPreviousIdP($idp)
321  {
322  assert(is_string($idp));
323 
324  if ($this->cdcDomain === null) {
325  parent::setPreviousIdP($idp);
326  return;
327  }
328 
329  $list = $this->getCDC();
330 
331  $prevIndex = array_search($idp, $list, true);
332  if ($prevIndex !== false) {
333  unset($list[$prevIndex]);
334  }
335  $list[] = $idp;
336 
337  foreach ($list as &$value) {
338  $value = base64_encode($value);
339  }
340  $newCookie = implode(' ', $list);
341 
342  while (strlen($newCookie) > 4000) {
343  // the cookie is too long. Remove the oldest elements until it is short enough
344  $tmp = explode(' ', $newCookie, 2);
345  if (count($tmp) === 1) {
346  // we are left with a single entityID whose base64 representation is too long to fit in a cookie
347  break;
348  }
349  $newCookie = $tmp[1];
350  }
351 
352  $params = array(
353  'lifetime' => $this->cdcLifetime,
354  'domain' => $this->cdcDomain,
355  'secure' => true,
356  'httponly' => false,
357  );
358  \SimpleSAML\Utils\HTTP::setCookie('_saml_idp', $newCookie, $params, false);
359  }
360 
361 
369  protected function getPreviousIdP()
370  {
371  if ($this->cdcDomain === null) {
372  return parent::getPreviousIdP();
373  }
374 
375  $prevIdPs = $this->getCDC();
376  while (count($prevIdPs) > 0) {
377  $idp = array_pop($prevIdPs);
378  $idp = $this->validateIdP($idp);
379  if ($idp !== null) {
380  return $idp;
381  }
382  }
383 
384  return null;
385  }
386 }
idplistStructured($list)
Structure the list of IdPs in a hierarchy based upon the tags.
setPreviousIdP($idp)
Save the current IdP choice to a cookie.
$_COOKIE['client_id']
Definition: server.php:9
if(isset($_REQUEST['delete'])) $list
Definition: registry.php:41
$slist
Definition: registry.php:43
start()
Check if an IdP is set or if the request is passive, and redirect accordingly.
Definition: IdPDisco.php:512
handleRequest()
Handles a request to this discovery service.
getCDC()
Get the IdP entities saved in the common domain cookie.
Attribute-related utility methods.
static info($string)
Definition: Logger.php:199
catch(Exception $e) $message
static setCookie($name, $value, $params=null, $throw=true)
Set a cookie.
Definition: HTTP.php:1104
__construct(array $metadataSets, $instance)
Initializes this discovery service.
getIdPList()
Retrieve the list of IdPs which are stored in the metadata.
Definition: IdPDisco.php:459
log($message)
Log a message.
$tags
Definition: croninfo.php:19
filterList($list)
Filter a list of entities according to any filters defined in the parent class, plus discopower confi...
static getConfig($filename='config.php', $configSet='simplesaml')
Load a configuration file from a configuration set.
instance(Loop $newLoop=null)
Retrieves or sets the global Loop object.
Definition: functions.php:173
$default
Definition: build.php:20
getPreviousIdP()
Retrieve the previous IdP the user used.
getRecommendedIdP()
Try to determine which IdP the user should most likely use.
Definition: IdPDisco.php:365
$idp
Definition: prp.php:13
$ret
Definition: parser.php:6
processFilter($filter, $entry, $default=true)
Do the actual filtering according the rules defined.
static mcmp(array $a, array $b)
Compare two entities.
$key
Definition: croninfo.php:18
validateIdP($idp)
Validates the given IdP entity id.
Definition: IdPDisco.php:238
if(function_exists('posix_getuid') &&posix_getuid()===0) if(!array_key_exists('t', $options)) $tag
Definition: cron.php:35