diff --git a/config-templates/processFilterConfigurations-example.md b/config-templates/processFilterConfigurations-example.md index 55cda07bed7e16b19bed4f87891de535dc0912d4..b34280a29a190912efd5e29a79b323b198e83c66 100644 --- a/config-templates/processFilterConfigurations-example.md +++ b/config-templates/processFilterConfigurations-example.md @@ -72,9 +72,9 @@ Example how to configure filter EnsureVoMember: 'class' => 'perun:EnsureVoMember', 'triggerAttr' => 'triggerAttr', 'voDefsAttr' => 'voDefsAttr', - 'loginURL' => 'https://www.loginUrl.com', 'registrarURL' => 'https://www.registrarUrl.com', 'interface' => 'ldap', + 'loginUrlAttr' => 'facilityLoginAttr', # Will be used as callback if specified. If not callback will be back to proxy ), ``` @@ -381,6 +381,46 @@ Configuration options: ], ``` +## EnsureVoAup + +Filter checks if user accepted AUPs for VO specified by short name in attribute (Has to be enabled by trigger attribute). By given VO configuration it checks if expected value is set in the user attribute or not. If not, it redirects the user to specified registration component, where user will be asked to approve the AUP. + +Filter should be run after EnsureVoMember filter. + +Configuration options: + +- `interface`: specifies what interface of Perun should be used to fetch data. See class `SimpleSAML\Module\perun\PerunAdapter` for more details. +- `perun_approval_url`: the perun registrar url to which user will be redirected. The VO and Group parameters will be added dynamically. Parameters targetnew, targetexisting and targetextended will be set to callback URL to continue after the AUP approval is completed. +- `trigger_attr`: attribute which specify if the filter should be executed (boolean) +- `vo_defs_attr`: attribute with VO short name to proc AUP +- `vo_aup_conf`: array with VO short names as key and configs for the vo as values +- `vo_aup_conf.perun_approval_group`: group representing the AUP +- `vo_aup_conf.aup_value`: the value representing which AUP was accepted +- `vo_aup_conf.user_attribute`: the value to store the AUP acceptance + +```php +3 => [ + 'class' => 'perun:PerunAup', + 'interface' => 'ldap', + 'perun_approval_url' => 'https://signup.perun.cesnet.cz/fed/registrar/', + 'trigger_attr' => 'urn:perun:facility:attribute-def:def:rpEnableEnsureVoFiltering', + 'vo_defs_attr' => 'urn:perun:facility:attribute-def:def:rpEnsureVoDefinition', + 'vo_aup_conf' => [ + 'bbmri' => [ + 'perun_approval_group' => 'aup', + 'aup_value' => 'aup_1_3', + 'user_attribute' => 'urn:perun:user:attribute-def:def:userAup:bbmri' + ], + 'elixir' => [ + 'perun_approval_group' => 'aup', + 'aup_value' => 'aup_2016_06_14', + 'user_attribute' => 'urn:perun:user:attribute-def:def:userAup:elixir' + ], + ], +], +``` + + ## IsEligible Checks the eligibility timestamp. If the value is not older than `validity_period_months`, it lets the user in. Otherwise, user is forced to reauthenticate using other identity. diff --git a/lib/AdapterLdap.php b/lib/AdapterLdap.php index 2cf8e6a533face1110778a6c491b1a9675eccb18..933f91b69030ec91966da7641f4401f68cb8077a 100644 --- a/lib/AdapterLdap.php +++ b/lib/AdapterLdap.php @@ -398,9 +398,6 @@ class AdapterLdap extends Adapter public function getFacilityByClientId($clientId, $clientIdAttr = 'perunFacilityAttr_OIDCClientID') { - if (empty($spEntityId)) { - return null; - } $attrName = AttributeUtils::getLdapAttrName($clientIdAttr); if (empty($attrName)) { $attrName = 'OIDCClientID'; diff --git a/lib/Auth/Process/EnsureVoAup.php b/lib/Auth/Process/EnsureVoAup.php new file mode 100644 index 0000000000000000000000000000000000000000..f374bbb96d62ca63447dc39eb925e9bd28dde0d8 --- /dev/null +++ b/lib/Auth/Process/EnsureVoAup.php @@ -0,0 +1,226 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\perun\Auth\Process; + +use SimpleSAML\Auth\ProcessingFilter; +use SimpleSAML\Auth\State; +use SimpleSAML\Configuration; +use SimpleSAML\Error\Exception; +use SimpleSAML\Logger; +use SimpleSAML\Module; +use SimpleSAML\Module\perun\Adapter; +use SimpleSAML\Module\perun\CommonUtils; +use SimpleSAML\Module\perun\PerunConstants; +use SimpleSAML\Utils\HTTP; + +/** + * Class checks if the user has approved given aup of the VO on facility, and forwards to approval page if not. + * Should be run after EnsureVoMember filter + */ +class EnsureVoAup extends ProcessingFilter +{ + public const STAGE = 'perun:EnsureVoAup'; + + public const DEBUG_PREFIX = self::STAGE . ' - '; + + public const CALLBACK = 'perun/ensure_vo_aup_callback.php'; + + public const REDIRECT = 'perun/ensure_vo_aup.php'; + + //REUSED + public const TEMPLATE = 'perun:perun-aup-tpl.php'; + + public const PARAM_STATE_ID = PerunConstants::STATE_ID; + + public const PARAM_APPROVAL_URL = 'approvalUrl'; + public const PARAM_APPROVAL_VO = 'approvalVo'; + public const PARAM_APPROVAL_GROUP = 'approvalGroup'; + + public const PARAM_PARAMS = 'params'; + + public const INTERFACE = 'interface'; + + public const AUP_ATTR = 'user_attribute'; + + public const AUP_VALUE = 'aup_value'; + + public const PERUN_APPROVAL_URL = 'perun_approval_url'; + public const PERUN_APPROVAL_GROUP = 'perun_approval_group'; + + public const TRIGGER_ATTR = 'trigger_attr'; + + public const VO_DEFS_ATTR = 'vo_defs_attr'; + + public const VO_AUP_CONF = 'vo_aup_conf'; + + + private $adapter; + + private $triggerAttr; + + private $voDefsAttr; + + private $voAupConf; + + private $perunApprovalUrl; + + private $config; + + private $filterConfig; + + public function __construct($config, $reserved) + { + parent::__construct($config, $reserved); + $this->config = $config; + $this->filterConfig = Configuration::loadFromArray($config); + + $interface = $this->filterConfig->getString(self::INTERFACE, Adapter::RPC); + $this->adapter = Adapter::getInstance($interface); + + $this->triggerAttr = $this->filterConfig->getString(self::TRIGGER_ATTR, ''); + + if (empty($this->triggerAttr)) { + throw new Exception(self::DEBUG_PREFIX . 'Missing configuration option \'' . self::TRIGGER_ATTR . '\''); + } + + $this->voDefsAttr = $this->filterConfig->getString(self::VO_DEFS_ATTR, ''); + + if (empty($this->voDefsAttr)) { + throw new Exception(self::DEBUG_PREFIX . 'Missing configuration option \'' . self::VO_DEFS_ATTR . '\''); + } + + $this->voAupConf = $this->filterConfig->getArray(self::VO_AUP_CONF, []); + + if (empty($this->voAupConf)) { + throw new Exception(self::DEBUG_PREFIX . 'Missing configuration option \'' . self::VO_AUP_CONF . '\''); + } + + $this->perunApprovalUrl = $this->filterConfig->getString(self::PERUN_APPROVAL_URL, null); + if (empty($this->perunApprovalUrl)) { + throw new Exception( + self::DEBUG_PREFIX . 'Missing configuration option \'' . self::PERUN_APPROVAL_URL . '\'' + ); + } + + foreach ($this->voAupConf as $key => $value) { + if (!array_key_exists(self::AUP_VALUE, $value)) { + throw new Exception( + self::DEBUG_PREFIX . 'Missing configuration \'' . self::AUP_VALUE . '\' for VO \'' . $key . '\'' + ); + } elseif (!array_key_exists(self::AUP_ATTR, $value)) { + throw new Exception( + self::DEBUG_PREFIX . 'Missing configuration \'' . self::AUP_ATTR . '\' for VO \'' . $key . '\'' + ); + } elseif (!array_key_exists(self::PERUN_APPROVAL_GROUP, $value)) { + throw new Exception( + self::DEBUG_PREFIX . + 'Missing configuration \'' . + self::PERUN_APPROVAL_GROUP . + '\' for VO \'' . + $key . + '\'' + ); + } + } + } + + public function process(&$request) + { + assert(is_array($request)); + assert(!empty($request[PerunConstants::PERUN][PerunConstants::USER])); + + if (empty($request[PerunConstants::PERUN][PerunConstants::USER])) { + throw new Exception( + self::DEBUG_PREFIX . 'Request does not contain Perun user. Did you configure ' . PerunUser::STAGE . + ' filter before this filter in the processing chain?' + ); + } + $user = $request[PerunConstants::PERUN][PerunConstants::USER]; + + + if (!isset($request['SPMetadata']['entityid'])) { + throw new Exception( + self::DEBUG_PREFIX . 'Cannot find entityID of remote SP. ' . + 'hint: Do you have this filter in IdP context?' + ); + } + + $facility = CommonUtils::getFacilityFromRequest($request, $this->adapter); + + if ($facility === null) { + Logger::debug(self::DEBUG_PREFIX . 'skip execution - no facility provided'); + return; + } + + $attrValues = $this->adapter->getFacilityAttributesValues( + $facility, + [$this->voDefsAttr, $this->triggerAttr] + ); + $triggerAttrValue = $attrValues[$this->triggerAttr]; + if ($triggerAttrValue === null || $triggerAttrValue === false) { + Logger::debug( + self::DEBUG_PREFIX . 'skip execution - attribute ' . self::TRIGGER_ATTR . ' is null or false' + ); + return; + } + $voShortName = $attrValues[$this->voDefsAttr]; + if (empty($voShortName)) { + Logger::debug( + self::DEBUG_PREFIX . 'skip execution - attribute ' . self::VO_DEFS_ATTR . ' has null or no value' + ); + return; + } + + $aupConfig = $this->voAupConf[$voShortName]; + + if (empty($aupConfig)) { + Logger::warning( + self::DEBUG_PREFIX . 'Accepting of AUP for VO \'' . $voShortName . '\' is not configured.' + ); + } + + $aupAttrName = $aupConfig[self::AUP_ATTR]; + $aupExpectedValue = $aupConfig[self::AUP_VALUE]; + + $aupAttrValue = null; + $userAttributesValues = $this->adapter->getUserAttributesValues($user, [$aupAttrName]); + if (empty($userAttributesValues) || empty($userAttributesValues[$aupAttrName])) { + Logger::warning( + self::DEBUG_PREFIX . 'Attribute \'' . $aupAttrName . '\' is empty. Probably could not be ' + . 'fetched. Redirecting user to approve AUP.' + ); + } else { + $aupAttrValue = $userAttributesValues[$aupAttrName]; + } + + if ($aupAttrValue === $aupExpectedValue) { + Logger::info( + self::DEBUG_PREFIX . 'User approved AUP did match the expected value, continue processing.' + ); + return; + } + Logger::info( + self::DEBUG_PREFIX . 'User did not approve the expected AUP. Expected value \'' + . $aupExpectedValue . '\', actual value \'' . $aupAttrValue . '\'. Redirecting user to AUP approval page.' + ); + $this->redirect($request, $aupConfig, $voShortName); + } + + private function redirect(&$request, $aupConfig, $voShortName): void + { + $request[PerunConstants::CONTINUE_FILTER_CONFIG] = $this->config; + + $request[self::STAGE] = [ + self::PARAM_APPROVAL_URL => $this->perunApprovalUrl, + self::PARAM_APPROVAL_VO => $voShortName, + self::PARAM_APPROVAL_GROUP => $aupConfig[self::PERUN_APPROVAL_GROUP], + ]; + $stateId = State::saveState($request, self::STAGE); + + $redirectUrl = Module::getModuleURL(self::REDIRECT, [self::PARAM_STATE_ID => $stateId]); + Logger::debug(self::DEBUG_PREFIX . 'Redirecting to \'' . $redirectUrl . '\''); + HTTP::redirectTrustedURL($redirectUrl); + } +} diff --git a/lib/Auth/Process/EnsureVoMember.php b/lib/Auth/Process/EnsureVoMember.php index db0eea7655ed79a1bbddbbb70dbf9c8538791017..f98fd7963b681be57c21438e5c68c41952db348a 100644 --- a/lib/Auth/Process/EnsureVoMember.php +++ b/lib/Auth/Process/EnsureVoMember.php @@ -11,71 +11,99 @@ use SimpleSAML\Error\Exception; use SimpleSAML\Logger; use SimpleSAML\Module; use SimpleSAML\Module\perun\Adapter; +use SimpleSAML\Module\perun\CommonUtils; +use SimpleSAML\Module\perun\PerunConstants; use SimpleSAML\Utils\HTTP; class EnsureVoMember extends ProcessingFilter { + public const STAGE = 'perun:EnsureVoMember'; + + public const DEBUG_PREFIX = self::STAGE . ' - '; + + public const CALLBACK = 'perun/ensure_vo_member_callback.php'; + + public const REDIRECT = 'perun/ensure_vo_member.php'; + + //REUSED + public const TEMPLATE = 'perun:perun-ensure-member-tpl.php'; + public const ENSURE_VO_MEMBER = 'ensureVoMember'; + public const PARAM_STATE_ID = PerunConstants::STATE_ID; + + public const PARAM_REGISTRATION_URL = 'registrationUrl'; + + public const PARAM_REGISTRATION_VO = 'registrationVo'; + + public const PARAM_PARAMS = 'params'; + + public const PARAM_SERVICE_LOGIN_URL = 'serviceLoginUrl'; + public const TRIGGER_ATTR = 'triggerAttr'; public const VO_DEFS_ATTR = 'voDefsAttr'; - public const LOGIN_URL = 'loginURL'; - public const REGISTRAR_URL = 'registrarURL'; public const INTERFACE_PROPNAME = 'interface'; public const RPC = 'rpc'; + public const LOGIN_URL_ATTR = 'loginUrlAttr'; + + private $config; + private $triggerAttr; private $voDefsAttr; private $adapter; - private $loginUrlAttr; + private $rpcAdapter; private $registrarUrl; + private $loginUrlAttr; + public function __construct($config, $reserved) { parent::__construct($config, $reserved); + $this->config = $config; $config = Configuration::loadFromArray($config); if ($config === null) { throw new Exception( - 'perun:EnsureVoMember: Property \'' . self::ENSURE_VO_MEMBER . '\' is missing or invalid!' + self::DEBUG_PREFIX . 'Property \'' . self::ENSURE_VO_MEMBER . '\' is missing or invalid!' ); } $this->triggerAttr = $config->getString(self::TRIGGER_ATTR, ''); if (empty($this->triggerAttr)) { - throw new Exception('perun:EnsureVoMember: Missing configuration option \'' . self::TRIGGER_ATTR . '\''); + throw new Exception(self::DEBUG_PREFIX . 'Missing configuration option \'' . self::TRIGGER_ATTR . '\''); } $this->voDefsAttr = $config->getString(self::VO_DEFS_ATTR, ''); if (empty($this->voDefsAttr)) { - throw new Exception('perun:EnsureVoMember: Missing configuration option \'' . self::VO_DEFS_ATTR . '\''); + throw new Exception(self::DEBUG_PREFIX . 'Missing configuration option \'' . self::VO_DEFS_ATTR . '\''); } - $this->loginUrlAttr = $config->getString(self::LOGIN_URL, null); + $this->loginUrlAttr = $config->getString(self::LOGIN_URL_ATTR, ''); + $this->registrarUrl = $config->getString(self::REGISTRAR_URL, null); $interface = $config->getString(self::INTERFACE_PROPNAME, self::RPC); $this->adapter = Adapter::getInstance($interface); + $this->rpcAdapter = Adapter::getInstance(Adapter::RPC); } public function process(&$request) { - if (isset($request['SPMetadata']['entityid'])) { - $spEntityId = $request['SPMetadata']['entityid']; - } else { + if (!isset($request['SPMetadata']['entityid'])) { throw new Exception( - 'perun:EnsureVoMember: Cannot find entityID of remote SP. ' . + self::DEBUG_PREFIX . 'Cannot find entityID of remote SP. ' . 'hint: Do you have this filter in IdP context?' ); } @@ -84,28 +112,33 @@ class EnsureVoMember extends ProcessingFilter $user = $request['perun']['user']; } else { throw new Exception( - 'perun:EnsureVoMember: ' . 'missing mandatory field \'perun.user\' in request.' . + self::DEBUG_PREFIX . 'missing mandatory field \'perun.user\' in request.' . 'Hint: Did you configured PerunIdentity filter before this filter?' ); } - $facility = $this->adapter->getFacilityByEntityId($spEntityId); + $facility = CommonUtils::getFacilityFromRequest($request, $this->adapter); if ($facility === null) { - Logger::debug('perun:EnsureVoMember: skip execution - no facility provided'); + Logger::debug(self::DEBUG_PREFIX . 'skip execution - no facility provided'); return; } + $facilityAttributes = [$this->voDefsAttr, $this->triggerAttr]; + if (!empty($this->loginUrlAttr)) { + $facilityAttributes[] = $this->loginUrlAttr; + } + $attrValues = $this->adapter->getFacilityAttributesValues( $facility, - [$this->voDefsAttr, $this->triggerAttr, $this->loginUrlAttr] + $facilityAttributes ); $triggerAttrValue = $attrValues[$this->triggerAttr]; if ($triggerAttrValue === null || $triggerAttrValue === false) { Logger::debug( - 'perun:EnsureVoMember: skip execution - attribute ' . self::TRIGGER_ATTR . ' is null or false' + self::DEBUG_PREFIX . 'skip execution - attribute ' . self::TRIGGER_ATTR . ' is null or false' ); return; @@ -114,59 +147,55 @@ class EnsureVoMember extends ProcessingFilter $voShortName = $attrValues[$this->voDefsAttr]; if (empty($voShortName)) { Logger::debug( - 'perun:EnsureVoMember: skip execution - attribute ' . self::VO_DEFS_ATTR . ' has null or no value' + self::DEBUG_PREFIX . 'skip execution - attribute ' . self::VO_DEFS_ATTR . ' has null or no value' ); - return; } $canAccess = $this->adapter->isUserInVo($user, $voShortName); if ($canAccess) { - Logger::debug('perun:EnsureVoMember: user allowed to continue'); + Logger::debug(self::DEBUG_PREFIX . 'user allowed to continue'); } else { - $this->redirect($request, $attrValues[$this->loginUrlAttr], $voShortName); + $this->redirect($request, $voShortName, $attrValues); } } - private function redirect($request, $loginUrl, $voShortName) + private function redirect(&$request, $voShortName, $facilityAttrValues) { if ( !empty($voShortName) && !empty($this->registrarUrl) && - $this->adapter->hasRegistrationFormByVoShortName($voShortName) + $this->rpcAdapter->hasRegistrationFormByVoShortName($voShortName) ) { - $this->redirectToRegistration($loginUrl, $voShortName); + $this->redirectToRegistration($request, $voShortName, $facilityAttrValues); } else { - $this->redirectUnapproved($request); + Logger::debug( + self::DEBUG_PREFIX . + 'User is not valid in vo/group and cannot be sent to the registration - sending to unauthorized' + ); + PerunIdentity::unauthorized($request); } } - private function redirectToRegistration($loginUrl, $voShortName) + private function redirectToRegistration(&$request, $voShortName, $facilityAttrValues) { - HTTP::redirectTrustedURL( - $this->registrarUrl, - [ - 'vo' => $voShortName, - 'targetnew' => $loginUrl, - 'targetexisting' => $loginUrl, - ] - ); - } - - private function redirectUnapproved($request) - { - $id = State::saveState($request, 'perunauthorize:Perunauthorize'); - $url = Module::getModuleURL('perunauthorize/perunauthorize_403.php'); - - $params = []; - $params['StateId'] = $id; - $params['administrationContact'] = $request['SPMetadata']['administrationContact']; - $params['serviceName'] = $request['SPMetadata']['name']['en']; - - if (isset($request['SPMetadata']['InformationURL']['en'])) { - $params['informationURL'] = $request['SPMetadata']['InformationURL']['en']; + $request[PerunConstants::CONTINUE_FILTER_CONFIG] = $this->config; + $request[self::STAGE] = [ + self::PARAM_REGISTRATION_URL => $this->registrarUrl, + self::PARAM_REGISTRATION_VO => $voShortName, + ]; + + if (!empty($this->loginUrlAttr)) { + $serviceLoginUrl = empty( + $facilityAttrValues[$this->loginUrlAttr] + ) ? '' : $facilityAttrValues[$this->loginUrlAttr]; + $request[self::STAGE][self::PARAM_SERVICE_LOGIN_URL] = $serviceLoginUrl; } - HTTP::redirectTrustedURL($url, $params); + $stateId = State::saveState($request, self::STAGE); + + $redirectUrl = Module::getModuleURL(self::REDIRECT, [self::PARAM_STATE_ID => $stateId]); + Logger::debug(self::DEBUG_PREFIX . 'Redirecting to \'' . $redirectUrl . '\''); + HTTP::redirectTrustedURL($redirectUrl); } } diff --git a/lib/CommonUtils.php b/lib/CommonUtils.php new file mode 100644 index 0000000000000000000000000000000000000000..e0ef167c7b09b9cd1aac6f31a6ab3f8cb285db1a --- /dev/null +++ b/lib/CommonUtils.php @@ -0,0 +1,32 @@ +<?php + +namespace SimpleSAML\Module\perun; + +class CommonUtils +{ + public static function substrInArray($needle, array $haystack) + { + foreach ($haystack as $item) { + if (strpos($item, $needle) !== false) { + return $item; + } + } + + return null; + } + + public static function getFacilityFromRequest($request, $adapter) + { + $spEntityId = $request['SPMetadata']['entityid']; + $clientIdWithPrefix = !isset($request[PerunConstants::REQUESTER_ID]) ? null : + CommonUtils::substrInArray(PerunConstants::CLIENT_ID_PREFIX, $request[PerunConstants::REQUESTER_ID]); + + if (!is_null($clientIdWithPrefix)) { + $clientId = str_replace(PerunConstants::CLIENT_ID_PREFIX, '', $clientIdWithPrefix); + $facility = $adapter->getFacilityByClientId($clientId); + } else { + $facility = $adapter->getFacilityByEntityId($spEntityId); + } + return $facility; + } +} diff --git a/lib/Disco.php b/lib/Disco.php index c83a11d786479a2278d1ca08854977a62240afe9..458b038899e9fa8bd7f37e5d001e80bfb57b8898 100644 --- a/lib/Disco.php +++ b/lib/Disco.php @@ -116,8 +116,6 @@ class Disco extends PowerIdPDisco public const AUTH_ID = 'AuthID'; - public const REQUESTER_ID = 'saml:RequesterID'; - // METADATA KEYS public const METADATA_DO_NOT_FILTER_IDPS = 'disco.doNotFilterIdps'; @@ -157,8 +155,6 @@ class Disco extends PowerIdPDisco public const NAME = 'name'; // DISPLAY SERVICE NAME KEYS - - public const CLIENT_ID_PREFIX = 'urn:cesnet:proxyidp:client_id:'; public const ENTITY_ID_PREFIX = 'urn:cesnet:proxyidp:entity_id:'; public const SERVICE_NAME_ATTR = 'service_name_attr'; @@ -880,17 +876,6 @@ class Disco extends PowerIdPDisco return transliterator_transliterate("Any-Latin; Latin-ASCII; Lower(); [:Punctuation:] Remove", $res); } - private static function substrInArray($needle, array $haystack) - { - foreach ($haystack as $item) { - if (strpos($item, $needle) !== false) { - return $item; - } - } - - return null; - } - private function fillSpName($t, $displaySpNameMode) { $clientId = null; @@ -899,17 +884,23 @@ class Disco extends PowerIdPDisco $displaySpNameMode === self::DISPLAY_SP_NAME_MODE_ACR && !empty($this->originalAuthnContextClassRef) ) { - $clientId = self::substrInArray(self::CLIENT_ID_PREFIX, $this->originalAuthnContextClassRef); + $clientId = CommonUtils::substrInArray( + PerunConstants::CLIENT_ID_PREFIX, + $this->originalAuthnContextClassRef + ); if (empty($clientId)) { - $entityId = self::substrInArray(self::ENTITY_ID_PREFIX, $this->originalAuthnContextClassRef); + $entityId = CommonUtils::substrInArray(self::ENTITY_ID_PREFIX, $this->originalAuthnContextClassRef); } } elseif ( $displaySpNameMode === self::DISPLAY_SP_NAME_MODE_REQUESTER_ID - && !empty($this->state[self::REQUESTER_ID]) + && !empty($this->state[PerunConstants::REQUESTER_ID]) ) { - $clientId = self::substrInArray(self::CLIENT_ID_PREFIX, $this->state[self::REQUESTER_ID]); - if (empty($clientId) && !empty($this->state[self::REQUESTER_ID][0])) { - $entityId = $this->state[self::REQUESTER_ID][0]; + $clientId = CommonUtils::substrInArray( + PerunConstants::CLIENT_ID_PREFIX, + $this->state[PerunConstants::REQUESTER_ID] + ); + if (empty($clientId) && !empty($this->state[PerunConstants::REQUESTER_ID][0])) { + $entityId = $this->state[PerunConstants::REQUESTER_ID][0]; } } @@ -940,7 +931,7 @@ class Disco extends PowerIdPDisco if ($clientIdWithPrefix === null) { return; } - $clientId = str_replace(self::CLIENT_ID_PREFIX, '', $clientIdWithPrefix); + $clientId = str_replace(PerunConstants::CLIENT_ID_PREFIX, '', $clientIdWithPrefix); $clientIdAttr = $this->wayfConfiguration->getString(self::CLIENT_ID_ATTR, null); if ($clientIdAttr === null) { @@ -1016,7 +1007,10 @@ class Disco extends PowerIdPDisco private function getSpIdentifier() { - $clientIdWithPrefix = self::substrInArray(self::CLIENT_ID_PREFIX, $this->originalAuthnContextClassRef); + $clientIdWithPrefix = CommonUtils::substrInArray( + PerunConstants::CLIENT_ID_PREFIX, + $this->originalAuthnContextClassRef + ); if ($clientIdWithPrefix !== null) { $parts = explode(':', $clientIdWithPrefix); diff --git a/lib/PerunConstants.php b/lib/PerunConstants.php index 74cdf914db2951d43c8bdb007316f53eb96731ed..74cb7baad08516926a5cb705b97d53dd0d0a63ff 100644 --- a/lib/PerunConstants.php +++ b/lib/PerunConstants.php @@ -47,4 +47,8 @@ class PerunConstants public const DESTINATION = 'Destination'; public const DESTINATION_ATTRIBUTES = 'attributes'; + + public const REQUESTER_ID = 'saml:RequesterID'; + + public const CLIENT_ID_PREFIX = 'urn:cesnet:proxyidp:client_id:'; } diff --git a/www/ensure_vo_aup.php b/www/ensure_vo_aup.php new file mode 100644 index 0000000000000000000000000000000000000000..5fd19ce114014e24ca2d957d91a487a488065ccd --- /dev/null +++ b/www/ensure_vo_aup.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +use SimpleSAML\Auth\State; +use SimpleSAML\Configuration; +use SimpleSAML\Module; +use SimpleSAML\Module\perun\Auth\Process\EnsureVoAup; +use SimpleSAML\Module\perun\PerunConstants; +use SimpleSAML\XHTML\Template; + +$config = Configuration::getInstance(); +$t = new Template($config, EnsureVoAup::TEMPLATE); + +$stateId = $_REQUEST[EnsureVoAup::PARAM_STATE_ID]; +$state = State::loadState($stateId, EnsureVoAup::STAGE); + +$callback = Module::getModuleURL(EnsureVoAup::CALLBACK, [ + EnsureVoAup::PARAM_STATE_ID => $stateId, +]); + +$data = $state[EnsureVoAup::STAGE]; + +$t->data[EnsureVoAup::PARAM_APPROVAL_URL] = $data[EnsureVoAup::PARAM_APPROVAL_URL]; +$params = [ + PerunConstants::TARGET_NEW => $callback, + PerunConstants::TARGET_EXISTING => $callback, + PerunConstants::TARGET_EXTENDED => $callback, + PerunConstants::VO => $data[EnsureVoAup::PARAM_APPROVAL_VO], +]; + +if (!empty($data[EnsureVoAup::PARAM_APPROVAL_GROUP])) { + $params[PerunConstants::GROUP] = $data[EnsureVoAup::PARAM_APPROVAL_GROUP]; +} + +$t->data[EnsureVoAup::PARAM_PARAMS] = $params; + +$t->show(); diff --git a/www/ensure_vo_aup_callback.php b/www/ensure_vo_aup_callback.php new file mode 100644 index 0000000000000000000000000000000000000000..0711b29cbf097a05f0fe0cd1f1930258ca8e31ed --- /dev/null +++ b/www/ensure_vo_aup_callback.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +use SimpleSAML\Auth\ProcessingChain; +use SimpleSAML\Auth\State; +use SimpleSAML\Error\BadRequest; +use SimpleSAML\Module\perun\Auth\Process\EnsureVoAup; +use SimpleSAML\Module\perun\PerunConstants; + +if (empty($_REQUEST[EnsureVoAup::PARAM_STATE_ID])) { + throw new BadRequest('Missing required \'' . EnsureVoAup::PARAM_STATE_ID . '\' query parameter.'); +} +$state = State::loadState($_REQUEST[EnsureVoAup::PARAM_STATE_ID], EnsureVoAup::STAGE); + +$filterConfig = $state[PerunConstants::CONTINUE_FILTER_CONFIG]; +$ensureVoAup = new EnsureVoAup($filterConfig, null); +$ensureVoAup->process($state); + +// we have not been redirected, continue processing +ProcessingChain::resumeProcessing($state); diff --git a/www/ensure_vo_member.php b/www/ensure_vo_member.php new file mode 100644 index 0000000000000000000000000000000000000000..714aa686324fb43d34f9ea3765d8c1e48e99659f --- /dev/null +++ b/www/ensure_vo_member.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +use SimpleSAML\Auth\State; +use SimpleSAML\Configuration; +use SimpleSAML\Module; +use SimpleSAML\Module\perun\Auth\Process\EnsureVoMember; +use SimpleSAML\Module\perun\PerunConstants; +use SimpleSAML\XHTML\Template; + +$config = Configuration::getInstance(); +$t = new Template($config, EnsureVoMember::TEMPLATE); + +$stateId = $_REQUEST[EnsureVoMember::PARAM_STATE_ID]; +$state = State::loadState($stateId, EnsureVoMember::STAGE); + +$data = $state[EnsureVoMember::STAGE]; + +if (array_key_exists(EnsureVoMember::PARAM_SERVICE_LOGIN_URL, $data)) { + $callback = $data[EnsureVoMember::PARAM_SERVICE_LOGIN_URL]; +} else { + $callback = Module::getModuleURL(EnsureVoMember::CALLBACK, [ + EnsureVoMember::PARAM_STATE_ID => $stateId, + ]); +} + +$t->data[EnsureVoMember::PARAM_REGISTRATION_URL] = $data[EnsureVoMember::PARAM_REGISTRATION_URL]; +$params = [ + PerunConstants::VO => $data[EnsureVoMember::PARAM_REGISTRATION_VO], +]; + +if (!empty($callback)) { + $params[PerunConstants::TARGET_NEW] = $callback; + $params[PerunConstants::TARGET_EXISTING] = $callback; + $params[PerunConstants::TARGET_EXTENDED] = $callback; +} + +$t->data[EnsureVoMember::PARAM_PARAMS] = $params; + +$t->show(); diff --git a/www/ensure_vo_member_callback.php b/www/ensure_vo_member_callback.php new file mode 100644 index 0000000000000000000000000000000000000000..c48ba8b5503997a94ca3bb0fd95769aefad64605 --- /dev/null +++ b/www/ensure_vo_member_callback.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +use SimpleSAML\Auth\ProcessingChain; +use SimpleSAML\Auth\State; +use SimpleSAML\Error\BadRequest; +use SimpleSAML\Module\perun\Auth\Process\EnsureVoMember; +use SimpleSAML\Module\perun\PerunConstants; + +if (empty($_REQUEST[EnsureVoMember::PARAM_STATE_ID])) { + throw new BadRequest('Missing required \'' . EnsureVoMember::PARAM_STATE_ID . '\' query parameter.'); +} + +$state = State::loadState($_REQUEST[EnsureVoMember::PARAM_STATE_ID], EnsureVoMember::STAGE); + +$filterConfig = $state[PerunConstants::CONTINUE_FILTER_CONFIG]; + +$ensureVoMember = new EnsureVoMember($filterConfig, null); +$ensureVoMember->process($state); + +// we have not been redirected, continue processing +ProcessingChain::resumeProcessing($state);