icingaweb2/application/controllers/TwoFactorController.php
Johannes Rauh 238ce10e6b Make TwoFactorHook::first() throw and migrate its only caller
`TwoFactorController` used `TwoFactorHook::first() === null` as a presence
check. This is replaced with `TwoFactorHook::all() === []` so the intent is
explicit and the call is no longer dependent on `first()`'s nullable return.

`first()` itself is updated to throw `RuntimeException` when no method is
registered rather than returning null. Callers that reach `first()` expect
at least one method to be available. A missing registration indicates a
misconfiguration rather than a recoverable condition. This matches the
behavior of `fromName()`.
2026-05-27 10:47:21 +02:00

82 lines
2.9 KiB
PHP

<?php
// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
// SPDX-License-Identifier: GPL-3.0-or-later
namespace Icinga\Controllers;
use Icinga\Application\Hook\TwoFactorHook;
use Icinga\Forms\Account\TwoFactorEnrollmentForm;
use ipl\Html\Contract\Form;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Web\Compat\CompatController;
/**
* Two-factor authentication configuration
*/
class TwoFactorController extends CompatController
{
public function init(): void
{
$this->getTabs()
->add('account', [
'title' => $this->translate('Update your account'),
'label' => $this->translate('My Account'),
'url' => 'account'
])
->add('navigation', [
'title' => $this->translate('List and configure your own navigation items'),
'label' => $this->translate('Navigation'),
'url' => 'navigation'
])
->add('devices', [
'title' => $this->translate('List of devices you are logged in'),
'label' => $this->translate('My Devices'),
'url' => 'my-devices'
])
->add('two-factor', [
'title' => $this->translate('Configure two-factor authentication'),
'label' => $this->translate('Two-Factor Auth'),
'url' => 'two-factor/config'
]);
}
/**
* Render the two-factor authentication configuration page
*
* Shows an informational notice when no two-factor method is registered.
* Otherwise, renders {@see TwoFactorEnrollmentForm}, letting the user
* enroll in or unenroll from registered two-factor methods.
*
* @return void
*/
public function configAction(): void
{
$this->getTabs()->activate('two-factor');
$this->addContent(HtmlElement::create('h1', null, Text::create($this->translate('Two-Factor Authentication'))));
if (TwoFactorHook::all() === []) {
$this->addContent(Text::create($this->translate(
'No two-factor authentication method is available. Enable a module that provides'
. ' an implementation to configure two-factor authentication for your account.'
)));
return;
}
$enrolledMethodName = TwoFactorHook::loadEnrolled()?->getName();
$chooseMethodForm = (new TwoFactorEnrollmentForm())
->setEnrolled($enrolledMethodName !== null)
->populate([TwoFactorEnrollmentForm::METHOD => $enrolledMethodName])
->on(Form::ON_SUBMIT, function (TwoFactorEnrollmentForm $form) {
if ($redirectUrl = $form->getRedirectUrl()) {
$this->redirectNow($redirectUrl);
}
})
->handleRequest($this->getServerRequest());
$this->addContent($chooseMethodForm);
}
}