mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
Improve passkeys management for domain joined computers
This commit is contained in:
@@ -8,11 +8,25 @@ use App\Support\Passkeys\RelyingPartyIdResolver;
|
||||
use Spatie\LaravelPasskeys\Actions\GeneratePasskeyRegisterOptionsAction as BaseGeneratePasskeyRegisterOptionsAction;
|
||||
use Spatie\LaravelPasskeys\Models\Concerns\HasPasskeys;
|
||||
use Spatie\LaravelPasskeys\Support\Config;
|
||||
use Webauthn\AuthenticatorSelectionCriteria;
|
||||
use Webauthn\PublicKeyCredentialCreationOptions;
|
||||
use Webauthn\PublicKeyCredentialRpEntity;
|
||||
|
||||
final class GeneratePasskeyRegisterOptionsAction extends BaseGeneratePasskeyRegisterOptionsAction
|
||||
{
|
||||
/**
|
||||
* WebAuthn algorithms we tell the browser we accept. Order matters:
|
||||
* the authenticator will pick the first algorithm it supports.
|
||||
* -7 = ES256 (used by most FIDO2 hardware keys, Apple, Android)
|
||||
* -257 = RS256 (used by Windows Hello / TPM-backed platform authenticators)
|
||||
* -8 = EdDSA (used by some modern security keys & password managers)
|
||||
*/
|
||||
private const SUPPORTED_ALGORITHMS = [
|
||||
['type' => 'public-key', 'alg' => -7],
|
||||
['type' => 'public-key', 'alg' => -257],
|
||||
['type' => 'public-key', 'alg' => -8],
|
||||
];
|
||||
|
||||
public function execute(
|
||||
HasPasskeys $authenticatable,
|
||||
bool $asJson = true,
|
||||
@@ -28,24 +42,88 @@ final class GeneratePasskeyRegisterOptionsAction extends BaseGeneratePasskeyRegi
|
||||
return $options;
|
||||
}
|
||||
|
||||
$supportedAlgorithms = [
|
||||
['type' => 'public-key', 'alg' => -7], // ES256
|
||||
['type' => 'public-key', 'alg' => -257], // RS256
|
||||
];
|
||||
|
||||
// Different serializer/browser integrations can use either shape:
|
||||
// - options.pubKeyCredParams (WebAuthn JSON)
|
||||
// - options.publicKey.pubKeyCredParams (navigator.credentials.create payload)
|
||||
// Enforce valid algorithms for both to prevent "alg undefined" errors.
|
||||
$decoded['pubKeyCredParams'] = $supportedAlgorithms;
|
||||
// Enforce valid algorithms (including RS256 for Windows Hello) for both
|
||||
// to prevent "alg undefined" errors and to allow Windows TPM-backed
|
||||
// platform authenticators to participate.
|
||||
$decoded['pubKeyCredParams'] = self::SUPPORTED_ALGORITHMS;
|
||||
|
||||
// WebAuthn L3 hints help the browser show a richer chooser including
|
||||
// Windows Hello (client-device), phones (hybrid) and security keys.
|
||||
$hints = array_values(array_filter((array) config('passkeys.hints', [])));
|
||||
if ($hints !== []) {
|
||||
$decoded['hints'] = $hints;
|
||||
}
|
||||
|
||||
// Request the credProps extension so we know whether a discoverable
|
||||
// (resident) key was actually created by the authenticator.
|
||||
if ((bool) config('passkeys.request_cred_props_extension', true)) {
|
||||
$decoded['extensions'] = array_merge(
|
||||
(array) ($decoded['extensions'] ?? []),
|
||||
['credProps' => true],
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($decoded['publicKey']) && is_array($decoded['publicKey'])) {
|
||||
$decoded['publicKey']['pubKeyCredParams'] = $supportedAlgorithms;
|
||||
$decoded['publicKey']['pubKeyCredParams'] = self::SUPPORTED_ALGORITHMS;
|
||||
|
||||
if ($hints !== []) {
|
||||
$decoded['publicKey']['hints'] = $hints;
|
||||
}
|
||||
|
||||
if ((bool) config('passkeys.request_cred_props_extension', true)) {
|
||||
$decoded['publicKey']['extensions'] = array_merge(
|
||||
(array) ($decoded['publicKey']['extensions'] ?? []),
|
||||
['credProps' => true],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return json_encode($decoded, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default selection criteria so that:
|
||||
* - both platform authenticators (Windows Hello, Touch ID, password
|
||||
* managers) and roaming/cross-platform FIDO2 security keys are offered;
|
||||
* - a resident key is "preferred" rather than "required" — Windows
|
||||
* domain-joined machines frequently refuse to expose Windows Hello when
|
||||
* `required` is requested, which is why those users only saw the
|
||||
* hardware-key dialog.
|
||||
*/
|
||||
public function authenticatorSelection(): AuthenticatorSelectionCriteria
|
||||
{
|
||||
$attachment = config('passkeys.authenticator_selection.authenticator_attachment');
|
||||
$userVerification = (string) config(
|
||||
'passkeys.authenticator_selection.user_verification',
|
||||
AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_PREFERRED,
|
||||
);
|
||||
$residentKey = config(
|
||||
'passkeys.authenticator_selection.resident_key',
|
||||
AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENT_PREFERRED,
|
||||
);
|
||||
|
||||
if (! in_array($attachment, AuthenticatorSelectionCriteria::AUTHENTICATOR_ATTACHMENTS, true)) {
|
||||
$attachment = AuthenticatorSelectionCriteria::AUTHENTICATOR_ATTACHMENT_NO_PREFERENCE;
|
||||
}
|
||||
|
||||
if (! in_array($userVerification, AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENTS, true)) {
|
||||
$userVerification = AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_PREFERRED;
|
||||
}
|
||||
|
||||
if (! in_array($residentKey, AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENTS, true)) {
|
||||
$residentKey = AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENT_PREFERRED;
|
||||
}
|
||||
|
||||
return new AuthenticatorSelectionCriteria(
|
||||
authenticatorAttachment: $attachment,
|
||||
userVerification: $userVerification,
|
||||
residentKey: $residentKey,
|
||||
);
|
||||
}
|
||||
|
||||
protected function relatedPartyEntity(): PublicKeyCredentialRpEntity
|
||||
{
|
||||
$rpId = RelyingPartyIdResolver::resolve();
|
||||
|
||||
@@ -42,6 +42,50 @@ return [
|
||||
'icon' => null,
|
||||
],
|
||||
|
||||
/*
|
||||
* Controls the WebAuthn `authenticatorSelection` ceremony parameters that are
|
||||
* sent to the browser when a user is registering a new passkey.
|
||||
*
|
||||
* - `authenticator_attachment` accepts: null (no preference - allows both
|
||||
* Windows Hello / Touch ID / password managers AND roaming FIDO2 keys),
|
||||
* "platform" (Windows Hello / Touch ID / Android only) or
|
||||
* "cross-platform" (only roaming/hardware security keys).
|
||||
* Leave it `null` so users on Windows domain machines see Windows Hello,
|
||||
* password managers AND hardware keys in the browser picker.
|
||||
*
|
||||
* - `resident_key` accepts: "preferred" (recommended), "required" or
|
||||
* "discouraged". Some locked-down Windows domain machines refuse to expose
|
||||
* the platform authenticator when "required" is requested. Use
|
||||
* "preferred" for the widest interoperability.
|
||||
*
|
||||
* - `user_verification` accepts: "preferred", "required" or "discouraged".
|
||||
*/
|
||||
'authenticator_selection' => [
|
||||
'authenticator_attachment' => env('PASSKEY_AUTHENTICATOR_ATTACHMENT'), // null = no preference
|
||||
'resident_key' => env('PASSKEY_RESIDENT_KEY', 'preferred'),
|
||||
'user_verification' => env('PASSKEY_USER_VERIFICATION', 'preferred'),
|
||||
],
|
||||
|
||||
/*
|
||||
* WebAuthn Level 3 client hints. Modern Chromium based browsers (including
|
||||
* Edge on Windows) use these to render a richer credential chooser that
|
||||
* lists Windows Hello, mobile (hybrid/QR) and security keys side by side.
|
||||
*
|
||||
* Allowed values: "client-device", "hybrid", "security-key".
|
||||
*/
|
||||
'hints' => [
|
||||
'client-device',
|
||||
'hybrid',
|
||||
'security-key',
|
||||
],
|
||||
|
||||
/*
|
||||
* Whether to request the `credProps` WebAuthn extension. It tells the
|
||||
* server (via the browser response) whether the created credential is a
|
||||
* discoverable / resident key. Safe to leave enabled.
|
||||
*/
|
||||
'request_cred_props_extension' => true,
|
||||
|
||||
/*
|
||||
* The models used by the package.
|
||||
*
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
data-passkeys='@json($passkeyPayload)'
|
||||
>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300">
|
||||
Register a passkey from your security key, browser, or password manager.
|
||||
Register a passkey using Windows Hello, Touch ID / Face ID, your phone, a password manager, or a FIDO2 security key.
|
||||
</p>
|
||||
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
|
||||
On managed/company devices, platform passkeys (Windows Hello/PIN) may be disabled by policy. In that case, use a FIDO2 security key or another allowed passkey provider.
|
||||
On a Windows domain / managed device the browser will show all available options. If Windows Hello is still disabled by group policy, you can fall back to a hardware security key or scan a QR code with your phone.
|
||||
</p>
|
||||
|
||||
<template x-if="!supported">
|
||||
|
||||
Reference in New Issue
Block a user