Skip to content

Streamline authentication process#5387

Open
nilmerg wants to merge 5 commits intomainfrom
streamline-authentication-process
Open

Streamline authentication process#5387
nilmerg wants to merge 5 commits intomainfrom
streamline-authentication-process

Conversation

@nilmerg
Copy link
Copy Markdown
Member

@nilmerg nilmerg commented Jul 8, 2025

This is split into four distinct parts: (One commit is only performing a clean up)

1. EmbeddedWeb: Explicitly perform authentication

It is nowadays no exception that stylesheet may be dependent on who's using the app. So to avoid race conditions like in #5385 authentication is an explicit step during bootstrap now.
EmbeddedWeb now knows about and is responsible to initially set up the user object. So this does not change when Web sets up the user, it just allows EmbeddedWeb to do it.

A small side-effect introduced by this change is fully optional, but doesn't break anything either: Method Web::setupSession() and the accompanying Web::$session property are gone now as the property was obsolete already. Initializing the session is still done at the previous stage though, but implicitly by Web::setupNotifications().

2. Auth: Perform authentication only once and not lazily

Since authentication is now performed even for static resources, there's no reason anymore to support implicit authentication. This also limits authentication attempts to a single one, previously failed attempts were repeated. Requiring authentication during bootstrapping, i.e. before authentication has been performed, will now throw an error.

This conflicts with #5430 as it also affects Auth::isAuthenticated(). But this should be easy to resolve.

3. Manager: Perform module loading asynchronously

So that authentication can suspend it. There are cases, e.g. cube, where authentication is required in run.php. During bootstrapping loading modules is mostly required to load libraries, register routes and hooks. Most of the time authentication is not required for these, but if it is, evaluation is now interrupted and continued after authentication has actually been performed.

I don't see a real risk for any breaking change here, since authentication happens shortly after. It actually avoids a breaking change, since without this, cube's Icinga DB support would break or at least malfunction.

And cube is only a single example. As long as the monitoring module is still supported by them, they will keep being affected.

Enable the monitoring module and Icinga DB Web in an environment and look at the debug log to see this change in effect.

4. Module: Expect user and group backends upon registration

Providing a user or user group backend in configuration.php now triggers a deprecation or warning. They are expected to be announced in run.php, just like hooks. Authentication attempts during a configuration.php run, while Authentication has not been performed yet, will be also suspended now. This ensures that the current behavior, being broken or working, stays the same.

You might think that this is a breaking change, but it was rather always broken and only worked in such particular situations that custom backends were never used in conjunction with any of the official modules mentioned in 3.

Removing the compatibility layer (the suspension part) with v2.15 might indeed be a bit hasty. But I rather like to get rid of this as early as possible and I think those who have custom extensions like this, in a functional state, are a minority and known to us. (i.e. Icinga partners which we can forewarn)

@nilmerg nilmerg added this to the 2.13 milestone Jul 8, 2025
@nilmerg nilmerg self-assigned this Jul 8, 2025
@nilmerg nilmerg added area/framework Affects third party integration/development area/authentication Affects user authentication or authorization affects-upgrades The change requires migration or user awareness labels Jul 8, 2025
@cla-bot cla-bot Bot added the cla/signed label Jul 8, 2025
@nilmerg nilmerg force-pushed the streamline-authentication-process branch 2 times, most recently from 02f3532 to e21071c Compare July 8, 2025 14:41
@nilmerg nilmerg force-pushed the streamline-authentication-process branch 3 times, most recently from 2a857f1 to 4534aad Compare February 11, 2026 11:48
@nilmerg nilmerg force-pushed the streamline-authentication-process branch from 4534aad to 36314e1 Compare March 11, 2026 16:58
@lippserd lippserd removed this from the 2.13 milestone Mar 24, 2026
@nilmerg nilmerg force-pushed the streamline-authentication-process branch from 36314e1 to a39fd7b Compare April 30, 2026 11:19
@nilmerg nilmerg added this to the 2.14.0 milestone Apr 30, 2026
@nilmerg nilmerg force-pushed the streamline-authentication-process branch from a39fd7b to 4caf9db Compare April 30, 2026 12:52
@nilmerg nilmerg requested review from Copilot and lippserd April 30, 2026 12:52
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 restructures Icinga Web’s authentication flow to be performed explicitly during bootstrap (including for static resources) and introduces Fiber-based suspension/resumption so module loading and configuration evaluation can defer user-dependent logic until authentication has completed.

Changes:

  • Add Auth::authenticate() and make Auth::isAuthenticated() block (via Fiber suspension) until authentication has been performed.
  • Move initial user setup responsibility into EmbeddedWeb (and simplify Web by removing now-obsolete session setup and duplicative user setup).
  • Load enabled modules/config scripts “asynchronously” using Fibers, and deprecate providing user/user-group backends from configuration.php (expect run.php instead).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
library/Icinga/Authentication/Auth.php Introduces explicit authentication and Fiber suspension/resumption behavior
library/Icinga/Application/Web.php Removes legacy session/user setup and delegates initial user setup to EmbeddedWeb
library/Icinga/Application/EmbeddedWeb.php Performs authentication + initial user setup during embedded bootstrap
library/Icinga/Application/Modules/Manager.php Loads enabled modules in Fibers (non-CLI) to allow suspension during auth
library/Icinga/Application/Modules/Module.php Runs module config scripts in Fibers for backend discovery + adds deprecation warnings
doc/80-Upgrading.md Documents deprecation: custom backends must move from configuration.php to run.php
Comments suppressed due to low confidence (1)

library/Icinga/Application/Modules/Manager.php:213

  • In async mode, loadEnabledModules() sets $this->loadedAllEnabledModules = true even though module loading is happening inside fibers that can suspend during authentication. This can leave enabled modules not actually loaded/registered while loadedAllEnabledModules() returns true, which breaks the ClassLoader fallback path that conditionally calls $modules->loadModule() when not all modules are loaded. Track the fibers and only flip this flag once they have terminated, or keep the flag false in async mode until authentication resumes all suspended module-load fibers.
        if (! $this->loadedAllEnabledModules) {
            $async = ! $this->app->isCli();
            foreach ($this->listEnabledModules() as $name) {
                if ($async) {
                    // May be suspended during authentication and resumed upon finish
                    (new Fiber(function () use ($name) {
                        Logger::debug(
                            'Loading enabled module "%s" asynchronously (Process %d; Fiber %d)',
                            $name,
                            getmypid() ?: 0,
                            spl_object_id(Fiber::getCurrent())
                        );

                        $this->loadModule($name);
                    }))->start();
                } else {
                    $this->loadModule($name);
                }
            }

            $this->loadedAllEnabledModules = true;
        }

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

Comment thread library/Icinga/Authentication/Auth.php Outdated
Comment thread library/Icinga/Application/Modules/Module.php
Comment thread library/Icinga/Application/Modules/Module.php
Comment thread library/Icinga/Application/Web.php
@nilmerg nilmerg force-pushed the streamline-authentication-process branch from 4caf9db to d467ad1 Compare May 4, 2026 14:33
@nilmerg nilmerg requested a review from Copilot May 4, 2026 14:35
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

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.


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

Comment thread library/Icinga/Authentication/Auth.php
Comment thread library/Icinga/Authentication/Auth.php
nilmerg added 2 commits May 4, 2026 16:56
It is nowadays no exception that stylesheet may be dependent
on who's using the app. So to avoid race conditions like
in #5385 authentication is an explicit step during bootstrap
now.

fixes #5385
Since authentication is now performed even for static
resources, there's no reason anymore to support implicit
authentication. This also limits authentication attempts
to a single one, previously failed attempts were repeated.

Requiring authentication during bootstrapping, i.e. before
authentication has been performed, will now throw an error.

refs #5265
nilmerg added 3 commits May 4, 2026 17:01
So that authentication can suspend it. There are cases,
e.g. cube, where authentication is required in run.php.
During bootstrapping loading modules is mostly required
to load libraries, register routes and hooks. Most of the
time authentication is not required for these, but if
it is, evaluation is now interrupted and continued
after authentication has actually been performed.

I don't see a real risk for any breaking change here,
since authentication happens shortly after. It actually
avoids a breaking change, since without this, cube's
Icinga DB support would break or at least malfunction.

And cube is only a single example.

refs #5265
The related controller action is gone since
b6b5caa
Providing a user or user group backend in configuration.php
now triggers a deprecation or warning. They are expected to
be announced in run.php, just like hooks. Authentication
attempts during a configuration.php run, while Authentication
has not been performed yet, will be also suspended now.
This ensures that the current behavior, being broken or
working, stays the same.

refs #5265
@nilmerg nilmerg force-pushed the streamline-authentication-process branch from d467ad1 to 5478d4a Compare May 4, 2026 15:01
@nilmerg nilmerg requested a review from Copilot May 4, 2026 15:03
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

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

library/Icinga/Application/Modules/Manager.php:213

  • loadEnabledModules() now starts module registration in separate Fibers and immediately sets $this->loadedAllEnabledModules = true, even though some module-load fibers may still be suspended (e.g. when module code calls Auth::isAuthenticated() before Auth::authenticate()). This can leave the manager in an inconsistent state where “all enabled modules are loaded” is reported while $this->loadedModules is still missing modules, and downstream logic that relies on this flag (e.g. module lazy-loading in ClassLoader, or one-time caching of custom backends from getLoadedModules()) may never re-check once the suspended fibers finally resume. Consider deferring loadedAllEnabledModules=true until all module fibers have completed (or tracking/waiting for pending fibers and only flipping the flag once the loadedModules map is complete).
            }

            $this->loadedAllEnabledModules = true;
        }

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

affects-upgrades The change requires migration or user awareness area/authentication Affects user authentication or authorization area/framework Affects third party integration/development cla/signed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CustomUserBackend is loaded too late Users who are not allowed to change the theme, cannot change the theme mode either

3 participants