Trying to configuring privacyIdea as 2FA with SimpleSAMLphp

Hi all!
I am trying to set privacyIdea as 2FA in a single sign on with simplesamlphp. My idea is to use privacyIdea as a second factor ( ‘authproc’) by emailing an OTP to the user trying to log in.

Here is my saml20-idp-hosted.php:

$metadata['sso'] = [
    /*
     * The hostname of the server (VHOST) that will use this SAML entity.
     *
     * Can be '__DEFAULT__', to use this entry by default.
     */
   ...


     /*
      * Authentication source to use. Must be one that is configured in
      * 'config/authsources.php'.
      */
    'auth' => '**',
    'authproc' => array(

    /**
     *  Configuration for the privacyIDEA server.
     */
    20 => array(
        'class'             => 'privacyidea:PrivacyideaAuthProc',

        /**
         *  Enter the URL to your privacyIDEA instance
         */
        'privacyideaServerURL' => 'myHost',

        /**
         *  Enter the realm, where your users are stored (remove it or set it to '' to use default)
         */
        'realm'             => 'sso',

        /**
         *  The uidKey is the username's attribute key.
         *  You can choose a single one or multiple ones. The first set will be used.
         */
        'uidKey'            => 'uid',
        //  'uidKey'        => array('uid', 'userName', 'uName'),

        /**
         *  Check if the hostname matches the name in the certificate.
         *  The value have to be a string.
         */
        'sslVerifyHost'     => 'true',

        /**
         *  Check if the certificate is valid, signed by a trusted CA
         *  The value have to be a string.
         */
        'sslVerifyPeer'     => 'true',

        /**
         *  Here you need to enter the username of your service account
         */
        'serviceAccount'    => 'service',

        /**
         *  Enter here the password for your service account
         */
        'servicePass'       => 'service',

        /**
         *  You can add this option, if you want to enroll tokens for users, who do not have one yet.
         *  The value have to be a string.
         */
        'doEnrollToken'     => 'true',

        /**
         *  You can select a time based otp (totp), an event based otp (hotp) or an u2f (u2f)
         */
        'tokenType'         => 'totp',

        /**
         *  You can enable or disable trigger challenge.
         *  The value have to be a string.
         */
        'doTriggerChallenge' => 'true',

        /**
         * Set this to 'true' if you want to use single sign on.
         * All information required for SSO will be saved in the session.
         * After logging out, the SSO data will be removed from the session.
         */
        'SSO' => 'true',

        /**
         * Set preferredTokenType to your favourite token type.
         * If the choosen token is triggered, it will be used to authenticate directly
         * without having to press the button for the type.
         * Possible values are: push, webauthn or u2f.
         * When left empty, defaults to showing an input field for OTPs.
         */
        'preferredTokenType' => '',

        /**
         * Set custom hints for the OTP and password fields
         */
        'otpFieldHint' => 'OTP',
        'passFieldHint' => 'Password',

        /**
         *  Other authproc filters can disable 2FA if you want to.
         *  If privacyIDEA should listen to the setting, you have to enter the state's path and key.
         *  The value of this key will be set by a previous auth proc filter.
         *  privacyIDEA will only be disabled, if the value of the key is set to false,
         *  in any other situation (e.g. the key is not set or does not exist), privacyIDEA will be enabled.
         */
        'enabledPath'       => '',
        'enabledKey'        => '',

        /**
         *  If you want to use passOnNoToken or passOnNoUser, you can decide, if this module should send a password to
         *  privacyIDEA. If passOnNoToken is activated and the user does not have a token, he will be passed by privacyIDEA.
         *  NOTE: Do not use it with privacyidea:tokenEnrollment.
         */
        'tryFirstAuthentication' => 'true',

        /**
         *  You can decide, which password should be used for tryFirstAuthentication
         */
        'tryFirstAuthPass' => 'simpleSAMLphp',

        /**
         *
         *  You can exclude clients with specified ip addresses.
         *  Enter a range like "10.0.0.0-10.2.0.0" or a single ip like "192.168.178.2"
         *  The selected ip addresses do not need 2FA
         *
        'excludeClientIPs'  => array("10.0.0.0-10.2.0.0", "192.168.178.2"),


        /**
         *  Check Entity ID is optional. If you want to selectively disable the privacyIDEA authentication using
         *  the entityID and/or SAML attributes, you may enable this filter.
         *  Value have to be string.
         */
        'checkEntityID'        => 'true',

        /**
         *  Depending on excludeEntityIDs and includeAttributes the filter will set the state variable
         *  $state[$setPath][$setPath] to true or false.
         *  To selectively enable or disable privacyIDEA, make sure that you specify setPath and setKey such
         *  that they equal enabledPath and enabledKey from privacyidea:privacyidea.
         */
        'setPath'              => 'privacyIDEA',
        'setKey'               => 'enabled',
        /**
         *  The requesting SAML provider's entityID will be tested against this list of regular expressions.
         *  If there is a match, the filter will set the specified state variable to false and thereby disables
         *  privacyIDEA for this entityID The first matching expression will take precedence.
         */
        'excludeEntityIDs' => array(
            '/http(s)\/\/conditional-no2fa-provider.de\/(.*)/',
            '/http(.*)no2fa-provider.de/'
        ),
        /**
         *  Per value in excludeEntityIDs, you may specify another set of regular expressions to match the
         *  attributes in the SAML request. If there is a match in any attribute value, this filter will
         *  set the state variable to true and thereby enable privacyIDEA where it would be normally disabled
         *  due to the matching entityID. This may be used to enable 2FA at this entityID only for privileged
         *  accounts.
         *  The key in includeAttributes must be identical to a value in excludeEntityIDs to have an effect!
         */
        'includeAttributes' => array(
            '/http(s)\/\/conditional-no2fa-provider.de\/(.*)/' => array(
                'memberOf' => array(
                    '/cn=2fa-required([-_])regexmatch(.*),cn=groups,(.*)/',
                    'cn=2fa-required-exactmatch,ou=section,dc=privacyidea,dc=org'
                ),
                'myAttribute' => array(
                    '/(.*)2fa-required/', '2fa-required',
                )
            )
        ),
    ),
)
];

EDITED:
Privacyidea does not send the email with the 2FA string when I login from simplesamlphp, if I try from the privacyIdea configuration screen, the OTP is sent and I can test it correctly. This is the output from simplesamlphp log file:

Apr 28 10:01:27 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_Logger' is now using namespaces, please use 'SimpleSAML\Logger'.
Apr 28 10:01:27 simplesamlphp DEBUG [ef46ab925c] privacyIDEA: Utils::authenticatePI with form data:
username=, pass=, otp=1234, mode=otp, pushAvailable=, otpAvailable=1, modeChanged=0, webAuthnSignResponse=, webAuthnSignRequest=, origin=, u2fSignRequest=, u2fSignResponse=, message=, loadCounter=1
Apr 28 10:01:27 simplesamlphp DEBUG [ef46ab925c] privacyIDEA-PHP-Client: Sending user=*****, pass=1234, realm=sso to /validate/check
Apr 28 10:01:27 simplesamlphp DEBUG [ef46ab925c] privacyIDEA-PHP-Client: /validate/check returned null
Apr 28 10:01:27 simplesamlphp ERROR [ef46ab925c] privacyIDEA-PHP-Client: Response from the server is malformed:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>

Apr 28 10:01:27 simplesamlphp DEBUG [ef46ab925c] privacyIDEA-PHP-Client: Server did not respond.
Apr 28 10:01:27 simplesamlphp DEBUG [ef46ab925c] Saved state: '_a072a9db935335063a04dfe5e1dfac9d12e0ff2bb1:https://****
Apr 28 10:01:27 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_Module' is now using namespaces, please use 'SimpleSAML\Module'.
Apr 28 10:01:27 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_Utilities' is now using namespaces, please use 'SimpleSAML\Utilities'.
Apr 28 10:01:28 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_Logger' is now using namespaces, please use 'SimpleSAML\Logger'.
Apr 28 10:01:28 simplesamlphp DEBUG [ef46ab925c] Loading privacyIDEA form..
Apr 28 10:01:28 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_Auth_State' is now using namespaces, please use 'SimpleSAML\Auth\State'.
Apr 28 10:01:28 simplesamlphp DEBUG [ef46ab925c] Loading state: '_a072a9db935335063a04dfe5e1dfac9d12e0ff2bb1:https://cerberodes.unizar.es/uzauth/saml2/idp/SSOService.php?spentityid=ssoauthcircuito.unizar.es&RelayState=http%3A%2F%2Fcircuitodes.unizar.es%2F%3Fopcion%3Dlogin&cookieTime=1651132570'
Apr 28 10:01:28 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_XHTML_Template' is now using namespaces, please use 'SimpleSAML\XHTML\Template'.
Apr 28 10:01:28 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_Configuration' is now using namespaces, please use 'SimpleSAML\Configuration'.
Apr 28 10:01:28 simplesamlphp DEBUG [ef46ab925c] Localization: using old system
Apr 28 10:01:28 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_Module' is now using namespaces, please use 'SimpleSAML\Module'.
Apr 28 10:01:28 simplesamlphp WARNING [ef46ab925c] The class or interface 'SimpleSAML_Session' is now using namespaces, please use 'SimpleSAML\Session'.
Apr 28 10:01:28 simplesamlphp DEBUG [ef46ab925c] /uzauth/module.php/privacyidea/FormBuilder.php - Template: Could not find template file [privacyidea:LoginForm.php] at [/.../bin/simplesamlphp/modules/multiauth/themes/unizar/privacyidea/LoginForm] - now trying the base template
Apr 28 10:01:28 simplesamlphp DEBUG [ef46ab925c] Translate: Reading dictionary [/.../bin/simplesamlphp/modules/privacyidea/dictionaries/privacyidea]
Apr 28 10:01:28 simplesamlphp DEBUG [ef46ab925c] Translate: Reading dictionary [/.../bin/simplesamlphp/dictionaries/login]
Apr 28 10:01:28 simplesamlphp DEBUG [ef46ab925c] Translate: Reading dictionary [/.../bin/simplesamlphp/dictionaries/status]
Apr 28 10:01:28 simplesamlphp ERROR [ef46ab925c] SimpleSAML\Error\Exception: Error 8 - Undefined index: pushAvailable at /.../bin/simplesamlphp/modules/privacyidea/templates/LoginForm.php:300
Apr 28 10:01:28 simplesamlphp ERROR [ef46ab925c] Backtrace:
Apr 28 10:01:28 simplesamlphp ERROR [ef46ab925c] 5 /.../bin/simplesamlphp/www/_include.php:48 (SimpleSAML_error_handler)
Apr 28 10:01:28 simplesamlphp ERROR [ef46ab925c] 4 /.../bin/simplesamlphp/modules/privacyidea/templates/LoginForm.php:300 (require)
Apr 28 10:01:28 simplesamlphp ERROR [ef46ab925c] 3 /.../bin/simplesamlphp/lib/SimpleSAML/XHTML/Template.php:546 (SimpleSAML\XHTML\Template::show)
Apr 28 10:01:28 simplesamlphp ERROR [ef46ab925c] 2 /.../bin/simplesamlphp/modules/privacyidea/www/FormBuilder.php:130 (require)
Apr 28 10:01:28 simplesamlphp ERROR [ef46ab925c] 1 /.../bin/simplesamlphp/lib/SimpleSAML/Module.php:260 (SimpleSAML\Module::process)
Apr 28 10:01:28 simplesamlphp ERROR [ef46ab925c] 0 /.../bin/simplesamlphp/www/module.php:10 (N/A)

Can someone help me?

what is the problem?

Hi!
My bad, I forgot to post the error, im gonna edit.

Privacyidea does not send the email with the 2FA string, when I login from simplesamlphp, if I try from the privacyIdea configuration screen, the OTP is sent and I can test it correctly

Hi,
you need to configure the SSP module to trigger the email token before the user is prompted for the OTP. With your current config, you are sending the username and PIN=simpleSAMLphp to the server (tryFirstAuthentication and tryFirstAuthPass config entries). This would require all email token to have the PIN ‘simpleSAMLphp’ or any other static string. Alternatively (and probably preffered) you can set tryFirstAuthentication to false and set the ‘servicePass’ and ‘serviceAccount’ to an admin account of privacyIDEA. That account will be user to trigger all token for user that is trying to log in.

1 Like

Thanks mate!

Just one question, what do you mean when you talk about the SSP module to trigger the email token?

The email token is a challenge-response token:
https://privacyidea.readthedocs.io/en/latest/tokens/authentication_modes.html#challenge-mode

The challenge in this case would be to be able to receive the email.
The challenge has to be triggered in some way. Either using the token PIN or using /triggerchallenge with an admin account. The SSP module offers possibilites for both cases.
The response to the challenge is sending the OTP received in the email to privacyIDEA.

2 Likes

I think I have configured the SSP correctly but the problem is as follows:
I have activated the parameter: doTriggerChallenge => true

Apr 29 12:59:59 simplesamlphp DEBUG [1094e29421] privacyIDEA-PHP-Client: Sending username=user, password=pass to /auth
Apr 29 12:59:59 simplesamlphp DEBUG [1094e29421] privacyIDEA-PHP-Client: /auth response did not contain a auth token.
Apr 29 12:59:59 simplesamlphp DEBUG [1094e29421] privacyIDEA-PHP-Client: Sending user=username, realm=sso to /validate/triggerchallenge
Apr 29 12:59:59 simplesamlphp DEBUG [1094e29421] privacyIDEA-PHP-Client: /validate/triggerchallenge returned null
Apr 29 12:59:59 simplesamlphp ERROR [1094e29421] privacyIDEA-PHP-Client: Response from the server is malformed: