simplesamlphp / simplesamlphp-module-webauthn

A module implementing FIDO2 / WebAuthn as a second authentication factor
GNU Lesser General Public License v2.1
15 stars 8 forks source link

Expected the key "UserID" to exist #45

Closed subhrajyoti21 closed 1 year ago

subhrajyoti21 commented 1 year ago

I am very new to PHP. I have trying to setup webauthn for simplesaml idp server. I have followed guide provided in SimpleSaml docs to setup an SP instance and an IDP instance. The connection between SP and IDP works flawlessly without webauthn. After following the documentation given in this github repo when i try setting up webauthn, i am getting below error post first level authentication.

SimpleSAML\Error\Error: UNHANDLEDEXCEPTION

Backtrace:
1 www/_include.php:17 (SimpleSAML_exception_handler)
0 [builtin] (N/A)
Caused by: SimpleSAML\Module\saml\Error: Responder: SimpleSAML\Error\UnserializableException: Expected the key "UserID" to exist.
Backtrace:
4 modules/saml/lib/Message.php:503 (SimpleSAML\Module\saml\Message::getResponseError)
3 modules/saml/lib/Message.php:635 (SimpleSAML\Module\saml\Message::processResponse)
2 modules/saml/www/sp/saml2-acs.php:141 (require)
1 lib/SimpleSAML/Module.php:266 (SimpleSAML\Module::process)
0 www/module.php:10 (N/A)

Here is my config in module_webauthn.php:

$config = [
    'store' => [
        'webauthn:Database',
        'database.dsn' => 'mysql:host=localhost;port=3306;dbname=auth',
        'database.username' => 'authuser',
        'database.password' => 'password',
    ],
    'attrib_username' => 'urn:oid:1.3.6.1.4.1.23735.100.0',
    'attrib_displayname' => 'urn:oid:2.5.4.3',
    'scope' => '<my_idp_domain>’,
    'request_tokenmodel' => true,
    'default_enable' => true,
    'force' => true,
    'attrib_toggle' => 'toggle',
    'use_database' => false,
    'use_inflow_registration' => true,
    'registration_auth_source' => 'default-sp',
];

Please let me know where am i going wrong.

Edit: I am using example-userpass as auth in my idp.

restena-sw commented 1 year ago

Which version of the module are you using? simpleSAMLphp 1.x should use the 0.11 branch; simpleSAMLphp 2.0 should use 2.0-rc2 or better the tip of release-2.0

subhrajyoti21 commented 1 year ago

I am using simplesaml php v1.19.7

subhrajyoti21 commented 1 year ago

webauthn version

{
            "name": "simplesamlphp/simplesamlphp-module-webauthn",
            "version": "v1.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/simplesamlphp/simplesamlphp-module-webauthn.git",
                "reference": "ce3f93804c73991e01302a51201a12f56627f4aa"
            },
…
restena-sw commented 1 year ago

The "latest" tag is on v0.11.1, please use that instead.

tvdijen commented 1 year ago

@restena-sw Now that the release-2.0 branch is deemed stable now, should we overwrite master? Because if I remember well, the master-branch was broken beyond repair..

restena-sw commented 1 year ago

Yes, good idea. That's not something I do very often though - can you do it?

tvdijen commented 1 year ago

Done! Now should I remove any v1.0.x tags?

restena-sw commented 1 year ago

I thought we had done that a long time ago, to prevent people to fall for it - like in this issue here. Please go ahead.

subhrajyoti21 commented 1 year ago

@restena-sw Thanks for the help. v0.11.1 seems to have fixed the error showing up.

I setup the tables as mentioned in the documentation for v0.11.1. Setup users student and employee(these are default for example-userpass which i am using at the moment) to use FIDO2 in the table userstatus. The user is however not asked to register for Webauthn post login via username and password. Is there anything else i might be missing?

restena-sw commented 1 year ago

The workflow for registering new tokens is controlled with the use_inflow_registration parameter.

With 0 tokens registered, and with use_inline_registration = true, the user will be asked to register after the username/password phase.

With 0 tokens registered, and with use_inflow_registration = false, the user will have to visit the dedicated token management page to register a token; they will NOT get a prompt to do so during the authentication phase.

Does this answer your question? If not, it would be helpful if you could share the complete module configuration.

restena-sw commented 1 year ago

Ah, I see the config above now :-) Do you actually enable the module as an authproc in config.php or saml20-idp-hosted.php?

restena-sw commented 1 year ago

Assuming you have it enabled, here is a probable catch: you have set "force" => true and "attrib_toggle" => "toggle".

When you read the doc comments regarding these parameters:

force : This parameter is used only if "use_database" is false. If the value of "force" is true then we trigger WebAuthn only if "attrib_toggle" from the user is not empty. If the value of "force" is false then we switch the value of "default_enable" only if "attrib_toggle" from the user is not empty. Default value is true.

attrib_toggle : This parameter stores the name of the attribute that is sent with user and which determines whether to trigger WebAuthn. Default value is 'toggle'.

You did set use_database to false. So, WebAuthN is only triggered if your users got an attribute named "toggle" with arbitrary content in their first-level authentication. example-userpass does not set any such attribute by default.

You are probably better off with default_enable: true, use_database: false, force: false (and then not actually setting an attribute called "toggle" in the first-factor auth).

(Note that adding those two users to the database was a pointless exercise - you have set use_database to false, so the DB will not be consulted for the purpose of determining whether WebAuthN should be triggered)

subhrajyoti21 commented 1 year ago

I have enabled webauth in both config.php and saml20-idp-hosted.php. I have remove the database details from the config. Below is what i have now:

'authproc' => [
        100 => array(
        'class' => 'webauthn:WebAuthn',
        ),
    ],

Below are details in module_webauth.php:

$config = [
    'debug' => false,
    'store' => [
        'webauthn:Database',
        'database.dsn' => 'mysql:host=localhost;port=3306;dbname=auth',
        'database.username' => 'authuser',
        'database.password' => 'password',
    ],
    'attrib_username' => 'urn:oid:1.3.6.1.4.1.23735.100.0',
    'attrib_displayname' => 'urn:oid:2.5.4.3',
    'scope' => '<my_idp_domain>’,
    'request_tokenmodel' => true,
    'default_enable' => true,
    'force' => false,
    'attrib_toggle' => 'toggle',
    'use_database' => false,
    'use_inflow_registration' => false,
    'registration_auth_source' => 'default-sp',
];

Below is my saml20-idp-hosted.php config:

$metadata['__DYNAMIC:1__'] = [
    'host' => '__DEFAULT__',
    'privatekey' => 'idp.pem',
    'certificate' => 'idp.crt',
    'auth' => 'example-userpass',
    'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
    'authproc' => [
        // Convert LDAP names to oids.
        //100 => ['class' => 'core:AttributeMap', 'name2oid'],
        100 => array(
        'class' => 'webauthn:WebAuthn',
        ),
    ],
];
restena-sw commented 1 year ago

'attrib_username' => 'urn:oid:1.3.6.1.4.1.23735.100.0' is just an example value and most certainly not correct (23735 is the IANA Enterprise number of my employer, and what we use here).

This setting has to match the attribute name that the first-factor authentication yields as "the attribute that identifies the user". I don't know from the top of my head how example-userpass calls the identifying attribute - maybe "uid". You can find out by going to the Admin / Test page and do a test auth with example-userpass. It will tell you the attribute that stores the username.

Then, set attrib_username to that attribute. Otherwise, the module cannot know who authenticated, and can not do anything.

You should check the logs. In the case of not-found user identifying attribute, the module logs a very telling warning about it: https://github.com/simplesamlphp/simplesamlphp-module-webauthn/blob/6fb48da23bca44d762f655ed5d7908457d8ee537/src/Auth/Process/WebAuthn.php#L120

subhrajyoti21 commented 1 year ago

@restena-sw Thanks for the suggestion to updating the attrib_username to uid. Registration page now loads up with message.

Please first register your token on the registration page before continuing.

After clicking on registration page link the flow was directed to a page where it asked to choose an idp. image

I investigated and found that registration_auth_source was set as default-sp. After changing the value of registration_auth_source to example-userpass assuming that it is the idp i am currently using, the registration page shows up the registration does not go through and throws the attached error.

image

restena-sw commented 1 year ago

This error is now in the middle of the WebAuthN transaction inside the browser, and out of direct control of the module.

The first thing to do is: remove cookies and re-open the browser fresh. Maybe there are some artifacts of the previous attempts in the session.

If the issue persists, do another attempt with the browser's JS console open - there will be an error message about the failed transaction (with varying amount of information included).

Also, make sure that the URL that serves the simpleSAMLphp session is on a host equal to the domain name configured in the "scope" parameter (you have blinded that part both in the config and the screenshot, so I can't check that aspect).

Lastly, you are executing the transaction on a host with an untrusted TLS certificate. I have never done so; and am not sure whether this violates the "secure context" requirement of WebAuthN. If so, I guess the JS error message would indicate this.

subhrajyoti21 commented 1 year ago

@restena-sw Thanks for the reply. https was the issue. Adding a ssl certificate resolved the issue. Webauthn now works perfectly on my SimpleSaml server.

Thanks for your help.