Skip to content
Snippets Groups Projects
Verified Commit f95e8cc0 authored by Jan Pavlíček's avatar Jan Pavlíček
Browse files

feat: user without tokens is redirected to new page, when mfa is enforced

parent abdb245e
No related branches found
No related tags found
1 merge request!54feat: user without tokens is redirected to new page, when mfa is enforced
Pipeline #275351 passed with stages
in 6 minutes and 29 seconds
...@@ -74,6 +74,11 @@ Add an instance of the auth proc filter with example configuration `authswitcher ...@@ -74,6 +74,11 @@ Add an instance of the auth proc filter with example configuration `authswitcher
'preferred_filter' => 'privacyidea:PrivacyideaAuthProc', 'preferred_filter' => 'privacyidea:PrivacyideaAuthProc',
'max_user_capability_attr' => 'maxUserCapability', 'max_user_capability_attr' => 'maxUserCapability',
'max_auth' => 'https://id.muni.cz/profile/maxAuth', 'max_auth' => 'https://id.muni.cz/profile/maxAuth',
'mfa_excluded_sps' => [
[1] => 'example_entity_id1',
[2] => 'example_entity_id2',
],
'setup_mfa_redirect_url' => 'mfa.id.muni.cz',
//'password_contexts' => array_merge(AuthSwitcher::PASSWORD_CONTEXTS, [ //'password_contexts' => array_merge(AuthSwitcher::PASSWORD_CONTEXTS, [
// 'my-custom-authn-context-for-password', // 'my-custom-authn-context-for-password',
// '/^my-regex-.*/', // '/^my-regex-.*/',
...@@ -127,6 +132,8 @@ Add an instance of the auth proc filter with example configuration `authswitcher ...@@ -127,6 +132,8 @@ Add an instance of the auth proc filter with example configuration `authswitcher
You can override which AuthnContextClassRefs are treated as password authentication (`password_contexts`) and MFA authentication (`mfa_contexts`). It is recommended to keep the contexts supported by default, e.g. by merging arrays. If you set `contexts_regex` to `true` and a value in one of these options is a regular expression (wrapped in `/`), all contexts matching the expression are matched (but the regular expression is never used as a response). You can override which AuthnContextClassRefs are treated as password authentication (`password_contexts`) and MFA authentication (`mfa_contexts`). It is recommended to keep the contexts supported by default, e.g. by merging arrays. If you set `contexts_regex` to `true` and a value in one of these options is a regular expression (wrapped in `/`), all contexts matching the expression are matched (but the regular expression is never used as a response).
Use `setup_mfa_redirect_url` for redirecting user without MFA tokens to page, where he can register it. User is redirected when MFA is enforced and service is not excluded from this behaviour by `mfa_excluded_sps` configuration option.
## MFA tokens ## MFA tokens
This module expects that there will be a user attribute (`$attributes` aka `$state['Attributes']`) with This module expects that there will be a user attribute (`$attributes` aka `$state['Attributes']`) with
......
{
"setup_mfa_text": {
"en": "To access service, you have to configure multi-factor authentication token.",
"cs": "K přístupu ke službě nejprve musíte nastavit token pro vícefázové ověření."
},
"manage_tokens_button": {
"en": "Continue",
"cs": "Pokračovat"
}
}
...@@ -9,17 +9,25 @@ use SimpleSAML\Auth\State; ...@@ -9,17 +9,25 @@ use SimpleSAML\Auth\State;
use SimpleSAML\Configuration; use SimpleSAML\Configuration;
use SimpleSAML\Error\Exception; use SimpleSAML\Error\Exception;
use SimpleSAML\Logger; use SimpleSAML\Logger;
use SimpleSAML\Module;
use SimpleSAML\Module\authswitcher\AuthnContextHelper; use SimpleSAML\Module\authswitcher\AuthnContextHelper;
use SimpleSAML\Module\authswitcher\AuthSwitcher; use SimpleSAML\Module\authswitcher\AuthSwitcher;
use SimpleSAML\Module\authswitcher\ContextSettings; use SimpleSAML\Module\authswitcher\ContextSettings;
use SimpleSAML\Module\authswitcher\ProxyHelper; use SimpleSAML\Module\authswitcher\ProxyHelper;
use SimpleSAML\Module\authswitcher\Utils; use SimpleSAML\Module\authswitcher\Utils;
use SimpleSAML\Utils\HTTP;
class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
{ {
/* constants */ /* constants */
private const DEBUG_PREFIX = 'authswitcher:SwitchAuth: '; private const DEBUG_PREFIX = 'authswitcher:SwitchAuth: ';
private const SETUP_MFA_URL = 'authswitcher/setupMFA.php';
public const SETUP_MFA_TPL_URL = 'authswitcher/setup-mfa-tpl.php';
public const PARAM_MFA_REDIRECT_URL = 'mfa_redirect_url';
private $type_filter_array = [ private $type_filter_array = [
'TOTP' => 'privacyidea:PrivacyideaAuthProc', 'TOTP' => 'privacyidea:PrivacyideaAuthProc',
'WebAuthn' => 'privacyidea:PrivacyideaAuthProc', 'WebAuthn' => 'privacyidea:PrivacyideaAuthProc',
...@@ -62,6 +70,10 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter ...@@ -62,6 +70,10 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
private $entityID; private $entityID;
private $mfa_excluded_sps;
private $setup_mfa_redirect_url;
/** /**
* @override * @override
* *
...@@ -95,6 +107,8 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter ...@@ -95,6 +107,8 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
$this->sfa_len_attr = $config->getString('sfa_len_attr', $this->sfa_len_attr); $this->sfa_len_attr = $config->getString('sfa_len_attr', $this->sfa_len_attr);
$this->check_entropy = $config->getBoolean('check_entropy', $this->check_entropy); $this->check_entropy = $config->getBoolean('check_entropy', $this->check_entropy);
$this->entityID = $config->getValue('entityID', null); $this->entityID = $config->getValue('entityID', null);
$this->mfa_excluded_sps = $config->getArray('mfa_excluded_sps', []);
$this->setup_mfa_redirect_url = $config->getString('setup_mfa_redirect_url', "");
list($this->password_contexts, $this->mfa_contexts, $password_contexts_patterns, $mfa_contexts_patterns) list($this->password_contexts, $this->mfa_contexts, $password_contexts_patterns, $mfa_contexts_patterns)
= ContextSettings::parseConfig($config); = ContextSettings::parseConfig($config);
...@@ -120,6 +134,16 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter ...@@ -120,6 +134,16 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
$usersCapabilities = $this->getMFAForUid($state); $usersCapabilities = $this->getMFAForUid($state);
if (
$mfaEnforced && empty($state['Attributes'][AuthSwitcher::MFA_TOKENS]) &&
!in_array($this->entityID, $this->mfa_excluded_sps) && !empty($this->setup_mfa_redirect_url)
) {
$url = Module::getModuleURL(self::SETUP_MFA_URL);
$params = [];
$params[self::PARAM_MFA_REDIRECT_URL] = $this->setup_mfa_redirect_url;
HTTP::redirectTrustedURL($url, $params);
}
self::info('user capabilities: ' . json_encode($usersCapabilities)); self::info('user capabilities: ' . json_encode($usersCapabilities));
self::setErrorHandling($state); self::setErrorHandling($state);
...@@ -143,8 +167,8 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter ...@@ -143,8 +167,8 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
self::info('supported requested contexts: ' . json_encode($this->supported_requested_contexts)); self::info('supported requested contexts: ' . json_encode($this->supported_requested_contexts));
$shouldPerformMFA = !$this->authnContextHelper->MFAin([ $shouldPerformMFA = !$this->authnContextHelper->MFAin([
$upstreamContext, $upstreamContext,
]) && ($mfaEnforced || $this->authnContextHelper->isMFAprefered($this->supported_requested_contexts)); ]) && ($mfaEnforced || $this->authnContextHelper->isMFAprefered($this->supported_requested_contexts));
if ( if (
$this->mfa_preferred_privacyidea_fail $this->mfa_preferred_privacyidea_fail
...@@ -160,7 +184,7 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter ...@@ -160,7 +184,7 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
$maxUserCapability = ''; $maxUserCapability = '';
if ( if (
in_array(AuthSwitcher::REFEDS_MFA, $usersCapabilities, true) || $this->authnContextHelper->MFAin([ in_array(AuthSwitcher::REFEDS_MFA, $usersCapabilities, true) || $this->authnContextHelper->MFAin([
$upstreamContext, $upstreamContext,
]) ])
) { ) {
$maxUserCapability = AuthSwitcher::REFEDS_MFA; $maxUserCapability = AuthSwitcher::REFEDS_MFA;
......
<?php
declare(strict_types=1);
use SimpleSAML\Module\authswitcher\Auth\Process\SwitchAuth;
$this->includeAtTemplateBase('includes/header.php');
?>
<div class="row">
<div>
<p><?php echo $this->t('{authswitcher:mfa:setup_mfa_text}'); ?></p>
<?php if (!empty($this->data[SwitchAuth::PARAM_MFA_REDIRECT_URL])) { ?>
<a class="btn btn-lg btn-block btn-primary"
href="<?php echo $this->data[SwitchAuth::PARAM_MFA_REDIRECT_URL]; ?>">
<?php echo $this->t('{authswitcher:mfa:manage_tokens_button}'); ?>
</a>
<?php } ?>
</div>
</div>
<?php
$this->includeAtTemplateBase('includes/footer.php');
?>
<?php
declare(strict_types=1);
use SimpleSAML\Configuration;
use SimpleSAML\Module\authswitcher\Auth\Process\SwitchAuth;
use SimpleSAML\XHTML\Template;
$config = Configuration::getInstance();
$t = new Template($config, SwitchAuth::SETUP_MFA_TPL_URL);
$t->data[SwitchAuth::PARAM_MFA_REDIRECT_URL] = $_REQUEST[SwitchAuth::PARAM_MFA_REDIRECT_URL];
$t->show();
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment