Skip to content
Snippets Groups Projects
Verified Commit 109f0a45 authored by Pavel Břoušek's avatar Pavel Břoušek
Browse files

fix: use configuration options in DiscoUtils as well

parent 132162d0
No related branches found
No related tags found
1 merge request!46utility class for proxy, configurable lists of AuthnContextClassRefs
...@@ -160,8 +160,9 @@ filter. ...@@ -160,8 +160,9 @@ filter.
## Running in proxy mode ## Running in proxy mode
In the proxy mode, it is assumed that the upstream IdP used for authentication could handle the requested `AuthnContext` In proxy mode, you need to make a couple of changes.
already. You need to set the `proxy_mode` configuration option to `true`:
First, set the `proxy_mode` configuration option to `true`:
```php ```php
53 => [ 53 => [
...@@ -174,6 +175,8 @@ already. You need to set the `proxy_mode` configuration option to `true`: ...@@ -174,6 +175,8 @@ already. You need to set the `proxy_mode` configuration option to `true`:
] ]
``` ```
If you want to modify `password_contexts` or `mfa_contexts`, move the contents of the `config` array into a new file called `config/module_authswitcher.php`. See `config-templates/module_authswitcher.php` for an example. If you do not want to modify these two options, you can keep the config inside the auth proc filter.
You also need to call `DiscoUtils::setUpstreamRequestedAuthnContext($state)` before the user is redirected to upstream IdP, e.g. in the discovery page's code, so that correct AuthnContext is sent to the upstream IdP. You also need to call `DiscoUtils::setUpstreamRequestedAuthnContext($state)` before the user is redirected to upstream IdP, e.g. in the discovery page's code, so that correct AuthnContext is sent to the upstream IdP.
If you only modified the requested AuthnContextClassRef by using the `AuthnContextClassRef` option in `config/authsources.php`, the login at upstream IdP will work, but authswitcher won't be able to process the originally requested AuthnContextClassRefs (because they would be overwriten by the config option). If you only modified the requested AuthnContextClassRef by using the `AuthnContextClassRef` option in `config/authsources.php`, the login at upstream IdP will work, but authswitcher won't be able to process the originally requested AuthnContextClassRefs (because they would be overwriten by the config option).
......
<?php
declare(strict_types=1);
$config = [
'type_filter_array' => [
'TOTP' => 'privacyidea:PrivacyideaAuthProc',
'WebAuthn' => 'privacyidea:PrivacyideaAuthProc',
],
'token_type_attr' => 'type',
'preferred_filter' => 'privacyidea:PrivacyideaAuthProc',
'max_user_capability_attr' => 'maxUserCapability',
'max_auth' => 'https://id.muni.cz/profile/maxAuth',
//'password_contexts' => array_merge(AuthSwitcher::PASSWORD_CONTEXTS, [
// 'my-custom-authn-context-for-password',
// '/^my-regex-.*/',
//]),
//'mfa_contexts' => array_merge(AuthSwitcher::MFA_CONTEXTS, [
// 'my-custom-authn-context-for-mfa',
//]),
//'contexts_regex' => true,
];
...@@ -8,7 +8,7 @@ use Symplify\EasyCodingStandard\Config\ECSConfig; ...@@ -8,7 +8,7 @@ use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\ValueObject\Set\SetList; use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
return static function (ECSConfig $ecsConfig): void { return static function (ECSConfig $ecsConfig): void {
$ecsConfig->paths([__DIR__ . '/ecs.php', __DIR__ . '/lib', __DIR__ . '/www']); $ecsConfig->paths([__DIR__ . '/config-templates', __DIR__ . '/ecs.php', __DIR__ . '/lib', __DIR__ . '/www']);
$ecsConfig->sets([ $ecsConfig->sets([
SetList::CLEAN_CODE, SetList::CLEAN_CODE,
......
...@@ -11,6 +11,7 @@ use SimpleSAML\Error\Exception; ...@@ -11,6 +11,7 @@ use SimpleSAML\Error\Exception;
use SimpleSAML\Logger; use SimpleSAML\Logger;
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\ProxyHelper; use SimpleSAML\Module\authswitcher\ProxyHelper;
use SimpleSAML\Module\authswitcher\Utils; use SimpleSAML\Module\authswitcher\Utils;
...@@ -78,7 +79,9 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter ...@@ -78,7 +79,9 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
$this->config = $config; $this->config = $config;
$this->reserved = $reserved; $this->reserved = $reserved;
$config = Configuration::loadFromArray($config['config']); $config = isset($config['config']) ? Configuration::loadFromArray(
$config['config']
) : Configuration::getOptionalConfig('module_authswitcher.php');
$this->type_filter_array = $config->getArray('type_filter_array', $this->type_filter_array); $this->type_filter_array = $config->getArray('type_filter_array', $this->type_filter_array);
$this->mobile_friendly_filters = $config->getArray('mobile_friendly_filters', $this->mobile_friendly_filters); $this->mobile_friendly_filters = $config->getArray('mobile_friendly_filters', $this->mobile_friendly_filters);
$this->token_type_attr = $config->getString('token_type_attr', $this->token_type_attr); $this->token_type_attr = $config->getString('token_type_attr', $this->token_type_attr);
...@@ -97,24 +100,15 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter ...@@ -97,24 +100,15 @@ 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->contexts_regex = $config->getBoolean('contexts_regex', false); list($this->password_contexts, $this->mfa_contexts, $password_contexts_patterns, $mfa_contexts_patterns) = ContextSettings::parse_config(
$this->password_contexts = $config->getArray('password_contexts', AuthSwitcher::PASSWORD_CONTEXTS); $config
$this->mfa_contexts = $config->getArray('mfa_contexts', AuthSwitcher::MFA_CONTEXTS); );
if ($this->contexts_regex) {
$this->password_contexts_patterns = array_filter(self::is_regex, $this->password_contexts);
$this->password_contexts = array_diff($this->password_contexts, $this->password_contexts_patterns);
$this->mfa_contexts_patterns = array_filter(self::is_regex, $this->mfa_contexts);
$this->mfa_contexts = array_diff($this->mfa_contexts, $this->mfa_contexts_patterns);
} else {
$this->password_contexts_patterns = [];
$this->mfa_contexts_patterns = [];
}
$this->authnContextHelper = new AuthnContextHelper( $this->authnContextHelper = new AuthnContextHelper(
$this->password_contexts, $this->password_contexts,
$this->mfa_contexts, $this->mfa_contexts,
$this->password_contexts_patterns, $password_contexts_patterns,
$this->mfa_contexts_patterns $mfa_contexts_patterns
); );
} }
...@@ -206,11 +200,6 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter ...@@ -206,11 +200,6 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
} }
} }
private static function is_regex($str)
{
return strlen($str) > 2 && substr($str, 0, 1) === '/' && substr($str, -1) === '/';
}
private function checkSfaEntropy($attributes) private function checkSfaEntropy($attributes)
{ {
if (!$this->sfa_len_attr || !$this->sfa_alphabet_attr || !in_array( if (!$this->sfa_len_attr || !$this->sfa_alphabet_attr || !in_array(
......
<?php
declare(strict_types=1);
namespace SimpleSAML\Module\authswitcher;
class ContextSettings
{
public static function parse_config($config)
{
$contexts_regex = $config->getBoolean('contexts_regex', false);
$password_contexts = $config->getArray('password_contexts', AuthSwitcher::PASSWORD_CONTEXTS);
$mfa_contexts = $config->getArray('mfa_contexts', AuthSwitcher::MFA_CONTEXTS);
if ($contexts_regex) {
$password_contexts_patterns = array_filter(self::is_regex, $password_contexts);
$password_contexts = array_diff($password_contexts, $password_contexts_patterns);
$mfa_contexts_patterns = array_filter(self::is_regex, $mfa_contexts);
$mfa_contexts = array_diff($mfa_contexts, $mfa_contexts_patterns);
} else {
$password_contexts_patterns = [];
$mfa_contexts_patterns = [];
}
return [$password_contexts, $mfa_contexts, $password_contexts_patterns, $mfa_contexts_patterns];
}
private static function is_regex($str)
{
return strlen($str) > 2 && substr($str, 0, 1) === '/' && substr($str, -1) === '/';
}
}
...@@ -4,6 +4,7 @@ declare(strict_types=1); ...@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SimpleSAML\Module\authswitcher; namespace SimpleSAML\Module\authswitcher;
use SimpleSAML\Configuration;
use SimpleSAML\Logger; use SimpleSAML\Logger;
/** /**
...@@ -14,7 +15,7 @@ use SimpleSAML\Logger; ...@@ -14,7 +15,7 @@ use SimpleSAML\Logger;
*/ */
class DiscoUtils class DiscoUtils
{ {
private static const DEBUG_PREFIX = 'AuthSwitcher: '; private const DEBUG_PREFIX = 'authswitcher:DiscoUtils: ';
/** /**
* Store requested AuthnContextClassRef from SP and modify them before sending to upstream IdP. * Store requested AuthnContextClassRef from SP and modify them before sending to upstream IdP.
...@@ -26,6 +27,17 @@ class DiscoUtils ...@@ -26,6 +27,17 @@ class DiscoUtils
*/ */
public static function setUpstreamRequestedAuthnContext(array &$state) public static function setUpstreamRequestedAuthnContext(array &$state)
{ {
$config = Configuration::getOptionalConfig('module_authswitcher.php');
list($password_contexts, $mfa_contexts, $password_contexts_patterns, $mfa_contexts_patterns) = ContextSettings::parse_config(
$config
);
$authnContextHelper = new AuthnContextHelper(
$password_contexts,
$mfa_contexts,
$password_contexts_patterns,
$mfa_contexts_patterns
);
$spRequestedContexts = $state['saml:RequestedAuthnContext']['AuthnContextClassRef'] ?? []; $spRequestedContexts = $state['saml:RequestedAuthnContext']['AuthnContextClassRef'] ?? [];
// store originally requested contexts for correct handling in SwitchAuth // store originally requested contexts for correct handling in SwitchAuth
...@@ -34,23 +46,15 @@ class DiscoUtils ...@@ -34,23 +46,15 @@ class DiscoUtils
$upstreamRequestedContexts = []; $upstreamRequestedContexts = [];
if (empty($spRequestedContexts)) { if (empty($spRequestedContexts)) {
Logger::debug(self::DEBUG_PREFIX . 'No AuthnContextClassRef requested, not sending any to upstream IdP.'); Logger::debug(self::DEBUG_PREFIX . 'No AuthnContextClassRef requested, not sending any to upstream IdP.');
} elseif (!empty(array_diff(AuthSwitcher::REPLY_CONTEXTS_MFA, $spRequestedContexts))) { } elseif ($authnContextHelper->MFAin($spRequestedContexts)) {
Logger::debug(self::DEBUG_PREFIX . 'SP requested MFA, will prefer MFA at upstream IdP.'); Logger::debug(self::DEBUG_PREFIX . 'SP requested MFA, will prefer MFA at upstream IdP.');
$upstreamRequestedContexts = array_values( $upstreamRequestedContexts = array_values(
array_unique(array_merge( array_unique(array_merge($mfa_contexts, $spRequestedContexts, $password_contexts))
AuthSwitcher::REPLY_CONTEXTS_MFA,
$spRequestedContexts,
AuthSwitcher::REPLY_CONTEXTS_SFA
))
); );
} else { } else {
Logger::debug(self::DEBUG_PREFIX . 'SP did not request MFA, will prefer SFA at upstream IdP.'); Logger::debug(self::DEBUG_PREFIX . 'SP did not request MFA, will prefer SFA at upstream IdP.');
$upstreamRequestedContexts = array_values( $upstreamRequestedContexts = array_values(
array_unique(array_merge( array_unique(array_merge($spRequestedContexts, $password_contexts, $mfa_contexts))
$spRequestedContexts,
AuthSwitcher::REPLY_CONTEXTS_SFA,
AuthSwitcher::REPLY_CONTEXTS_MFA
))
); );
} }
if (!empty($upstreamRequestedContexts)) { if (!empty($upstreamRequestedContexts)) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment