Jump to content

Logging in to admin using just WebAuthn (a YubiKey in my case)


netcarver
 Share

Recommended Posts

I guess I'm just becomming really lazy as I age, and this tutorial can be taken as a sign of my growing sloth.

I have a Yubikey that I use as my 2nd factor on a localy hosted PW site. And I've become tired of typing my admin username + password and hitting enter/clicking Submit + then having to tap the Yubikey to log in.  I know, it's a local install, and I could just turn off my 2FA, but then I'd still have to type the username and password, and I'm too lazy even for that now (plus, I've started to hate passwords.) I'd really rather just tap the yubikey to be logged in!

As PW's so hookable, I figured it would be pretty easy to modify the login process to allow me to do this, just for this site (well, maybe not just this one). Sure enough, it turned out to be pretty simple - though I do not recommend trying this on any sites hosted in the cloud.

Firstly, you'll need the TfaWebAuthn module installed on the site, and have configured it on your superuser account. Once you are logging in successfully with that, add the following to site/templates/admin.php...

/**
 * If there is only 1 superuser with TfaWebAuthn set up on the site,
 * and if the username is empty on login submission, we change the login_name
 * to the superuser's account name, and the login_pass to a dummy value to
 * allow the Session::authenticate hook to be called.
 *
 * Although the Session::authenticate method will fail we will hookAfter it
 * and pretend that it didn't. That will start 2FA credential collection
 * allowing us to proceed with just that protecting the account.
 *
 * For local installs where I have a YubiKey, this will be good enough.
 */
wire()->addHookAfter("ProcessLogin::loginFormProcessReady", function($event) {
    $uname = wire()->input->post->login_name ?? '';
    if ('' === $uname) {
        $super_role_id = wire()->config->superUserRolePageID;
        $supers = wire()->users->find("roles=$super_role_id, tfa_type=TfaWebAuthn");
        $num = count($supers);
        if (1 === $num) {
            $super = $supers->eq(0);
            wire()->input->post->login_name = $super->name;
            wire()->input->post->login_pass = 'dummy_password';
        }
    }
});
wire()->addHookAfter("Session::authenticate", function($event) {
    $super_role_id = wire()->config->superUserRolePageID;
    $supers = wire()->users->find("roles=$super_role_id, tfa_type=TfaWebAuthn");
    $num = count($supers);
    if (1 === $num) {
        $user = $event->arguments(0);
        $super = $supers->eq(0);
        if ($user->id === $super->id && 'TfaWebAuthn' === $user->hasTfa()) {
            $event->return = true; // Override earlier failed authentication for this user
        }
    }
});

As long as you leave the initial login details blank, all you need to do now is hit enter (or click Submit) and then tap the Yubikey to be logged in.

Nice :)

  • Like 4
Link to comment
Share on other sites

  • netcarver changed the title to Logging in to admin using just WebAuthn (a YubiKey in my case)

Ok, if anyone wants to explore this, and has RockMigrations installed, here's a slightly improved version of the above, packaged as a Tweak.

QuickWebAuthnLogin.php
 

Spoiler
<?php

namespace RockMigrations\Tweaks;

use ProcessWire\HookEvent;
use function ProcessWire\wire;

/**
 * If there is only 1 superuser with TfaWebAuthn set up on a debug mode site
 * and if the username is empty on login submission, we change the login_name
 * to the superuser's account name, and the login_pass to a dummy value to
 * allow the Session::authenticate hook to be called.
 *
 * Although the Session::authenticate method will fail we will hookAfter it
 * and pretend that it didn't. That will start 2FA credential collection
 * allowing us to proceed with just that protecting the account.
 *
 * For local installs where I have a YubiKey, this will be good enough.
 */
final class QuickWebAuthnLogin extends Tweak
{
  public $description = "Allow Quick Login as unique SuperUser to sites in debug mode using just WebAuthn credentials";

  private $supers;
  private $superuser;

  public function ready() {
    if ($this->wire->page->template != 'admin') return; // Not admin interface
    if ($this->wire->fields->get('tfa_type') === null) return; // No 2FA set up
    if (!$this->wire->config->debug) return; // Not a debug mode site

    $super_role_id = $this->wire->config->superUserRolePageID;
    $this->supers = $this->wire->users->find("roles=$super_role_id, tfa_type=TfaWebAuthn");

    if (1 !== count($this->supers)) return; // Not exactly 1 TfaWebAuthn superuser

    $this->superuser = $this->supers->eq(0);

    if ('TfaWebAuthn' !== $this->superuser->hasTfa()) return; // TfaWebAuthn Not fully configured for superuser

    wire()->addHookAfter("ProcessLogin::loginFormProcessReady", $this, "fillLoginForm");
    wire()->addHookAfter("Session::authenticate", $this, "overridePasswordAuthentication");
  }

  protected function fillLoginForm(HookEvent $event) {
    $uname = wire()->input->post->login_name ?? '';
    $upass = wire()->input->post->login_pass ?? '';
    if ('' === $uname && '' === $upass) {
      wire()->input->post->login_name = $this->superuser->name;
      wire()->input->post->login_pass = 'dummy_password'; // Not empty so PW to processes it
    }
  }

  protected function overridePasswordAuthentication(HookEvent $event) {
    $user = $event->arguments(0);
    if ($user->id === $this->superuser->id && 'TfaWebAuthn' === $user->hasTfa()) {
      // Override earlier failed password authentication for this user
      // WebAuthn 2FA will kick in now, just as if the password was entered correctly.
      // So we only need to press our YubiKey button or use our face/fingerprint etc.
      $event->return = true;
    }
  }

}

 

 

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...