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

Commit 045e72b

Browse files
author
Dominik František Bučík
authored
Merge pull request #261 from dBucik/additional_identifiers
feat: 🎸 Additional identifiers lookup
2 parents 705d62a + 36f7f7c commit 045e72b

File tree

6 files changed

+103
-10
lines changed

6 files changed

+103
-10
lines changed

config-templates/processFilterConfigurations-example.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Example how to configure PerunIdentity module:
1212
'registerUrlBase' => 'https://perun.cesnet.cz/allfed/registrar',
1313
'registerUrl' => 'https://login.cesnet.cz/register',
1414
'interface' => 'ldap',
15+
'useAdditionalIdentifiersLookup' => true,
16+
'additionalIdentifiersAttribute' => 'additionalIdentifiers',
1517
'facilityCheckGroupMembershipAttr' => 'urn:perun:facility:attribute-def:def:checkGroupMembership',
1618
'facilityVoShortNamesAttr' => 'urn:perun:facility:attribute-def:virt:voShortNames',
1719
'facilityDynamicRegistrationAttr' => 'urn:perun:facility:attribute-def:def:dynamicRegistration',
@@ -193,6 +195,8 @@ Configuration options:
193195
* `register_url`: URL to which the user will be forwarded for registration. Leave empty to use the Perun registrar.
194196
* `callback_parameter_name`: name of the parameter wich will hold callback URL, where the user should be redirected after the registration on URL configured in the `register_url` property.
195197
* `perun_register_url`: the complete URL (including vo and group) to which user will be redirected, if `register_url` has not been configured. Parameters targetnew, targetexisting and targetextended will be set to callback URL to continue after the registration is completed.
198+
* `use_additional_identifiers_lookup`: `true` or `false`, set it to `true` if you want to use additionalIdentifiers as fallback lookup method if the standard one fails.
199+
* `additional_identifiers_attribute`: name of the attribute (from `$request['Attributes']` array), which holds the additional identifiers. If you use RPC adapter, the value in the attribute resolved using `idp_id_attr` will be used as well for locating the user in Perun.
196200

197201
```php
198202
2 => [
@@ -202,7 +206,9 @@ Configuration options:
202206
'idp_id_attr' => 'authenticating_idp',
203207
'register_url' => 'https://signup.cesnet.cz/',
204208
'callback_parameter_name' => 'callback',
205-
'perun_register_url' => 'https://signup.perun.cesnet.cz/fed/registrar/?vo=cesnet'
209+
'perun_register_url' => 'https://signup.perun.cesnet.cz/fed/registrar/?vo=cesnet',
210+
'use_additional_identifiers_lookup' => true,
211+
'additional_identifiers_attribute' => 'additionalIdentifiers',
206212
],
207213
```
208214

lib/Adapter.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ public static function getInstance($interface)
5454
*/
5555
abstract public function getPerunUser($idpEntityId, $uids);
5656

57+
/**
58+
* @param string $idpEntityId entity id of hosted idp used as extSourceName
59+
* @param array $uids list of user identifiers received from remote idp used as userExtSourceLogin
60+
*
61+
* @return User or null if not exists
62+
*/
63+
abstract public function getPerunUserByAdditionalIdentifiers($idpEntityId, $uids);
64+
5765
/**
5866
* @param model\Vo $vo
5967
* @param string $name group name. Note that name of group is without VO name prefix.

lib/AdapterLdap.php

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,29 @@ public function getPerunUser($idpEntityId, $uids)
100100
'(|' . $query . ')',
101101
['perunUserId', 'displayName', 'cn', 'givenName', 'sn', 'preferredMail', 'mail']
102102
);
103-
if (null === $user) {
104-
return $user;
103+
104+
return self::mapUser($user);
105+
}
106+
107+
public function getPerunUserByAdditionalIdentifiers($idpEntityId, $uids)
108+
{
109+
// Build a LDAP query, we are searching for the user who has at least one of the uid
110+
$query = '';
111+
foreach ($uids as $uid) {
112+
$query .= '(internalUserIdentifiers=' . $uid . ')';
105113
}
106114

107-
if (isset($user['displayName'][0])) {
108-
$name = $user['displayName'][0];
109-
} elseif (isset($user['cn'][0])) {
110-
$name = $user['cn'][0];
111-
} else {
112-
$name = null;
115+
if (empty($query)) {
116+
return null;
113117
}
114118

115-
return new User($user['perunUserId'][0], $name);
119+
$user = $this->connector->searchForEntity(
120+
'ou=People,' . $this->ldapBase,
121+
'(|' . $query . ')',
122+
['perunUserId', 'displayName', 'cn', 'givenName', 'sn', 'preferredMail', 'mail']
123+
);
124+
125+
return self::mapUser($user);
116126
}
117127

118128
public function getMemberGroups($user, $vo)
@@ -608,6 +618,22 @@ public function getFacilityCapabilities($entityId)
608618
return $facilityCapabilities['capabilities'];
609619
}
610620

621+
private function mapUser($user)
622+
{
623+
if (null === $user) {
624+
return null;
625+
}
626+
if (isset($user['displayName'][0])) {
627+
$name = $user['displayName'][0];
628+
} elseif (isset($user['cn'][0])) {
629+
$name = $user['cn'][0];
630+
} else {
631+
$name = null;
632+
}
633+
634+
return new User($user['perunUserId'][0], $name);
635+
}
636+
611637
private function resolveAttrValue($attrsNameTypeMap, $attrsFromLdap, $attr)
612638
{
613639
if (!array_key_exists($attr, $attrsFromLdap)) {

lib/AdapterRpc.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ public function getPerunUser($idpEntityId, $uids)
112112
return $user;
113113
}
114114

115+
public function getPerunUserByAdditionalIdentifiers($idpEntityId, $uids)
116+
{
117+
return $this->getPerunUser($idpEntityId, $uids);
118+
}
119+
115120
public function getMemberGroups($user, $vo)
116121
{
117122
try {

lib/Auth/Process/PerunIdentity.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use SimpleSAML\Module\perun\model\Member;
1717
use SimpleSAML\Module\perun\model\User;
1818
use SimpleSAML\Module\perun\model\Vo;
19+
use SimpleSAML\Module\perun\PerunConstants;
1920
use SimpleSAML\Utils\HTTP;
2021

2122
/**
@@ -66,6 +67,10 @@ class PerunIdentity extends \SimpleSAML\Auth\ProcessingFilter
6667

6768
public const LIST_OF_SPS_WITHOUT_INFO_ABOUT_REDIRECTION = 'listOfSpsWithoutInfoAboutRedirection';
6869

70+
public const USE_ADDITIONAL_IDENTIFIERS_LOOKUP = 'useAdditionalIdentifiersLookup';
71+
72+
public const ADDITIONAL_IDENTIFIERS_ATTRIBUTE = 'additionalIdentifiersAttribute';
73+
6974
public const MODE = 'mode';
7075

7176
public const MODE_FULL = 'FULL';
@@ -188,6 +193,14 @@ public function __construct($config, $reserved)
188193
);
189194
}
190195

196+
$this->useAdditionalIdentifiersLookup = $config->getBoolean(self::USE_ADDITIONAL_IDENTIFIERS_LOOKUP, false);
197+
$this->additionalIdentifiersAttribute = $config->getString(self::ADDITIONAL_IDENTIFIERS_ATTRIBUTE, null);
198+
if ($this->useAdditionalIdentifiersLookup && null === $this->additionalIdentifiersAttribute) {
199+
throw new Exception(
200+
'perun:PerunIdentity: Invalid configuration: no attribute configured for extracting additional identifiers. Use option \'' . self::ADDITIONAL_IDENTIFIERS_ATTRIBUTE . '\' to configure the name of the attribute, that should be considered as additional identifiers of the user.'
201+
);
202+
}
203+
191204
$this->adapter = Adapter::getInstance($this->interface);
192205
$this->rpcAdapter = new AdapterRpc();
193206
}
@@ -235,6 +248,15 @@ public function process(&$request)
235248
$groups = [];
236249

237250
$user = $this->adapter->getPerunUser($idpEntityId, $uids);
251+
if ($this->useAdditionalIdentifiersLookup && null === $user) {
252+
$additionalIdentifiers = $request[PerunConstants::ATTRIBUTES][$this->additionalIdentifiersAttribute] ?? null;
253+
if (empty($additionalIdentifiers)) {
254+
throw new Exception(
255+
'perun:PerunIdentity: missing mandatory attribute [' . $this->additionalIdentifiersAttribute . '] in request.'
256+
);
257+
}
258+
$user = $this->adapter->getPerunUserByAdditionalIdentifiers($idpEntityId, $additionalIdentifiers);
259+
}
238260

239261
if (self::MODE_FULL === $this->mode) {
240262
$this->getSPAttributes($this->spEntityId);

lib/Auth/Process/PerunUser.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,17 @@ class PerunUser extends ProcessingFilter
3838
public const REGISTER_URL = 'register_url';
3939
public const CALLBACK_PARAMETER_NAME = 'callback_parameter_name';
4040
public const PERUN_REGISTER_URL = 'perun_register_url';
41+
public const USE_ADDITIONAL_IDENTIFIERS_LOOKUP = 'use_additional_identifiers_lookup';
42+
public const ADDITIONAL_IDENTIFIERS_ATTRIBUTE = 'additional_identifiers_attribute';
4143

4244
private $adapter;
4345
private $idpEntityIdAttr;
4446
private $userIdAttrs;
4547
private $registerUrl;
4648
private $callbackParameterName;
4749
private $perunRegisterUrl;
50+
private $useAdditionalIdentifiersLookup;
51+
private $additionalIdentifiersAttribute;
4852
private $config;
4953
private $filterConfig;
5054

@@ -78,6 +82,19 @@ public function __construct($config, $reserved)
7882
. If you wish to use the Perun registrar, use the option \'' . self::PERUN_REGISTER_URL . '\'.'
7983
);
8084
}
85+
$this->useAdditionalIdentifiersLookup = $this->filterConfig->getBoolean(
86+
self::USE_ADDITIONAL_IDENTIFIERS_LOOKUP,
87+
false
88+
);
89+
$this->additionalIdentifiersAttribute = $this->filterConfig->getString(
90+
self::ADDITIONAL_IDENTIFIERS_ATTRIBUTE,
91+
null
92+
);
93+
if ($this->useAdditionalIdentifiersLookup && null === $this->additionalIdentifiersAttribute) {
94+
throw new Exception(
95+
self::DEBUG_PREFIX . 'Invalid configuration: no attribute configured for extracting additional identifiers. Use option \'' . self::ADDITIONAL_IDENTIFIERS_ATTRIBUTE . '\' to configure the name of the attribute, that should be considered as additional identifiers of the user.'
96+
);
97+
}
8198
}
8299

83100
public function process(&$request)
@@ -107,6 +124,15 @@ public function process(&$request)
107124
}
108125

109126
$user = $this->adapter->getPerunUser($idpEntityId, $uids);
127+
if ($this->useAdditionalIdentifiersLookup && null === $user) {
128+
$additionalIdentifiers = $request[PerunConstants::ATTRIBUTES][$this->additionalIdentifiersAttribute] ?? null;
129+
if (empty($additionalIdentifiers)) {
130+
throw new Exception(
131+
self::DEBUG_PREFIX . 'missing mandatory attribute [' . $this->additionalIdentifiersAttribute . '] in request.'
132+
);
133+
}
134+
$user = $this->adapter->getPerunUserByAdditionalIdentifiers($idpEntityId, $additionalIdentifiers);
135+
}
110136

111137
if (!empty($user)) {
112138
$this->processUser($request, $user, $uids);

0 commit comments

Comments
 (0)