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

Commit 2a331bb

Browse files
BaranekDvyskocilpavel
authored andcommitted
feat: Implemented EnsureVoMember filter
1 parent 4e5e00f commit 2a331bb

File tree

7 files changed

+237
-5
lines changed

7 files changed

+237
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file.
44
## [Unreleased]
55
#### Changed
66
- Improve WAYF searching by localized name and domain
7+
- Implemented filter EnsureVoMember
78

89
#### Fixed
910
- Detailed endpoint format when spaced in EndpointMapToArray

config-templates/processFilterConfigurations-example.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ Example how to enable filter IdPAttribute:
4242
'OrganizationName:en' => 'idp_organizationName' means that the $IdPMetadata['Organization']['en'] will be save into
4343
$request['Attributes']['idp_organizationName']
4444

45+
## EnsureVoMember
46+
47+
Example how to configure filter EnsureVoMember:
48+
49+
```php
50+
31 => array(
51+
'class' => 'perun:EnsureVoMember',
52+
'triggerAttr' => 'triggerAttr',
53+
'voDefsAttr' => 'voDefsAttr',
54+
'loginURL' => 'https://www.loginUrl.com',
55+
'registrarURL' => 'https://www.registrarUrl.com',
56+
'interface' => 'ldap',
57+
),
58+
```
59+
4560
## PerunEntitlement
4661

4762
Example how to enable/configure filter PerunEntitlement:

lib/Adapter.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ abstract public function setUserExtSourceAttributes($userExtSourceId, $attribute
195195
*/
196196
abstract public function getMemberStatusByUserAndVo($user, $vo);
197197

198+
/**
199+
* @param User $user
200+
* @param string $voShortName
201+
* @return boolean
202+
*/
203+
abstract public function isUserInVo($user, $voShortName);
204+
198205
/**
199206
* @param $entityId int entityId
200207
* @param $userGroups array of groups where user belongs to

lib/AdapterLdap.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,24 @@ public function getMemberStatusByUserAndVo($user, $vo)
443443
return Member::VALID;
444444
}
445445

446+
public function isUserInVo($user, $voShortName)
447+
{
448+
if (empty($user->getId())) {
449+
throw new Exception('userId is empty');
450+
}
451+
if (empty($voShortName)) {
452+
throw new Exception('voShortName is empty');
453+
}
454+
455+
$vo = $this->getVoByShortName($voShortName);
456+
if ($vo === null) {
457+
Logger::debug('isUserInVo - No VO found, returning false');
458+
return false;
459+
}
460+
461+
return $this->getMemberStatusByUserAndVo($user, $vo) === Member::VALID;
462+
}
463+
446464
public function getResourceCapabilities($entityId, $userGroups)
447465
{
448466
$facility = $this->getFacilityByEntityId($entityId);

lib/AdapterRpc.php

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -423,23 +423,53 @@ public function getMemberByUser($user, $vo)
423423
return new Member($member['id'], $member['voId'], $member['status']);
424424
}
425425

426+
public function isUserInVo($user, $voShortName)
427+
{
428+
if (empty($user->getId())) {
429+
throw new Exception('userId is empty');
430+
}
431+
if (empty($voShortName)) {
432+
throw new Exception('voShortName is empty');
433+
}
434+
435+
$vo = $this->getVoByShortName($voShortName);
436+
if ($vo === null) {
437+
Logger::debug('isUserInVo - No VO found, returning false');
438+
return false;
439+
}
440+
441+
return $this->getMemberStatusByUserAndVo($user, $vo) === Member::VALID;
442+
}
443+
426444
/**
427-
* Returns true if group has registration form, false otherwise
428-
* @param Group $group
445+
* Returns true if entity has registration form, false otherwise
446+
* @param $entityId
447+
* @param $entityName
429448
* @return bool
430449
*/
431-
public function hasRegistrationForm($group)
450+
public function hasRegistrationForm($entityId, $entityName)
432451
{
433452
try {
434453
$this->connector->get('registrarManager', 'getApplicationForm', [
435-
'group' => $group->getId(),
454+
$entityName => $entityId,
436455
]);
437456
return true;
438457
} catch (\Exception $exception) {
439458
return false;
440459
}
441460
}
442461

462+
public function hasRegistrationFormByVoShortName($voShortName)
463+
{
464+
$vo = $this->getVoByShortName($voShortName);
465+
466+
if (empty($vo)) {
467+
return false;
468+
}
469+
470+
return $this->hasRegistrationForm($vo->getId(), 'vo');
471+
}
472+
443473
public function searchFacilitiesByAttributeValue($attribute)
444474
{
445475
$perunAttrs = $this->connector->post('searcher', 'getFacilities', [
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<?php
2+
3+
namespace SimpleSAML\Module\perun\Auth\Process;
4+
5+
use SimpleSAML\Auth\ProcessingFilter;
6+
use SimpleSAML\Auth\State;
7+
use SimpleSAML\Configuration;
8+
use SimpleSAML\Error\Exception;
9+
use SimpleSAML\Logger;
10+
use SimpleSAML\Module;
11+
use SimpleSAML\Module\perun\Adapter;
12+
use SimpleSAML\Utils\HTTP;
13+
14+
class EnsureVoMember extends ProcessingFilter
15+
{
16+
const ENSURE_VO_MEMBER = 'ensureVoMember';
17+
const TRIGGER_ATTR = 'triggerAttr';
18+
const VO_DEFS_ATTR = 'voDefsAttr';
19+
const LOGIN_URL = 'loginURL';
20+
const REGISTRAR_URL = 'registrarURL';
21+
const INTERFACE_PROPNAME = 'interface';
22+
const RPC = 'rpc';
23+
24+
private $triggerAttr;
25+
private $voDefsAttr;
26+
private $adapter;
27+
private $loginUrlAttr;
28+
private $registrarUrl;
29+
30+
public function __construct($config, $reserved)
31+
{
32+
parent::__construct($config, $reserved);
33+
$config = Configuration::loadFromArray($config);
34+
35+
if (is_null($config)) {
36+
throw new Exception(
37+
'perun:EnsureVoMember: Property \'' . self::ENSURE_VO_MEMBER . '\' is missing or invalid!'
38+
);
39+
}
40+
41+
$this->triggerAttr = $config->getString(self::TRIGGER_ATTR, "");
42+
43+
if (empty($this->triggerAttr)) {
44+
throw new Exception(
45+
'perun:EnsureVoMember: Missing configuration option \'' . self::TRIGGER_ATTR . '\''
46+
);
47+
}
48+
49+
$this->voDefsAttr = $config->getString(self::VO_DEFS_ATTR, "");
50+
51+
if (empty($this->voDefsAttr)) {
52+
throw new Exception(
53+
'perun:EnsureVoMember: Missing configuration option \'' . self::VO_DEFS_ATTR . '\''
54+
);
55+
}
56+
57+
$this->loginUrlAttr = $config->getString(self::LOGIN_URL, null);
58+
$this->registrarUrl = $config->getString(self::REGISTRAR_URL, null);
59+
60+
$interface = $config->getString(self::INTERFACE_PROPNAME, self::RPC);
61+
$this->adapter = Adapter::getInstance($interface);
62+
}
63+
64+
public function process(&$request)
65+
{
66+
if (isset($request['SPMetadata']['entityid'])) {
67+
$spEntityId = $request['SPMetadata']['entityid'];
68+
} else {
69+
throw new Exception(
70+
'perun:EnsureVoMember: Cannot find entityID of remote SP. ' .
71+
'hint: Do you have this filter in IdP context?'
72+
);
73+
}
74+
75+
if (isset($request['perun']['user'])) {
76+
$user = $request['perun']['user'];
77+
} else {
78+
throw new Exception(
79+
'perun:EnsureVoMember: ' .
80+
'missing mandatory field \'perun.user\' in request.' .
81+
'Hint: Did you configured PerunIdentity filter before this filter?'
82+
);
83+
}
84+
85+
$facility = $this->adapter->getFacilityByEntityId($spEntityId);
86+
87+
if ($facility === null) {
88+
Logger::debug('perun:EnsureVoMember: skip execution - no facility provided');
89+
return;
90+
}
91+
92+
$attrValues = $this->adapter->getFacilityAttributesValues(
93+
$facility,
94+
[$this->voDefsAttr, $this->triggerAttr, $this->loginUrlAttr]
95+
);
96+
97+
$triggerAttrValue = $attrValues[$this->triggerAttr];
98+
if ($triggerAttrValue === null || $triggerAttrValue === false) {
99+
Logger::debug(
100+
'perun:EnsureVoMember: skip execution - attribute ' . self::TRIGGER_ATTR . ' is null or false'
101+
);
102+
return;
103+
}
104+
105+
$voShortName = $attrValues[$this->voDefsAttr];
106+
if (empty($voShortName)) {
107+
Logger::debug(
108+
'perun:EnsureVoMember: skip execution - attribute ' . self::VO_DEFS_ATTR . ' has null or no value'
109+
);
110+
return;
111+
}
112+
113+
$canAccess = $this->adapter->isUserInVo($user, $voShortName);
114+
if ($canAccess) {
115+
Logger::debug('perun:EnsureVoMember: user allowed to continue');
116+
} else {
117+
$this->redirect($request, $attrValues[$this->loginUrlAttr], $voShortName);
118+
}
119+
}
120+
121+
private function redirect($request, $loginUrl, $voShortName)
122+
{
123+
if (!empty($voShortName) &&
124+
!empty($this->registrarUrl) &&
125+
$this->adapter->hasRegistrationFormByVoShortName($voShortName)
126+
) {
127+
$this->redirectToRegistration($loginUrl, $voShortName);
128+
} else {
129+
$this->redirectUnapproved($request);
130+
}
131+
}
132+
133+
private function redirectToRegistration($loginUrl, $voShortName)
134+
{
135+
HTTP::redirectTrustedURL(
136+
$this->registrarUrl,
137+
[
138+
'vo' => $voShortName,
139+
'targetnew' => $loginUrl,
140+
'targetexisting' => $loginUrl
141+
]
142+
);
143+
}
144+
145+
private function redirectUnapproved($request)
146+
{
147+
$id = State::saveState($request, 'perunauthorize:Perunauthorize');
148+
$url = Module::getModuleURL('perunauthorize/perunauthorize_403.php');
149+
150+
$params = [];
151+
$params['StateId'] = $id;
152+
$params['administrationContact'] = $request['SPMetadata']['administrationContact'];
153+
$params['serviceName'] = $request['SPMetadata']['name']['en'];
154+
155+
if (isset($request['SPMetadata']['InformationURL']['en'])) {
156+
$params['informationURL'] = $request['SPMetadata']['InformationURL']['en'];
157+
}
158+
159+
HTTP::redirectTrustedURL($url, $params);
160+
}
161+
}

www/perun_identity_choose_vo_and_group.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
foreach ($spGroups as $group) {
3232
if (in_array($group->getVoId(), $vosIdForRegistration)) {
33-
if ($group->getName() === 'members' || $rpcAdapter->hasRegistrationForm($group)) {
33+
if ($group->getName() === 'members' || $rpcAdapter->hasRegistrationForm($group->getId(), 'group')) {
3434
$vo = $adapter->getVoById($group->getVoId());
3535
if (!isset($vosForRegistration[$vo->getShortName()])) {
3636
$vosForRegistration[$vo->getShortName()] = $vo;

0 commit comments

Comments
 (0)