Skip to content
This repository was archived by the owner on Sep 19, 2022. It is now read-only.

Commit 6c6110f

Browse files
author
Dominik Frantisek Bucik
committed
feat: 🎸 New filter for extracting attribute from request var
1 parent 80a67bc commit 6c6110f

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

config-templates/processFilterConfigurations-example.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,24 @@ Example how to enable filter AttributeMap:
160160
// 'interface' => 'rpc', # optional, rpc/ldap, default rpc
161161
],
162162
```
163+
164+
## ExtractRequestAttribute
165+
166+
Filter is intended to extract an attribute specified by set of keys forming the chain of keys in the `$request` variable into the configured destination attribute.
167+
Configuration options:
168+
* `attr_name`: specifies attribute name, into which the extracted value will be stored
169+
* `request_keys`: string, which contains a semicolon (`;`) separated chain of keys that are examined in the state. Numeric keys are automatically treated as array indexes. For instance, value `'saml:AuthenticatingAuthority;0'` will be treated as code `$request['saml:AuthenticatingAuthority'][0]`. In case of this value being empty, exception is thrown. Otherwise, extracted value is stored into the configured destination attribute.
170+
* `fail_on_nonexisting_keys`: `true` or `false`, specifies if in case of missing key in the request variable the filter should terminate with an exception or not
171+
* `default_value`: array, which will be set as default value, if the configured keys did not lead to value
172+
173+
```php
174+
// EXTRACT AUTHENTICATING ENTITY INTO authenticating_idp attribute
175+
1 => [
176+
'class' => 'perun:ExtractRequestAttribute',
177+
'attr_name' => 'authenticating_idp',
178+
'request_keys' => 'saml:AuthenticatingAuthority;0',
179+
'fail_on_nonexisting_keys' => 'true',
180+
'default_value' => null,
181+
],
182+
183+
```
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Module\perun\Auth\Process;
6+
7+
use SimpleSAML\Auth\ProcessingFilter;
8+
use SimpleSAML\Configuration;
9+
use SimpleSAML\Error\Exception;
10+
use SimpleSAML\Logger;
11+
use SimpleSAML\Module\perun\PerunConstants;
12+
13+
/**
14+
* Extracts request variable value specified by chain of keys into the configured destination attribute.
15+
*/
16+
class ExtractRequestAttribute extends ProcessingFilter
17+
{
18+
public const STAGE = 'perun:ExtractRequestAttribute';
19+
public const DEBUG_PREFIX = self::STAGE . ' - ';
20+
21+
public const DESTINATION_ATTRIBUTE_NAME = 'destination_attribute_name';
22+
public const REQUEST_KEYS = 'request_keys';
23+
public const FAIL_ON_NON_EXISTING_KEY = 'fail_on_not_existing_key';
24+
public const DEFAULT_VALUE = 'default_value';
25+
26+
public const KEYS_SEPARATOR = ';';
27+
public const FAILURE_VALUE = '%$FAILURE_VALUE$%';
28+
29+
private $destinationAttrName;
30+
private $requestKeys;
31+
private $failOnNonExistingKey;
32+
private $defaultValue;
33+
private $filterConfig;
34+
35+
public function __construct($config, $reserved)
36+
{
37+
parent::__construct($config, $reserved);
38+
$this->filterConfig = Configuration::loadFromArray($config);
39+
40+
$this->destinationAttrName = $this->filterConfig->getString(self::DESTINATION_ATTRIBUTE_NAME, null);
41+
if (empty($this->requestKeys)) {
42+
throw new Exception(
43+
self::DEBUG_PREFIX . 'missing mandatory configuration for option \'' . self::DESTINATION_ATTRIBUTE_NAME . '\''
44+
);
45+
}
46+
47+
$this->requestKeys = $this->filterConfig->getString(self::REQUEST_KEYS, null);
48+
if (empty($this->requestKeys)) {
49+
throw new Exception(
50+
self::DEBUG_PREFIX . 'missing mandatory configuration for option \'' . self::REQUEST_KEYS . '\''
51+
);
52+
}
53+
$this->requestKeys = explode(self::KEYS_SEPARATOR, $this->requestKeys);
54+
55+
$this->failOnNonExistingKey = $this->filterConfig->getBoolean(self::FAIL_ON_NON_EXISTING_KEY, true);
56+
$this->defaultValue = $this->filterConfig->getArray(self::DEFAULT_VALUE, self::FAILURE_VALUE);
57+
if (
58+
!$this->failOnNonExistingKey
59+
&& self::FAILURE_VALUE === $this->defaultValue
60+
) {
61+
throw new Exception(
62+
self::DEBUG_PREFIX . 'invalid configuration, fail on missing key is disabled, but no default value ' . 'for the attribute has been set'
63+
);
64+
}
65+
}
66+
67+
public function process(&$request)
68+
{
69+
assert(is_array($request));
70+
71+
$value = $request;
72+
foreach ($this->requestKeys as $key) {
73+
if (is_numeric($key)) {
74+
$key = (int) $key;
75+
}
76+
if (!array_key_exists($key, $value)) {
77+
Logger::warning(
78+
self::DEBUG_PREFIX . 'Cannot find key \'' .
79+
$key . '\' in the supposed path towards the value. Did you configure the right path of keys ' .
80+
'to extract it?'
81+
);
82+
if ($this->failOnNonExistingKey) {
83+
throw new Exception(self::DEBUG_PREFIX . 'Specified chain of keys does not exist');
84+
}
85+
$value = $this->defaultValue;
86+
break;
87+
}
88+
$value = $value[$key];
89+
}
90+
91+
if (self::FAILURE_VALUE === $value) {
92+
throw new Exception(self::DEBUG_PREFIX . 'Value cannot be extracted');
93+
}
94+
95+
if (!array_key_exists(PerunConstants::ATTRIBUTES, $request)) {
96+
$request[PerunConstants::ATTRIBUTES] = [];
97+
}
98+
if (!is_array($value) || !is_object($value)) {
99+
$value = [$value];
100+
}
101+
$request[PerunConstants::ATTRIBUTES][$this->destinationAttrName] = $value;
102+
Logger::debug(
103+
self::DEBUG_PREFIX . 'Value \'' . implode(',', $value)
104+
. '\' has been extracted and set to attribute ' . $this->destinationAttrName
105+
);
106+
}
107+
}

lib/PerunConstants.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace SimpleSAML\Module\perun;
4+
5+
class PerunConstants
6+
{
7+
public const ATTRIBUTES = 'Attributes';
8+
9+
public const TARGET_NEW = 'targetnew';
10+
11+
public const TARGET_EXISTING = 'targetexisting';
12+
13+
public const TARGET_EXTENDED = 'targetextended';
14+
15+
}

0 commit comments

Comments
 (0)