Confirm a console password against the console's own record
parent
f54d00b3e7
commit
513cadc5ce
|
|
@ -50,6 +50,11 @@ class Mail extends Component
|
|||
*/
|
||||
public bool $usable = true;
|
||||
|
||||
protected function confirmationGuard(): string
|
||||
{
|
||||
return 'operator';
|
||||
}
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->authorize('mail.manage');
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ class Secrets extends Component
|
|||
/** Result of the last connection test, for display only. */
|
||||
public ?array $check = null;
|
||||
|
||||
protected function confirmationGuard(): string
|
||||
{
|
||||
return 'operator';
|
||||
}
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->authorize('secrets.manage');
|
||||
|
|
|
|||
|
|
@ -39,9 +39,23 @@ trait ConfirmsPassword
|
|||
return $at > 0 && (time() - $at) < $this->confirmationWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Which guard's record this component confirms against.
|
||||
*
|
||||
* Overridden to 'operator' by the console components. A default of 'web'
|
||||
* keeps the portal working unchanged — and an override is explicit, where
|
||||
* sniffing the request would be one more thing to get wrong on a page that
|
||||
* gates access to credentials.
|
||||
*/
|
||||
protected function confirmationGuard(): string
|
||||
{
|
||||
return 'web';
|
||||
}
|
||||
|
||||
public function confirmPassword(): void
|
||||
{
|
||||
$key = 'confirm-password:'.auth()->id().'|'.request()->ip();
|
||||
$account = auth()->guard($this->confirmationGuard())->user();
|
||||
$key = 'confirm-password:'.$this->confirmationGuard().'|'.$account?->getAuthIdentifier().'|'.request()->ip();
|
||||
|
||||
if (RateLimiter::tooManyAttempts($key, 5)) {
|
||||
$this->addError('confirmablePassword', __('auth.throttle', [
|
||||
|
|
@ -51,7 +65,7 @@ trait ConfirmsPassword
|
|||
return;
|
||||
}
|
||||
|
||||
if (! Hash::check($this->confirmablePassword, auth()->user()->password)) {
|
||||
if ($account === null || ! Hash::check($this->confirmablePassword, $account->password)) {
|
||||
RateLimiter::hit($key, 60);
|
||||
$this->addError('confirmablePassword', __('admin_settings.password_wrong'));
|
||||
$this->reset('confirmablePassword');
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ class EditMailbox extends ModalComponent
|
|||
/** Whether this mailbox logs in before it sends — Codex R15#4, P1b. */
|
||||
public bool $authenticates = true;
|
||||
|
||||
protected function confirmationGuard(): string
|
||||
{
|
||||
return 'operator';
|
||||
}
|
||||
|
||||
public function mount(string $uuid): void
|
||||
{
|
||||
$this->authorize('mail.manage');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use App\Livewire\Admin\Secrets;
|
||||
use App\Models\Operator;
|
||||
use App\Models\User;
|
||||
use Livewire\Livewire;
|
||||
|
||||
beforeEach(fn () => config()->set('admin_access.secrets_key', 'base64:'.base64_encode(random_bytes(32))));
|
||||
|
||||
it('confirms a console password against the operator record, not a portal user', function () {
|
||||
$operator = Operator::factory()->role('Owner')->create(['password' => 'operator-passwort']);
|
||||
|
||||
Livewire::actingAs($operator, 'operator')->test(Secrets::class)
|
||||
->set('confirmablePassword', 'operator-passwort')
|
||||
->call('confirmPassword')
|
||||
->assertHasNoErrors();
|
||||
});
|
||||
|
||||
it('rejects a password that belongs to a portal user with the same address', function () {
|
||||
// The trap: two tables, one address. Confirming against the wrong one would
|
||||
// let a customer's password unlock the console.
|
||||
$operator = Operator::factory()->role('Owner')->create([
|
||||
'email' => 'doppelt@clupilot.test', 'password' => 'operator-passwort',
|
||||
]);
|
||||
User::factory()->create(['email' => 'doppelt@clupilot.test', 'password' => 'kunden-passwort']);
|
||||
|
||||
Livewire::actingAs($operator, 'operator')->test(Secrets::class)
|
||||
->set('confirmablePassword', 'kunden-passwort')
|
||||
->call('confirmPassword')
|
||||
->assertHasErrors('confirmablePassword');
|
||||
});
|
||||
|
||||
it('still confirms a portal password on the web guard', function () {
|
||||
$user = User::factory()->create(['password' => 'kunden-passwort']);
|
||||
|
||||
Livewire::actingAs($user)->test(App\Livewire\Settings::class)
|
||||
->set('confirmablePassword', 'kunden-passwort')
|
||||
->call('confirmPassword')
|
||||
->assertHasNoErrors();
|
||||
});
|
||||
Loading…
Reference in New Issue