Simplesamlphp and passOnNoUser asks for second factor

I’m trying to only have a subset of my users with more rights in some applications (teachers and staff), to use 2 factor authentication and the majority of the users (students) not.

Detailed scenario:
log in using simplesamlphp
filter logins using method 2 on https://github.com/privacyidea/simplesamlphp-module-privacyidea/blob/master/docs/privacyidea.md
-> privacyidea through a filter.

In privacyIdea I use the same authentication source as in simplesamlphp (a mysql database) and with the where clause I filter a subset of the users.
I use a policy with passonnotoken and passonnouser enabled, that applies only on a realm, not a resolver (see https://github.com/privacyidea/privacyidea/issues/798)
I switched of ‘class’ => ‘privacyidea:tokenEnrollment’ in simplesamlphp since I found somewhere that it is not a good idea to do this whit passonnouser. Therefore I enabled passonnotoken - I’ll find another way to enrol tokens later.

So the expected behaviour is that someone with an account in privacyIDEA and a token would

  • get the login-page from SimpleSamlphp
  • get the question for the 2nd factor
  • log in

Someone without a token or without an account would

  • get the login-page from SimpleSamlphp
  • log in

The result here is that I always get the 2nd factor page. For known and unknown users, for known users with and without a a token. The passonnotoken and passonnouser don’t seem to work. Users without a token or account are stuck there.

However, when I perform the validate script (https://FQDN/validate/check?user=username&pass=password&realm=realm) I get
{“detail”: {“message”: “user does not exist, accepted due to ‘passOnNoUser’”, “threadid”: 139765643695872}, “id”: 1, “jsonrpc”: “2.0”, “result”: {“status”: true, “value”: true}, “time”: 1591168062.2148845, “version”: “privacyIDEA 3.3.3”, “versionnumber”: “3.3.3”, “signature”:
So it seems to work on the PrivacyIDEA side.

If I try to login with such a non existent user anyway, I get (obviously) an error message:

SimpleSAML\Error\BadRequest: BADREQUEST(’%REASON%’ => ‘privacyIDEA: Valid JSON response, but some internal error occured in PI server’)

Backtrace:
3 modules/privacyidea/lib/Auth/Process/privacyidea.php:201 (sspmod_privacyidea_Auth_Process_privacyidea::authenticate)
2 modules/privacyidea/www/otpform.php:53 (require)
1 lib/SimpleSAML/Module.php:260 (SimpleSAML\Module::process)
0 www/module.php:10 (N/A)

How do I make it so the users without token or without an account on PrivacyIDEA don’t get the second factor page? I assumed (maybe wrongly) that this would happen automagically if privacyIDEA accepted.

If I understand your setup correctly this can not work, since you are using triggerchallenge.

The policies passOnNo.... do not work with triggerchallenge. This is by design. The enpoint triggerchallenge is not designed to return a successful authentication. triggerchallenge is by design the first step of a 2step authentication, so the auth can not end after the first step.

What tokentypes are you using? Are you really using challenge-response tokens? Which one? There might be other ways to do the enrollment.

If you are using tokentypes like HOTP or TOTP I recommend to not use triggerchallenge, but the normal /validate/check endpoint, which works with passOnNo....

Thank you for your reply. I seem to have missed something - rereading documentation.
I’m not using anything yet - roll out in august, so a lot can be changed. The plan was to use HOTP/TOTP anyway, with privacyIDEA-app and hardware tokens for people without a phone. SimpleSamlphp is heavily in use allready.

I’m just not aware of where I have chosen to use triggerchallenge :slight_smile: I’ll find it … Thank you for the pointer.

I found the triggerchallenge as a setting in ‘class’ => ‘privacyidea:serverconfig’ in the auth proc filter to load privacyIDEA in simplesamlphp. Changing it makes is possible to make the passonnotoken work, but the user still gets the dialog window for the pin + otp. However, it passes when left empty.
I didn’t get the passonnouser working. It seems that the simplesaml module sends to endpoint /validate/samlcheck rather then to /validate/check. May be that is why passonnouser doesn’t work? just a thought.

But looking again at that configuration file, I noticed the enabledPath/enabledKey settings, which seem to make it possible to not send users to privacyIDEA at all if certain criteria are met. That would also solve my problem.

I found discussion Authproc filter in simpleSAMLphp which unfortunately doesn’t seem to be resolved and does not have an example of a working configuration.

My aim is now to set the enabledkey to false for users, having the student attribute set to 1. If someone has a working configuration example for skipping privacy idea, based on a users attribute, that would be most helpful.

Hm, frustrating :frowning:

My autoproc configuration is like this:
‘authproc’ => [
10 => array(
‘class’ => ‘core:PHP’,
‘code’ => ’
$state[“use_pi”] = [“key” => “false”];
$results = print_r($state, true);
file_put_contents("/tmp/state.txt", $results);
',
),
20 => [
‘class’ => ‘privacyidea:serverconfig’,
‘privacyideaserver’ => ‘https://privacyidea.school.be’,
‘realm’ => ‘school.be’,
‘uidKey’ => ‘uid’,
‘sslverifyhost’ => true,
‘sslverifypeer’ => true,
‘enabledPath’ => ‘use_pi’,
‘enabledKey’ => ‘key’,
],
25 => [
‘class’ => ‘privacyidea:privacyidea’,
],
],
];

I see at the bottom of my state.txt log file
[use_pi] => Array
(
[key] => false
)

So I think everything is in place to not invoke privacyIDEA, and I still get the screen for the PIN+OTP

The idea is to extend the php code to add the use_pi key only for users who don’t need a second factor.

What am I missing?

Answering my own question. Found it!

If you use
$state[“use_pi”] = [“key” => “0”];

in stead of
$state[“use_pi”] = [“key” => “false”];

it works!

Reading https://www.php.net/manual/en/language.types.boolean.php I came up with the idea to use something else then the word “false”. I noticed that $state[“use_pi”] = [“key” => false; without the quotes (as is given as example in the previously mentioned discussion) doesn’t work either - in that case nothing of the key is added to $state.

So I suggest that someone with more in depth PHP knowledge then me elaborates this answer or that the documentation is changed and use a 0 rather then the word false for the boolean.

1 Like

Completely working solution in simplesamlphp/metadata/saml20-idp-hosted.php

Every user with the attribute “leerling” (= student in Dutch) set to “1” will not get the screen for a second authentication factor. All the other users will.

    'authproc' => [
        10 => [
          'class' => 'core:PHP',
          'code' => '
                  if ($state["Attributes"]["leerling"][0]==1) {
                   $state["use_pi"] = ["key" => "0"];
                   }
           ',
      ],
        20 => [
            'class'             => 'privacyidea:serverconfig',
            'privacyideaserver' => 'https://privacyidea.example.com',
            'realm'             => 'example.com',
            'uidKey'            => 'uid',
            'sslverifyhost'     => true,
            'sslverifypeer'     => true,
            'enabledPath'       => 'use_pi',
            'enabledKey'        => 'key',
        ],
        25 => [
            'class'             => 'privacyidea:privacyidea',
        ],
    ],

];

1 Like