Skip to content

Commit 3f03fed

Browse files
authored
Merge pull request #53902 from nextcloud/backport/53501/stable31
[stable31] fix: Fix theming for disabled accounts
2 parents eb2f309 + ac6b073 commit 3f03fed

File tree

11 files changed

+230
-5
lines changed

11 files changed

+230
-5
lines changed

.github/workflows/integration-sqlite.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ jobs:
6969
- 'setup_features'
7070
- 'sharees_features'
7171
- 'sharing_features'
72+
- 'theming_features'
7273
- 'videoverification_features'
7374

7475
php-versions: ['8.1']

build/integration/config/behat.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,14 @@ default:
255255
admin:
256256
- admin
257257
- admin
258-
regular_user_password: 123456
258+
regular_user_password: 123456
259+
theming:
260+
paths:
261+
- "%paths.base%/../theming_features"
262+
contexts:
263+
- FeatureContext:
264+
baseUrl: http://localhost:8080
265+
admin:
266+
- admin
267+
- admin
268+
regular_user_password: 123456

build/integration/features/bootstrap/BasicStructure.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ trait BasicStructure {
1919
use Avatar;
2020
use Download;
2121
use Mail;
22+
use Theming;
2223

2324
/** @var string */
2425
private $currentUser = '';
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/**
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
require __DIR__ . '/../../vendor/autoload.php';
8+
9+
trait Theming {
10+
11+
private bool $undoAllThemingChangesAfterScenario = false;
12+
13+
/**
14+
* @AfterScenario
15+
*/
16+
public function undoAllThemingChanges() {
17+
if (!$this->undoAllThemingChangesAfterScenario) {
18+
return;
19+
}
20+
21+
$this->loggingInUsingWebAs('admin');
22+
$this->sendingAToWithRequesttoken('POST', '/index.php/apps/theming/ajax/undoAllChanges');
23+
24+
$this->undoAllThemingChangesAfterScenario = false;
25+
}
26+
27+
/**
28+
* @When logged in admin uploads theming image for :key from file :source
29+
*
30+
* @param string $key
31+
* @param string $source
32+
*/
33+
public function loggedInAdminUploadsThemingImageForFromFile(string $key, string $source) {
34+
$this->undoAllThemingChangesAfterScenario = true;
35+
36+
$file = \GuzzleHttp\Psr7\Utils::streamFor(fopen($source, 'r'));
37+
38+
$this->sendingAToWithRequesttoken('POST', '/index.php/apps/theming/ajax/uploadImage?key=' . $key,
39+
[
40+
'multipart' => [
41+
[
42+
'name' => 'image',
43+
'contents' => $file
44+
]
45+
]
46+
]);
47+
$this->theHTTPStatusCodeShouldBe('200');
48+
}
49+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
2+
# SPDX-License-Identifier: AGPL-3.0-or-later
3+
Feature: theming
4+
5+
Background:
6+
Given user "user0" exists
7+
8+
Scenario: themed stylesheets are available for users
9+
Given As an "user0"
10+
When sending "GET" with exact url to "/index.php/apps/theming/theme/default.css"
11+
Then the HTTP status code should be "200"
12+
When sending "GET" with exact url to "/index.php/apps/theming/theme/light.css"
13+
Then the HTTP status code should be "200"
14+
When sending "GET" with exact url to "/index.php/apps/theming/theme/dark.css"
15+
Then the HTTP status code should be "200"
16+
When sending "GET" with exact url to "/index.php/apps/theming/theme/light-highcontrast.css"
17+
Then the HTTP status code should be "200"
18+
When sending "GET" with exact url to "/index.php/apps/theming/theme/dark-highcontrast.css"
19+
Then the HTTP status code should be "200"
20+
When sending "GET" with exact url to "/index.php/apps/theming/theme/opendyslexic.css"
21+
Then the HTTP status code should be "200"
22+
23+
Scenario: themed stylesheets are available for guests
24+
Given As an "anonymous"
25+
When sending "GET" with exact url to "/index.php/apps/theming/theme/default.css"
26+
Then the HTTP status code should be "200"
27+
When sending "GET" with exact url to "/index.php/apps/theming/theme/light.css"
28+
Then the HTTP status code should be "200"
29+
When sending "GET" with exact url to "/index.php/apps/theming/theme/dark.css"
30+
Then the HTTP status code should be "200"
31+
# Themes that can not be explicitly set by a guest could have been
32+
# globally set too through "enforce_theme".
33+
When sending "GET" with exact url to "/index.php/apps/theming/theme/light-highcontrast.css"
34+
Then the HTTP status code should be "200"
35+
When sending "GET" with exact url to "/index.php/apps/theming/theme/dark-highcontrast.css"
36+
Then the HTTP status code should be "200"
37+
When sending "GET" with exact url to "/index.php/apps/theming/theme/opendyslexic.css"
38+
Then the HTTP status code should be "200"
39+
40+
Scenario: themed stylesheets are available for disabled users
41+
Given As an "admin"
42+
And assure user "user0" is disabled
43+
And As an "user0"
44+
When sending "GET" with exact url to "/index.php/apps/theming/theme/default.css"
45+
Then the HTTP status code should be "200"
46+
When sending "GET" with exact url to "/index.php/apps/theming/theme/light.css"
47+
Then the HTTP status code should be "200"
48+
When sending "GET" with exact url to "/index.php/apps/theming/theme/dark.css"
49+
Then the HTTP status code should be "200"
50+
When sending "GET" with exact url to "/index.php/apps/theming/theme/light-highcontrast.css"
51+
Then the HTTP status code should be "200"
52+
When sending "GET" with exact url to "/index.php/apps/theming/theme/dark-highcontrast.css"
53+
Then the HTTP status code should be "200"
54+
When sending "GET" with exact url to "/index.php/apps/theming/theme/opendyslexic.css"
55+
Then the HTTP status code should be "200"
56+
57+
Scenario: themed images are available for users
58+
Given Logging in using web as "admin"
59+
And logged in admin uploads theming image for "background" from file "data/clouds.jpg"
60+
And logged in admin uploads theming image for "logo" from file "data/coloured-pattern-non-square.png"
61+
And logged in admin uploads theming image for "logoheader" from file "data/coloured-pattern-non-square.png"
62+
And As an "user0"
63+
When sending "GET" with exact url to "/index.php/apps/theming/image/background"
64+
Then the HTTP status code should be "200"
65+
When sending "GET" with exact url to "/index.php/apps/theming/image/logo"
66+
Then the HTTP status code should be "200"
67+
When sending "GET" with exact url to "/index.php/apps/theming/image/logoheader"
68+
Then the HTTP status code should be "200"
69+
70+
Scenario: themed images are available for guests
71+
Given Logging in using web as "admin"
72+
And logged in admin uploads theming image for "background" from file "data/clouds.jpg"
73+
And logged in admin uploads theming image for "logo" from file "data/coloured-pattern-non-square.png"
74+
And logged in admin uploads theming image for "logoheader" from file "data/coloured-pattern-non-square.png"
75+
And As an "anonymous"
76+
When sending "GET" with exact url to "/index.php/apps/theming/image/background"
77+
Then the HTTP status code should be "200"
78+
When sending "GET" with exact url to "/index.php/apps/theming/image/logo"
79+
Then the HTTP status code should be "200"
80+
When sending "GET" with exact url to "/index.php/apps/theming/image/logoheader"
81+
Then the HTTP status code should be "200"
82+
83+
Scenario: themed images are available for disabled users
84+
Given Logging in using web as "admin"
85+
And logged in admin uploads theming image for "background" from file "data/clouds.jpg"
86+
And logged in admin uploads theming image for "logo" from file "data/coloured-pattern-non-square.png"
87+
And logged in admin uploads theming image for "logoheader" from file "data/coloured-pattern-non-square.png"
88+
And As an "admin"
89+
And assure user "user0" is disabled
90+
And As an "user0"
91+
When sending "GET" with exact url to "/index.php/apps/theming/image/background"
92+
Then the HTTP status code should be "200"
93+
When sending "GET" with exact url to "/index.php/apps/theming/image/logo"
94+
Then the HTTP status code should be "200"
95+
When sending "GET" with exact url to "/index.php/apps/theming/image/logoheader"
96+
Then the HTTP status code should be "200"
97+
98+
Scenario: themed icons are available for users
99+
Given As an "user0"
100+
When sending "GET" with exact url to "/index.php/apps/theming/favicon"
101+
Then the HTTP status code should be "200"
102+
When sending "GET" with exact url to "/index.php/apps/theming/icon"
103+
Then the HTTP status code should be "200"
104+
When sending "GET" with exact url to "/index.php/apps/theming/favicon/dashboard"
105+
Then the HTTP status code should be "200"
106+
When sending "GET" with exact url to "/index.php/apps/theming/icon/dashboard"
107+
Then the HTTP status code should be "200"
108+
109+
Scenario: themed icons are available for guests
110+
Given As an "anonymous"
111+
When sending "GET" with exact url to "/index.php/apps/theming/favicon"
112+
Then the HTTP status code should be "200"
113+
When sending "GET" with exact url to "/index.php/apps/theming/icon"
114+
Then the HTTP status code should be "200"
115+
When sending "GET" with exact url to "/index.php/apps/theming/favicon/dashboard"
116+
Then the HTTP status code should be "200"
117+
When sending "GET" with exact url to "/index.php/apps/theming/icon/dashboard"
118+
Then the HTTP status code should be "200"
119+
120+
Scenario: themed icons are available for disabled users
121+
Given As an "admin"
122+
And assure user "user0" is disabled
123+
And As an "user0"
124+
When sending "GET" with exact url to "/index.php/apps/theming/favicon"
125+
Then the HTTP status code should be "200"
126+
When sending "GET" with exact url to "/index.php/apps/theming/icon"
127+
Then the HTTP status code should be "200"
128+
When sending "GET" with exact url to "/index.php/apps/theming/favicon/dashboard"
129+
Then the HTTP status code should be "200"
130+
When sending "GET" with exact url to "/index.php/apps/theming/icon/dashboard"
131+
Then the HTTP status code should be "200"

lib/base.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use OC\Share20\Hooks;
1212
use OC\Share20\UserDeletedListener;
1313
use OC\Share20\UserRemovedListener;
14+
use OC\User\DisabledUserException;
1415
use OCP\EventDispatcher\IEventDispatcher;
1516
use OCP\Group\Events\GroupDeletedEvent;
1617
use OCP\Group\Events\UserRemovedEvent;
@@ -1026,7 +1027,27 @@ public static function handleRequest(): void {
10261027
// OAuth needs to support basic auth too, so the login is not valid
10271028
// inside Nextcloud and the Login exception would ruin it.
10281029
if ($request->getRawPathInfo() !== '/apps/oauth2/api/v1/token') {
1029-
self::handleLogin($request);
1030+
try {
1031+
self::handleLogin($request);
1032+
} catch (DisabledUserException $e) {
1033+
// Disabled users would not be seen as logged in and
1034+
// trying to log them in would fail, so the login
1035+
// exception is ignored for the themed stylesheets and
1036+
// images.
1037+
if ($request->getRawPathInfo() !== '/apps/theming/theme/default.css'
1038+
&& $request->getRawPathInfo() !== '/apps/theming/theme/light.css'
1039+
&& $request->getRawPathInfo() !== '/apps/theming/theme/dark.css'
1040+
&& $request->getRawPathInfo() !== '/apps/theming/theme/light-highcontrast.css'
1041+
&& $request->getRawPathInfo() !== '/apps/theming/theme/dark-highcontrast.css'
1042+
&& $request->getRawPathInfo() !== '/apps/theming/theme/opendyslexic.css'
1043+
&& $request->getRawPathInfo() !== '/apps/theming/image/background'
1044+
&& $request->getRawPathInfo() !== '/apps/theming/image/logo'
1045+
&& $request->getRawPathInfo() !== '/apps/theming/image/logoheader'
1046+
&& !str_starts_with($request->getRawPathInfo(), '/apps/theming/favicon')
1047+
&& !str_starts_with($request->getRawPathInfo(), '/apps/theming/icon')) {
1048+
throw $e;
1049+
}
1050+
}
10301051
}
10311052
}
10321053
}

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,7 @@
20902090
'OC\\User\\Backend' => $baseDir . '/lib/private/User/Backend.php',
20912091
'OC\\User\\BackgroundJobs\\CleanupDeletedUsers' => $baseDir . '/lib/private/User/BackgroundJobs/CleanupDeletedUsers.php',
20922092
'OC\\User\\Database' => $baseDir . '/lib/private/User/Database.php',
2093+
'OC\\User\\DisabledUserException' => $baseDir . '/lib/private/User/DisabledUserException.php',
20932094
'OC\\User\\DisplayNameCache' => $baseDir . '/lib/private/User/DisplayNameCache.php',
20942095
'OC\\User\\LazyUser' => $baseDir . '/lib/private/User/LazyUser.php',
20952096
'OC\\User\\Listeners\\BeforeUserDeletedListener' => $baseDir . '/lib/private/User/Listeners/BeforeUserDeletedListener.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,6 +2139,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
21392139
'OC\\User\\Backend' => __DIR__ . '/../../..' . '/lib/private/User/Backend.php',
21402140
'OC\\User\\BackgroundJobs\\CleanupDeletedUsers' => __DIR__ . '/../../..' . '/lib/private/User/BackgroundJobs/CleanupDeletedUsers.php',
21412141
'OC\\User\\Database' => __DIR__ . '/../../..' . '/lib/private/User/Database.php',
2142+
'OC\\User\\DisabledUserException' => __DIR__ . '/../../..' . '/lib/private/User/DisabledUserException.php',
21422143
'OC\\User\\DisplayNameCache' => __DIR__ . '/../../..' . '/lib/private/User/DisplayNameCache.php',
21432144
'OC\\User\\LazyUser' => __DIR__ . '/../../..' . '/lib/private/User/LazyUser.php',
21442145
'OC\\User\\Listeners\\BeforeUserDeletedListener' => __DIR__ . '/../../..' . '/lib/private/User/Listeners/BeforeUserDeletedListener.php',
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
/**
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: AGPL-3.0-only
6+
*/
7+
namespace OC\User;
8+
9+
class DisabledUserException extends LoginException {
10+
}

lib/private/User/Session.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ public function completeLogin(IUser $user, array $loginDetails, $regenerateSessi
319319
// disabled users can not log in
320320
// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
321321
$message = \OCP\Util::getL10N('lib')->t('Account disabled');
322-
throw new LoginException($message);
322+
throw new DisabledUserException($message);
323323
}
324324

325325
if ($regenerateSessionId) {

0 commit comments

Comments
 (0)