Skip to content

Modernize login#5500

Open
jrauh01 wants to merge 7 commits intomainfrom
modernize-login
Open

Modernize login#5500
jrauh01 wants to merge 7 commits intomainfrom
modernize-login

Conversation

@jrauh01
Copy link
Copy Markdown
Contributor

@jrauh01 jrauh01 commented May 4, 2026

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

resolve #5495

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the login flow by migrating the legacy Zend-based login view/controller/form to ipl/compat equivalents and consolidating the login page markup into a reusable widget, with related CSS/JS adjustments.

Changes:

  • Replace the Zend LoginForm with an ipl CompatForm implementation and adapt login handling to the compat lifecycle.
  • Replace the legacy login.phtml view script with a new LoginPage widget used by a CompatController-based AuthenticationController.
  • Update login-related CSS/JS selectors and styles, including spacing for additional login buttons and a typo fix in orb IDs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
public/js/icinga/history.js Adjusts the login selector used during onload redirect handling for the new nesting.
public/css/icinga/login.less Updates layout and spacing for the new login markup and added login buttons container.
public/css/icinga/login-orbs.less Fixes the orb ID typo to match the updated markup (orb-notifications).
library/Icinga/Web/Widget/LoginPage.php Introduces a widget encapsulating the full login page structure (form, footer, social links, orbs).
application/views/scripts/authentication/login.phtml Removes the legacy view script in favor of the widget-based rendering.
application/forms/Authentication/LoginForm.php Migrates the login form to CompatForm, adds CSRF/UID, and updates success/error handling.
application/controllers/AuthenticationController.php Migrates controller to CompatController and renders LoginPage instead of a view script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

'class' => $this->getPopulatedValue('username') === null ? 'autofocus' : '',
'placeholder' => $this->translate('Username'),
'decorators' => [
'RenderElement' => new RenderElementDecorator(),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the username field does need an errors decorator as it's never rendering an error.

Comment thread library/Icinga/Web/Widget/LoginPage.php Outdated
$setupNote = $this->translate(
'It appears that you did not configure Icinga Web 2 yet so it\'s not possible to log in'
. ' without any defined authentication method. Please define an authentication method by'
. ' following the instructions in the %s or by using our %s.',
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +180 to +185
'a',
Attributes::create([
'href' => 'https://www.facebook.com/icinga',
'target' => '_blank',
'title' => $this->translate('Icinga on Facebook'),
'aria-label' => $this->translate('Icinga on Facebook')
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary, because we link to our own page.

Comment on lines +198 to +203
'a',
Attributes::create([
'href' => 'https://github.com/Icinga',
'target' => '_blank',
'title' => $this->translate('Icinga on GitHub'),
'aria-label' => $this->translate('Icinga on GitHub'),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary, because we link to our own page.

.errors {
background-color: @color-critical;
color: white;
margin: 0;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already done by form.icinga-forms .errors in forms.less.

jrauh01 added 7 commits May 5, 2026 14:43
Replace the legacy Zend-based `LoginForm` with an ipl `CompatForm`-based form:

- Add `CsrfCounterMeasure` and `FormUid` traits
- Replace `init()`/`createElements()` with `__construct()´/`assemble()` using
  inline ipl decorator objects instead of Zend decorator arrays
- Replace `getRedirectUrl()` with `createRedirectUrl()` because
  `getRedirectUrl()` would override `ipl\Html\Form::getRedirectUrl()`
    - use `hasBeenAssembled()` instead of `$this->created`
    - use `str_contains()` instead of `strpos()`
- Rewrite `onSuccess()` for `CompatForm`:
    - void return type
    - use `Icinga::app()->getResponse()` instead of `$this->getResponse()`
    - use `addMessage()` instead of `addError()`
    - call `setRedirectUrl()` explicitly
- Expose `onError()` as public so controller event listeners can call it
Extract the login page structure (logo, footer, social links, decorative orbs)
from `login.phtml` into a reusable ipl-html widget. Extending `HtmlDocument`
rather than `BaseHtmlElement` lets it emit `#login` and the seven `.orb` sibling
divs without a wrapping root tag.

Both the login action and the upcoming 2FA challenge action can now share the
same visual scaffolding without duplicating markup and without using view
scripts anymore.
Convert `AuthenticationController` from the legacy Zend Controller to
`CompatController`, dropping `login.phtml` in favour of the new `LoginPage`
widget and `addContent()`. The view variable assignments are replaced by
`setTitle()` and `addContent(new LoginPage(...))`.

In `CompatController`, `$this->controls` is the tab bar area rendered above the
page content. When no tabs are added it still emits an empty
`<div class="controls">` wrapper. Replacing it with a bare `HtmlDocument` which
renders as nothing when empty suppresses that wrapper entirely, keeping the
login page markup clean.

Handle the redirect on success in an `ON_SUBMIT` event handler. Delegate the
external-backend-only check to `LoginForm::onRequest()` via `ON_REQUEST`. Use
`$this->getServerRequest()` instead of `ServerRequest::fromGlobals()`.

Two structural fixes required by the changed DOM nesting:
- `login.less`: height `100%` -> `100vh` (`#login` is now inside `.content`
  which has no explicit height, so percentage inheritance breaks)
- `history.js`: `#layout > #login` -> `#layout #login` (direct-child selector
  breaks because `#login` is now a grandchild of `#layout` through `.content`)
Adjust login.less to match the HTML structure emitted by CompatForm:

- Add width: unset and margin on `.icinga-form` inside `.login-form` so the ipl
  form does not overflow its container and control groups have spacing
- Restyle `.errors` at the li level rather than the container level, giving each
  error message its own red box with margin between them
- Remove the padding from `.errors`/`.form-errors` that was set at the container
  level (now on each li)
- Change `.remember-me-box` align-items from `flex-start` to `center` so the
  toggle switch and label sit at the same baseline

Also fix a pre-existing typo in `login-orbs.less`: `#orb-notifactions` ->
`#orb-notifications`
Group the `LoginButtonHook`-provided buttons inside a `div.login-buttons`
so they can be styled independently from the main form submit button, and
skip the wrapper entirely when no additional buttons are present.
Ensure `.errors` inside `.login-buttons` has no extra padding and that
the last error item retains a bottom margin, matching the layout used
for the primary login form errors.
@jrauh01 jrauh01 force-pushed the modernize-login branch from d14271f to 9feb539 Compare May 5, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoginButtons via LoginButtonHook could use some margin

3 participants