cesnet / simplesamlphp-module-authswitcher
A SimpleSAMLphp module for applying 2FA modules to specific users
Maintainers
Details
gitlab.ics.muni.cz/perun/perun-proxyidp/v1/simplesamlphp-module-authswitcher.git
Requires
- php: ^7.1 || ^8
- ext-curl: *
- ext-json: *
- mobiledetect/mobiledetectlib: ^3.0
- simplesamlphp/composer-module-installer: ~1.0
- simplesamlphp/saml2: ^4.1
- simplesamlphp/simplesamlphp: ^1.19
- web-token/jwt-easy: ^2.2
Suggests
- cesnet/simplesamlphp-module-totp: TOTP 2FA
- cesnet/simplesamlphp-module-webauthn: WebAuthn 2FA
- privacyidea/simplesamlphp-module-privacyidea: privacyIDEA 2FA
- dev-main
- v12.1.2
- v12.1.1
- v12.1.0
- v12.0.1
- v12.0.0
- v11.1.2
- v11.1.1
- v11.1.0
- v11.0.0
- v10.7.6
- v10.7.5
- v10.7.4
- v10.7.3
- v10.7.2
- v10.7.1
- v10.7.0
- v10.6.0
- v10.5.2
- v10.5.1
- v10.5.0
- v10.4.0
- v10.3.0
- v10.2.2
- v10.2.1
- v10.2.0
- v10.1.0
- v10.0.0
- v9.2.0
- v9.1.0
- v9.0.2
- v9.0.1
- v9.0.0
- v8.0.1
- v8.0.0
- v7.1.1
- v7.1.0
- v7.0.2
- v7.0.1
- v7.0.0
- v6.1.3
- v6.1.2
- v6.1.1
- v6.1.0
- v6.0.0
- v5.0.0
- v4.1.3
- v4.1.2
- v4.1.1
- v4.1.0
- v4.0.0
- v3.4.3
- v3.4.2
- v3.4.1
- v3.4.0
- v3.3.1
- v3.3.0
- v3.2.0
- v3.1.1
- v3.1.0
- v3.0.1
- v3.0.0
- v2.0.0
- 1.1
- 1.0
- dev-xpavlic/disco_fix
- dev-renovate/lock-file-maintenance
This package is auto-updated.
Last update: 2024-10-10 13:19:13 UTC
README
This project has reached end of life, which means no new features will be added. Security patches and important bug fixes will end as of 2024. Check out Apereo CAS instead.
Description
Module for switching between different MFA modules and honoring + setting AuthnContextClassRef
, both for IdP and proxy. Tested
with PrivacyIDEA.
It is assumed that the auth source is password based, then secondary authentication (based on a token) is performed via this module. The following authentication contexts are supported for password (single factor) authentication:
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
- REFEDS SFA profile
The following authentication contexts are supported for multi-factor authentication:
- REFEDS MFA profile
http://schemas.microsoft.com/claims/multipleauthn
Install
You have to install this module using Composer together with SimpleSAMLphp so that dependencies are installed as well.
The module is enabled by default.
The modules that are going to be controlled by authswitcher need to be installed separately.
Security consideration: It is assumed that none of the auth proc modules allows user to skip the verification in other way than using the method switching/skipping of this module. If there is such option, you need to disable it, otherwise users can bypass MFA while asserting the REFEDS MFA profile.
GetMfaTokensPrivacyIDEA auth proc filter
Use this filter to read user mfa tokens from PrivacyIDEA server to state attributes.
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
],
],
To enable caching of the privacyIDEA auth token, add:
// ...
'enable_cache' => true, // defaults to false
'cache_expiration_seconds' => 30 * 60, // defaults to 55 minutes
// ...
Use (configure as auth proc filter)
Add an instance of the auth proc filter with example configuration 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',
],
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
This module expects that there will be a user attribute ($attributes
aka $state['Attributes']
) with
key "mfaTokens"
filled with the tokens registered by the supported 2FA modules (array of arrays).
example of mfaTokens:
[
[
"added" => "2021-09-06 14:40:06",
"revoked" => false,
"secret" => "topsecret",
"userId" => "43215",
"type" => "TOTP",
],
[
// ...
],
]
When MFA is run, if there is at least one MFA token which is not revoked and MFA should be done according to "mfaEnforceSettings"
or MFA is preferred by SP (from AuthnContext
), the SwitchAuth
auth proc filter runs one of the configured supported
2FA modules, decided by type of user's MFA tokens. If more than one token types are available, the 2FA method is decided
by device type (TOTP is preferred for mobile devices, WebAuthn for desktops and laptops).
If the user has multiple token types, it is possible to switch between them. The supported MFA modules redirect
to switchMfaMethods.php
, which checks authentication result and if MFA has not completed, it runs the next 2FA method
filter.
Running in proxy mode
In proxy mode, you need to make a couple of changes.
First, set the proxy_mode
configuration option to true
:
53 => [
'class' => 'authswitcher:SwitchAuth',
'config' => [
'proxy_mode' => 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.
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).
The last but very important requirement is that you need to modify SimpleSAMLphp by including this patch: https://github.com/simplesamlphp/simplesamlphp/pull/833/files which adds support for passing AuthnContextClassRef to upstream IdP and getting the returned one. To enable the patch, add 'proxymode.passAuthnContextClassRef' => true,
to your config/config.php
.
Enforce MFA per user
If a user should only use MFA, set mfaEnforceSettings
user attribute to {"all":true}
. You can fill this attribute any way you like, for example from LDAP or from a database.
If the user has no MFA tokens and mfaEnforceSettings
is non-empty, it is ignored (to prevent lock-outs).
When the attribute is not empty, multi-factor authentication is always performed. Because it is assumed that the first factor is always password based, when a SP requests https://refeds.org/profile/sfa
or PasswordProtectedTransport
specifically, MFA is performed but one of the requested authentication contexts is returned.
When used with proxy mode, MFA is not forced if it was already done at upstream IdP.
Enforce MFA per user per service
If some user should use MFA for some services, set mfaEnforceSettings
user attribute to one of the following JSON-encoded object types:
{"all":true}
to force MFA for all services{"include_categories":["category1","category2"]}
to force MFA for all services from the listed categories{"include_categories":["category1","category2"],"exclude_rps":["entityID1","entityID2"]}
to force MFA for all services from the listed categories except services with entity IDentityID1
andentityID2
For this to work, you must also fill the rpCategory
user attribute with the appropriate category. If this attribute is empty, the service is assumed to belong to a category named "other"
.
By default, entity ID is read from the metadata of the current SP. You can override this by specifying the entityID
config option to either a string (which is used as is) or a callable in the form function getEntityID($state){return "str";}
. See example configs for more.
Add additional attributes when MFA is performed
To add attributes only if MFA was performed, you can use a filter called AddAdditionalAttributesAfterMfa
.
This filter sets attributes based on whether MFA was in fact performed (at upstream IdP or locally) - not based on whether MFA is in the response AuthnContext.
AddAdditionalAttributesAfterMfa
needs to run after the SwitchAuth
filter.
In configuration, you just need to add a custom_attrs
option which contains a map of additional attributes and their values.
55 => [
'class' => 'authswitcher:AddAdditionalAttributesAfterMfa',
'config' => [
'custom_attrs' => [
'attr1' => ['value1'],
'attr2' => ['value2'],
// ...
],
// ...
],
//...
]
Password entropy check
Without check, it is assumed that user password fulfill REFEDS SFA. If the check should be performed, set check_entropy
to true
. Also set sfa_alphabet_attr
and sfa_len_attr
configuration options, which represent names of attributes in $state
.
It is assumed that MFA always satisfies REFEDS SFA, that it contains TOTP, WebAuthn, or similar user verification. Therefore, there are two scenarios for a user with weak password. User with configured MFA must perform MFA, and user without configured MFA will be redirected to a page with additional information and with configurable button which leads to a password reset.
Use change_weak_password_urls
to configure redirect button.
sfa_alphabet
represents number of characters which can be used in password
sfa_len
represents length of password
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',
],
//...
]
]
Copyright
© 2017-2022 Pavel Břoušek, Institute of Computer Science, Masaryk University and CESNET, z. s. p. o. All rights reserved.