From f83bf89cd1b558ba21e76a892a9b73a75b528e15 Mon Sep 17 00:00:00 2001
From: "Alexander A. Klimov"
Date: Wed, 5 Nov 2025 10:33:48 +0100
Subject: [PATCH] LoginButtonHook: additional buttons to be displayed below the
login form
---
.../controllers/AuthenticationController.php | 32 ++++++++++++++
.../forms/Authentication/ButtonForm.php | 42 +++++++++++++++++++
.../views/scripts/authentication/login.phtml | 1 +
.../Hook/LoginButton/LoginButton.php | 25 +++++++++++
.../Application/Hook/LoginButtonHook.php | 28 +++++++++++++
public/css/icinga/login.less | 10 ++---
6 files changed, 133 insertions(+), 5 deletions(-)
create mode 100644 application/forms/Authentication/ButtonForm.php
create mode 100644 library/Icinga/Application/Hook/LoginButton/LoginButton.php
create mode 100644 library/Icinga/Application/Hook/LoginButtonHook.php
diff --git a/application/controllers/AuthenticationController.php b/application/controllers/AuthenticationController.php
index 752f8453c..dbb155fd0 100644
--- a/application/controllers/AuthenticationController.php
+++ b/application/controllers/AuthenticationController.php
@@ -3,17 +3,23 @@
namespace Icinga\Controllers;
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Application\ClassLoader;
use Icinga\Application\Hook\AuthenticationHook;
+use Icinga\Application\Hook\LoginButton\LoginButton;
+use Icinga\Application\Hook\LoginButtonHook;
use Icinga\Application\Icinga;
use Icinga\Application\Logger;
use Icinga\Common\Database;
use Icinga\Exception\AuthenticationException;
+use Icinga\Forms\Authentication\ButtonForm;
use Icinga\Forms\Authentication\LoginForm;
use Icinga\Web\Controller;
use Icinga\Web\Helper\CookieHelper;
use Icinga\Web\RememberMe;
use Icinga\Web\Url;
use RuntimeException;
+use Throwable;
/**
* Application wide controller for authentication
@@ -93,7 +99,33 @@ class AuthenticationController extends Controller
}
$form->handleRequest();
}
+
+ $loginButtons = [];
+ $request = ServerRequest::fromGlobals();
+
+ foreach (LoginButtonHook::all() as $class => $hook) {
+ try {
+ foreach ($hook->getButtons() as $index => $button) {
+ assert($button instanceof LoginButton);
+
+ $loginButtons[] = (new ButtonForm(
+ "$class!$index",
+ $button,
+ ClassLoader::classBelongsToModule($class) ? ClassLoader::extractModuleName($class) : null
+ ))
+ ->on(ButtonForm::ON_SUCCESS, function () use ($button): void {
+ ($button->onClick)();
+ })
+ ->handleRequest($request);
+ }
+ } catch (Throwable $e) {
+ Logger::error('Failed to execute login button hook: %s', $e);
+ continue;
+ }
+ }
+
$this->view->form = $form;
+ $this->view->loginButtons = $loginButtons;
$this->view->defaultTitle = $this->translate('Icinga Web 2 Login');
$this->view->requiresSetup = $requiresSetup;
}
diff --git a/application/forms/Authentication/ButtonForm.php b/application/forms/Authentication/ButtonForm.php
new file mode 100644
index 000000000..99ef7f8ed
--- /dev/null
+++ b/application/forms/Authentication/ButtonForm.php
@@ -0,0 +1,42 @@
+defaultAttributes['name'] = $name;
+ }
+
+ protected function assemble(): void
+ {
+ $button = new SubmitButtonElement('btn_submit', $this->button->attributes);
+
+ if ($this->moduleName) {
+ $button->addAttributes(['class' => "icinga-module module-$this->moduleName"]);
+ }
+
+ $this->addElement($button->addHtml($this->button->content));
+ $this->addHtml($this->createUidElement());
+ $this->addElement($this->createCsrfCounterMeasure(Session::getSession()->getId()));
+ }
+}
diff --git a/application/views/scripts/authentication/login.phtml b/application/views/scripts/authentication/login.phtml
index 130e9b97b..bf538d337 100644
--- a/application/views/scripts/authentication/login.phtml
+++ b/application/views/scripts/authentication/login.phtml
@@ -22,6 +22,7 @@
) ?>
= $this->form ?>
+ = implode('', $this->loginButtons) ?>