cesnet/simplesamlphp-module-authswitcher

SimpleSAMLphp 模块,用于将双因素认证模块应用于特定用户


README

maintenance status: end of life

此项目已达到生命周期的结束,这意味着不会添加新功能。安全补丁和重要错误修复将于 2024 年结束。请改用 Apereo CAS

描述

模块,用于在不同 MFA 模块之间切换,并尊重/设置 AuthnContextClassRef,适用于 IdP 和代理。与 PrivacyIDEA 进行了测试。

假设认证来源基于密码,然后通过此模块执行基于令牌的二次认证。以下认证上下文支持密码(单因素)认证

以下认证上下文支持多因素认证

安装

您必须使用 Composer 与 SimpleSAMLphp 一起安装此模块,以便安装依赖项。

默认情况下启用模块。

将要由 authswitcher 控制的模块需要单独安装。

安全考虑:假设没有认证过程模块允许用户通过除使用此模块的方法切换/跳过之外的其他方式跳过验证。如果存在此类选项,则需要禁用它,否则用户可以在声明 REFEDS MFA 配置文件时绕过多因素认证。

GetMfaTokensPrivacyIDEA 认证过程过滤器

使用此过滤器从 PrivacyIDEA 服务器读取用户 MFA 令牌到状态属性。

52 => [
    'class' => 'authswitcher:GetMfaTokensPrivacyIDEA',
    'config' => [
        'tokens_Attr' => 'privacyIDEATokens',
        'privacy_idea_username' => 'admin',
        'privacy_idea_passwd' => 'secret',
        //'privacy_idea_realm' => 'superadminrealm', // optional
        'privacy_idea_domain' => 'https://mfa.id.muni.cz',
        'tokens_type' => [
            'TOTP',
            'WebAuthn',
        ],
        'user_attribute' => 'eduPersonPrincipalName',
        'token_type_attr' => 'type',
        //'connect_timeout' => 10, // optional, connect timeout in seconds
        //'timeout' => 10, // optional, timeout in seconds
    ],
],

要启用隐私 IDEA 认证令牌的缓存,请添加

    // ...
        'enable_cache' => true, // defaults to false
        'cache_expiration_seconds' => 30 * 60, // defaults to 55 minutes
    // ...

使用(配置为认证过程过滤器)

添加一个具有示例配置 authswitcher:SwitchAuth 的认证过程过滤器实例

54 => [
      'class' => 'authswitcher:SwitchAuth',
      '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',
          '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, [
          //    'my-custom-authn-context-for-password',
          //    '/^my-regex-.*/',
          //]),
          //'mfa_contexts' => array_merge(AuthSwitcher::MFA_CONTEXTS, [
          //    'my-custom-authn-context-for-mfa',
          //]),
          //'contexts_regex' => true,
          //'entityID' => function($request){
          //    return empty($request["saml:RequesterID"]) ? $request["SPMetadata"]["entityid"] : $request["saml:RequesterID"][0];
          //},
      ],
      'configs' => [
            'totp:Totp' => [
                'secret_attr' => 'totp_secret',
                'enforce_2fa' => true,
                'skip_redirect_url' => 'https://simplesaml/module.php/authswitcher/switchMfaMethods.php',
            ],
            'webauthn:WebAuthn' => [
                'redirect_url' => 'https://webauthn/authentication_request',
                'api_url' => 'https://webauthn/request',
                'signing_key' => '/var/webauthn_private.pem',
                'user_id' => 'eduPersonPrincipalName',
                'skip_redirect_url' => 'https://simplesaml/module.php/authswitcher/switchMfaMethods.php',
            ],
            'privacyidea:PrivacyideaAuthProc' => [
                'privacyideaServerURL' => 'https://mfa.id.muni.cz',
                'realm'                => 'muni.cz',
                'uidKey'               => 'eduPersonPrincipalName',
                'sslVerifyHost'        => 'true',
                'sslVerifyPeer'        => 'true',
                'serviceAccount'       => 'admin',
                'servicePass'          => 'secret',
                'doEnrollToken'        => 'false',
                'tokenType'            =>  [
                    'webauthn',
                    'totp',
                ],
                'doTriggerChallenge'   => 'true',
            ],
        ],
    ],
// as a safety precausion, remove the "secret" attributes
54 => [
    'class' => 'core:AttributeAlter',
    'subject' => 'totp_secret',
    'pattern' => '/.*/',
    '%remove',
],

您可以覆盖哪些 AuthnContextClassRefs 被视为密码认证(password_contexts)和 MFA 认证(mfa_contexts)。建议保留默认支持上下文,例如通过合并数组。如果您将 contexts_regex 设置为 true,并且这些选项中的一个值是正则表达式(用 / 括起来),则与表达式匹配的所有上下文都将匹配(但正则表达式永远不会用作响应)。

使用 setup_mfa_redirect_url 将没有 MFA 令牌的用户重定向到注册页面的页面。当强制执行 MFA 且服务未通过 mfa_excluded_sps 配置选项排除此行为时,用户将被重定向。

MFA 令牌

此模块期望存在一个用户属性($attributes$state['Attributes'])具有键 "mfaTokens",其中填充了由支持的 2FA 模块注册的令牌(数组数组)。

mfaTokens 的示例

[
    [
        "added"   => "2021-09-06 14:40:06",
        "revoked" => false,
        "secret"  => "topsecret",
        "userId"  => "43215",
        "type"    => "TOTP",
    ],
    [
        // ...
    ],
]

当运行 MFA 时,如果至少有一个未撤销的 MFA 令牌并且应根据 "mfaEnforceSettings" 执行 MFA 或 MFA 由 SP(来自 AuthnContext)首选,则 SwitchAuth 认证过程过滤器将运行配置的受支持 2FA 模块之一,该模块由用户的 MFA 令牌类型决定。如果有多个令牌类型可用,则 2FA 方法由设备类型决定(移动设备首选 TOTP,桌面和笔记本电脑首选 WebAuthn)。

如果用户有多种令牌类型,可以在这之间切换。支持的MFA模块重定向到switchMfaMethods.php,该文件检查认证结果,如果MFA未完成,则运行下一个2FA方法过滤器。

以代理模式运行

在代理模式下,需要做一些更改。

首先,将proxy_mode配置选项设置为true

53 => [
    'class' => 'authswitcher:SwitchAuth',
    'config' => [
        'proxy_mode' => true,
        // ...
    ],
    //...
]

如果您想修改password_contextsmfa_contexts,将config数组的内容移动到名为config/module_authswitcher.php的新文件中。有关示例,请参阅config-templates/module_authswitcher.php。如果您不想修改这两个选项,可以保留配置在auth proc过滤器内部。

在用户重定向到上游IdP之前,您还需要调用DiscoUtils::setUpstreamRequestedAuthnContext($state),例如在发现页面的代码中,以确保将正确的AuthnContext发送到上游IdP。

如果您仅通过在config/authsources.php中使用AuthnContextClassRef选项修改了请求的AuthnContextClassRef,则上游IdP的登录将正常工作,但authswitcher将无法处理原始请求的AuthnContextClassRefs(因为它们将被配置选项覆盖)。

最后一个但非常重要的要求是,您需要修改SimpleSAMLphp,包括以下补丁:https://github.com/simplesamlphp/simplesamlphp/pull/833/files,该补丁添加了对将AuthnContextClassRef传递给上游IdP并获取返回值的支持。要启用补丁,请将'proxymode.passAuthnContextClassRef' => true,添加到您的config/config.php中。

按用户强制执行MFA

如果用户应该仅使用MFA,将mfaEnforceSettings用户属性设置为{"all":true}。您可以按任何方式填充此属性,例如从LDAP或从数据库中。

如果用户没有MFA令牌且mfaEnforceSettings不为空,则将其忽略(以防止锁定)。

当该属性不为空时,始终执行多因素认证。因为假设第一个因素总是基于密码,当SP专门请求https://refeds.org/profile/sfaPasswordProtectedTransport时,将执行MFA,但返回其中一个请求的认证上下文。

当与代理模式一起使用时,如果在上游IdP中已执行,则不会强制执行MFA。

按用户和服务强制执行MFA

如果某些用户应使用某些服务的MFA,将mfaEnforceSettings用户属性设置为以下JSON编码对象类型之一

  • {"all":true}强制所有服务使用MFA
  • {"include_categories":["category1","category2"]}强制所有列出的类别中的服务使用MFA
  • {"include_categories":["category1","category2"],"exclude_rps":["entityID1","entityID2"]}强制所有列出的类别中的服务使用MFA,但排除具有实体IDentityID1entityID2的服务

为此,您还必须填充rpCategory用户属性以包含适当的类别。如果此属性为空,则假定服务属于名为"other"的类别。

默认情况下,实体ID从当前SP的元数据中读取。您可以通过指定entityID配置选项为字符串(直接使用)或调用形式为function getEntityID($state){return "str";}的可调用对象来覆盖此值。有关更多信息,请参阅示例配置。

在执行MFA时添加附加属性

要仅当执行MFA时添加属性,可以使用名为AddAdditionalAttributesAfterMfa的过滤器。此过滤器根据是否实际执行了MFA(在上游IdP或本地)来设置属性,而不是根据是否在响应AuthnContext中包含MFA。

AddAdditionalAttributesAfterMfa需要在SwitchAuth过滤器之后运行。

在配置中,您只需添加一个包含附加属性及其值的映射的custom_attrs选项。

55 => [
    'class' => 'authswitcher:AddAdditionalAttributesAfterMfa',
    'config' => [
        'custom_attrs' => [
            'attr1' => ['value1'],
            'attr2' => ['value2'],
            // ...
        ],
        // ...
    ],
    //...
]

密码熵检查

未经检查,默认认为用户密码满足REFEDS SFA。如果需要执行检查,将check_entropy设置为true。同时设置配置选项sfa_alphabet_attrsfa_len_attr,它们代表$state中属性的名称。假设多因素认证(MFA)始终满足REFEDS SFA,它包含TOTP、WebAuthn或类似的用户验证。因此,对于密码较弱的用户,存在两种场景。配置了MFA的用户必须执行MFA,而没有配置MFA的用户将被重定向到包含额外信息和可配置按钮的页面,该按钮可引导到密码重置页面。使用change_weak_password_urls配置重定向按钮。

sfa_alphabet代表密码中可用的字符数量

sfa_len代表密码的长度

54 => [
    'class' => 'authSwitcher:SwitchAuth',
    'config' => [
        'check_entropy' => true,
        'sfa_alphabet_attr' => 'sfa_alphabet',
        'sfa_len_attr' => 'sfa_len'
        'change_weak_password_urls' => [
            'en' => 'https://example.org/en/change_password',
            'cs' => 'https://example.org/cs/zmena_hesla',
        ],
        //...
    ]
]

版权

© 2017-2022 Pavel Břoušek,Masaryk大学计算机科学研究所和CESNET,z. s. p. o. 版权所有。