====== IdP-Authn-Plugin fudiscr ======
===== General =====
This plugin can be used as an additional factor for multi-factor authentication (MFA) by the [[https://shibboleth.atlassian.net/wiki/spaces/IDP4/overview|Shibboleth Identity Provider (IdP)]].
It supports token-based authentication and at its core follows the challenge-response pattern.
The username has to be determined by one of the previous factors in the MFA chain.
A common use-case is the preceding authentication with username/password against an LDAP using the authn/password flow.
The plugin itself does not contain functions for token administration nor special algorithms for validating tokens.
An external token system can be connected via the generic ChallengeResponseClientInterface.
An implementation of this interface for [[https://www.privacyidea.org/|privacyIDEA]] is included as well as
a mock-up implementation for testing purposes.
Also an external implementation for Fortinet already exists.
So far the development has been done by Steffen Hofmann of [[https://www.fu-berlin.de|Freien Universität Berlin]]. He is an employee at the university's IT department [[https://www.zedat.fu-berlin.de|(ZEDAT – Zentraleinrichtung für Datenverarbeitung)]] and in charge of identity management. Because the identity management at FU is called FUDIS (FU Directory and Identity Service), for the challenge-response plugin the name 'fudiscr' is used for configuration parameters, etc.
In the future the support for the plugin will be provided by [[https://www.fu-berlin.de|Freie Universität Berlin]].
In case this can no longer be ensured by the university anymore, partner organizations will ensure it.
===== Prerequisites =====
Installation of privacyIDEA: https://gitlab.daasi.de/training/privacyidea
===== Supported token methods from privacyIDEA =====
Currently the following token methods from privacyIDEA ([[https://privacyidea.readthedocs.io/en/latest/tokens/tokentypes.html|Token types in privacyIDEA]]) are supported:
* Email
* HOTP Token
* Indexed Secret Token
* mOTP Token
* Paper Token (PPR)
* Questionnaire Token (Limitation: //If only one answer is requested per directive.//)
* SMS Token
* TAN Token
* TOTP
* WebAuthn (from version 1.2.0)
Support of //Push Token// is currently in development.
===== Installation =====
The plugin can be used with Shibboleth IdP version >= 4.1.2.
Installation and updates are done via the Shibboleth plugin mechanism (see official docs [[https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1294074003/PluginInstallation|PluginInstallation]])
**Warning:** The Shibboleth Identity Provider will restart after plugin installation.
Plugin is installed using the following command:
%{idp.home}/bin/plugin.sh -i https://identity.fu-berlin.de/downloads/shibboleth/idp/plugins/authn/fudiscr/current/fudis-shibboleth-idp-plugin-authn-fudiscr-current.tar.gz
Future updates can be installed like this:
%{idp.home}/bin/plugin.sh -u de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr
For unattended installations the PGP keys can be downloaded upfront and supplied on installation like this:
wget -O %{idp.home}/PGP_KEYS_FUDIS https://identity.fu-berlin.de/downloads/shibboleth/idp/plugins/PGP_KEYS
%{idp.home}/bin/plugin.sh -i https://identity.fu-berlin.de/downloads/shibboleth/idp/plugins/authn/fudiscr/current/fudis-shibboleth-idp-plugin-authn-fudiscr-current.tar.gz --truststore %{idp.home}/PGP_KEYS_FUDIS
===== Configuration =====
==== Connecting privacyIDEA ====
=== Adding a system user in privacyIDEA ===
The Shibboleth plugin communicates with privacyIDEA by its API. The following three end points are used:
* /token/ (request a list of tokens)
* /validate/triggerchallenge (initiate token challenge)
* /validate/check (check an OTP, possibly in combination with a PIN)
Therefore the user has to have sufficient rights to carry out all the actions that are triggered by those request and
ideally no additional rights.
== Setting up an admin user ==
First we need to set up an admin user. It is recommended to set up a separate (administrative) realm as well in order to be able to differentiate between different types of rights for administrative users later on. The user account can be supplied by any external source and be imported by a resolver defined in PrivacyIdea.
The setup of realms and resolvers os not part of this documentation but for the sake of simplicity and clarity we will set up the privacyIDEA internal user //idp-admin//.
pi-manage admin add idp-admin
Furthermore we assume that the initial admin super user //admin// exists.
== Granting permissions ==
The required permissions are granted in privacyIDEA via policy.
**Warning**: Admins in privacyIDEA get all permissions by default.
This holds as long as no admin policy is defined.
Once a policy is defined with scope 'admin', all admin users are restricted by the rights in this policy.
In case there is no admin policy yet, make sure not to lock yourself out of the Web UI.
That's why privacyIDEA informs you, if you define an admin policy, but the rights to edit policies are not granted in this (or any other) policy.
At first we create the functionally required policy for the super user and assign it to user //admin//.
Then we add a new policy for our //idp-admin// user.
Therefore we create a new file //idp-admin-policy//, which contains parameters for the policy as a python dictionary.
The content should be like this:
{
'action': {'tokenlist':True, 'triggerchallenge':True},
'active': True,
'adminuser': ['idp-admin'],
'name': 'idp-admin-policy',
'scope': 'admin'
}
The policy can then be created by using the file template like this:
pi-manage policy create -f idp-admin-policy name scope action
== Creating an API-Token ==
In order to successfully authenticate against the API an authorization token hast to be supplied. This token can be requested either by an API call to the //auth// endpoint or created by using //pi-manage//. By using the //pi-manage//-script you can create a token with an arbitrary expiry time in days (default 365). Tokens requested from the API are only valid for one hour. Therefore we use //pi-manage//:
pi-manage api createtoken -r admin -u idp-admin
=== Configuration of privacyIDEA ===
The connection to privacyIDEA is set up by the configuration options in ''%{idp.home}/conf/authn/fudiscr.properties''
fudiscr.privacyidea.base_uri=
fudiscr.privacyidea.authorization_token=
#System user from previous step. Can be use to extend the authorization token:
#fudiscr.privacyidea.service_username=
#fudiscr.privacyidea.service_realm=
#fudiscr.privacyidea.service_password=
#Realm which is added to the user by default:
#fudiscr.privacyidea.default_realm=
#In case the server certificate should not be validated by the API, set this value to 'false"
#fudiscr.privacyidea.check_connection_certificate=true
==== MFA configuration ====
(For REFEDS Multi-Factor Authentication profile see [[de:aai:refeds_authn_profiles_idp|REFEDS AuthN Profiles - Hinweise für Identity Provider]] (in German))
\\
To use this plugin with MFA, the MFA module itself has to be enabled in the Identity Provider.
This is done by:
%{idp.home}/bin/module.sh -e idp.authn.MFA
In ''%{idp.home}/conf/authn/authn.properties'' the following settings should be done:
idp.authn.flows = MFA
idp.authn.fudiscr.supportedPrincipals= \
saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR
idp.authn.MFA.supportedPrincipals = \
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol, \
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport, \
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:Password, \
saml1/urn:oasis:names:tc:SAML:1.0:am:password, \
saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR
''idp.authn.MFA.supportedPrincipals'' is already activated by default.
We only add the [[https://docs.oasis-open.org/security/saml/v2.0/saml-authn-context-2.0-os.pdf|AuthenticationContextClass]] ''saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR''.
Instead of ''saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR'' you can set a different or additional [[https://docs.oasis-open.org/security/saml/v2.0/saml-authn-context-2.0-os.pdf|AuthenticationContextClass]]
using ''idp.authn.fudiscr.supportedPrincipals'' AND ''idp.authn.MFA.supportedPrincipals''.
It is recommended to set at least one additional class by which the multi factor authentication can be triggered.
This is not mandatory because multi factor authentication might be triggered by other mechanisms as well.
By using the transitions in ''%{idp.home}/conf/authn/mfa-authn-config.xml'' the order of the individual factors is specified.
You can use various mechanisms here to define conditions for transitions to the following factors.
The official documentation can be found here:
[[https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1265631610/MultiFactorAuthnConfiguration|MultiFactorAuthnConfiguration]]
=== Examples ===
Now we will look at three examples for MFA configuration.
**Example 1**: After authentication with username and password, a token based authentication using fudiscr is done in any case.
**Example 2**: After authentication with username and password we request a token based authentication using fudiscr if the AuthenticationContextClass required by the service provider is not sufficient.
**Example 3**: After authentication with username and password we request a token based authentication using fudiscr if the AuthenticationContextClass required by the service provider is not sufficient or if the user belongs to the group 'employee' according to eduPersonAffiliation.
**Example 4**:
version >=1.1.0
After authentication with username and password we request a token based authentication using fudiscr if the AuthenticationContextClass required by the service provider is not sufficient
or if the user owns at least one token. The state of the tokens is not checked here, so a deactivated token would result in ''fudiscr.UserHasAnyTokenPredicate'' returning ''true''. This predicate
was introduced primarily for rollout scenarios.
=== Reuse Condition ===
For authentication methods on Shibboleth Identity Provider a //reuse condition// can be defined.
In general the default value is ''shibboleth.Conditions.TRUE'' which makes this condition be fulfilled in any case.
You can define your own functions as //reuse conditions//.
For multi factor authentication special rules apply. You can find a description in the official documentation: [[https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1265631610/MultiFactorAuthnConfiguration|MultiFactorAuthnConfiguration]]
Using the following configuration you can achieve that username and password is requested only once inside a SSO session, but token based authentication is requested once on every service provider authentication.
idp.authn.MFA.reuseCondition=shibboleth.Conditions.FALSE
idp.authn.Password.reuseCondition=shibboleth.Conditions.TRUE
idp.authn.fudiscr.reuseCondition=shibboleth.Conditions.FALSE
This means the result of the MFA authentication can not be reused. Inside of a multi factor authentication the existing successful result of the username/password authentication (//password//) can be reused, but the result of //fudiscr// can not.
It is recommended to set ''idp.authn.MFA.reuseCondition=shibboleth.Conditions.FALSE'' in case on every authentication request the logic in ''./conf/authn/mfa-authn-config.xml'' is gone through. In the reuse case for instance during a valid SSO session, it is not checked whether a user has a certain affiliation.
==== Further Configuration ====
You can find further configuration options in ''%{idp.home}/conf/authn/fudiscr.properties''.
This document might be of help [[https://identity.fu-berlin.de/downloads/shibboleth/idp/plugins/authn/fudiscr/doc/ChallengeResponseFlow.pdf|ChallengeResponseFlow.pdf]].
===== WebAuthn =====
Starting from version 1.2.0 WebAuthn token can be used.
The fudiscr plugin offers some options which permit multiple selection of tokens. If multiple tokens are selected during login it is assumed that the parameters
//rpId// (relying party Id), //challenge//, //userVerification// and //timeout// are identical.
If a user owns multiple active WebAuthn tokens and you set ''fudiscr.user_token_selection=none'', ''fudiscr.user_token_selection=multipleToken'' or ''fudiscr.user_token_selection=multipleTokenTypeGroup'' in ''%{idp.home}/conf/authn/fudiscr.properties'',
you have to set ''fudiscr.privacyidea.single_trigger_challenges=false'' as well.
In general it applies that the domain of the Identity Provider has to either be identical to the //rpId// from WebAuthn or a subdomain of it.
There is no preliminary filtering done in order to check if the domain of the Identity Provider is compatible to the //rpId// of the WebAuthn token.
===== Further resources ====
* Documents from the [[de:aai:events:ws2022|Shibboleth Workshops February 2022]] (in German)
{{tag>2FA MFA two-factor-authentication multi-factor-authentication}}
===== Contact =====
Please email [[fudis@zedat.fu-berlin.de|fudis@zedat.fu-berlin.de]] for corrections, questions and suggestions.