Skip to content

Commit 0b266cd

Browse files
authored
Modernize login (#5500)
This PR replaces the legacy Zend-based login form and authentication controller with their ipl equivalents, and extracts the login page view script markup into a reusable widget. ### Convert `LoginForm` to `CompatForm` `LoginForm` now extends `CompatForm`, replacing `init()`/`createElements()` with `__construct()`/`assemble()` and Zend decorator arrays with inline ipl decorator objects. The `CsrfCounterMeasure` and `FormUid` traits are added. `getRedirectUrl()` is renamed to `createRedirectUrl()` to avoid overriding `CompatForm::getRedirectUrl()`, using `hasBeenAssembled` instead of `$this->created` and `str_contains()` instead of `strpos()`. `onSuccess()` is rewritten for the CompatForm lifecycle: void return, explicit `setRedirectUrl()` call, `Icinga::app()->getResponse()` instead of `$this->getResponse()`, and `addMessage()` instead of `addError()`. ### New `LoginPage` widget to replace view script Extracts the login page structure (logo, footer, social links, decorative orbs) from `login.phtml` into a new `LoginPage` widget extending `HtmlDocument`, so the markup is defined in one place and no longer lives in a view script. Additional login buttons provided by `LoginButtonHook` are now grouped in a `div.login-buttons` flex container, rendered only when buttons are actually present. ### Convert `AuthenticationController` to `CompatController` `AuthenticationController` now extends `CompatController`, dropping `login.phtml` in favour of `LoginPage` and `addContent()`. The form is built with an `ON_SUBMIT` handler for the redirect and an `ON_REQUEST` handler delegating to `LoginForm::onRequest()`. Uses `$this->getServerRequest()` instead of `ServerRequest::fromGlobals()`. ### CSS / JS fixes - `login.less`: - `height: 100%` -> `100vh` on `#login` (now a grandchild of `#layout` via `.content`) - `.login-buttons` styled as a flex column with a row gap and top margin - per-`li` error styling, including spacing inside `.login-buttons` - `.icinga-form` width and control-group spacing - `align-items: center` on `.remember-me-box` - label `margin-right` reset for the disabled-state description - `history.js`: `#layout > #login` -> `#layout #login` (direct-child selector broke with the new nesting) - `login-orbs.less`: fixes long-standing typo `#orb-notifactions` -> `#orb-notifications`
2 parents 845792b + 059073a commit 0b266cd

7 files changed

Lines changed: 425 additions & 186 deletions

File tree

application/controllers/AuthenticationController.php

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
namespace Icinga\Controllers;
77

8-
use GuzzleHttp\Psr7\ServerRequest;
98
use Icinga\Application\ClassLoader;
109
use Icinga\Application\Hook\AuthenticationHook;
1110
use Icinga\Application\Hook\LoginButtonHook;
@@ -16,17 +15,20 @@
1615
use Icinga\Common\Database;
1716
use Icinga\Exception\AuthenticationException;
1817
use Icinga\Forms\Authentication\LoginForm;
19-
use Icinga\Web\Controller;
2018
use Icinga\Web\Helper\CookieHelper;
2119
use Icinga\Web\RememberMe;
2220
use Icinga\Web\Url;
21+
use Icinga\Web\Widget\LoginPage;
22+
use ipl\Html\Contract\Form;
23+
use ipl\Web\Compat\CompatController;
24+
use Psr\Http\Message\ServerRequestInterface;
2325
use RuntimeException;
2426
use Throwable;
2527

2628
/**
2729
* Application wide controller for authentication
2830
*/
29-
class AuthenticationController extends Controller
31+
class AuthenticationController extends CompatController
3032
{
3133
use Database;
3234

@@ -49,7 +51,17 @@ public function loginAction()
4951
if (($requiresSetup = $icinga->requiresSetup()) && $icinga->setupTokenExists()) {
5052
$this->redirectNow(Url::fromPath('setup'));
5153
}
52-
$form = new LoginForm();
54+
55+
$form = (new LoginForm())
56+
->setAction(Url::fromRequest()->getAbsoluteUrl())
57+
->on(Form::ON_SUBMIT, function (LoginForm $form) {
58+
if ($redirectUrl = $form->getRedirectUrl()) {
59+
$this->redirectNow($redirectUrl);
60+
}
61+
})
62+
->on(Form::ON_REQUEST, function (ServerRequestInterface $_, LoginForm $form) {
63+
$form->onRequest();
64+
});
5365

5466
if (RememberMe::hasCookie() && $this->hasDb()) {
5567
$authenticated = false;
@@ -81,14 +93,16 @@ public function loginAction()
8193
if ($redirect) {
8294
$redirectUrl = Url::fromPath($redirect, [], $this->getRequest());
8395
if ($redirectUrl->isExternal()) {
84-
$this->httpBadRequest('nope');
96+
$this->httpBadRequest('Redirect to an external host is not allowed');
8597
}
8698
} else {
87-
$redirectUrl = $form->getRedirectUrl();
99+
$redirectUrl = $form->createRedirectUrl();
88100
}
89101

90102
$this->redirectNow($redirectUrl);
91103
}
104+
105+
$request = $this->getServerRequest();
92106
if (! $requiresSetup) {
93107
$cookies = new CookieHelper($this->getRequest());
94108
if (! $cookies->isSupported()) {
@@ -99,11 +113,10 @@ public function loginAction()
99113
->sendResponse();
100114
exit;
101115
}
102-
$form->handleRequest();
116+
$form->handleRequest($request);
103117
}
104118

105119
$loginButtons = [];
106-
$request = ServerRequest::fromGlobals();
107120

108121
foreach (LoginButtonHook::all() as $class => $hook) {
109122
try {
@@ -115,7 +128,7 @@ public function loginAction()
115128
$button,
116129
ClassLoader::classBelongsToModule($class) ? ClassLoader::extractModuleName($class) : null
117130
))
118-
->on(LoginButtonForm::ON_SUCCESS, function () use ($button): void {
131+
->on(Form::ON_SUBMIT, function () use ($button): void {
119132
($button->onClick)();
120133
})
121134
->handleRequest($request);
@@ -126,10 +139,10 @@ public function loginAction()
126139
}
127140
}
128141

129-
$this->view->form = $form;
130-
$this->view->loginButtons = $loginButtons;
131-
$this->view->defaultTitle = $this->translate('Icinga Web 2 Login');
132-
$this->view->requiresSetup = $requiresSetup;
142+
// Suppress the rendering of controls bar
143+
$this->view->compact = true;
144+
$this->setTitle($this->translate('Icinga Web 2 Login'));
145+
$this->addContent(new LoginPage($form, $loginButtons, $requiresSetup));
133146
}
134147

135148
/**

0 commit comments

Comments
 (0)