ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
ProcessingChain.php
Go to the documentation of this file.
1 <?php
2 
14 
15 
19  const FILTERS_INDEX = 'SimpleSAML_Auth_ProcessingChain.filters';
20 
21 
25  const COMPLETED_STAGE = 'SimpleSAML_Auth_ProcessingChain.completed';
26 
27 
32  const AUTHPARAM = 'AuthProcId';
33 
34 
38  private $filters;
39 
40 
48  public function __construct($idpMetadata, $spMetadata, $mode = 'idp') {
49  assert('is_array($idpMetadata)');
50  assert('is_array($spMetadata)');
51 
52  $this->filters = array();
53 
55  $configauthproc = $config->getArray('authproc.' . $mode, NULL);
56 
57  if (!empty($configauthproc)) {
58  $configfilters = self::parseFilterList($configauthproc);
59  self::addFilters($this->filters, $configfilters);
60  }
61 
62  if (array_key_exists('authproc', $idpMetadata)) {
63  $idpFilters = self::parseFilterList($idpMetadata['authproc']);
64  self::addFilters($this->filters, $idpFilters);
65  }
66 
67  if (array_key_exists('authproc', $spMetadata)) {
68  $spFilters = self::parseFilterList($spMetadata['authproc']);
69  self::addFilters($this->filters, $spFilters);
70  }
71 
72 
73  SimpleSAML\Logger::debug('Filter config for ' . $idpMetadata['entityid'] . '->' .
74  $spMetadata['entityid'] . ': ' . str_replace("\n", '', var_export($this->filters, TRUE)));
75 
76  }
77 
78 
87  private static function addFilters(&$target, $src) {
88  assert('is_array($target)');
89  assert('is_array($src)');
90 
91  foreach ($src as $filter) {
92  $fp = $filter->priority;
93 
94  // Find insertion position for filter
95  for($i = count($target)-1; $i >= 0; $i--) {
96  if ($target[$i]->priority <= $fp) {
97  // The new filter should be inserted after this one
98  break;
99  }
100  }
101  /* $i now points to the filter which should preceede the current filter. */
102  array_splice($target, $i+1, 0, array($filter));
103  }
104 
105  }
106 
107 
114  private static function parseFilterList($filterSrc) {
115  assert('is_array($filterSrc)');
116 
117  $parsedFilters = array();
118 
119  foreach ($filterSrc as $priority => $filter) {
120 
121  if (is_string($filter)) {
122  $filter = array('class' => $filter);
123  }
124 
125  if (!is_array($filter)) {
126  throw new Exception('Invalid authentication processing filter configuration: ' .
127  'One of the filters wasn\'t a string or an array.');
128  }
129 
130  $parsedFilters[] = self::parseFilter($filter, $priority);
131  }
132 
133  return $parsedFilters;
134  }
135 
136 
145  private static function parseFilter($config, $priority) {
146  assert('is_array($config)');
147 
148  if (!array_key_exists('class', $config))
149  throw new Exception('Authentication processing filter without name given.');
150 
151  $className = SimpleSAML\Module::resolveClass($config['class'], 'Auth_Process', 'SimpleSAML_Auth_ProcessingFilter');
152  $config['%priority'] = $priority;
153  unset($config['class']);
154  return new $className($config, NULL);
155  }
156 
157 
178  public function processState(&$state) {
179  assert('is_array($state)');
180  assert('array_key_exists("ReturnURL", $state) || array_key_exists("ReturnCall", $state)');
181  assert('!array_key_exists("ReturnURL", $state) || !array_key_exists("ReturnCall", $state)');
182 
183  $state[self::FILTERS_INDEX] = $this->filters;
184 
185  try {
186 
187  // TODO: remove this in SSP 2.0
188  if (!array_key_exists('UserID', $state)) {
189  // No unique user ID present. Attempt to add one.
190  self::addUserID($state);
191  }
192 
193  while (count($state[self::FILTERS_INDEX]) > 0) {
194  $filter = array_shift($state[self::FILTERS_INDEX]);
195  $filter->process($state);
196  }
197 
198  } catch (SimpleSAML_Error_Exception $e) {
199  // No need to convert the exception
200  throw $e;
201  } catch (Exception $e) {
202  /*
203  * To be consistent with the exception we return after an redirect,
204  * we convert this exception before returning it.
205  */
207  }
208 
209  // Completed
210  }
211 
212 
224  public static function resumeProcessing($state) {
225  assert('is_array($state)');
226 
227  while (count($state[self::FILTERS_INDEX]) > 0) {
228  $filter = array_shift($state[self::FILTERS_INDEX]);
229  try {
230  $filter->process($state);
231  } catch (SimpleSAML_Error_Exception $e) {
233  } catch (Exception $e) {
236  }
237  }
238 
239  // Completed
240 
241  assert('array_key_exists("ReturnURL", $state) || array_key_exists("ReturnCall", $state)');
242  assert('!array_key_exists("ReturnURL", $state) || !array_key_exists("ReturnCall", $state)');
243 
244 
245  if (array_key_exists('ReturnURL', $state)) {
246  /*
247  * Save state information, and redirect to the URL specified
248  * in $state['ReturnURL'].
249  */
250  $id = SimpleSAML_Auth_State::saveState($state, self::COMPLETED_STAGE);
251  \SimpleSAML\Utils\HTTP::redirectTrustedURL($state['ReturnURL'], array(self::AUTHPARAM => $id));
252  } else {
253  /* Pass the state to the function defined in $state['ReturnCall']. */
254 
255  // We are done with the state array in the session. Delete it.
257 
258  $func = $state['ReturnCall'];
259  assert('is_callable($func)');
260 
261  call_user_func($func, $state);
262  assert(FALSE);
263  }
264  }
265 
266 
277  public function processStatePassive(&$state) {
278  assert('is_array($state)');
279  // Should not be set when calling this method
280  assert('!array_key_exists("ReturnURL", $state)');
281 
282  // Notify filters about passive request
283  $state['isPassive'] = TRUE;
284 
285  $state[self::FILTERS_INDEX] = $this->filters;
286 
287  // TODO: remove this in SSP 2.0
288  if (!array_key_exists('UserID', $state)) {
289  // No unique user ID present. Attempt to add one.
290  self::addUserID($state);
291  }
292 
293  while (count($state[self::FILTERS_INDEX]) > 0) {
294  $filter = array_shift($state[self::FILTERS_INDEX]);
295  try {
296  $filter->process($state);
297 
298  // Ignore SimpleSAML_Error_NoPassive exceptions
299  } catch (SimpleSAML_Error_NoPassive $e) { }
300  }
301  }
302 
310  public static function fetchProcessedState($id) {
311  assert('is_string($id)');
312 
313  return SimpleSAML_Auth_State::loadState($id, self::COMPLETED_STAGE);
314  }
315 
316 
320  private static function addUserID(&$state) {
321  assert('is_array($state)');
322  assert('array_key_exists("Attributes", $state)');
323 
324  if (isset($state['Destination']['userid.attribute'])) {
325  $attributeName = $state['Destination']['userid.attribute'];
326  SimpleSAML\Logger::warning("The 'userid.attribute' option has been deprecated.");
327  } elseif (isset($state['Source']['userid.attribute'])) {
328  $attributeName = $state['Source']['userid.attribute'];
329  SimpleSAML\Logger::warning("The 'userid.attribute' option has been deprecated.");
330  } else {
331  // Default attribute
332  $attributeName = 'eduPersonPrincipalName';
333  }
334 
335  if (!array_key_exists($attributeName, $state['Attributes'])) {
336  return;
337  }
338 
339  $uid = $state['Attributes'][$attributeName];
340  if (count($uid) === 0) {
341  SimpleSAML\Logger::warning('Empty user id attribute [' . $attributeName . '].');
342  return;
343  }
344 
345  if (count($uid) > 1) {
346  SimpleSAML\Logger::warning('Multiple attribute values for user id attribute [' . $attributeName . '].');
347  return;
348  }
349 
350  // TODO: the attribute value should be trimmed
351  $uid = $uid[0];
352 
353  if (empty($uid)) {
354  SimpleSAML\Logger::warning('Empty value in attribute '.$attributeName.". on user. Cannot set UserID.");
355  return;
356  }
357  $state['UserID'] = $uid;
358  }
359 
360 }
static addFilters(&$target, $src)
Sort & merge filter configuration.
static throwException($state, SimpleSAML_Error_Exception $exception)
Throw exception to the state exception handler.
Definition: State.php:343
static debug($string)
Definition: Logger.php:213
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:962
$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
__construct($idpMetadata, $spMetadata, $mode='idp')
Initialize an authentication processing chain for the given service provider and identity provider...
static warning($string)
Definition: Logger.php:179
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
Create styles array
The data for the language used.
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:252
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.