IdP-Authn-Plugin fudiscr

Das Plugin kann als weiterer Faktor für die Multi-Faktor-Authentifizierung (MFA) vom Shibboleth Identity Provider (IdP) verwendet werden. Es unterstützt tokenbasierte Authentifizierungen und folgt im Kern dem Challenge-Response-Pattern. Aus einem der vorherigen Faktoren in der MFA-Abfolge muss als Basis ein Benutzername ermittelt werden. Ein häufiger Fall ist eine vorangestellte Authentifizierung mit Benutzer und Passwort gegen LDAP mit dem authn/Password-Flow.

Das Plugin besitzt selbst keine Funktionen zur Verwaltung von Token. Es enthält auch selbst keine speziellen Algorithmen zur Validierung von Token. Über ein generisches ChallengeResponseClientInterface kann ein Token-System angebunden werden. Das Plugin enthält bereits eine Implementierung dieses Interfaces für privacyIDEA. Zudem ist eine Mockup-Implementierung für Tests enthalten. Eine externe Implementierung für Fortinet existiert auch bereits.

Die primären Entwicklungsarbeiten wurden von Steffen Hofmann von der Freien Universität Berlin durchgeführt. Er ist Mitarbeiter des Rechenzentrums (FUB-IT Infrastruktur) und zuständig für den Bereich Identity Management. Das Identity Management System der Freien Universität Berlin trägt den Namen FUDIS (FU Directory and Identity Service). Aus diesem Grund wird für das Challenge-Response-Plugin in Konfigurationsparametern u.a. das Kürzel fudiscr verwendet.

Mit der Version 1.4.0 erfolgt eine Zusammenarbeit im Bereich FIDO2/WebAuthn mit der Hochschule München. Die Pflege des Plugins erfolgt mit dieser Version in Kooperation der Freien Universität Berlin und der Hochschule München.

Plugin-Version IdP-Version privacyIDEA-Version Support-Level
1.0.0 min. 4.1.2 und < 4.3.0 min. 3.7 nicht mehr verwenden
1.1.0 min. 4.1.2 und < 4.3.0 min. 3.7 nicht mehr verwenden
1.1.1 min. 4.1.2 und < 4.3.0 min. 3.7 nicht mehr verwenden
1.2.0 min. 4.1.2 und < 4.3.0 min. 3.7 nicht mehr verwenden
1.3.0 min. 4.3.0 und < 5.0.0 min. 3.7 nicht mehr verwenden
1.4.0 min. 4.3.0 und < 5.0.0 min. 3.9 aktuell
2.0.0 min. 5.0.0 und < 5.1.0 min. 3.9 aktuell
2.1.0 min. 5.1.0 min. 3.9 aktuell

Aktuell werden die folgenden Tokenverfahren aus privacyIDEA (Token types in privacyIDEA) unterstützt:

Tokenverfahren Typbezeichnung im Plugin min. Plugin-Version Einschränkungen / Hinweise
Email mail 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 Es darf nur eine Antwort per Richtlinie verlangt werden.
Registration registration_code 1.3.0
Remote referenzierter Tokentyp 1.3.0 Nur referenzierte Token vom Typ Email, HOTP Token, mOTP Token, Paper Token (PPR), Registration, SMS Token, TAN Token, TOTP, Yubico und Yubikey werden unterstützt.
SMS Token sms 1.0.0
TAN Token tan 1.0.0
TOTP totp 1.0.0
WebAuthn web_authn 1.2.0 bei Version 1.2.0 nur mit Konfigurationsoption fudiscr.privacyidea.single_trigger_challenges=false, ab Version 1.3.0 siehe Richtlinie und Event ab Version 1.3.0
Yubico yubico_otp 1.3.0
Yubikey yubikey_aes 1.3.0

Einrichtung eines Funktionsnutzers in privacyIDEA

Das Shibboleth-Plugin kommuniziert mit privacyIDEA über dessen API. Es werden drei Endpunkte verwendet:

  • /token/ (Abrufen einer Liste von Tokens)
  • /validate/triggerchallenge (Initiieren einer Token-Challenge)
  • /validate/check (Überprüfen eines OTP ggf. in Kombination mit einer PIN)

Ein Nutzer muss also über die Berechtigungen verfügen, die Aktionen, die bei Aufruf dieser Endpunkte ausgelöst werden, ausführen zu dürfen. Am besten sollte dieser Nutzer über keine weiteren Rechte verfügen.

Anlegen eines Admin-Nutzers

Achtung: Wir gehen davon aus, das der initiale Admin-Supernutzer admin vorhanden ist. Zunächst muss ein Admin-Nutzer für den Zugriff vom Identity Provider angelegt werden. Es empfiehlt sich, hierfür auch einen eigenen (administrativen) Realm anzulegen, um Berechtigungen für unterschiedliche Arten von Admin später besser trennen zu können. Der anzulegende Nutzer kann dann aus einer beliebigen externen Quelle kommen und über einen in privacyIDEA definierten Resolver importiert werden.

Das Anlegen von Realms und Resolvern ist nicht Thema dieser Anleitung. Wir legen hier jedoch der Einfachheit und Anschaulichkeit wegen einen PrivacyIDEA-internen IdP-Admin-Nutzer an.

pi-manage admin add idp-admin

Um die Anzahl an API-Anfragen zu reduzieren, sollte für den idp-admin anstelle von Benutzernamen und Passwort ein Token für den Zugriff erzeugt werden. Dieser Token kann mit einer beliebigen Gültigkeitsdauer in Tagen (default 365) versehen werden. Das nachfolgende Beispiel legt eine Gültigkeitsdauer von zehn Jahren fest:

pi-manage api createtoken -r admin -u idp-admin -d 3650


Vergeben der Berechtigungen

Die notwendigen Berechtigungen werden via Policy in privacyIDEA eingetragen.

Achtung: Admins in privacyIDEA haben zu Beginn Rechte für alle Aktionen. Dies gilt solange, wie keine Admin-Policy definiert ist. Definiert man eine Policy im Scope 'admin', so gelten für alle Admins nur noch die den Policies eingetragenen Rechte. Sollte es noch keine weitere Admin-Policy geben, sollte man daher darauf achten, sich nicht selbst aus dem Web-UI auszusperren.

Zunächst wird mit der Richtlinien-Vorlage superuser die funktionserhaltende Richtlinie für den Admin-Supernutzer erstellt, und der Nutzer admin zugewiesen.

Anschließend wird nun eine neue Policy für den Nutzer idp-admin erstellt.

Hierfür wird eine neue Datei idp-admin-policy erstellt, welche die Parameter der Policy als Python-Dictionary enthält. Der Inhalt sollte wie folgt aussehen:

idp-admin-policy
{   'policy': [   
      {
        'action': {'tokenlist':True, 'triggerchallenge':True},
        'active': True,
        'adminuser': ['idp-admin'],
        'name': 'idp-admin-policy',
        'scope': 'admin'
      }
   ]
}

Die Policy kann unter Nutzung dieser Datei erstellt werden:

pi-manage policy p_import -f idp-admin-policy


Zusätzliche Richtlinie ab fudiscr-Version Version 1.3.0

Das fudiscr-Plugin benötigt für bestimmte Tokenverfahren wie WebAuthn und zur Reduzierung von API-Anfragen das Recht, für /validate/triggerchallenge auf Tokentypen einschränken zu können.

Hierfür wird eine neue Datei idp-application-tokentype erstellt, welche die Parameter der Policy als Python-Dictionary enthält. Der Inhalt sollte so aussehen:

idp-application-tokentype
{   'policy': [
      {
        'action': {
          'application_tokentype': True
        },
        'active': True,
        'name': 'idp-application-tokentype',
        'scope': 'authorization'
      }
   ]
}

Die Policy kann unter Nutzung dieser Datei erstellt werden:

pi-manage policy p_import -f idp-application-tokentype


Event ab fudiscr-Version 1.3.0

Tests mit privcyIDEA haben ergeben, dass aufgrund eines Features/Bugs in Verbindung mit der zuvor genannten Policy idp-application-tokentype der Parameter webauthn_allowed_transports per Event gesetzt werden muss.

Hierfür wird eine neue Datei idp-webauthn-allowed-transports erstellt, welche die Parameter des Events als Python-Dictionary enthält. Der Inhalt sollte so aussehen:

idp-webauthn-allowed-transports
{   'event': [
      {
        'action': 'set',
        'active': True,
        'conditions': {
          'tokentype': 'webauthn'
        },
        'event': [
          'validate_triggerchallenge'
        ],
        'handlermodule': 'RequestMangler',
        'name': 'idp-webauthn-allowed-transports',
        'options': {
          'parameter': 'webauthn_allowed_transports',
          'value': 'usb ble nfc internal'
        },
        'position': 'pre'
      }
   ]
}

Das Event kann unter Nutzung dieser Datei erstellt werden:

pi-manage event e_import -f idp-webauthn-allowed-transports

Achtung: Wenn per Policy der Wert webauthn_allowed_transports angepasst wird, dann sollte auch passend dazu das Event angepasst werden.

Weitere Konfigurationsempfehlung

Damit möglichst viele WebAuthn-Token funktionieren und auch Passkey via QR-Code im Browser funktioniert, wird folgende weitere Richtlinie (Datei webauthn-enrollment) empfohlen:

webauthn-enrollment
{   'policy': [
      {
        'action': {
          'webauthn_authenticator_attestation_form': 'indirect',
          'webauthn_authenticator_attestation_level': 'none'
        },
        'active': True,
        'name': 'webauthn-enrollment',
        'scope': 'enrollment',
      }
   ]
}

Die Policy kann unter Nutzung der Datei (webauthn-enrollment) erstellt werden:

pi-manage policy p_import -f webauthn-enrollment

Die die für WebAuthn notwendigen Enrollment Parameter webauthn_relying_party_id und webauthn_relying_party_name können mit dieser oder einer separaten Richtlinie definiert werden. Allgemein gilt, dass die Domain des Identity Providers entweder identisch mit webauthn_relying_party_id oder eine Subdomain von webauthn_relying_party_id sein muss. (Es findet keine Vorabfilterung statt, ob die Domain des Identity Providers mit der webauthn_relying_party_id des WebAuthn-Token verträglich ist.)

Das fudiscr-Plugin benötigt das MFA-Modul. Dieses sollte wie folgt aktiviert werden:

%{idp.home}/bin/module.sh -e idp.authn.MFA

Mit dem MFA-Modul wird auch die Konfigurationsdatei, %{idp.home}/conf/authn/mfa-authn-config.xml abgelegt.

(siehe auch Shibboleth-IdP MultiFactorAuthnConfiguration)

Die Installation sowie Updates erfolgen über den Shibboleth Plugin-Mechanismus (siehe offizielle Dokumentation PluginInstallation)

Achtung: Der Shibboleth Identity Provider führt nach einer Plugin-Installation automatisch einen Neustart durch.

Mit dem folgenden Aufruf wird das Plugin installiert und aktiviert:

%{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

Zukünftige Updates werden automatisch mit dem folgendem Kommando installiert:

%{idp.home}/bin/plugin.sh -u de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr

Für ein vollautomatische Installation können die PGP-Keys vorab heruntergeladen und bei der Installation mit angeben werden:

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


Installation der Testversion 1.4.0

Mit dem folgenden Aufruf kann die aktuelle Testversion des Plugins installiert und aktiviert werden:

%{idp.home}/bin/plugin.sh -i https://identity.fu-berlin.de/downloads/shibboleth/idp/plugins/authn/fudiscr/1.3.0/fudis-shibboleth-idp-plugin-authn-fudiscr-1.3.0.tar.gz

Für ein Update auf die aktuelle Testversion ist folgender Aufruf zu verwenden:

%{idp.home}/bin/plugin.sh -u de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr -fu 1.4.0

Hinweis zu älteren IdP-Konfigurationen

Wenn Sie eine IdP-Konfiguration von vor Version 4.1.0 weiterpflegen, achten Sie bitte darauf, dass die Datei %{idp.home}/conf/idp.properties zu Beginn die folgende Zeile enthält, damit automatisch alle .properties-Dateien unterhalb des %{idp.home}/conf-Ordners (wie z.B. %{idp.home}/conf/fudiscr.properties) eingelesen werden.

idp.searchForProperties=true


Konfigurationsdateien

Mit der Installation des fudiscr-Plugins wird die Konfigurationsdatei %{idp.home}/conf/authn/fudiscr.properties abgelegt. Änderungen in dieser Datei werden in der Regel erst mit einem Neustart des Identity Providers wirksam.

ab Version 1.3.0

Ab der Version 1.3.0 wird zusätzlich die Konfigurationsdatei %{idp.home}/conf/authn/fudiscr.xml abgelegt. Die in dieser Datei enthaltenen Konfigurations-Beans werden über den ReloadableService-Mechanismus vom Shibboleth Identity Provider verwaltet (siehe auch ReloadableServices).

Der Service kann wie folgt neu geladen werden:

%{idp.home}/bin/reload-service.sh -id fudiscr.ConfigurationBeansService

Alternativ kann der Reload durch direkten Aufruf der URL ausgelöst werden und vermeidet Fehler durch den Wrapper in relaod-service.sh.

GET http(s)://[idp-base-url]/idp/profile/admin/reload-service?id=fudiscr.ConfigurationBeansService

Analog zu den Parametern für die anderen ReloadableServices vom Shibboleth Identity Provider existieren die nachfolgenden für das fudiscr-Plugin:

fudiscr.service.failFast=false
fudiscr.service.checkInterval=PT0S
fudiscr.service.resources=fudiscr.ConfigurationResources

Sollen Konfigurationsänderungen in %{idp.home}/conf/authn/fudiscr.xml automatisch geladen werden, so ist das Prüfintervall mit fudiscr.service.checkInterval zu setzen. Per Default (PT0S) ist die regelmäßige Prüfung der Veränderung des Zeitstempels von %{idp.home}/conf/authn/fudiscr.xml deaktiviert.

Allgemeine Konfigurationsoptionen

Folgende allgemeine Konfigurationsoptionen können über die Konfigurationsdatei %{idp.home}/conf/authn/fudiscr.properties gesetzt werden.

OptionDefault-WertBeschreibung
fudiscr.username_realm_split_regex@Aus einem vorherigen Faktor wird bei der Authentifizierung ein Benutzername erzeugt. Dieser kann auch einen Realm enthalten, z.B. dummy@fu-berlin.de. Mit dieser Option wird das Trennzeichen festgelegt, anhand dessen die Auftrennung in Benutzernamen und Realm erfolgt. Der Defaultwert ist @
fudiscr.default_users_realmleer
fudiscr.filter_tokens.type_exclude_regexleerMit dieser Option können Tokentypen für die Verwendung im fudiscr-Plugin ausgeschlossen werden. Z.B. werden mit ^totp$ alle TOTP-Token ignoriert. Per Default wird der Filter nicht verwendet. Die Regular Expression ist nicht definiert.
fudiscr.filter_tokens.id_exclude_regexleerMit dieser Option können Token anhand ihrer ID/Seriennummer für die Verwendung im fudiscr-Plugin ausgeschlossen werden. Z.B. werden mit ^HOTP.*$ alle HOTP-Token ignoriert, die als Softwaretoken in privacyIDEA angelegt wurden und eine Seriennummer beginnend mit HOTP erhalten. Per Default wird der Filter nicht verwendet. Die Regular Expression ist nicht definiert.
fudiscr.user_token_selectionnoneDiese Option legt fest, ob Token durch Nutzer*innen ausgewählt werden können. Mögliche Werte sind: none=keine Auswahl, singleToken=Auswahl eines einzelnen Token (anhand der ID/Seriennummer), multipleToken=Auswahl mehrerer Token (anhand der Seriennummer), singleTokenTypeGroup=Auswahl eines einzelnen Tokentyps (z.B. totp), singleTokenTypeGroup=Auswahl mehrerer Tokentypen. Per Default (none) wird eine Challenge für alle aktive Token erzeugt.
fudiscr.max_retries10Anzahl an Fehlversuchen für die Validierung. Ist der Wert erreicht, wird die Validierung erfolglos beendet. Dieser Wert ist unabhängig von den erlaubten Fehlversuchen in privacyIDEA. Sollen ausschließlich die Fehlerzähler aus privacyIDEA wirken, so empfiehlt es sich, den Wert für fudiscr.max_retries passend zu erhöhen (> max. Failcounter in privacyIDEA).
fudiscr.restart_allowed.max_retries_exceededshibboleth.Conditions.TRUEDieses Predicate legt fest, ob ein Neustart der Authentifizierung im fudiscr-Plugin erlaubt ist, wenn fudiscr.max_retries erreicht ist.
fudiscr.restart_allowed.selected_tokens_not_availableshibboleth.Conditions.TRUEDieses Predicate legt fest, ob ein Neustart der Authentifizierung im fudiscr-Plugin erlaubt ist, wenn die durch Nutzer ausgewählten Token nicht mehr verfügbar sind (z.B. durch Sperrung in privacyIDEA).
fudiscr.restart_allowed.within_response_pageshibboleth.Conditions.TRUEDieses Predicate legt fest, ob ein Neustart der fudiscr-Authentifizierung über die Eingabeseite für die Response (OTP, TAN u.a.) erlaubt ist.
fudiscr.on_failed_restart_completely_mfashibboleth.Conditions.FALSEDieses Predicate legt fest, ob bei einem Neustart der Authentifizieurung aus dem fudiscr-Plugin heraus nur der Faktor fudiscr im MFA-Flow (Default) oder die gesamte Authentifizierung neu gestartet wird. Gibt das Predicate TRUE zurück, werden also die Ergebnisse der vorherigen Faktoren zurückgesetzt. Es werden also Benutzername und Passwort u.a. erneut verlangt.
fudiscr.result_with_username_principalshibboleth.Conditions.TRUEDieses Predicate legt fest, ob nach erfolgreicher Authentifizierung ein UsernamePrincipal dem Subject hinzugefügt wird. Per Default enthält das Authentifizierungsergebnis nach erfolgreicher Authentifizierung mit dem fudiscr-Plugin einen UsernamePrincipal.
fudiscr.result_with_realm_in_username_principalshibboleth.Conditions.TRUEAb fudiscr-Version 1.3.0: Wenn mit fudiscr.result_with_username_principal ein UsernamePrincipal erzeugt wird, dann legt dieses Predicate fest, ob der Realm enthalten ist. TRUE (default) erzeugt z.B. dummy@fu-berlin.de, FALSE nur dummy als Username.
fudiscr.result_idp_attribute_principal_attribute_nameleerWird mit dieser Option ein Attributname angeben, so wird ein IdpAttributePrincipal mit diesem Attributnamen dem erfolgreichen Authentifizierungsergebnis des fudiscr-Plugins hinzugefügt. Der Attributwert enthält die ID/Seriennummer des Token, mit dem die Authentifizierung erfolgt ist.
fudiscr.result_idp_attribute_principal_attribute_name_for_token_typeleerAb fudiscr-Version 1.3.0: Wird mit dieser Option ein Attributname angeben, so wird ein IdpAttributePrincipal mit diesem Attributnamen dem erfolgreichen Authentifizierungsergebnis des fudiscr-Plugins hinzugefügt. Der Attributwert enthält den Tokentyp des Token, mit dem die Authentifizierung erfolgt ist.

Konfigurationsoptionen für privacyIDEA

OptionDefault-WertBeschreibung
fudiscr.privacyidea.base_urileerBasis-URL der privacyIDEA-API, z.B. https://localhost . Mit der fudiscr-Version 1.3.0 können mehrere URLs durch Leerzeichen getrennt angegeben werden.
fudiscr.privacyidea.connection_strategyACTIVE_PASSIVEErlaubt die fudiscr-Version in fudiscr.privacyidea.base_uri die Angabe mehrere privacyIDEA-Server, so kann mit dieser Option festgelegt werden, wie die Anfragen verteilt werden. Bei ACTIVE_PASSIVE (default) werden die URLs immer beginnend mit der ersten URL in Reihenfolge angefragt bis ein Server erfolgreich antwortet. Bei ROUND_ROBIN werden die URLs als zyklische Liste verwendet und bei jeder Anfrage wird die nächste URL aus der Liste benutzt.
fudiscr.privacyidea.authorization_tokenleerAuthorization-Token aus vorherigem Anleitungsschritt für die Zugriffssteuerung auf die privacyIDEA-API.
fudiscr.privacyidea.service_usernameleerUsername des Admin-Users; Alternative zu fudiscr.privacyidea.authorization_token oder zur Absicherung, falls Authorization-Token abläuft.
fudiscr.privacyidea.service_realmleerRealm des Admin-Users; Alternative zu fudiscr.privacyidea.authorization_token oder zur Absicherung, falls Authorization-Token abläuft.
fudiscr.privacyidea.service_passwordleerPasswort des Admin-Users; Alternative zu fudiscr.privacyidea.authorization_token oder zur Absicherung, falls Authorization-Token abläuft.
fudiscr.privacyidea.check_connection_certificatetrueFalls das Serverzertifikat vom API-Endpunkt nicht geprüft werden soll, kann der Wert auf false gesetzt werden.
fudiscr.privacyidea.default_realmleerMit dieser Option kann festgelegt werden, ob ein Realm der API-Anfrage an privacyIDEA hinzugefügt wird, wenn in vorherigen Schritten kein Realm dem Nutzer zugeordnet ist. Der hier definierte Realm wird dem allgemeinen User-Objekt im fudiscr-Plugin nicht hinzugefügt!
fudiscr.privacyidea.preferred_parameter_nameleerWird mit dieser Option ein Name angegeben, so wird nach diesem Namen in den Token-Infos in privacyIDEA gesucht und versucht, den zugehörigen Wert als Boolean zu interpretieren. Sollte der Wert true ergeben, so wird der Token auf der eventuellen Auswahlseite der Token vorselektiert.
fudiscr.privacyidea.relying_party_id_parameter_nameleerWird mit dieser Option ein Name angegeben, so wird bei jeder Anfrage gegen die privacyIDEA-API die entityID des Service Providers als Parameter mit diesem Namen übergeben.
fudiscr.privacyidea.user_agent_ip_address_parameter_nameleerWird mit dieser Option ein Name angegeben, so wird bei jeder Anfrage gegen die privacyIDEA-API die IP-Adresse des Users als Parameter mit diesem Namen übergeben.
fudiscr.privacyidea.singletontrueGibt an, ob der vom fudiscr-Plugin verwendete PrivacyIdeaChallengeResponseClient nur einmal instanziiert wird. In manchen Anwendungsfällen kann es die Performance verbessern, wenn mehrere Instanzen zugelassen werden.
fudiscr.privacyidea.with_additional_pin_responsefalseIn privacyIDEA ist es möglich, neben dem one time password/code noch eine PIN zu verlangen. Wenn dieser Konfigurationsparameter auf true gesetzt ist, dann ergänzt das fudiscr-Plugin auf der Eingabeseite für die Response ein PIN-Feld. Nur für die Tokentypen hotp, indexed_tan, registration_code, tan, totp und yubikey_otp wird diese Funktionalität unterstützt. (Bis fudiscr-Version 1.2.0 wurde diese Option unter dem Namen fudiscr.with_additional_pin_response geführt.)
fudiscr.privacyidea.single_trigger_challengestrueDies Option existiert nur bis zur fudiscr-Version 1.2.0. Wird der Wert auf false gesetzt, wird über alle aktive Token der Nutzer*innen eine Challange ausgelöst und nicht (wie bei true) eine separate Challenge pro Token. Wird WebAuthn mit mehreren aktiven WebAuthn-Token pro Nutzer in der fudiscr-Version 1.2.0 eingesetzt, so sollte der Wert auf false gesetzt werden.

Hinweis: In Abhängigkeit von der Konfigurationsweise des Shibboleth Identity Providers empfiehlt es sich, Token und Passwörter wie in fudiscr.privacyidea.authorization_token und fudiscr.privacyidea.service_password in geschützte/unversionierte Dateien wie %{idp.home}/credentials/secrets.properties auszulagern.

Custom Token in privacyIDEA (ab Version 1.3.0)

Für den Sonderfall, dass in privacyIDEA eigene Tokentypen implementiert werden, gibt es die Möglichkeit, diese auch über das fudiscr-Plugin zur Verfügung zu stellen. Dies ist aber nur möglich, wenn dieser neue Tokentyp keine Challenge erzeugt, die an Nutzer*innen zurückgegeben werden muss und wenn nur ein einfaches one time password verlangt wird. Der Token muss sich in der Nutzer-Interaktion also vergleichbar zu TOTP verhalten.

In %{idp.home}/conf/global.xml kann hierfür die Bean fudiscr.privacyidea.CustomTokenTypesMap definiert werden:

<util:map id="fudiscr.privacyidea.CustomTokenTypesMap" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String">
   <entry key="custom_token_type_name_in_privacyidea" value="custom_token_type_name_in_fudiscr"/>
</util:map>

Die Map fudiscr.privacyidea.CustomTokenTypesMap kann auch dafür verwendet werden, das Mapping der Tokentypen auf die Bezeichnung in fudiscr anzupassen. Erlaubt sind nur 1:1-Beziehungen.

Ergänzend entscheidet die Option fudiscr.privacyidea.replace_all_token_types_with_custom_map darüber, ob die Mappings aus fudiscr.privacyidea.CustomTokenTypesMap das Standardmapping ergänzen (false default) oder vollständig ersetzen (true).

Filterung von Token (ab Version 1.3.0)

Ergänzend oder altenrativ zu den o.g. Konfigurationsoptionen fudiscr.filter_tokens.type_exclude_regex und fudiscr.filter_tokens.id_exclude_regex können weitere Ausschlussbedingungen für Token definiert werden.

In %{idp.home}/conf/authn/fudiscr.xml kann mit fudiscr.ExcludeTokenPredicates eine Liste von Ausschlussfunktionen definiert werden.

<util:list id="fudiscr.ExcludeTokenPredicates">
   <ref bean="fudiscr.ExcludeTokenPredicate1"/>
   <ref bean="fudiscr.ExcludeTokenPredicate2"/>
   <!-- ... -->   
</util:list>

Die Ausschlussbedingungen können Scripted oder anhand von Regular Expressions bezogen auf Tokeneigenschaften formuliert werden.

Beispiel Scripted
<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.idp.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>

In diesem Beispiel dürfen Notfallcodes (registration_code) nur für ein (Service-)Portal und sonst keinen anderen Service Provider verwendet werden. In diesem Szenario können z.B. Nutzer sich mit Hilfe der Notfallcodes wieder andere Tokenverfahren im (Service-)Portal einrichten bzw. freischalten.

Beispiel mit Regular Expression
<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 diesem Beispiel werden Token anhand einer Tokeneigenschaft herausgefiltert. In privacyIDEA können aktive Token existieren, die eine erste Validierung erfordern, bevor sie effektiv verwendet werden können. So soll z.B. erzwungen werden, dass Nutzer bei der Einrichtung eines TOTP-Token den QR-Code mit dem Authenticator einscannen und diesen Vorgang mit einem OTP bestätigen. Die Token besitzen bis zur Bestätigung die Eigenschaft rollout_state mit den Werten verify oder clientwait. Die in dem Beispiel verwendeten zwei Predicates lassen sich auch mit einem Predicate und der Regular Expression ^(clientwait|verify)$ abbilden. Es soll in dem Bespiel nur die Listeneigenschaft von fudiscr.ExcludeTokenPredicates verdeutlicht werden.

(Mit dem Konstruktor-Parameter c:negateResult=„true“ kann das Ergbnis eines ExcludeTokenPredicates negiert werden.)

Filterung von Token für die Funtkion fudiscr.UserHasTokenPredicate (ab Version 1.3.0)

Mit der fudiscr-Version 1.1.0 wurde die Funktion fudiscr.UserHasAnyTokenPredicate eingeführt, die mit der Version 1.3.0 unter dem Namen fudiscr.UserHasTokenPredicate zur Verfügung steht. Diese Funktion dient dazu, um zu entscheiden, ob Nutzer generell schon für den zweiten Faktor bzw. für ein Tokenverfahren eingerichtet wurden. Während in fudiscr-Versionen vor 1.3.0 nur geprüft wurde, ob mindestens ein Token zu einem Nutzer egal in welchem Zustand existiert, können auch für diese Funktion Token äquivalent zur allgemeinen Filterung ausgeschlossen werden. Die zugehörige Bean-ID lautet hierfür fudiscr.UserHasTokenExcludeTokenPredicates.

Das vorherige Filterbeispiel lässt sich wie folgt übertragen:

Beispiel mit Regular Expression
<util:list id="fudiscr.UserHasTokenExcludeTokenPredicates">
   <ref bean="fudiscr.RegexExcludeTokenPredicateExample1/>
   <ref bean="fudiscr.RegexExcludeTokenPredicateExample2"/>
</util:list>

Die Beans fudiscr.RegexExcludeTokenPredicateExample1 und fudiscr.RegexExcludeTokenPredicateExample2 können aus dem vorherigen Beispiel wiederverwendet werden.

Wenn die allgemeine Tokenfilterung und die Filterung für die Funktion fudiscr.UserHasTokenPredicate identisch sind, kann auch ein Alias gesetzt werden:

<alias name="fudiscr.ExcludeTokenPredicates" alias="fudiscr.UserHasTokenExcludeTokenPredicates"/>


vorselektierte Token (ab Version 1.3.0)

Äquivalent zu den Filtern fudiscr.ExcludeTokenPredicates und fudiscr.UserHasTokenExcludeTokenPredicates kann ein Filter definiert werden, der die bevorzugten Token eines Nutzers herausfiltert. Wird die Exclude-Filter-Liste fudiscr.PreferredExcludeTokenPredicates definiert, so werden initial nur die bevorzugten Token verwendet. Führt die Filterung dazu, dass alle Token ausgeschlossen werden, wird die Filterung zurückgesetzt. Sollte die Filterung die Ausgangsliste reduzieren, so wird dem Nutzer auf der Auswahlseite für die Token und der Eingabeseite für die Response ein Button angeboten, um die vollständige Tokenauswahl zu erhalten. Sollte nach der Filterung mit fudiscr.PreferredExcludeTokenPredicates eine Selektion durch die Nutzer*innen nicht mehr notwendig sein, wird sofort die Challenge erzeugt. Ergibt also z.B. die Filterung, dass nur TOTP-Token übrig bleiben und wurde fudiscr.user_token_selection=singleTokenTypeGroup konfiguriert, so wird sofort eine Challenge auf die TOTP-Token ausgelöst und die Eingabeseite für die Response angezeigt. Nutzer erhalten aber dann wie zuvor genannt die Möglichkeit, trotzdem andere Token-Verfahren auszuwählen.

Beispiel
<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)false$"
         p:returnValueForNullInput="false"/>
   <bean class="de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.function.impl.RegexExcludeTokenPropertiesPredicate"
         c:propertyName="type"
         c:excludePattern="^totp$"
         c:negateResult="true"/>
</util:list>

Das Beispiel filtert alle Token heraus, die nicht das Token-Info-Attribut fudis_preferred mit dem Wert true (case-insensitive) und nicht vom Typ 'totp' sind. p:returnValueForNullInput=„false“ bewirkt, dass das RegexExcludeTokenPropertiesPredicate bei fehlendem Token-(Info-)Attribut false zurückgibt. Bitte beachten Sie, dass durch c:negateResult=„true“ aus einem Exclude eine Include wird. In dem Beispiel werden im Gegensatz zu den vorherigen Filterbeispielen die Beans direkt in der Liste und nicht als Referenzen definiert.

Realm-Transformation (ab Version 1.3.0)

Es kann vorkommen, dass Nutzer im Identity Management über mehrere Datenquellen verteilt sind. So können z.B. Studierende und Beschätigte in zwei getrennten LDAP-Servern verwaltet werden. Dies führt wiederum dazu, dass z.B. in privacyIDEA zwei Realms angelegt werden müssen und bei den API-Anfragen gegen privacyIDEA müssen diese Realms unterschieden werden. Für das User-Objekt im fudiscr-Plugin wird folgende Logik durchlaufen, um den Realm zu ermitteln:

  1. Mit der Java-Klasse net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy wird zunächst gemäß Shibboleth-Standard der Benutzername aus den vorherigen Authentifizierungsergebnissen ermittelt.
  2. Anhand von fudiscr.username_realm_split_regex wird versucht, den Realm als gesondertes Attribut vom Benutzernamen abzutrennen.
  3. Wenn eine Liste fudiscr.UserRealmTransformationStrategies mit Realm-Transformationsstrategien in %{idp.home}/conf/authn/fudiscr.xml definiert wurde, dann werden diese Strategien in der aufgeführten Reihenfolge durchlaufen.
  4. Sollte noch kein Realm existieren, wird ein Default-Realm zugeordnet, wenn dieser mit fudiscr.default_users_realm definiert wurde.

Der so ermittelte Realm wird im fudiscr-Plugin von allen Klassen verwendet, die ein User-Objekt verarbeiten.

Sollte der Realm im User-Objekt vom fudiscr-Plugin nicht definiert (null) sein, dann kann mit fudiscr.privacyidea.default_realm ein Realm für die API-Anfrage gegen privacyIDEA hinzugefügt werden. Der so hinzugefügte Realm wird aber nicht in das allgemeine User-Objekt vom fudiscr-Plugin übernommen!

Beispiel Realm-Transformationsstrategien
<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 dem Beispiel wird geprüft, ob in dem aktiven Authentifizierungsergebnis aus der Authentifizierung mit Benutzername und Passwort (authn/Password) ein LdapPrincipal existiert und ob dieser LdapPrincipal das Attribut realm enthält. Der erste Wert aus realm wird als Realm übernommen. Anschließend wird eine Scripted Strategie angewandt.

(Zum REFEDS Multi-Factor Authentication Profile siehe unter REFEDS AuthN Profiles - Hinweise für Identity Provider)
In %{idp.home}/conf/authn/authn.properties sind folgende Einstellungen vorzunehmen:

./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 ist bereits im Standard aktiviert. Es wird lediglich die AuthenticationContextClass saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR ergänzt. Anstelle von saml2/urn:de:zedat:fudis:SAML:2.0:ac:classes:CR kann auch eine andere AuthenticationContextClass oder zusätzliche unter idp.authn.fudiscr.supportedPrincipals UND idp.authn.MFA.supportedPrincipals eingetragen werden. Es wird empfohlen, mindestens eine zusätzliche Klasse zu definieren, über die explizit die Multi-Faktor-Authentifizierung ausgelöst werden kann. Es besteht aber keine Verpflichtung, da eine Multi-Faktor-Authentifizierung auch über andere Mechanismen ausgelöst werden kann.

Über die Transitionen in %{idp.home}/conf/authn/mfa-authn-config.xml wird die Abfolge der einzelnen Faktoren gesteuert. Hier können verschiedene Mechanismen verwendet werden, um die Bedingungen für die Übergänge in die nächsten Faktoren zu formulieren. Die offizielle Dokumentation dazu finden Sie hier: MultiFactorAuthnConfiguration

Beispiele

Im Folgenden werden drei Beispiele für eine MFA-Konfiguration aufgeführt

Beispiel 1: Nach der Authentifizierung mit Benutzername und Passwort erfolgt immer eine tokenbasierte Authentifizierung mit fudiscr.

./conf/authn/mfa-authn-config.xml
<?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/IDP4/pages/1265631610/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>

Beispiel 2: Nach der Authentifizierung mit Benutzername und Passwort erfolgt dann eine tokenbasierte Authentifizierung, wenn die AuthenticationContextClass, die der ServiceProvider benötigt, nicht ausreicht.

./conf/authn/mfa-authn-config.xml
<?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/IDP4/pages/1265631610/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>

Beispiel 3: Nach der Authentifizierung mit Benutzername und Passwort erfolgt dann eine tokenbasierte Authentifizierung, wenn die AuthenticationContextClass, die der ServiceProvider benötigt, nicht ausreicht oder wenn der/die Benutzer*in nach eduPersonAffiliation zu der Gruppe der Beschäftigten (employee) gehört.

./conf/authn/mfa-authn-config.xml
<?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/IDP4/pages/1265631610/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>

Beispiel 4:

Nach der Authentifizierung mit Benutzername und Passwort erfolgt dann eine tokenbasierte Authentifizierung, wenn die AuthenticationContextClass, die der ServiceProvider benötigt, nicht ausreicht oder wenn der/die Benutzer*in bereits mindestens einen Token besitzt. Bei den Tokens wird der Zustand nicht geprüft. Ein gesperrter Token würde z.B. dafür sorgen, dass das fudiscr.UserHasTokenPredicate den Wert true zurückgibt. Dieses Predicate wurde insbesondere für Rollout-Szenarien eingeführt.

./conf/authn/mfa-authn-config.xml
<?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>


Beispiel 5: Wahlweise authn/Password und authn/SPNEGO als ersten Faktor → hier.


Reuse Condition

Für Authentifizierungsverfahren im Shibboleth Identity Provider kann generell eine Reuse Condition definiert werden. In der Regel ist der Default-Wert shibboleth.Conditions.TRUE. Die Bedingung ist also immer erfüllt. Es können als Reuse Condition auch eigene Funktionen definiert werden.

Für die Multi-Faktor-Authentifizierung gelten besondere Regeln. Eine Beschreibung finden Sie in der offiziellen Dokumentation unter MultiFactorAuthnConfiguration.

Mit folgender Konfiguration in %{idp.home}/conf/authn/authn.properties erreichen Sie, dass innerhalb einer Single-Sign-On-Session nur einmal Benutzername und Passwort verlangt wird, aber pro Service Provider Authentifizierung immer eine tokenbasierte Authentifizierung mit fudiscr.

./conf/authn/authn.properties
idp.authn.MFA.reuseCondition=shibboleth.Conditions.FALSE
idp.authn.Password.reuseCondition=shibboleth.Conditions.TRUE
idp.authn.fudiscr.reuseCondition=shibboleth.Conditions.FALSE

Das Ergebnis der MFA-Authentifizierung darf demnach nicht erneut verwendet werden, aber innerhalb der Multi-Faktor-Authentifizierung darf das existierende erfolgreiche Ergebnis der Benutzername-Passwort-Authentifizierung (Password) verwendet werden und das Ergebnis von fudiscr aber nicht.

Wenn 'ForceAuthn' via SAML angefragt wird, dann gibt die Funktion mfaCtx.isAcceptable() immer false zurück.

Um detaillierte Logging-Informationen vom fudiscr-Plugin zu erhalten, kann die folgende Zeile in %{idp.home}/conf/logback.xml ergänzt werden:

<logger name="de.zedat.fudis" level="DEBUG"/>

Sollen alle API-Anfragen gegen privacyIDEA separat protokolliert werden, so wird folgende zusätzliche Konfiguration vorgeschlagen:

<logger name="de.zedat.fudis.rest.interceptors" level="TRACE">
   <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>

Als Zusatzangebot kann für den Prozess der SubjectCanonicalization im Shibboleth Identity Provider ein Flow auf Basis von de.zedat.fudis.shibboleth.idp.plugin.authn.fudiscr.domain.ChallengeResponseTokenIdPrincipal aktiviert werden. Dieser vom fudiscr-Plugin erzeugte zusätzliche Principal enthält die ID/Seriennummer des erfolgreich verwendeten Token.

Um den Flow zu aktivieren, muss in der Konfigurationsdatei %{idp.home}/conf/c14n/subject-c14n.xml die Referenz <ref bean=„c14n/fudiscr“ /> in die Liste shibboleth.PostLoginSubjectCanonicalizationFlows aufgenommen werden.

Zusätzlich können wie für andere Principals Transformationsoptionen z.B.in %{idp.home}/conf/c14n/subject-c14n.properties angegeben werden:

idp.c14n.fudiscr.lowercase=false
idp.c14n.fudiscr.uppercase=false
idp.c14n.fudiscr.trim=true

Mit der aktuellen Testversion 1.4.0 wurde in Zusammenarbeit mit der Hochschule München ein neues Authentifizierungsverfahren eingeführt. Weitere Details folgen in Kürze.

Hochschulen und andere öffentliche Einrichtungen erhalten auf Anfrage Zugriff auf den Quellcode. Bitte senden Sie hierfür eine E-Mail an fudis@zedat.fu-berlin.de. Es wird daran gearbeitet, sämtliche Komponenten des fudiscr-Plugins unter der Apache 2.0 Lizenz zu veröffentlichen. Wir bitten um Geduld.

Fehler, Fragen, Anregungen etc. bitte per E-Mail an fudis@zedat.fu-berlin.de senden.

  • Zuletzt geändert: vor 29 Stunden