diff options
author | Daniel Calviño Sánchez <danxuliu@gmail.com> | 2025-06-05 04:25:34 +0200 |
---|---|---|
committer | Daniel Calviño Sánchez <danxuliu@gmail.com> | 2025-07-11 02:54:16 +0200 |
commit | ac6b07356d305bb773b057fb28a323106e50e8d1 (patch) | |
tree | ace72b27c29b40a9245e2485c319303d5c4b285b | |
parent | ce8baf75c63f3aa9eb25b938670a038f2f85df95 (diff) | |
download | nextcloud-server-backport/53501/stable31.tar.gz nextcloud-server-backport/53501/stable31.zip |
fix: Fix theming for disabled accountsbackport/53501/stable31
The Theming app injects the stylesheets for the different themes in the
"<header>" element of the page, and those stylesheets are then loaded by
the browser from a "Controller" (a plain "Controller", not an
"OCSController"). The stylesheets, in turn, may also get some images
(like the background) also from the "Controller".
When handling a request to "index.php" it is checked whether the user is
logged in and, if not, a login is tried. A disabled user is explicitly
seen as not logged in, so a login is always tried in that case, but
disabled users are also explicitly prevented to log in, so the login
also fails. Due to that trying to get any of the themed stylesheets or
images with a disabled account (to be able to show the "Account
disabled" error page) fails with an HTTP status 401.
To solve that, and to avoid touching this basic logic as much as
possible, the login exception is now ignored (if the user is disabled)
for some specific requests to the Theming app.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
-rw-r--r-- | .github/workflows/integration-sqlite.yml | 1 | ||||
-rw-r--r-- | build/integration/config/behat.yml | 12 | ||||
-rw-r--r-- | build/integration/features/bootstrap/BasicStructure.php | 1 | ||||
-rw-r--r-- | build/integration/features/bootstrap/Theming.php | 49 | ||||
-rw-r--r-- | build/integration/theming_features/theming.feature | 131 | ||||
-rw-r--r-- | lib/base.php | 23 |
6 files changed, 215 insertions, 2 deletions
diff --git a/.github/workflows/integration-sqlite.yml b/.github/workflows/integration-sqlite.yml index 5eb89c23761..c0d3f701a49 100644 --- a/.github/workflows/integration-sqlite.yml +++ b/.github/workflows/integration-sqlite.yml @@ -69,6 +69,7 @@ jobs: - 'setup_features' - 'sharees_features' - 'sharing_features' + - 'theming_features' - 'videoverification_features' php-versions: ['8.1'] diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml index a3018c3966c..f27183e920c 100644 --- a/build/integration/config/behat.yml +++ b/build/integration/config/behat.yml @@ -255,4 +255,14 @@ default: admin: - admin - admin - regular_user_password: 123456
\ No newline at end of file + regular_user_password: 123456 + theming: + paths: + - "%paths.base%/../theming_features" + contexts: + - FeatureContext: + baseUrl: http://localhost:8080 + admin: + - admin + - admin + regular_user_password: 123456 diff --git a/build/integration/features/bootstrap/BasicStructure.php b/build/integration/features/bootstrap/BasicStructure.php index a8c232d6fe7..0290297dd88 100644 --- a/build/integration/features/bootstrap/BasicStructure.php +++ b/build/integration/features/bootstrap/BasicStructure.php @@ -19,6 +19,7 @@ trait BasicStructure { use Avatar; use Download; use Mail; + use Theming; /** @var string */ private $currentUser = ''; diff --git a/build/integration/features/bootstrap/Theming.php b/build/integration/features/bootstrap/Theming.php new file mode 100644 index 00000000000..f44a6533a1b --- /dev/null +++ b/build/integration/features/bootstrap/Theming.php @@ -0,0 +1,49 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +require __DIR__ . '/../../vendor/autoload.php'; + +trait Theming { + + private bool $undoAllThemingChangesAfterScenario = false; + + /** + * @AfterScenario + */ + public function undoAllThemingChanges() { + if (!$this->undoAllThemingChangesAfterScenario) { + return; + } + + $this->loggingInUsingWebAs('admin'); + $this->sendingAToWithRequesttoken('POST', '/index.php/apps/theming/ajax/undoAllChanges'); + + $this->undoAllThemingChangesAfterScenario = false; + } + + /** + * @When logged in admin uploads theming image for :key from file :source + * + * @param string $key + * @param string $source + */ + public function loggedInAdminUploadsThemingImageForFromFile(string $key, string $source) { + $this->undoAllThemingChangesAfterScenario = true; + + $file = \GuzzleHttp\Psr7\Utils::streamFor(fopen($source, 'r')); + + $this->sendingAToWithRequesttoken('POST', '/index.php/apps/theming/ajax/uploadImage?key=' . $key, + [ + 'multipart' => [ + [ + 'name' => 'image', + 'contents' => $file + ] + ] + ]); + $this->theHTTPStatusCodeShouldBe('200'); + } +} diff --git a/build/integration/theming_features/theming.feature b/build/integration/theming_features/theming.feature new file mode 100644 index 00000000000..2ae5d4f75c3 --- /dev/null +++ b/build/integration/theming_features/theming.feature @@ -0,0 +1,131 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +Feature: theming + + Background: + Given user "user0" exists + + Scenario: themed stylesheets are available for users + Given As an "user0" + When sending "GET" with exact url to "/index.php/apps/theming/theme/default.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/light.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/dark.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/light-highcontrast.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/dark-highcontrast.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/opendyslexic.css" + Then the HTTP status code should be "200" + + Scenario: themed stylesheets are available for guests + Given As an "anonymous" + When sending "GET" with exact url to "/index.php/apps/theming/theme/default.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/light.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/dark.css" + Then the HTTP status code should be "200" + # Themes that can not be explicitly set by a guest could have been + # globally set too through "enforce_theme". + When sending "GET" with exact url to "/index.php/apps/theming/theme/light-highcontrast.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/dark-highcontrast.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/opendyslexic.css" + Then the HTTP status code should be "200" + + Scenario: themed stylesheets are available for disabled users + Given As an "admin" + And assure user "user0" is disabled + And As an "user0" + When sending "GET" with exact url to "/index.php/apps/theming/theme/default.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/light.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/dark.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/light-highcontrast.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/dark-highcontrast.css" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/theme/opendyslexic.css" + Then the HTTP status code should be "200" + + Scenario: themed images are available for users + Given Logging in using web as "admin" + And logged in admin uploads theming image for "background" from file "data/clouds.jpg" + And logged in admin uploads theming image for "logo" from file "data/coloured-pattern-non-square.png" + And logged in admin uploads theming image for "logoheader" from file "data/coloured-pattern-non-square.png" + And As an "user0" + When sending "GET" with exact url to "/index.php/apps/theming/image/background" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/image/logo" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/image/logoheader" + Then the HTTP status code should be "200" + + Scenario: themed images are available for guests + Given Logging in using web as "admin" + And logged in admin uploads theming image for "background" from file "data/clouds.jpg" + And logged in admin uploads theming image for "logo" from file "data/coloured-pattern-non-square.png" + And logged in admin uploads theming image for "logoheader" from file "data/coloured-pattern-non-square.png" + And As an "anonymous" + When sending "GET" with exact url to "/index.php/apps/theming/image/background" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/image/logo" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/image/logoheader" + Then the HTTP status code should be "200" + + Scenario: themed images are available for disabled users + Given Logging in using web as "admin" + And logged in admin uploads theming image for "background" from file "data/clouds.jpg" + And logged in admin uploads theming image for "logo" from file "data/coloured-pattern-non-square.png" + And logged in admin uploads theming image for "logoheader" from file "data/coloured-pattern-non-square.png" + And As an "admin" + And assure user "user0" is disabled + And As an "user0" + When sending "GET" with exact url to "/index.php/apps/theming/image/background" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/image/logo" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/image/logoheader" + Then the HTTP status code should be "200" + + Scenario: themed icons are available for users + Given As an "user0" + When sending "GET" with exact url to "/index.php/apps/theming/favicon" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/icon" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/favicon/dashboard" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/icon/dashboard" + Then the HTTP status code should be "200" + + Scenario: themed icons are available for guests + Given As an "anonymous" + When sending "GET" with exact url to "/index.php/apps/theming/favicon" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/icon" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/favicon/dashboard" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/icon/dashboard" + Then the HTTP status code should be "200" + + Scenario: themed icons are available for disabled users + Given As an "admin" + And assure user "user0" is disabled + And As an "user0" + When sending "GET" with exact url to "/index.php/apps/theming/favicon" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/icon" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/favicon/dashboard" + Then the HTTP status code should be "200" + When sending "GET" with exact url to "/index.php/apps/theming/icon/dashboard" + Then the HTTP status code should be "200" diff --git a/lib/base.php b/lib/base.php index f8a90bd63f2..63f2e758428 100644 --- a/lib/base.php +++ b/lib/base.php @@ -11,6 +11,7 @@ use OC\Share20\GroupDeletedListener; use OC\Share20\Hooks; use OC\Share20\UserDeletedListener; use OC\Share20\UserRemovedListener; +use OC\User\DisabledUserException; use OCP\EventDispatcher\IEventDispatcher; use OCP\Group\Events\GroupDeletedEvent; use OCP\Group\Events\UserRemovedEvent; @@ -1026,7 +1027,27 @@ class OC { // OAuth needs to support basic auth too, so the login is not valid // inside Nextcloud and the Login exception would ruin it. if ($request->getRawPathInfo() !== '/apps/oauth2/api/v1/token') { - self::handleLogin($request); + try { + self::handleLogin($request); + } catch (DisabledUserException $e) { + // Disabled users would not be seen as logged in and + // trying to log them in would fail, so the login + // exception is ignored for the themed stylesheets and + // images. + if ($request->getRawPathInfo() !== '/apps/theming/theme/default.css' + && $request->getRawPathInfo() !== '/apps/theming/theme/light.css' + && $request->getRawPathInfo() !== '/apps/theming/theme/dark.css' + && $request->getRawPathInfo() !== '/apps/theming/theme/light-highcontrast.css' + && $request->getRawPathInfo() !== '/apps/theming/theme/dark-highcontrast.css' + && $request->getRawPathInfo() !== '/apps/theming/theme/opendyslexic.css' + && $request->getRawPathInfo() !== '/apps/theming/image/background' + && $request->getRawPathInfo() !== '/apps/theming/image/logo' + && $request->getRawPathInfo() !== '/apps/theming/image/logoheader' + && !str_starts_with($request->getRawPathInfo(), '/apps/theming/favicon') + && !str_starts_with($request->getRawPathInfo(), '/apps/theming/icon')) { + throw $e; + } + } } } } |