The plugin can be used as an additional factor for Multi-Factor Authentication (MFA) by the Shibboleth Identity Provider (IdP). It supports token-based authentication and fundamentally follows the Challenge-Response pattern. A username is determined as a basis from one of the previous factors in the MFA sequence. A common case is a preceding authentication with username and password against LDAP using the authn/Password-Flow.
The plugin itself has no functions for token management. It also contains no special algorithms for token validation. A token system can be connected via a generic ChallengeResponseClientInterface. The plugin already includes an implementation of this interface for eduMFA and privacyIDEA. Additionally, a rudimentary mockup implementation for testing is included. An external implementation for Fortinet also already exists. The primary development work was carried out by Steffen Hofmann from the Free University of Berlin. He is an employee of the Computing Center (FUB-IT) and responsible for the Identity Management area. The Identity Management System of the Free University of Berlin is called FUDIS (FU Directory and Identity Service). For this reason, the abbreviation fudiscr is used in configuration parameters for the Challenge-Response-Plugin.
With versions 1.4.0/2.0.0, a collaboration in the area of Passkeys with the Munich University of Applied Sciences was established. From these versions onward, the plugin contains an additional authentication method called fudispasskeys. Instead of a two-step authentication using e.g., username/password and token validation with fudiscr, a single authentication with Passkeys can be performed.
Plugin Version | IdP Version | eduMFA Version | privacyIDEA Version | Support Level |
---|---|---|---|---|
1.0.0 | min. 4.1.2 and < 4.3.0 | N/A | min. 3.7 | no longer use |
1.1.0 | min. 4.1.2 and < 4.3.0 | N/A | min. 3.7 | no longer use |
1.1.1 | min. 4.1.2 and < 4.3.0 | N/A | min. 3.7 | no longer use |
1.2.0 | min. 4.1.2 and < 4.3.0 | N/A | min. 3.7 | no longer use |
1.3.0 | min. 4.3.0 and < 5.0.0 | N/A | min. 3.7 | no longer use |
1.4.0 | min. 4.3.0 and < 5.0.0 | min. 2.0.0 | min. 3.9.2 | no longer use |
Plugin Version | IdP Version | eduMFA Version | privacyIDEA Version | Support Level |
---|---|---|---|---|
2.0.0 | min. 5.0.0 | min. 2.0.0 | min. 3.9.2 | no longer use |
2.1.0 | min. 5.1.0 | min. 2.0.0 | min. 3.9.2 | current |
Currently, the following token methods from eduMFA (Token types in eduMFA) and privacyIDEA (Token types in privacyIDEA) are supported:
Token Method | Type Designation in Plugin | min. Plugin Version | Limitations / Notes |
---|---|---|---|
1.0.0 | |||
HOTP Token | hotp | 1.0.0 | |
Indexed Secret Token | indexed_secret | 1.0.0 | |
mOTP Token | motp | 1.0.0 | |
Paper Token (PPR) | indexed_tan | 1.0.0 | |
Questionnaire Token | question | 1.0.0 | Only one answer may be required by policy. |
Registration | registration_code | 1.3.0 | |
Remote | referenced token type | 1.3.0 | Only referenced tokens of type Email, HOTP Token, mOTP Token, Paper Token (PPR), Registration, SMS Token, TAN Token, TOTP, Yubico and Yubikey are supported. |
SMS Token | sms | 1.0.0 | |
Spass | simple_pass_token | 1.4.0 / 2.0.0 | |
TAN Token | tan | 1.0.0 | |
TOTP | totp | 1.0.0 | |
WebAuthn | web_authn | 1.2.0 | |
Yubico | yubico_otp | 1.3.0 | |
Yubikey | yubikey_aes | 1.3.0 |
The fudiscr plugin requires the MFA module. This should be activated as follows:
%{idp.home}/bin/module.sh -e idp.authn.MFA
With the MFA module, the configuration file %{idp.home}/conf/authn/mfa-authn-config.xml
is also stored.
(see also Shibboleth-IdP MultiFactorAuthnConfiguration)
The installation and updates are performed via the Shibboleth Plugin mechanism (see official documentation PluginInstallation)
Attention: The Shibboleth Identity Provider automatically performs a restart after a plugin installation.
The plugin is installed and activated with 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 will be automatically installed with the following command:
%{idp.home}/bin/plugin.sh -u de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr
For a fully automatic installation, the PGP keys can be downloaded in advance and specified during installation:
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
(For the REFEDS Multi-Factor Authentication Profile, see REFEDS AuthN Profiles - Information for Identity Providers)
The following settings need to be made in %{idp.home}/conf/authn/authn.properties
:
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.
Only the AuthenticationContextClass saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR
is added.
Instead of saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR
, another AuthenticationContextClass
or additional ones can be entered under idp.authn.fudiscr.supportedPrincipals
AND idp.authn.MFA.supportedPrincipals
.
It is recommended to define at least one additional class through which multi-factor authentication can be explicitly triggered.
However, there is no obligation, as multi-factor authentication can also be triggered through other mechanisms.
The sequence of individual factors is controlled via the transitions in %{idp.home}/conf/authn/mfa-authn-config.xml
.
Different mechanisms can be used here to formulate the conditions for transitions to the next factors.
You can find the official documentation here:
MultiFactorAuthnConfiguration
Below are three examples of MFA configuration.
Example 1: After authentication with username and password, token-based authentication with fudiscr always follows.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" default-init-method="initialize" default-destroy-method="destroy"> <!-- most parts copied from https://shibboleth.atlassian.net/wiki/spaces/IDP5/pages/3199505534/MultiFactorAuthnConfiguration --> <util:map id="shibboleth.authn.MFA.TransitionMap"> <entry key=""> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/Password"/> </entry> <entry key="authn/Password"> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/fudiscr"/> </entry> </util:map> </beans>
Example 2: After authentication with username and password, token-based authentication follows if the AuthenticationContextClass required by the ServiceProvider is insufficient.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" default-init-method="initialize" default-destroy-method="destroy"> <!-- most parts copied from https://shibboleth.atlassian.net/wiki/spaces/IDP5/pages/3199505534/MultiFactorAuthnConfiguration --> <util:map id="shibboleth.authn.MFA.TransitionMap"> <entry key=""> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/Password"/> </entry> <entry key="authn/Password"> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlowStrategy-ref="checkSecondFactor"/> </entry> </util:map> <bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"> <constructor-arg> <value> <![CDATA[ nextFlow = "authn/fudiscr"; authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext"); if (mfaCtx.isAcceptable()) { nextFlow = null; } nextFlow; ]]> </value> </constructor-arg> </bean> </beans>
Example 3: After authentication with username and password, token-based authentication follows if the AuthenticationContextClass required by the ServiceProvider is insufficient or if the user belongs to the employee group according to eduPersonAffiliation.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" default-init-method="initialize" default-destroy-method="destroy"> <!-- most parts copied from https://shibboleth.atlassian.net/wiki/spaces/IDP5/pages/3199505534/MultiFactorAuthnConfiguration --> <util:map id="shibboleth.authn.MFA.TransitionMap"> <entry key=""> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/Password"/> </entry> <entry key="authn/Password"> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlowStrategy-ref="checkSecondFactor"/> </entry> </util:map> <bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript" p:customObject-ref="shibboleth.AttributeResolverService"> <constructor-arg> <value> <![CDATA[ nextFlow = "authn/fudiscr"; authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext"); if (mfaCtx.isAcceptable()) { nextFlow = null; resCtx = input.getSubcontext( "net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext", true); usernameLookupStrategyClass = Java.type("net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy"); usernameLookupStrategy = new usernameLookupStrategyClass(); resCtx.setPrincipal(usernameLookupStrategy.apply(input)); resCtx.getRequestedIdPAttributeNames().add("eduPersonAffiliation"); resCtx.resolveAttributes(custom); attribute = resCtx.getResolvedIdPAttributes().get("eduPersonAffiliation"); valueType = Java.type("net.shibboleth.idp.attribute.StringAttributeValue"); if (attribute != null && attribute.getValues().contains(new valueType("employee"))) { nextFlow = "authn/fudiscr"; } input.removeSubcontext(resCtx); } nextFlow; ]]> </value> </constructor-arg> </bean> </beans>
Example 4: After authentication with username and password, token-based authentication follows if the AuthenticationContextClass required by the ServiceProvider is insufficient or if the user already has at least one token. The token status is not checked. A blocked token would, for example, cause the fudiscr.UserHasTokenPredicate
to return true
. This predicate was introduced specifically for rollout scenarios.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" default-init-method="initialize" default-destroy-method="destroy"> <util:map id="shibboleth.authn.MFA.TransitionMap"> <entry key=""> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/Password"/> </entry> <entry key="authn/Password"> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlowStrategy-ref="checkSecondFactor"/> </entry> </util:map> <bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript" p:customObject-ref="fudiscr.UserHasTokenPredicate"> <constructor-arg> <value> <![CDATA[ nextFlow = "authn/fudiscr"; authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext"); if (mfaCtx.isAcceptable()) { nextFlow = null; if (custom.test(input)) { nextFlow = "authn/fudiscr"; } } nextFlow; ]]> </value> </constructor-arg> </bean> </beans>
Example 5: Optional authn/Password and authn/SPNEGO as first factor → here.
A Reuse Condition can generally be defined for authentication procedures in the Shibboleth Identity Provider.
Usually, the default value is shibboleth.Conditions.TRUE
.
Thus, the condition is always fulfilled.
Custom functions can also be defined as Reuse Conditions.
Special rules apply to multi-factor authentication. A description can be found in the official documentation under MultiFactorAuthnConfiguration.
With the following configuration in %{idp.home}/conf/authn/authn.properties
, you achieve that username and password are only requested once within a single sign-on session, but token-based authentication with fudiscr is required for each Service Provider authentication.
idp.authn.MFA.reuseCondition=shibboleth.Conditions.FALSE idp.authn.Password.reuseCondition=shibboleth.Conditions.TRUE idp.authn.fudiscr.reuseCondition=shibboleth.Conditions.FALSE
Accordingly, the MFA authentication result must not be reused, but within the multi-factor authentication, the existing successful result of the username-password authentication (Password) may be used, while the result of fudiscr may not.
idp.authn.MFA.reuseCondition=shibboleth.Conditions.FALSE
so that the logic in ./conf/authn/mfa-authn-config.xml
is executed for each authentication request. In the reuse case, for example, with an existing SSO session, it is not checked whether a user belongs to a specific affiliation.mfaCtx.isAcceptable()
in connection with Reuse Conditions. This function does not consider Reuse Conditions. If a requested AuthenticationContextClass has been previously fulfilled, the function returns true
.
<?xml version="1.0" encoding="UTF-8"?> <beans ...> ... <!-- For example, if a second factor is requested with 'urn:de:zedat:fudis:SAML:2.0:ac:classes:CR', it will be requested for the first Service Provider. If 'idp.authn.MFA.reuseCondition=shibboleth.Conditions.FALSE' is set, 'checkSecondFactor' is always executed for additional Service Providers. However, the function 'mfaCtx.isAcceptable()' returns 'true' for subsequent Service Providers and the second factor is not requested again. 'idp.authn.fudiscr.reuseCondition' is therefore ineffective at this point. --> <bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"> <constructor-arg> <value> <![CDATA[ nextFlow = "authn/fudiscr"; authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext"); if (mfaCtx.isAcceptable()) { nextFlow = null; } nextFlow; ]]> </value> </constructor-arg> </bean> ... </beans>
The following example extends the previous example and forces the call of the second factor with fudiscr when it is requested via AuthenticationContextClass 'urn:de:zedat:fudis:SAML:2.0:ac:classes:CR'.
<?xml version="1.0" encoding="UTF-8"?> <beans ...> ... <!-- (The following extended logic can also be represented differently.) If 'urn:de:zedat:fudis:SAML:2.0:ac:classes:CR' is requested, then 'fudiscr' is always executed and the Reuse Condition 'idp.authn.fudiscr.reuseCondition' is evaluated. With 'idp.authn.fudiscr.reuseCondition=shibboleth.Conditions.FALSE', a token is requested for each Service Provider that requires a second factor. With 'idp.authn.fudiscr.reuseCondition=shibboleth.Conditions.TRUE', there is no difference in the login behavior for users compared to the previous example. --> <bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"> <constructor-arg> <value> <![CDATA[ nextFlow = "authn/fudiscr"; authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext"); if (mfaCtx.isAcceptable()) { AuthnContextClassRefPrincipal = Java.type("net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal"); refPrincipal = new AuthnContextClassRefPrincipal("urn:de:zedat:fudis:SAML:2.0:ac:classes:CR"); rpCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.RequestedPrincipalContext"); if (rpCtx == null || !rpCtx.getRequestedPrincipals().contains(refPrincipal)) { nextFlow = null; } } nextFlow; ]]> </value> </constructor-arg> </bean> ... </beans>
When 'ForceAuthn' is requested via SAML, the function mfaCtx.isAcceptable()
always returns false
.
Each authentication method in the Shibboleth Identity Provider is based on an abstract Flow with an AuthenticationFlowDescriptor, see AuthenticationConfiguration.
The properties of the AuthenticationFlowDescriptor are usually set for all flows in %{idp.home}/conf/authn/authn.properties
. As a template, these are commented out in %{idp.home}/conf/authn/fudiscr.properties
to be provided after plugin installation:
#idp.authn.fudiscr.order=1000 #idp.authn.fudiscr.nonBrowserSupported=true #idp.authn.fudiscr.passiveAuthenticationSupported=true #idp.authn.fudiscr.forcedAuthenticationSupported=true #idp.authn.fudiscr.proxyRestrictionsEnforced=%{idp.authn.fudiscr.forcedAuthenticationSupported:true} #idp.authn.fudiscr.proxyScopingEnforced=false #idp.authn.fudiscr.discoveryRequired=false #idp.authn.fudiscr.lifetime=%{idp.authn.defaultLifetime:PT1H} #idp.authn.fudiscr.inactivityTimeout=%{idp.authn.defaultTimeout:PT30M} #idp.authn.fudiscr.reuseCondition=shibboleth.Conditions.TRUE #idp.authn.fudiscr.activationCondition=shibboleth.Conditions.TRUE #idp.authn.fudiscr.subjectDecorator= #idp.authn.fudiscr.errorMessageFunction = DefaultPasswordErrorFunction #idp.authn.fudiscr.genericMessageID = authn #idp.authn.fudiscr.addDefaultPrincipals=true #idp.authn.fudiscr.trimUsernamePrincipal=true #idp.authn.fudiscr.lowercaseUsernamePrincipal=false #idp.authn.fudiscr.uppercaseUsernamePrincipal=false #idp.authn.fudiscr.supportedPrincipals= \ # saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR
'idp.authn.fudiscr.supportedPrincipals' was already introduced in https://doku.tid.dfn.de/de:shibidp:plugin-fudiscr#mfa-konfiguration.
If you maintain an IdP configuration from before version 4.1.0, please ensure that the file %{idp.home}/conf/idp.properties
contains the following line at the beginning so that all .properties
files below the %{idp.home}/conf
folder (such as %{idp.home}/conf/fudiscr.properties
) are automatically read.
idp.searchForProperties=true
With the installation of the fudiscr plugin, the configuration file %{idp.home}/conf/authn/fudiscr.properties
is created. Changes in this file usually only take effect after restarting the Identity Provider.
Additionally, the configuration file %{idp.home}/conf/authn/fudiscr.xml
is created. The configuration beans contained in this file are managed by the ReloadableService mechanism of the Shibboleth Identity Provider (see also ReloadableServices).
The service can be reloaded as follows:
%{idp.home}/bin/reload-service.sh -id fudiscr.ConfigurationBeansService
Alternatively, the reload can be triggered by directly calling the URL and avoids errors from the wrapper in reload-service.sh
.
GET http(s)://[idp-base-url]/idp/profile/admin/reload-service?id=fudiscr.ConfigurationBeansService
Similar to the parameters for other ReloadableServices from the Shibboleth Identity Provider, the following exist for the fudiscr plugin:
fudiscr.service.failFast=false fudiscr.service.checkInterval=PT0S fudiscr.service.resources=fudiscr.ConfigurationResources
If configuration changes in %{idp.home}/conf/authn/fudiscr.xml
should be loaded automatically, set the check interval with fudiscr.service.checkInterval
. By default (PT0S), regular checking of the timestamp change of %{idp.home}/conf/authn/fudiscr.xml
is disabled.
The following general configuration options can be set via the configuration file %{idp.home}/conf/authn/fudiscr.properties
.
Option | Default Value | Description | |
---|---|---|---|
fudiscr.challengeResponseClient | EduMfaChallengeResponseClient | This option determines which token backend should be addressed. Since version 2.1.0, the default value is EduMfaChallengeResponseClient , previously PrivacyIdeaChallengeResponseClient . There is also the possibility to use a PrivacyIdeaChallengeResponseClient that works without a backend and writes all information as DEBUG messages to the log files when starting the IdP. | |
fudiscr.default_users_realm | empty | If no realm can be determined from the username, this option can be used to set a realm that will be added when missing in the fudiscr plugin. In most cases, no realm is needed, so by default no realm is added. | |
fudiscr.filter_tokens.id_exclude_regex | empty | This option can be used to exclude tokens based on their ID/serial number for use in the fudiscr plugin. For example, ^HOTP.*$ ignores all HOTP tokens that were created as software tokens in privacyIDEA and received a serial number starting with HOTP. By default, the filter is not used. The regular expression is not defined. | |
fudiscr.filter_tokens.type_exclude_regex | empty | This option can be used to exclude token types for use in the fudiscr plugin. For example, ^totp$ ignores all TOTP tokens. By default, the filter is not used. The regular expression is not defined. | |
fudiscr.on_failed_restart_completely_mfa | shibboleth.Conditions.FALSE | This Predicate determines whether a restart of authentication from the fudiscr plugin only restarts the fudiscr factor in the MFA flow (default) or restarts the entire authentication. If the Predicate returns TRUE , the results of previous factors are reset. This means username and password, among others, will be requested again. | |
fudiscr.max_retries | 10 | Number of failed attempts for validation. When this value is reached, validation ends unsuccessfully. This value is independent of the allowed failed attempts in privacyIDEA. If only the error counters from privacyIDEA should take effect, it is recommended to increase the value for fudiscr.max_retries accordingly (> max. failcounter in privacyIDEA). | |
fudiscr.restart_allowed.max_retries_exceeded | shibboleth.Conditions.TRUE | This Predicate determines whether a restart of authentication in the fudiscr plugin is allowed when fudiscr.max_retries is reached. | |
fudiscr.restart_allowed.selected_tokens_not_available | shibboleth.Conditions.TRUE | This Predicate determines whether a restart of authentication in the fudiscr plugin is allowed when the tokens selected by users are no longer available (e.g., due to being blocked in privacyIDEA). | |
fudiscr.restart_allowed.within_response_page | shibboleth.Conditions.TRUE | This Predicate determines whether restarting fudiscr authentication is allowed via the response input page (OTP, TAN, etc.). | |
fudiscr.result_idp_attribute_principal_attribute_name | empty | If an attribute name is specified with this option, an IdpAttributePrincipal with this attribute name is added to the successful authentication result of the fudiscr plugin. The attribute value contains the ID/serial number of the token used for authentication. | |
fudiscr.result_idp_attribute_principal_attribute_name_for_token_type | empty | If an attribute name is specified with this option, an IdpAttributePrincipal with this attribute name is added to the successful authentication result of the fudiscr plugin. The attribute value contains the token type of the token used for authentication. | |
fudiscr.result_with_realm_in_username_principal | shibboleth.Conditions.FALSE | When a UsernamePrincipal is generated with fudiscr.result_with_username_principal , this Predicate determines whether the realm is included. TRUE (default) generates e.g., dummy@fu-berlin.de, FALSE only generates dummy as username. | |
fudiscr.result_with_username_principal | shibboleth.Conditions.TRUE | This Predicate determines whether a UsernamePrincipal is added to the Subject after successful authentication. By default, the authentication result contains a UsernamePrincipal after successful authentication with the fudiscr plugin. | |
fudiscr.username_realm_split_regex | @ | A username is generated from a previous factor during authentication. This can also contain a realm, e.g., dummy@fu-berlin.de. This option sets the separator used to split the username and realm. The default value is @ | |
fudiscr.user_token_selection | none | This option determines whether tokens can be selected by users. Possible values are: none =no selection, singleToken =selection of a single token (by ID/serial number), multipleToken =selection of multiple tokens (by serial number), singleTokenTypeGroup =selection of a single token type (e.g., totp), multipleTokenTypeGroup =selection of multiple token types. By default (none ), a challenge is generated for all active tokens. |
Tokens can be filtered based on properties such as token ID/serial number, status, type, and others. Additionally, properties from SAML or OIDC requests can be used for filtering. These include, for example, the entityID of the Service Provider, the Authentication Context Class, or the user's IP address.
Generally, tokens can be excluded based on their type or ID/serial number using the (above-mentioned) configuration options fudiscr.filter_tokens.type_exclude_regex
and fudiscr.filter_tokens.id_exclude_regex
in %{idp.home}/conf/authn/fudiscr.properties
.
fudiscr.filter_tokens.type_exclude_regex=^(sms|web_authn)$
In this example, all SMS and WebAuthn tokens are filtered out.
fudiscr.filter_tokens.id_exclude_regex=^(OATH|TOTP).+$
In this example, all tokens with the prefix OATH or TOTP in their serial number are filtered out. This affects all HOTP and TOTP tokens in eduMFA and privacyIDEA.
Advanced exclusion conditions can be defined in %{idp.home}/conf/authn/fudiscr.xml
. The conditions are combined in the list fudiscr.ExcludeTokenPredicates
and processed sequentially.
<util:list id="fudiscr.ExcludeTokenPredicates"> <ref bean="fudiscr.ExcludeTokenPredicate1"/> <ref bean="fudiscr.ExcludeTokenPredicate2"/> <ref bean="fudiscr.ExcludeTokenPredicate3"/> <!-- etc. --> </util:list>
This example shows how the exclusion list is generally defined.
The exclusion conditions can be formulated as Scripted or using Regular Expressions related to token properties.
<util:list id="fudiscr.ExcludeTokenPredicates"> <ref bean="fudiscr.ScriptedExcludeTokenPredicateExample1"/> </util:list> <!-- Input1: profileRequestContext (org.opensaml.profile.context.ProfileRequestContext) --> <!-- Input2: token (de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.domain.Token) --> <!-- Output -> java.lang.Boolean / boolean --> <bean id="fudiscr.ScriptedExcludeTokenPredicateExample1" parent="fudiscr.Functions.ScriptedExcludeTokenPredicate" factory-method="inlineScript"> <constructor-arg> <value> <![CDATA[ // default is to keep the token exclude = false; relyingPartyId = profileContext.getSubcontext("net.shibboleth.profile.context.RelyingPartyContext").getRelyingPartyId(); // if the service provider is not 'https://portal.local/shibboleth', tokens that are of type 'registration_code' are excluded if (!relyingPartyId.equals("https://portal.local/shibboleth") && token.getType().toString().equalsIgnoreCase("registration_code")) { exclude = true; } exclude; ]]> </value> </constructor-arg> </bean>
<util:list id="fudiscr.ExcludeTokenPredicates"> <ref bean="fudiscr.RegexExcludeTokenPredicateExample1"/> <ref bean="fudiscr.RegexExcludeTokenPredicateExample2"/> </util:list> <bean id="fudiscr.RegexExcludeTokenPredicateExample1" class="de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.function.impl.RegexExcludeTokenPropertiesPredicate" c:propertyName="rollout_state" c:excludePattern="^verify$"/> <bean id="fudiscr.RegexExcludeTokenPredicateExample2" class="de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.function.impl.RegexExcludeTokenPropertiesPredicate" c:propertyName="rollout_state" c:excludePattern="^clientwait$"/>
In this example, tokens are filtered based on a token property. In eduMFA and privacyIDEA, active tokens can exist that require initial validation before they can be effectively used. For example, it should be enforced that users scan the QR code with the authenticator when setting up a TOTP token and confirm this process with an OTP. Until confirmation, the tokens have the property rollout_state with the values verify or clientwait. The two predicates used in the example can also be represented with one predicate and the regular expression ^(clientwait|verify)$. The example is only meant to illustrate the list property of fudiscr.ExcludeTokenPredicates
.
(The constructor parameter c:negateResult=“true”
can be used to negate the result of an ExcludeTokenPredicate.)
The bean 'fudiscr.UserHasTokenPredicate' provides a function to determine whether users have generally been set up for the second factor or for a token procedure. This function can be particularly useful during the rollout phase. However, the decision whether users are activated for a second factor can also be controlled through groups in an LDAP directory service. This function also offers the previously mentioned filtering options via beans in '%{idp.home}/conf/authn/fudiscr.xml'. The filter list used has the id 'fudiscr.UserHasTokenExcludeTokenPredicates'. If the filter lists 'fudiscr.ExcludeTokenPredicates' and 'fudiscr.UserHasTokenExcludeTokenPredicates' should be identical, an alias can be defined for 'fudiscr.UserHasTokenExcludeTokenPredicates':
<alias name="fudiscr.ExcludeTokenPredicates" alias="fudiscr.UserHasTokenExcludeTokenPredicates"/>
Equivalent to the filters 'fudiscr.ExcludeTokenPredicates' and 'fudiscr.UserHasTokenExcludeTokenPredicates', a filter can be defined that filters out a user's preferred tokens. If the exclude filter list 'fudiscr.PreferredExcludeTokenPredicates' is defined, only the preferred tokens will be used initially. If the filtering results in all tokens being excluded, the filtering is reset. If the filtering reduces the initial list, users will be offered a button on the token selection page and the response input page to access the complete token selection. If selection by users is no longer necessary after filtering with 'fudiscr.PreferredExcludeTokenPredicates', the challenge is generated immediately. For example, if filtering results in only TOTP tokens remaining and 'fudiscr.user_token_selection=singleTokenTypeGroup' is configured, a challenge for the TOTP tokens is immediately triggered and the response input page is displayed. However, users will still have the option to select other token methods as mentioned before.
<util:list id="fudiscr.PreferredExcludeTokenPredicates"> <bean class="de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.function.impl.RegexExcludeTokenPropertiesPredicate" c:propertyName="info:fudis_preferred" c:excludePattern="^(?i)no$" p:defaultValueForMissingProperty="no"/> <bean class="de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.function.impl.RegexExcludeTokenPropertiesPredicate" c:propertyName="type" c:excludePattern="^totp$" c:negateResult="true"/> </util:list>
This example filters out all tokens that do not have the token info attribute 'fudis_preferred' with the value 'true' (case-insensitive) and are not of type 'totp'. 'p:defaultValueForMissingProperty=“no”' causes the RegexExcludeTokenPropertiesPredicate to return no when a token (info) attribute is missing. Please note that 'c:negateResult=“true”' turns an exclude into an include. In this example, unlike the previous filter examples, the beans are defined directly in the list and not as references.
It can happen that users are distributed across multiple data sources in Identity Management. For example, students and employees might be managed in two separate LDAP servers. This in turn means that two realms must be created in eduMFA or privacyIDEA, and these realms must be distinguished in API requests. For the User object in the fudiscr plugin, the following logic is followed to determine the realm:
- Using the Java class 'net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy', the username is first determined from the previous authentication results according to Shibboleth standard. - Using 'fudiscr.username_realm_split_regex', an attempt is made to separate the realm as a separate attribute from the username. - If a list 'fudiscr.UserRealmTransformationStrategies' with realm transformation strategies is defined in '%{idp.home}/conf/authn/fudiscr.xml', these strategies are processed in the listed order. - If no realm exists yet, a default realm is assigned if it has been defined with 'fudiscr.default_users_realm'. The realm determined in this way is used by all classes in the fudiscr plugin that process a User object.
If the realm in the User object from the fudiscr plugin is not defined (null), then a realm for the API request can be added with 'fudiscr.edumfa.default_realm' against eduMFA or with 'fudiscr.privacyidea.default_realm' against privacyIDEA. However, the realm added in this way is not incorporated into the general User object from the fudiscr plugin!
<util:list id="fudiscr.UserRealmTransformationStrategies"> <!-- The attribute specified under 'ldapAttributeName' must also be included in the list of 'idp.authn.LDAP.returnAttributes'. --> <bean class="de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.function.impl.UserRealmFromLdapPrincipalTransformationStrategy" p:activeAuthenticationResultKey="authn/Password" p:ldapAttributeName="realm"/> <!-- For ScriptedUserRealmTransformationStrategy: --> <!-- Input1: profileRequestContext (org.opensaml.profile.context.ProfileRequestContext) --> <!-- Input2: currentUserRealm (java.lang.String) --> <!-- Output -> java.lang.String --> <bean class="de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.function.impl.ScriptedUserRealmTransformationStrategy" factory-method="inlineScript"> <constructor-arg> <value> <![CDATA[ newUserRealm = null; if (currentUserRealm == null) { newUserRealm = "idp-users"; } newUserRealm; ]]> </value> </constructor-arg> </bean> </util:list>
In this example, it checks whether an LdapPrincipal exists in the active authentication result from the authentication with username and password (authn/Password) and whether this LdapPrincipal contains the attribute realm. The first value from realm is adopted as the realm. Subsequently, a Scripted strategy is applied.
The REFEDS Assurance Framework defines, among other things, profiles for multi-factor authentication. Generally, Service Providers can require properties via Authentication Context Class that only apply to specific tokens. Filtering of matching tokens is possible with fudiscr.ExcludeTokenPredicates
, but this filtering is not helpful when determining whether an authentication result in an SSO session can be used for another Service Provider.
Authentication Context Classes are mapped as Principals in the Shibboleth Identity Provider. Each authentication method has the properties idp.authn.<flowid>.supportedPrincipals
and idp.authn.<flowid>.addDefaultPrincipals
(Default: true). The idp.authn.<flowid>.supportedPrincipals
determine whether the respective authentication method matches the requested Authentication Context Class. With idp.authn.<flowid>.addDefaultPrincipals=true
, the idp.authn.<flowid>.supportedPrincipals
are added to the authentication result.
The list bean fudiscr.SubjectCustomizers
allows modifying the Principals for the Authentication Context Class.
Additionally, two functions are offered as Reuse-Conditions.
fudiscr.FlowSpecificRequestedPrincipalsReuseCondition
requires the single (second) factor again if the existing Authentication Context Classes are insufficient. fudiscr.GeneralRequestedPrincipalsReuseCondition
requires all factors if the existing Authentication Context Classes are insufficient.
The following example shows the interaction of the configuration elements.
In %{idp.home}/conf/authn/authn.properties
, the supportedPrincipals
are defined for the authentication procedure fudiscr
:
idp.authn.fudiscr.supportedPrincipals= \ saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR, \ saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:LOW, \ saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:HIGH
For the MFA flow, all supportedPrincipals must be defined that are covered by the individual factors used in total. If the first factor consists of the usual query for user name and password (flowid=password), then the entry in %{idp.home}/conf/authn/authn.properties
should look like this:
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, \ saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:LOW, \ saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:HIGH
A subject customizer is now defined in %{idp.home}/conf/authn/fudiscr.xml
, which always adds the authentication context class saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR
for fudiscr
. Depending on the properties of the successfully used token, either only saml2/urn:de:zedat:fudis:SAML:2. 0:ac:classes:CR:IAP:LOW
or saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:LOW
and saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:HIGH
are added.
<util:list id="fudiscr.SubjectCustomizers"> <ref bean="fudiscr.ScriptedAuthenticationMethodAndContextPrincipalsTokenBasedSubjectCustomizer"/> </util:list> <bean id="fudiscr.ScriptedAuthenticationMethodAndContextPrincipalsTokenBasedSubjectCustomizer" parent="fudiscr.Functions.ScriptedAuthenticationMethodAndContextPrincipalsSubjectCustomizer" factory-method="inlineScript"> <constructor-arg> <value> <![CDATA[ var logger = Java.type( "org.slf4j.LoggerFactory" ).getLogger("fudiscr.ScriptedAuthenticationMethodAndContextPrincipalsSubjectCustomizer"); logger.trace("Input 1, principals: '{}'", principals); logger.trace("Input 2, token: '{}'", token) var HashSet = Java.type("java.util.HashSet"); var newPrincipals = new HashSet(); var AuthnContextClassRefPrincipal = Java.type("net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal"); var standardPrincipal = new AuthnContextClassRefPrincipal("urn:de:zedat:fudis:SAML:2.0:ac:classes:CR"); newPrincipals.add(standardPrincipal); if (token.getProperties().get("description") != null && token.getProperties().get("description").toString().equalsIgnoreCase("IAP=high")) { var lowPrincipal = new AuthnContextClassRefPrincipal("urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:LOW"); newPrincipals.add(lowPrincipal); var highPrincipal = new AuthnContextClassRefPrincipal("urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:HIGH"); newPrincipals.add(highPrincipal); } if (token.getProperties().get("description") != null && token.getProperties().get("description").toString().equalsIgnoreCase("IAP=low")) { var lowPrincipal = new AuthnContextClassRefPrincipal("urn:de:zedat:fudis:SAML:2.0:ac:classes:CR:IAP:LOW"); newPrincipals.add(lowPrincipal); } logger.trace("Result, newPrincipals: '{}'", newPrincipals); newPrincipals; ]]> </value> </constructor-arg> </bean>
The two variants for the reuse conditions can now be set in %{idp.home}/conf/authn/authn.properties
.
Variant 1: Only the second factor is required again if the previous Authentication Context Classes are not sufficient.
idp.authn.MFA.reuseCondition=shibboleth.Conditions.FALSE idp.authn.Password.reuseCondition=shibboleth.Conditions.TRUE idp.authn.fudiscr.reuseCondition=fudiscr.FlowSpecificRequestedPrincipalsReuseCondition
Variant 2: All factors are required again if the previous Authentication Context Classes are not sufficient.
idp.authn.MFA.reuseCondition=shibboleth.Conditions.FALSE idp.authn.Password.reuseCondition=fudiscr.GeneralRequestedPrincipalsReuseCondition idp.authn.fudiscr.reuseCondition=fudiscr.GeneralRequestedPrincipalsReuseCondition
As an additional feature, a flow based on de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.domain.ChallengeResponseTokenIdPrincipal
can be activated for the SubjectCanonicalization process in the Shibboleth Identity Provider. This additional Principal generated by the fudiscr-Plugin contains the ID/serial number of the successfully used token.
To activate the flow, the reference <ref bean=“c14n/fudiscr” />
must be added to the list shibboleth.PostLoginSubjectCanonicalizationFlows
in the configuration file %{idp.home}/conf/c14n/subject-c14n.xml
.
In addition, transformation options can be specified as for other principals, e.g. in %{idp.home}/conf/c14n/subject-c14n.properties
:
idp.c14n.fudiscr.lowercase=false idp.c14n.fudiscr.uppercase=false idp.c14n.fudiscr.trim=true
Fudispasskeys provides an authentication method that integrates into the login page for username and password authentication and enables direct authentication with a security key or passkeys. The configuration is done in the following steps:
The procedure is only supported by the EduMfaChallengeResponseClient
in conjunction with eduMFA. The following property must therefore be set in %{idp.home}/conf/authn/fudiscr.properties
:
fudiscr.challengeResponseClient=EduMfaChallengeResponseClient
In addition, the Relying Party Id for WebAuthn/Passkeys must be set in %{idp.home}/conf/authn/fudiscr.properties
in accordance with the enrollment policy webauthn_relying_party_id from eduMFA:
fudispasskeys.relying_party_id=<same value here as in the enrollment policy 'webauthn_relying_party_id' in eduMFA>
To be able to access special functions in the views, the bean shibboleth.CustomViewContext
must be defined or extended in %{idp.home}/conf/global.xml
. This is a list that requires at least one entry for the fudispasskeys.ChallengeGenerationStrategy
:
<util:map id="shibboleth.CustomViewContext"> <!-- hier die bisherigen Einträge --> <entry key="fudispasskeys.ChallengeGenerationStrategy" value-ref="fudispasskeys.ChallengeGenerationStrategy" /> </util:map>
The following extensions must be made in %{idp.home}/conf/authn/authn-events-flow.xml
:
<flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd" abstract="true"> <!-- Custom error events to reflect back from user-supplied login subflows. --> <!-- <end-state id="MyCustomEvent" /> --> <end-state id="fudispasskeys" /><!-- add this for fudispasskeys --> <global-transitions> <!-- <transition on="MyCustomEvent" to="MyCustomEvent" /> --> <transition on="fudispasskeys" to="fudispasskeys" /><!-- add this for fudispasskeys --> <transition on="#{!'proceed'.equals(currentEvent.id)}" to="InvalidEvent" /> </global-transitions> </flow>
In the existing %{idp.home}/conf/authn/mfa-authn-config.xml
, the shibboleth.authn.MFA.TransitionMap
must be extended:
<util:map id="shibboleth.authn.MFA.TransitionMap"> <entry key=""> <bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/fudispasskeys"/> </entry> <entry key="authn/fudispasskeys"> <bean parent="shibboleth.authn.MFA.Transition"> <property name="nextFlowStrategyMap"> <map> <entry key="NoCredentials" value="authn/Password" /> <entry key="InvalidCredentials" value="authn/Password" /> </map> </property> </bean> </entry> <entry key="authn/Password"> <bean parent="shibboleth.authn.MFA.Transition"> <property name="nextFlowStrategyMap"> <map> <entry key="fudispasskeys" value="authn/fudispasskeys" /><!-- add this for fudispasskeys --> <entry key="proceed" value-ref="checkSecondFactor" /><!-- or the previous entry for the second factor --> </map> </property> </bean> </entry> </util:map>
In %{idp.home}/views/login.vm
the following line must be inserted outside the login form:
#parse("fudispasskeys/login-passkeys.vm")
In addition, the attribute autocomplete
with the value webauthn
can be inserted or added to the input fields for user name and password, e.g.
autocomplete="webauthn"
This means that additional passkey authentication is offered when these input fields are selected.
According to eduMFA guidelines for fudispasskeys, the following authentication and enrollment policies must be set in eduMFA:
for the scope authentication:
webauthn_user_verification_requirement = required webauthn_usernameless_authn = True
for scope enrollment:
webauthn_relying_party_id = <domain of your institution> webauthn_relying_party_name = <name of the relying party> webauthn_resident_key = required webauthn_user_verification_requirement = required
Analog zum AuthenticationFlowDescriptor für fudiscr existiert auch ein AuthenticationFlowDescriptor für fudispasskeys:
#idp.authn.fudispasskeys.order=1000 #idp.authn.fudispasskeys.nonBrowserSupported=true #idp.authn.fudispasskeys.passiveAuthenticationSupported=true #idp.authn.fudispasskeys.forcedAuthenticationSupported=true #idp.authn.fudispasskeys.proxyRestrictionsEnforced=%{idp.authn.fudispasskeys.forcedAuthenticationSupported:true} #idp.authn.fudispasskeys.proxyScopingEnforced=false #idp.authn.fudispasskeys.discoveryRequired=false #idp.authn.fudispasskeys.lifetime=%{idp.authn.defaultLifetime:PT1H} #idp.authn.fudispasskeys.inactivityTimeout=%{idp.authn.defaultTimeout:PT30M} #idp.authn.fudispasskeys.reuseCondition=shibboleth.Conditions.TRUE #idp.authn.fudispasskeys.activationCondition=shibboleth.Conditions.TRUE #idp.authn.fudispasskeys.subjectDecorator= #idp.authn.fudispasskeys.errorMessageFunction = DefaultPasswordErrorFunction #idp.authn.fudispasskeys.genericMessageID = authn #idp.authn.fudispasskeys.addDefaultPrincipals=true #idp.authn.fudispasskeys.trimUsernamePrincipal=true #idp.authn.fudispasskeys.lowercaseUsernamePrincipal=false #idp.authn.fudispasskeys.uppercaseUsernamePrincipal=false #idp.authn.fudispasskeys.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
To obtain detailed logging information from the fudiscr-Plugin, the following line can be added to %{idp.home}/conf/logback.xml
:
<logger name="de.fu.dis" level="DEBUG"/> <logger name="de.zedat.fudis" level="DEBUG"/>
If all API requests against privacyIDEA are to be logged separately, the following additional configuration is suggested:
<logger name="de.fu.dis.rest.interceptors" level="TRACE"> <appender-ref ref="IDP_FUDIS_REQUEST"/> </logger> <logger name="de.zedat.fudis.rest.interceptors" level="TRACE"> <appender-ref ref="IDP_FUDIS_REQUEST"/> </logger> <logger name="de.fu.dis.edumfa.client" level="WARN"> <appender-ref ref="IDP_FUDIS_REQUEST"/> </logger> <logger name="de.zedat.fudis.privacyidea.client" level="WARN"> <appender-ref ref="IDP_FUDIS_REQUEST"/> </logger> <!-- FUDIS-Interceptor log. --> <appender name="IDP_FUDIS_REQUEST" class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>${idp.logfiles}/idp-fudis-request.log</File> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${idp.logfiles}/idp-request-%d{yyyy-MM-dd}.log.gz</fileNamePattern> <maxHistory>${idp.loghistory}</maxHistory> </rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <charset>UTF-8</charset> <Pattern>%msg%n</Pattern> </encoder> </appender>
The Fortinet extension currently supports the token types FortiToken (Mobile and Hardware), SMS and Email. FIDO2 (WebAuthn) is currently not supported by the FortiAuthenticator API.
The extension is available under the Apache 2.0 License and is provided by DAASI International GmbH here. DAASI also offers software maintenance contracts for the extension. Please send inquiries to info@daasi.de.
Universities and other public institutions can get access to the source code upon request. Please send an email to fudis@fu-berlin.de. Work is in progress to publish all components of the fudiscr-Plugin under the Apache 2.0 License. We ask for (continued) patience.
Please send bugs, questions, suggestions etc. via email to fudis@fu-berlin.de.