nextcloud / twofactor_u2f

🔑 U2F second factor provider for Nextcloud
https://apps.nextcloud.com/apps/twofactor_u2f
GNU Affero General Public License v3.0
112 stars 26 forks source link

Unable to add YubiKey U2F #725

Open ahuemmer opened 4 years ago

ahuemmer commented 4 years ago

Steps to reproduce

  1. Try to register YubiKey using Two-Factor U2F

Expected behaviour

U2F registration should succeed

Actual behaviour

No progress is shown in the browser. JavaScript and backend errors are displayed in the development tools (see below).

Server configuration

Operating system: Gentoo Linux

Web server: Nginx 1.18.0-r1

Database: MariaDB 10.4.13-r2

PHP version: 7.4.8-r1

Version: 19.0.1.1 (problem also occurred in the newest 18.x version)

Updated from an older version or fresh install: Updated (several step-by-step-updates beginning with version 14 or 15)

List of activated apps:

Enabled:
  - accessibility: 1.5.0
  - activity: 2.12.0
  - bookmarks: 3.3.3
  - bruteforcesettings: 1.6.0
  - calendar: 2.0.3
  - cloud_federation_api: 1.2.0
  - comments: 1.9.0
  - contacts: 3.3.0
  - contactsinteraction: 1.0.0
  - dav: 1.15.0
  - federatedfilesharing: 1.9.0
  - federation: 1.9.0
  - files: 1.14.0
  - files_pdfviewer: 1.8.0
  - files_rightclick: 0.16.0
  - files_sharing: 1.11.0
  - files_texteditor: 2.11.0
  - files_trashbin: 1.9.0
  - files_versions: 1.12.0
  - files_videoplayer: 1.8.0
  - firstrunwizard: 2.8.0
  - logreader: 2.4.0
  - lookup_server_connector: 1.7.0
  - nextcloud_announcements: 1.8.0
  - notifications: 2.7.0
  - oauth2: 1.7.0
  - password_policy: 1.9.1
  - photos: 1.1.0
  - privacy: 1.3.0
  - provisioning_api: 1.9.0
  - recommendations: 0.7.0
  - serverinfo: 1.9.0
  - settings: 1.1.0
  - sharebymail: 1.9.0
  - support: 1.2.1
  - survey_client: 1.7.0
  - systemtags: 1.9.0
  - tasks: 0.13.3
  - text: 3.0.1
  - theming: 1.10.0
  - twofactor_backupcodes: 1.8.0
  - twofactor_totp: 4.1.3
  - twofactor_u2f: 5.1.0
  - updatenotification: 1.9.0
  - viewer: 1.3.0
  - workflowengine: 2.1.0
Disabled:
  - admin_audit
  - encryption
  - files_external
  - user_ldap

The content of config/config.php:

{
    "system": {
        "instanceid": "***REMOVED SENSITIVE VALUE***",
        "passwordsalt": "***REMOVED SENSITIVE VALUE***",
        "secret": "***REMOVED SENSITIVE VALUE***",
        "trusted_domains": [
            "some.domain",
            "some.other.domain",
            "and.so.on"
        ],
        "datadirectory": "***REMOVED SENSITIVE VALUE***",
        "dbtype": "mysql",
        "version": "19.0.1.1",
        "overwrite.cli.url": "https:\/\/some.domain",
        "overwriteprotocol": "https",
        "dbname": "***REMOVED SENSITIVE VALUE***",
        "dbhost": "***REMOVED SENSITIVE VALUE***",
        "dbport": "3306",
        "dbtableprefix": "oc_",
        "mysql.utf8mb4": true,
        "dbuser": "***REMOVED SENSITIVE VALUE***",
        "dbpassword": "***REMOVED SENSITIVE VALUE***",
        "installed": true,
        "updater.release.channel": "stable",
        "maintenance": false,
        "log_type": "file",
        "logfile": "\/var\/log\/nextcloud\/nextcloud.log",
        "log_authfailip": true,
        "forcessl": true,
        "theme": "",
        "loglevel": 2,
        "memcache.local": "\\OC\\Memcache\\APCu",
        "mail_smtpmode": "sendmail",
        "mail_sendmailmode": "smtp",
        "mail_from_address": "***REMOVED SENSITIVE VALUE***",
        "mail_domain": "***REMOVED SENSITIVE VALUE***",
        "twofactor_enforced": true,
        "twofactor_enforced_groups": [],
        "twofactor_enforced_excluded_groups": [],
        "updater.secret": "***REMOVED SENSITIVE VALUE***"
    }
}

Client configuration

Browser: Firefox 79

Operating system: Windows 10

Logs

Web server error log

(No meaningful entries considering the problem.)

Server log (data/nextcloud.log)
{
   "reqId":"NT9Cp09520MB7moGTqmI",
   "level":3,
   "time":"2020-08-14T14:57:32+00:00",
   "remoteAddr":"123.123.123.123",
   "user":"my_user",
   "app":"index",
   "method":"POST",
   "url":"/apps/twofactor_u2f/settings/finishregister",
   "message":{
      "Exception":"Exception",
      "Message":"Argument 1 passed to OCA\\TwoFactorU2F\\Controller\\SettingsController::finishRegister() must be of the type string, null given, called in /var/www/localhost/htdocs/cloud/lib/private/AppFramework/Http/Dispatcher.php on line 170",
      "Code":0,
      "Trace":[
         {
            "file":"/var/www/localhost/htdocs/cloud/lib/private/AppFramework/App.php",
            "line":137,
            "function":"dispatch",
            "class":"OC\\AppFramework\\Http\\Dispatcher",
            "type":"->"
         },
         {
            "file":"/var/www/localhost/htdocs/cloud/lib/private/AppFramework/Routing/RouteActionHandler.php",
            "line":47,
            "function":"main",
            "class":"OC\\AppFramework\\App",
            "type":"::"
         },
         {
            "function":"__invoke",
            "class":"OC\\AppFramework\\Routing\\RouteActionHandler",
            "type":"->"
         },
         {
            "file":"/var/www/localhost/htdocs/cloud/lib/private/Route/Router.php",
            "line":297,
            "function":"call_user_func"
         },
         {
            "file":"/var/www/localhost/htdocs/cloud/lib/base.php",
            "line":1007,
            "function":"match",
            "class":"OC\\Route\\Router",
            "type":"->"
         },
         {
            "file":"/var/www/localhost/htdocs/cloud/index.php",
            "line":37,
            "function":"handleRequest",
            "class":"OC",
            "type":"::"
         }
      ],
      "File":"/var/www/localhost/htdocs/cloud/lib/private/AppFramework/Http/Dispatcher.php",
      "Line":110,
      "Previous":{
         "Exception":"TypeError",
         "Message":"Argument 1 passed to OCA\\TwoFactorU2F\\Controller\\SettingsController::finishRegister() must be of the type string, null given, called in /var/www/localhost/htdocs/cloud/lib/private/AppFramework/Http/Dispatcher.php on line 170",
         "Code":0,
         "Trace":[
            {
               "file":"/var/www/localhost/htdocs/cloud/lib/private/AppFramework/Http/Dispatcher.php",
               "line":170,
               "function":"finishRegister",
               "class":"OCA\\TwoFactorU2F\\Controller\\SettingsController",
               "type":"->"
            },
            {
               "file":"/var/www/localhost/htdocs/cloud/lib/private/AppFramework/Http/Dispatcher.php",
               "line":100,
               "function":"executeController",
               "class":"OC\\AppFramework\\Http\\Dispatcher",
               "type":"->"
            },
            {
               "file":"/var/www/localhost/htdocs/cloud/lib/private/AppFramework/App.php",
               "line":137,
               "function":"dispatch",
               "class":"OC\\AppFramework\\Http\\Dispatcher",
               "type":"->"
            },
            {
               "file":"/var/www/localhost/htdocs/cloud/lib/private/AppFramework/Routing/RouteActionHandler.php",
               "line":47,
               "function":"main",
               "class":"OC\\AppFramework\\App",
               "type":"::"
            },
            {
               "function":"__invoke",
               "class":"OC\\AppFramework\\Routing\\RouteActionHandler",
               "type":"->"
            },
            {
               "file":"/var/www/localhost/htdocs/cloud/lib/private/Route/Router.php",
               "line":297,
               "function":"call_user_func"
            },
            {
               "file":"/var/www/localhost/htdocs/cloud/lib/base.php",
               "line":1007,
               "function":"match",
               "class":"OC\\Route\\Router",
               "type":"->"
            },
            {
               "file":"/var/www/localhost/htdocs/cloud/index.php",
               "line":37,
               "function":"handleRequest",
               "class":"OC",
               "type":"::"
            }
         ],
         "File":"/var/www/localhost/htdocs/cloud/apps/twofactor_u2f/lib/Controller/SettingsController.php",
         "Line":66
      },
      "CustomMessage":"--"
   },
   "userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0",
   "version":"19.0.1.1"
}
Browser log

From the JavaScript console log:

Just after clicking on "Add U2F device", without any other actions:

Uncaught (in promise) Error: U2F device registration failed (error code unknown)
    rejectRegistration AddDeviceDialog.vue:157
    register AddDeviceDialog.vue:135
    promise callback*register AddDeviceDialog.vue:135
    promise callback*start AddDeviceDialog.vue:105
    VueJS 29
    <anonymous> main-settings.js:52
    Webpack 3
AddDeviceDialog.vue:157
    rejectRegistration AddDeviceDialog.vue:157
    rejectRegistration self-hosted:935
    register AddDeviceDialog.vue:135
    (Async: promise callback)
    register AddDeviceDialog.vue:135
    register self-hosted:935
    (Async: promise callback)
    start AddDeviceDialog.vue:105
    start self-hosted:935
    VueJS 29
    <anonym> main-settings.js:52
    Webpack 3

After naming the device and clicking "Add":

twofactor_u2f: Error persisting registration 
Object { app: "twofactor_u2f", uid: "andy", config: {…}, request: XMLHttpRequest, response: {…}, isAxiosError: true, toJSON: toJSON()
 }
ConsoleLogger.js:54:18
    value ConsoleLogger.js:54
    value ConsoleLogger.js:80
    saveRegistrationData AddDeviceDialog.vue:188
    (Async: promise callback)
    saveRegistrationData AddDeviceDialog.vue:187
    submit AddDeviceDialog.vue:170
    VueJS 26
    start AddDeviceDialog.vue:106
    (Async: promise callback)
    start AddDeviceDialog.vue:106

and

[ERROR] twofactor_u2f: Error: Server error while trying to complete U2F device registration 
Object { app: "twofactor_u2f", uid: "andy" }
ConsoleLogger.js:54:18
    value ConsoleLogger.js:54
    value ConsoleLogger.js:80
    submit AddDeviceDialog.vue:175
    VueJS 26
    start AddDeviceDialog.vue:106
    (Async: promise callback)
    start AddDeviceDialog.vue:106
    VueJS 29
    <anonym> main-settings.js:52
    Webpack 3

The relevant requests I can see in the network tab:

startregister, response (request body was empty), code 200:

{"req":{"version":"U2F_V2","challenge":"ivnkLjiQAZKT5xDXDpRxgplT9jfd7HPxUP9Oz6y2HU4","appId":"https://some.domain"},"sigs":[]}

finishregister, request:

{"name":"Test"}

(No more content!) Response code was 500 with nextcloud standard 500 error page.

Personal remarks

I see a big similarity to #622 and #690 here, but IMHO I have done everything right, following the instructions there (esp. the overwriteprotocol and overwrite.cli.url settings.

The Nextcloud installation is served "directly" by the nginx, no proxy or anything in between.

In the Nextcloud admin tab, there are no open issues ("All checks passed.").

What I tried so far:

No luck for now.

Any help would be greatly appreciated! :) Thanks in advance!

cogliostro commented 4 years ago

Seeing the same problem on our installation running Nextcloud 19.0.5.

ChristophWurst commented 4 years ago

Uncaught (in promise) Error: U2F device registration failed (error code unknown)

This is the important bit of information. @cogliostro do you see the same in the browser console?

cogliostro commented 4 years ago

Yes. But it seems to work in Firefox. It fails in MS Edge ( the new one ).

cogliostro commented 4 years ago

Also seems to work in Chrome.

ChristophWurst commented 4 years ago

Okay but @ahuemmer reported this as not working on Firefox. It could be two unrelated issues.

Also pay close attention to the logged error. Does it contain an error code?

cogliostro commented 4 years ago

"Exception":"TypeError","Message":"Argument 1 passed to OCA\TwoFactorU2F\Controller\SettingsController::finishRegister() must be of the type string, null given, called in /var/www/nextcloud/lib/private/AppFramework/Http/Dispatcher.php on line 170"

ChristophWurst commented 4 years ago

This is not a server error https://github.com/nextcloud/twofactor_u2f/issues/789#issuecomment-732056807

ChristophWurst commented 4 years ago

Check the browser console for the u2f error code

cogliostro commented 4 years ago

I'm seeing the same errors in the console as @ahuemmer registered.

Uncaught (in promise) Error: U2F device registration failed (error code unknown) at a.rejectRegistration (AddDeviceDialog.vue:157) at AddDeviceDialog.vue:135

POST https://xfiles.nhn.no/apps/twofactor_u2f/settings/finishregister 500 (Internal Server Error)

[ERROR] twofactor_u2f: Error persisting registration {app: "twofactor_u2f", uid: "KENNETHV", config: {…}, request: XMLHttpRequest, response: {…}, …}

[ERROR] twofactor_u2f: Error: Server error while trying to complete U2F device registration {app: "twofactor_u2f", uid: "KENNETHV"}

ChristophWurst commented 4 years ago

error code unknown

I guess we should add a console.error to https://github.com/nextcloud/twofactor_u2f/blob/27b330b5821e97cc1720172176a06a42cf4b6533/src/components/AddDeviceDialog.vue#L154-L159 so the original error is logged. Now it's impossible to find out what it was.

killua99 commented 3 years ago

For my case, I discover the error start happen on this callback

https://example.org/apps/twofactor_u2f/settings/startregister

there I get a json where the appId has the URL scheme as http:// even tho I'm doing a request from a valid https://. My server has a good setup on https, I could connect with desktop clients on my nextcloud installation and the overview said everything is clear and green, no error on https where I could see.

Now, I force it tho and push my id on client side (so browser, not PHP directly) to be https, it made the request well but then, when I'm about to save and store my data this next callback.

https://xample.org/apps/twofactor_u2f/settings/finishregister

Is where I stop, since the class on \OCA\TwoFactorU2F\Service\U2FManager::finishRegistration makes a call to \OCA\TwoFactorU2F\Service\U2FManager::getU2f

for some reason this code

    private function getU2f(): U2F {
        $url = $this->request->getServerProtocol() . '://' . $this->request->getServerHost();
        return new U2F($url);
    }

get the server protocol as http. I'm thinking is because my proxy server is behind a traefik reverse proxy where I call the port 80 on nginx and that pass it to the php-fpm as scheme http.

I'm going to force nginx to deliver the scheme https even on port 80 and come back with the result.

Hope this could provide some tracks on this matter.

killua99 commented 3 years ago

Yes, this system variable that you could place on config.php did the trick

'overwriteprotocol'  => ' https' ,

Now the appId has https: and when making the request the Yubikey could be added without issue if your browser detect you are on a valid SSL Cert, the php backend just need to be tricked.

ahuemmer commented 3 years ago

Thank you, @killua99, for your investigation! Unfortunately, this doesn't apply to my case, as I've always had the overwriteprotocol setting set to https as you suggested.

ChristophWurst commented 3 years ago

Btw https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/reverse_proxy_configuration.html is the docs page for reverse proxies if anyone wants to double-check their setups. That also covers the overwirteprotocol.

ashuio commented 3 years ago

@ChristophWurst Should i add a note in README letting users know to use https?

ChristophWurst commented 3 years ago

Yes please :+1: