Skip to content

Commit 82fb931

Browse files
nathanjrobertsonmonkeyiq
authored andcommitted
Add regular expression support to AttributeValueMap authproc filter (simplesamlphp#2558)
1 parent 5a99ba1 commit 82fb931

3 files changed

Lines changed: 132 additions & 2 deletions

File tree

modules/core/docs/authproc_attributevaluemap.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ Filter that creates a target attribute based on one or more value(s) in source a
55
Besides the mapping of source values to target values, the filter has the following options:
66

77
* `%replace` can be used to replace all existing values in target with new ones (any existing values will be lost)
8-
* `%keep` can be used to keep the source attribute, otherwise it will be removed.
8+
* `%keep` can be used to keep the source attribute, otherwise it will be removed (regardless of whether there is a match or not).
9+
* `%regex` can be used to evaluate the values as regular expressions instead of plain strings.
910

1011
**Examples**:
1112

@@ -84,3 +85,25 @@ Replace any existing `affiliation` attribute values and keep the `groups` attrib
8485
],
8586
],
8687
],
88+
89+
## Regular expressions
90+
91+
Will add eduPersonAffiliation containing value `student` if the `memberOf` attribute contains
92+
some value matching `/^cn=student,o=[a-z]+,o=organization,dc=org`
93+
(eg. `cn=student,o=some,o=organization,dc=org`).
94+
The `memberOf` attribute will be removed (use `%keep`, to keep it) and existing values in
95+
`eduPersonAffiliation` will be merged (use `%replace` to replace them).
96+
97+
'authproc' => [
98+
50 => [
99+
'class' => 'core:AttributeValueMap',
100+
'sourceattribute' => 'memberOf',
101+
'targetattribute' => 'eduPersonAffiliation',
102+
'%regex',
103+
'values' => [
104+
'student' => [
105+
'/^cn=student,o=[a-z]+,o=organization,dc=org$/',
106+
],
107+
],
108+
],
109+
],

modules/core/src/Auth/Process/AttributeValueMap.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ class AttributeValueMap extends Auth\ProcessingFilter
5454
*/
5555
private bool $replace = false;
5656

57+
/**
58+
* Whether $sourceattribute values should be treated as regular expressions or not.
59+
* @var bool
60+
*/
61+
private bool $regex = false;
62+
5763

5864
/**
5965
* Initialize the filter.
@@ -75,6 +81,8 @@ public function __construct(array &$config, $reserved)
7581
$this->replace = true;
7682
} elseif ($value === '%keep') {
7783
$this->keep = true;
84+
} elseif ($value === '%regex') {
85+
$this->regex = true;
7886
} else {
7987
// unknown configuration option, log it and ignore the error
8088
Logger::warning(
@@ -139,7 +147,19 @@ public function process(array &$state): void
139147
if (!is_array($values)) {
140148
$values = [$values];
141149
}
142-
if (count(array_intersect($values, $sourceattribute)) > 0) {
150+
if ($this->regex) {
151+
foreach ($sourceattribute as $sourcevalue) {
152+
foreach ($values as $pattern) {
153+
if (preg_match($pattern, $sourcevalue) === 1) {
154+
Logger::debug("AttributeValueMap: regex match for '$value'");
155+
$targetvalues[] = $value;
156+
// no need to check other patterns for this sourceattribute value
157+
break 2;
158+
}
159+
}
160+
}
161+
continue;
162+
} elseif (count(array_intersect($values, $sourceattribute)) > 0) {
143163
Logger::debug("AttributeValueMap: intersect match for '$value'");
144164
$targetvalues[] = $value;
145165
}

tests/modules/core/src/Auth/Process/AttributeValueMapTest.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,34 @@ public function testBasic(): void
6262
}
6363

6464

65+
/**
66+
* The most basic test of no match.
67+
*
68+
* @throws \SimpleSAML\Error\Exception
69+
*/
70+
public function testBasicNoMatch(): void
71+
{
72+
$config = [
73+
'sourceattribute' => 'memberOf',
74+
'targetattribute' => 'eduPersonAffiliation',
75+
'values' => [
76+
'member' => [
77+
'nomatch',
78+
],
79+
],
80+
];
81+
$request = [
82+
'Attributes' => [
83+
'memberOf' => ['theGroup'],
84+
],
85+
];
86+
$result = self::processFilter($config, $request);
87+
$attributes = $result['Attributes'];
88+
$this->assertArrayNotHasKey('memberOf', $attributes);
89+
$this->assertArrayNotHasKey('eduPersonAffiliation', $attributes);
90+
}
91+
92+
6593
/**
6694
* Test basic functionality, remove duplicates
6795
*
@@ -234,4 +262,63 @@ public function testMissingTargetAttribute(): void
234262
];
235263
self::processFilter($config, $request);
236264
}
265+
266+
267+
/**
268+
* Basic regular expression functionality test.
269+
*
270+
* @throws \SimpleSAML\Error\Exception
271+
*/
272+
public function testBasicRegex(): void
273+
{
274+
$config = [
275+
'sourceattribute' => 'memberOf',
276+
'targetattribute' => 'eduPersonAffiliation',
277+
'%regex',
278+
'values' => [
279+
'member' => [
280+
'/^the/',
281+
],
282+
],
283+
];
284+
$request = [
285+
'Attributes' => [
286+
'memberOf' => ['theGroup'],
287+
],
288+
];
289+
$result = self::processFilter($config, $request);
290+
$attributes = $result['Attributes'];
291+
$this->assertArrayNotHasKey('memberOf', $attributes);
292+
$this->assertArrayHasKey('eduPersonAffiliation', $attributes);
293+
$this->assertEquals($attributes['eduPersonAffiliation'], ['member']);
294+
}
295+
296+
297+
/**
298+
* Basic regular expression functionality test of a "no match".
299+
*
300+
* @throws \SimpleSAML\Error\Exception
301+
*/
302+
public function testBasicRegexNoMatch(): void
303+
{
304+
$config = [
305+
'sourceattribute' => 'memberOf',
306+
'targetattribute' => 'eduPersonAffiliation',
307+
'%regex',
308+
'values' => [
309+
'member' => [
310+
'/^nomatch$/',
311+
],
312+
],
313+
];
314+
$request = [
315+
'Attributes' => [
316+
'memberOf' => ['theGroup'],
317+
],
318+
];
319+
$result = self::processFilter($config, $request);
320+
$attributes = $result['Attributes'];
321+
$this->assertArrayNotHasKey('memberOf', $attributes);
322+
$this->assertArrayNotHasKey('eduPersonAffiliation', $attributes);
323+
}
237324
}

0 commit comments

Comments
 (0)