ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
ProcessingChain.php
Go to the documentation of this file.
1 <?php
2 
14 {
15 
16 
20  const FILTERS_INDEX = 'SimpleSAML_Auth_ProcessingChain.filters';
21 
22 
26  const COMPLETED_STAGE = 'SimpleSAML_Auth_ProcessingChain.completed';
27 
28 
33  const AUTHPARAM = 'AuthProcId';
34 
35 
39  private $filters;
40 
41 
49  public function __construct($idpMetadata, $spMetadata, $mode = 'idp')
50  {
51  assert(is_array($idpMetadata));
52  assert(is_array($spMetadata));
53 
54  $this->filters = array();
55 
57  $configauthproc = $config->getArray('authproc.' . $mode, null);
58 
59  if (!empty($configauthproc)) {
60  $configfilters = self::parseFilterList($configauthproc);
61  self::addFilters($this->filters, $configfilters);
62  }
63 
64  if (array_key_exists('authproc', $idpMetadata)) {
65  $idpFilters = self::parseFilterList($idpMetadata['authproc']);
66  self::addFilters($this->filters, $idpFilters);
67  }
68 
69  if (array_key_exists('authproc', $spMetadata)) {
70  $spFilters = self::parseFilterList($spMetadata['authproc']);
71  self::addFilters($this->filters, $spFilters);
72  }
73 
74 
75  SimpleSAML\Logger::debug('Filter config for ' . $idpMetadata['entityid'] . '->' .
76  $spMetadata['entityid'] . ': ' . str_replace("\n", '', var_export($this->filters, true)));
77  }
78 
79 
88  private static function addFilters(&$target, $src)
89  {
90  assert(is_array($target));
91  assert(is_array($src));
92 
93  foreach ($src as $filter) {
94  $fp = $filter->priority;
95 
96  // Find insertion position for filter
97  for ($i = count($target)-1; $i >= 0; $i--) {
98  if ($target[$i]->priority <= $fp) {
99  // The new filter should be inserted after this one
100  break;
101  }
102  }
103  /* $i now points to the filter which should preceede the current filter. */
104  array_splice($target, $i+1, 0, array($filter));
105  }
106  }
107 
108 
115  private static function parseFilterList($filterSrc)
116  {
117  assert(is_array($filterSrc));
118 
119  $parsedFilters = array();
120 
121  foreach ($filterSrc as $priority => $filter) {
122  if (is_string($filter)) {
123  $filter = array('class' => $filter);
124  }
125 
126  if (!is_array($filter)) {
127  throw new Exception('Invalid authentication processing filter configuration: ' .
128  'One of the filters wasn\'t a string or an array.');
129  }
130 
131  $parsedFilters[] = self::parseFilter($filter, $priority);
132  }
133 
134  return $parsedFilters;
135  }
136 
137 
146  private static function parseFilter($config, $priority)
147  {
148  assert(is_array($config));
149 
150  if (!array_key_exists('class', $config)) {
151  throw new Exception('Authentication processing filter without name given.');
152  }
153 
154  $className = SimpleSAML\Module::resolveClass($config['class'], 'Auth_Process', 'SimpleSAML_Auth_ProcessingFilter');
155  $config['%priority'] = $priority;
156  unset($config['class']);
157  return new $className($config, null);
158  }
159 
160 
181  public function processState(&$state)
182  {
183  assert(is_array($state));
184  assert(array_key_exists('ReturnURL', $state) || array_key_exists('ReturnCall', $state));
185  assert(!array_key_exists('ReturnURL', $state) || !array_key_exists('ReturnCall', $state));
186 
187  $state[self::FILTERS_INDEX] = $this->filters;
188 
189  try {
190  // TODO: remove this in SSP 2.0
191  if (!array_key_exists('UserID', $state)) {
192  // No unique user ID present. Attempt to add one.
193  self::addUserID($state);
194  }
195 
196  while (count($state[self::FILTERS_INDEX]) > 0) {
197  $filter = array_shift($state[self::FILTERS_INDEX]);
198  $filter->process($state);
199  }
200  } catch (SimpleSAML_Error_Exception $e) {
201  // No need to convert the exception
202  throw $e;
203  } catch (Exception $e) {
204  /*
205  * To be consistent with the exception we return after an redirect,
206  * we convert this exception before returning it.
207  */
209  }
210 
211  // Completed
212  }
213 
214 
226  public static function resumeProcessing($state)
227  {
228  assert(is_array($state));
229 
230  while (count($state[self::FILTERS_INDEX]) > 0) {
231  $filter = array_shift($state[self::FILTERS_INDEX]);
232  try {
233  $filter->process($state);
234  } catch (SimpleSAML_Error_Exception $e) {
236  } catch (Exception $e) {
239  }
240  }
241 
242  // Completed
243 
244  assert(array_key_exists('ReturnURL', $state) || array_key_exists('ReturnCall', $state));
245  assert(!array_key_exists('ReturnURL', $state) || !array_key_exists('ReturnCall', $state));
246 
247 
248  if (array_key_exists('ReturnURL', $state)) {
249  /*
250  * Save state information, and redirect to the URL specified
251  * in $state['ReturnURL'].
252  */
253  $id = SimpleSAML_Auth_State::saveState($state, self::COMPLETED_STAGE);
254  \SimpleSAML\Utils\HTTP::redirectTrustedURL($state['ReturnURL'], array(self::AUTHPARAM => $id));
255  } else {
256  /* Pass the state to the function defined in $state['ReturnCall']. */
257 
258  // We are done with the state array in the session. Delete it.
260 
261  $func = $state['ReturnCall'];
262  assert(is_callable($func));
263 
264  call_user_func($func, $state);
265  assert(false);
266  }
267  }
268 
269 
280  public function processStatePassive(&$state)
281  {
282  assert(is_array($state));
283  // Should not be set when calling this method
284  assert(!array_key_exists('ReturnURL', $state));
285 
286  // Notify filters about passive request
287  $state['isPassive'] = true;
288 
289  $state[self::FILTERS_INDEX] = $this->filters;
290 
291  // TODO: remove this in SSP 2.0
292  if (!array_key_exists('UserID', $state)) {
293  // No unique user ID present. Attempt to add one.
294  self::addUserID($state);
295  }
296 
297  while (count($state[self::FILTERS_INDEX]) > 0) {
298  $filter = array_shift($state[self::FILTERS_INDEX]);
299  try {
300  $filter->process($state);
301  // Ignore SimpleSAML_Error_NoPassive exceptions
302  } catch (SimpleSAML_Error_NoPassive $e) {
303  // @deprecated will be removed in 2.0
304  // Ignore \SimpleSAML\Error\NoPassive exceptions
305  } catch (\SimpleSAML\Module\saml\Error\NoPassive $e) {
306  // Ignore \SimpleSAML\Module\saml\Error\NoPassive exceptions
307  }
308  }
309  }
310 
318  public static function fetchProcessedState($id)
319  {
320  assert(is_string($id));
321 
322  return SimpleSAML_Auth_State::loadState($id, self::COMPLETED_STAGE);
323  }
324 
325 
329  private static function addUserID(&$state)
330  {
331  assert(is_array($state));
332  assert(array_key_exists('Attributes', $state));
333 
334  if (isset($state['Destination']['userid.attribute'])) {
335  $attributeName = $state['Destination']['userid.attribute'];
336  SimpleSAML\Logger::warning("The 'userid.attribute' option has been deprecated.");
337  } elseif (isset($state['Source']['userid.attribute'])) {
338  $attributeName = $state['Source']['userid.attribute'];
339  SimpleSAML\Logger::warning("The 'userid.attribute' option has been deprecated.");
340  } else {
341  // Default attribute
342  $attributeName = 'eduPersonPrincipalName';
343  }
344 
345  if (!array_key_exists($attributeName, $state['Attributes'])) {
346  return;
347  }
348 
349  $uid = $state['Attributes'][$attributeName];
350  if (count($uid) === 0) {
351  SimpleSAML\Logger::warning('Empty user id attribute [' . $attributeName . '].');
352  return;
353  }
354 
355  if (count($uid) > 1) {
356  SimpleSAML\Logger::warning('Multiple attribute values for user id attribute [' . $attributeName . '].');
357  return;
358  }
359 
360  // TODO: the attribute value should be trimmed
361  $uid = $uid[0];
362 
363  if (empty($uid)) {
364  SimpleSAML\Logger::warning('Empty value in attribute '.$attributeName.". on user. Cannot set UserID.");
365  return;
366  }
367  $state['UserID'] = $uid;
368  }
369 }
static addFilters(&$target, $src)
Sort & merge filter configuration.
$config
Definition: bootstrap.php:15
static throwException($state, SimpleSAML_Error_Exception $exception)
Throw exception to the state exception handler.
Definition: State.php:343
static debug($string)
Definition: Logger.php:211
processState(&$state)
Process the given state.
if(!array_key_exists('StateId', $_REQUEST)) $id
processStatePassive(&$state)
Process the given state passivly.
static redirectTrustedURL($url, $parameters=array())
This function redirects to the specified URL without performing any security checks.
Definition: HTTP.php:959
$spMetadata
static resumeProcessing($state)
Continues processing of the state.
const AUTHPARAM
The request parameter we will use to pass the state identifier when we redirect after having complete...
static parseFilter($config, $priority)
Parse an authentication processing filter.
Class SimpleSAML_Error_NoPassive.
Definition: NoPassive.php:12
if(!array_key_exists('stateid', $_REQUEST)) $state
Handle linkback() response from LinkedIn.
Definition: linkback.php:10
Attribute-related utility methods.
__construct($idpMetadata, $spMetadata, $mode='idp')
Initialize an authentication processing chain for the given service provider and identity provider...
static warning($string)
Definition: Logger.php:177
static parseFilterList($filterSrc)
Parse an array of authentication processing filters.
$filters
All authentication processing filters, in the order they should be applied.
static fetchProcessedState($id)
Retrieve a state which has finished processing.
static loadState($id, $stage, $allowMissing=false)
Retrieve saved state.
Definition: State.php:259
static deleteState(&$state)
Delete state.
Definition: State.php:319
$i
Definition: disco.tpl.php:19
$idpMetadata
const FILTERS_INDEX
The list of remaining filters which should be applied to the state.
static resolveClass($id, $type, $subclass=null)
Resolve module class.
Definition: Module.php:169
$target
Definition: test.php:19
const COMPLETED_STAGE
The stage we use for completed requests.
static saveState(&$state, $stage, $rawId=false)
Save the state.
Definition: State.php:194
static getInstance($instancename='simplesaml')
Get a configuration file by its instance name.