aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Schiwon <blizzz@arthur-schiwon.de>2024-06-07 11:25:36 +0200
committerGitHub <noreply@github.com>2024-06-07 11:25:36 +0200
commit98b5cdc43dfd62e1ceaca6b28ab607d66c1c168e (patch)
treed3ddc97b31be6814be82fc5150d6d0c983246475
parentef01dc72c1c92bdde6145954fe2a029e90c61e60 (diff)
parentf6d6efef3a26fc5524988cdfba780dce035cd61b (diff)
downloadnextcloud-server-98b5cdc43dfd62e1ceaca6b28ab607d66c1c168e.tar.gz
nextcloud-server-98b5cdc43dfd62e1ceaca6b28ab607d66c1c168e.zip
Merge pull request #43942 from nextcloud/fix/43612/avoid-pwd-confirm-sso
fix(Session): avoid password confirmation on SSO
-rw-r--r--apps/settings/lib/Controller/AuthSettingsController.php4
-rw-r--r--apps/settings/tests/Controller/AuthSettingsControllerTest.php20
-rw-r--r--apps/settings/tests/Settings/Personal/Security/AuthtokensTest.php5
-rw-r--r--core/Controller/OCJSController.php5
-rw-r--r--lib/private/AppFramework/DependencyInjection/DIContainer.php3
-rw-r--r--lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php27
-rw-r--r--lib/private/Authentication/Token/PublicKeyToken.php3
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenProvider.php1
-rw-r--r--lib/private/Lockdown/LockdownManager.php4
-rw-r--r--lib/private/Template/JSConfigHelper.php74
-rw-r--r--lib/private/TemplateLayout.php4
-rw-r--r--lib/private/legacy/OC_User.php10
-rw-r--r--lib/public/Authentication/Token/IToken.php9
-rw-r--r--tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php4
-rw-r--r--tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php60
-rw-r--r--tests/lib/Authentication/Token/PublicKeyTokenTest.php5
-rw-r--r--tests/lib/Lockdown/Filesystem/NoFSTest.php5
-rw-r--r--tests/lib/Lockdown/LockdownManagerTest.php5
18 files changed, 183 insertions, 65 deletions
diff --git a/apps/settings/lib/Controller/AuthSettingsController.php b/apps/settings/lib/Controller/AuthSettingsController.php
index 0e7f522d6eb..83db90fdc32 100644
--- a/apps/settings/lib/Controller/AuthSettingsController.php
+++ b/apps/settings/lib/Controller/AuthSettingsController.php
@@ -217,8 +217,8 @@ class AuthSettingsController extends Controller {
$currentName = $token->getName();
if ($scope !== $token->getScopeAsArray()) {
- $token->setScope(['filesystem' => $scope['filesystem']]);
- $this->publishActivity($scope['filesystem'] ? Provider::APP_TOKEN_FILESYSTEM_GRANTED : Provider::APP_TOKEN_FILESYSTEM_REVOKED, $token->getId(), ['name' => $currentName]);
+ $token->setScope([IToken::SCOPE_FILESYSTEM => $scope[IToken::SCOPE_FILESYSTEM]]);
+ $this->publishActivity($scope[IToken::SCOPE_FILESYSTEM] ? Provider::APP_TOKEN_FILESYSTEM_GRANTED : Provider::APP_TOKEN_FILESYSTEM_REVOKED, $token->getId(), ['name' => $currentName]);
}
if (mb_strlen($name) > 128) {
diff --git a/apps/settings/tests/Controller/AuthSettingsControllerTest.php b/apps/settings/tests/Controller/AuthSettingsControllerTest.php
index 02f57e4e3e5..4cc8be641c2 100644
--- a/apps/settings/tests/Controller/AuthSettingsControllerTest.php
+++ b/apps/settings/tests/Controller/AuthSettingsControllerTest.php
@@ -244,7 +244,7 @@ class AuthSettingsControllerTest extends TestCase {
$token->expects($this->once())
->method('getScopeAsArray')
- ->willReturn(['filesystem' => true]);
+ ->willReturn([IToken::SCOPE_FILESYSTEM => true]);
$token->expects($this->once())
->method('setName')
@@ -254,7 +254,7 @@ class AuthSettingsControllerTest extends TestCase {
->method('updateToken')
->with($this->equalTo($token));
- $this->assertSame([], $this->controller->update($tokenId, ['filesystem' => true], $newName));
+ $this->assertSame([], $this->controller->update($tokenId, [IToken::SCOPE_FILESYSTEM => true], $newName));
}
public function dataUpdateFilesystemScope(): array {
@@ -287,17 +287,17 @@ class AuthSettingsControllerTest extends TestCase {
$token->expects($this->once())
->method('getScopeAsArray')
- ->willReturn(['filesystem' => $filesystem]);
+ ->willReturn([IToken::SCOPE_FILESYSTEM => $filesystem]);
$token->expects($this->once())
->method('setScope')
- ->with($this->equalTo(['filesystem' => $newFilesystem]));
+ ->with($this->equalTo([IToken::SCOPE_FILESYSTEM => $newFilesystem]));
$this->tokenProvider->expects($this->once())
->method('updateToken')
->with($this->equalTo($token));
- $this->assertSame([], $this->controller->update($tokenId, ['filesystem' => $newFilesystem], 'App password'));
+ $this->assertSame([], $this->controller->update($tokenId, [IToken::SCOPE_FILESYSTEM => $newFilesystem], 'App password'));
}
public function testUpdateNoChange(): void {
@@ -316,7 +316,7 @@ class AuthSettingsControllerTest extends TestCase {
$token->expects($this->once())
->method('getScopeAsArray')
- ->willReturn(['filesystem' => true]);
+ ->willReturn([IToken::SCOPE_FILESYSTEM => true]);
$token->expects($this->never())
->method('setName');
@@ -328,7 +328,7 @@ class AuthSettingsControllerTest extends TestCase {
->method('updateToken')
->with($this->equalTo($token));
- $this->assertSame([], $this->controller->update($tokenId, ['filesystem' => true], 'App password'));
+ $this->assertSame([], $this->controller->update($tokenId, [IToken::SCOPE_FILESYSTEM => true], 'App password'));
}
public function testUpdateExpired() {
@@ -348,7 +348,7 @@ class AuthSettingsControllerTest extends TestCase {
->method('updateToken')
->with($this->equalTo($token));
- $this->assertSame([], $this->controller->update($tokenId, ['filesystem' => true], 'App password'));
+ $this->assertSame([], $this->controller->update($tokenId, [IToken::SCOPE_FILESYSTEM => true], 'App password'));
}
public function testUpdateTokenWrongUser() {
@@ -366,7 +366,7 @@ class AuthSettingsControllerTest extends TestCase {
$this->tokenProvider->expects($this->never())
->method('updateToken');
- $response = $this->controller->update($tokenId, ['filesystem' => true], 'App password');
+ $response = $this->controller->update($tokenId, [IToken::SCOPE_FILESYSTEM => true], 'App password');
$this->assertSame([], $response->getData());
$this->assertSame(\OCP\AppFramework\Http::STATUS_NOT_FOUND, $response->getStatus());
}
@@ -380,7 +380,7 @@ class AuthSettingsControllerTest extends TestCase {
$this->tokenProvider->expects($this->never())
->method('updateToken');
- $response = $this->controller->update(42, ['filesystem' => true], 'App password');
+ $response = $this->controller->update(42, [IToken::SCOPE_FILESYSTEM => true], 'App password');
$this->assertSame([], $response->getData());
$this->assertSame(\OCP\AppFramework\Http::STATUS_NOT_FOUND, $response->getStatus());
}
diff --git a/apps/settings/tests/Settings/Personal/Security/AuthtokensTest.php b/apps/settings/tests/Settings/Personal/Security/AuthtokensTest.php
index 0ed5145da2a..d2cd10e34d3 100644
--- a/apps/settings/tests/Settings/Personal/Security/AuthtokensTest.php
+++ b/apps/settings/tests/Settings/Personal/Security/AuthtokensTest.php
@@ -13,6 +13,7 @@ use OC\Authentication\Token\PublicKeyToken;
use OCA\Settings\Settings\Personal\Security\Authtokens;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
+use OCP\Authentication\Token\IToken;
use OCP\ISession;
use OCP\IUserSession;
use PHPUnit\Framework\MockObject\MockObject;
@@ -91,7 +92,7 @@ class AuthtokensTest extends TestCase {
'type' => 0,
'canDelete' => false,
'current' => true,
- 'scope' => ['filesystem' => true],
+ 'scope' => [IToken::SCOPE_FILESYSTEM => true],
'canRename' => false,
],
[
@@ -100,7 +101,7 @@ class AuthtokensTest extends TestCase {
'lastActivity' => 0,
'type' => 0,
'canDelete' => true,
- 'scope' => ['filesystem' => true],
+ 'scope' => [IToken::SCOPE_FILESYSTEM => true],
'canRename' => true,
],
]
diff --git a/core/Controller/OCJSController.php b/core/Controller/OCJSController.php
index 8eed7a871c6..11a6e5827d8 100644
--- a/core/Controller/OCJSController.php
+++ b/core/Controller/OCJSController.php
@@ -6,6 +6,7 @@
namespace OC\Core\Controller;
use bantu\IniGetWrapper\IniGetWrapper;
+use OC\Authentication\Token\IProvider;
use OC\CapabilitiesManager;
use OC\Template\JSConfigHelper;
use OCP\App\IAppManager;
@@ -42,6 +43,7 @@ class OCJSController extends Controller {
IURLGenerator $urlGenerator,
CapabilitiesManager $capabilitiesManager,
IInitialStateService $initialStateService,
+ IProvider $tokenProvider,
) {
parent::__construct($appName, $request);
@@ -56,7 +58,8 @@ class OCJSController extends Controller {
$iniWrapper,
$urlGenerator,
$capabilitiesManager,
- $initialStateService
+ $initialStateService,
+ $tokenProvider
);
}
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index 9e3119d262a..4add17396b0 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -249,7 +249,8 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$c->get(IControllerMethodReflector::class),
$c->get(ISession::class),
$c->get(IUserSession::class),
- $c->get(ITimeFactory::class)
+ $c->get(ITimeFactory::class),
+ $c->get(\OC\Authentication\Token\IProvider::class),
)
);
$dispatcher->registerMiddleware(
diff --git a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
index b95a69dc3e2..5ff9d7386da 100644
--- a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
@@ -7,12 +7,18 @@ namespace OC\AppFramework\Middleware\Security;
use OC\AppFramework\Middleware\Security\Exceptions\NotConfirmedException;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Authentication\Token\IProvider;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Authentication\Exceptions\ExpiredTokenException;
+use OCP\Authentication\Exceptions\InvalidTokenException;
+use OCP\Authentication\Exceptions\WipeTokenException;
+use OCP\Authentication\Token\IToken;
use OCP\ISession;
use OCP\IUserSession;
+use OCP\Session\Exceptions\SessionNotAvailableException;
use OCP\User\Backend\IPasswordConfirmationBackend;
use ReflectionMethod;
@@ -27,6 +33,7 @@ class PasswordConfirmationMiddleware extends Middleware {
private $timeFactory;
/** @var array */
private $excludedUserBackEnds = ['user_saml' => true, 'user_globalsiteselector' => true];
+ private IProvider $tokenProvider;
/**
* PasswordConfirmationMiddleware constructor.
@@ -39,11 +46,14 @@ class PasswordConfirmationMiddleware extends Middleware {
public function __construct(ControllerMethodReflector $reflector,
ISession $session,
IUserSession $userSession,
- ITimeFactory $timeFactory) {
+ ITimeFactory $timeFactory,
+ IProvider $tokenProvider,
+ ) {
$this->reflector = $reflector;
$this->session = $session;
$this->userSession = $userSession;
$this->timeFactory = $timeFactory;
+ $this->tokenProvider = $tokenProvider;
}
/**
@@ -68,8 +78,21 @@ class PasswordConfirmationMiddleware extends Middleware {
$backendClassName = $user->getBackendClassName();
}
+ try {
+ $sessionId = $this->session->getId();
+ $token = $this->tokenProvider->getToken($sessionId);
+ } catch (SessionNotAvailableException|InvalidTokenException|WipeTokenException|ExpiredTokenException) {
+ // States we do not deal with here.
+ return;
+ }
+ $scope = $token->getScopeAsArray();
+ if (isset($scope[IToken::SCOPE_SKIP_PASSWORD_VALIDATION]) && $scope[IToken::SCOPE_SKIP_PASSWORD_VALIDATION] === true) {
+ // Users logging in from SSO backends cannot confirm their password by design
+ return;
+ }
+
$lastConfirm = (int) $this->session->get('last-password-confirm');
- // we can't check the password against a SAML backend, so skip password confirmation in this case
+ // TODO: confirm excludedUserBackEnds can go away and remove it
if (!isset($this->excludedUserBackEnds[$backendClassName]) && $lastConfirm < ($this->timeFactory->getTime() - (30 * 60 + 15))) { // allow 15 seconds delay
throw new NotConfirmedException();
}
diff --git a/lib/private/Authentication/Token/PublicKeyToken.php b/lib/private/Authentication/Token/PublicKeyToken.php
index 0b7a2589f3e..961b7191d84 100644
--- a/lib/private/Authentication/Token/PublicKeyToken.php
+++ b/lib/private/Authentication/Token/PublicKeyToken.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace OC\Authentication\Token;
use OCP\AppFramework\Db\Entity;
+use OCP\Authentication\Token\IToken;
/**
* @method void setId(int $id)
@@ -162,7 +163,7 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken {
$scope = json_decode($this->getScope(), true);
if (!$scope) {
return [
- 'filesystem' => true
+ IToken::SCOPE_FILESYSTEM => true
];
}
return $scope;
diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
index 5363b82df69..767ece1e551 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
@@ -243,6 +243,7 @@ class PublicKeyTokenProvider implements IProvider {
OCPIToken::TEMPORARY_TOKEN,
$token->getRemember()
);
+ $newToken->setScope($token->getScopeAsArray());
$this->cacheToken($newToken);
$this->cacheInvalidHash($token->getToken());
diff --git a/lib/private/Lockdown/LockdownManager.php b/lib/private/Lockdown/LockdownManager.php
index 779b1ea2650..3b45709d5c9 100644
--- a/lib/private/Lockdown/LockdownManager.php
+++ b/lib/private/Lockdown/LockdownManager.php
@@ -5,7 +5,7 @@
*/
namespace OC\Lockdown;
-use OC\Authentication\Token\IToken;
+use OCP\Authentication\Token\IToken;
use OCP\ISession;
use OCP\Lockdown\ILockdownManager;
@@ -60,6 +60,6 @@ class LockdownManager implements ILockdownManager {
public function canAccessFilesystem() {
$scope = $this->getScopeAsArray();
- return !$scope || $scope['filesystem'];
+ return !$scope || $scope[IToken::SCOPE_FILESYSTEM];
}
}
diff --git a/lib/private/Template/JSConfigHelper.php b/lib/private/Template/JSConfigHelper.php
index 2f2ff9d64e3..a41e99ae8c4 100644
--- a/lib/private/Template/JSConfigHelper.php
+++ b/lib/private/Template/JSConfigHelper.php
@@ -8,10 +8,15 @@ declare(strict_types=1);
namespace OC\Template;
use bantu\IniGetWrapper\IniGetWrapper;
+use OC\Authentication\Token\IProvider;
use OC\CapabilitiesManager;
use OC\Share\Share;
use OCP\App\AppPathNotFoundException;
use OCP\App\IAppManager;
+use OCP\Authentication\Exceptions\ExpiredTokenException;
+use OCP\Authentication\Exceptions\InvalidTokenException;
+use OCP\Authentication\Exceptions\WipeTokenException;
+use OCP\Authentication\Token\IToken;
use OCP\Constants;
use OCP\Defaults;
use OCP\Files\FileInfo;
@@ -23,48 +28,30 @@ use OCP\ILogger;
use OCP\ISession;
use OCP\IURLGenerator;
use OCP\IUser;
+use OCP\Session\Exceptions\SessionNotAvailableException;
use OCP\Share\IManager as IShareManager;
use OCP\User\Backend\IPasswordConfirmationBackend;
use OCP\Util;
class JSConfigHelper {
- protected IL10N $l;
- protected Defaults $defaults;
- protected IAppManager $appManager;
- protected ISession $session;
- protected ?IUser $currentUser;
- protected IConfig $config;
- protected IGroupManager $groupManager;
- protected IniGetWrapper $iniWrapper;
- protected IURLGenerator $urlGenerator;
- protected CapabilitiesManager $capabilitiesManager;
- protected IInitialStateService $initialStateService;
/** @var array user back-ends excluded from password verification */
private $excludedUserBackEnds = ['user_saml' => true, 'user_globalsiteselector' => true];
- public function __construct(IL10N $l,
- Defaults $defaults,
- IAppManager $appManager,
- ISession $session,
- ?IUser $currentUser,
- IConfig $config,
- IGroupManager $groupManager,
- IniGetWrapper $iniWrapper,
- IURLGenerator $urlGenerator,
- CapabilitiesManager $capabilitiesManager,
- IInitialStateService $initialStateService) {
- $this->l = $l;
- $this->defaults = $defaults;
- $this->appManager = $appManager;
- $this->session = $session;
- $this->currentUser = $currentUser;
- $this->config = $config;
- $this->groupManager = $groupManager;
- $this->iniWrapper = $iniWrapper;
- $this->urlGenerator = $urlGenerator;
- $this->capabilitiesManager = $capabilitiesManager;
- $this->initialStateService = $initialStateService;
+ public function __construct(
+ protected IL10N $l,
+ protected Defaults $defaults,
+ protected IAppManager $appManager,
+ protected ISession $session,
+ protected ?IUser $currentUser,
+ protected IConfig $config,
+ protected IGroupManager $groupManager,
+ protected IniGetWrapper $iniWrapper,
+ protected IURLGenerator $urlGenerator,
+ protected CapabilitiesManager $capabilitiesManager,
+ protected IInitialStateService $initialStateService,
+ protected IProvider $tokenProvider,
+ ) {
}
public function getConfig(): string {
@@ -130,9 +117,13 @@ class JSConfigHelper {
}
if ($this->currentUser instanceof IUser) {
- $lastConfirmTimestamp = $this->session->get('last-password-confirm');
- if (!is_int($lastConfirmTimestamp)) {
- $lastConfirmTimestamp = 0;
+ if ($this->canUserValidatePassword()) {
+ $lastConfirmTimestamp = $this->session->get('last-password-confirm');
+ if (!is_int($lastConfirmTimestamp)) {
+ $lastConfirmTimestamp = 0;
+ }
+ } else {
+ $lastConfirmTimestamp = PHP_INT_MAX;
}
} else {
$lastConfirmTimestamp = 0;
@@ -287,4 +278,15 @@ class JSConfigHelper {
return $result;
}
+
+ protected function canUserValidatePassword(): bool {
+ try {
+ $token = $this->tokenProvider->getToken($this->session->getId());
+ } catch (ExpiredTokenException|WipeTokenException|InvalidTokenException|SessionNotAvailableException) {
+ // actually we do not know, so we fall back to this statement
+ return true;
+ }
+ $scope = $token->getScopeAsArray();
+ return !isset($scope[IToken::SCOPE_SKIP_PASSWORD_VALIDATION]) || $scope[IToken::SCOPE_SKIP_PASSWORD_VALIDATION] === false;
+ }
}
diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php
index 2e688f161bb..27e988711be 100644
--- a/lib/private/TemplateLayout.php
+++ b/lib/private/TemplateLayout.php
@@ -8,6 +8,7 @@
namespace OC;
use bantu\IniGetWrapper\IniGetWrapper;
+use OC\Authentication\Token\IProvider;
use OC\Search\SearchQuery;
use OC\Template\CSSResourceLocator;
use OC\Template\JSConfigHelper;
@@ -225,7 +226,8 @@ class TemplateLayout extends \OC_Template {
\OC::$server->get(IniGetWrapper::class),
\OC::$server->getURLGenerator(),
\OC::$server->get(CapabilitiesManager::class),
- \OCP\Server::get(IInitialStateService::class)
+ \OCP\Server::get(IInitialStateService::class),
+ \OCP\Server::get(IProvider::class),
);
$config = $jsConfigHelper->getConfig();
if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
diff --git a/lib/private/legacy/OC_User.php b/lib/private/legacy/OC_User.php
index e7708525c76..f9f751f7b14 100644
--- a/lib/private/legacy/OC_User.php
+++ b/lib/private/legacy/OC_User.php
@@ -5,7 +5,9 @@
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
+use OC\Authentication\Token\IProvider;
use OC\User\LoginException;
+use OCP\Authentication\Token\IToken;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IGroupManager;
use OCP\ISession;
@@ -166,6 +168,14 @@ class OC_User {
$userSession->createSessionToken($request, $uid, $uid, $password);
$userSession->createRememberMeToken($userSession->getUser());
+
+ if (empty($password)) {
+ $tokenProvider = \OC::$server->get(IProvider::class);
+ $token = $tokenProvider->getToken($userSession->getSession()->getId());
+ $token->setScope([IToken::SCOPE_SKIP_PASSWORD_VALIDATION => true]);
+ $tokenProvider->updateToken($token);
+ }
+
// setup the filesystem
OC_Util::setupFS($uid);
// first call the post_login hooks, the login-process needs to be
diff --git a/lib/public/Authentication/Token/IToken.php b/lib/public/Authentication/Token/IToken.php
index 4f232b83d4e..8c047280924 100644
--- a/lib/public/Authentication/Token/IToken.php
+++ b/lib/public/Authentication/Token/IToken.php
@@ -35,6 +35,15 @@ interface IToken extends JsonSerializable {
public const REMEMBER = 1;
/**
+ * @since 30.0.0
+ */
+ public const SCOPE_FILESYSTEM = 'filesystem';
+ /**
+ * @since 30.0.0
+ */
+ public const SCOPE_SKIP_PASSWORD_VALIDATION = 'password-unconfirmable';
+
+ /**
* Get the token ID
* @since 28.0.0
*/
diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php b/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php
index 82d6cf8f251..02159661ff6 100644
--- a/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php
+++ b/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php
@@ -30,4 +30,8 @@ class PasswordConfirmationMiddlewareController extends \OCP\AppFramework\Control
#[PasswordConfirmationRequired]
public function testAttribute() {
}
+
+ #[PasswordConfirmationRequired]
+ public function testSSO() {
+ }
}
diff --git a/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
index 3613ca624a3..beee7151264 100644
--- a/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
@@ -9,7 +9,9 @@ namespace Test\AppFramework\Middleware\Security;
use OC\AppFramework\Middleware\Security\Exceptions\NotConfirmedException;
use OC\AppFramework\Middleware\Security\PasswordConfirmationMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Authentication\Token\IProvider;
use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Authentication\Token\IToken;
use OCP\IRequest;
use OCP\ISession;
use OCP\IUser;
@@ -32,6 +34,7 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
private $controller;
/** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
private $timeFactory;
+ private IProvider|\PHPUnit\Framework\MockObject\MockObject $tokenProvider;
protected function setUp(): void {
$this->reflector = new ControllerMethodReflector();
@@ -39,6 +42,7 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
$this->userSession = $this->createMock(IUserSession::class);
$this->user = $this->createMock(IUser::class);
$this->timeFactory = $this->createMock(ITimeFactory::class);
+ $this->tokenProvider = $this->createMock(IProvider::class);
$this->controller = new PasswordConfirmationMiddlewareController(
'test',
$this->createMock(IRequest::class)
@@ -48,7 +52,8 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
$this->reflector,
$this->session,
$this->userSession,
- $this->timeFactory
+ $this->timeFactory,
+ $this->tokenProvider,
);
}
@@ -90,6 +95,13 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
$this->timeFactory->method('getTime')
->willReturn($currentTime);
+ $token = $this->createMock(IToken::class);
+ $token->method('getScopeAsArray')
+ ->willReturn([]);
+ $this->tokenProvider->expects($this->once())
+ ->method('getToken')
+ ->willReturn($token);
+
$thrown = false;
try {
$this->middleware->beforeController($this->controller, __FUNCTION__);
@@ -118,6 +130,13 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
$this->timeFactory->method('getTime')
->willReturn($currentTime);
+ $token = $this->createMock(IToken::class);
+ $token->method('getScopeAsArray')
+ ->willReturn([]);
+ $this->tokenProvider->expects($this->once())
+ ->method('getToken')
+ ->willReturn($token);
+
$thrown = false;
try {
$this->middleware->beforeController($this->controller, __FUNCTION__);
@@ -128,6 +147,8 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
$this->assertSame($exception, $thrown);
}
+
+
public function dataProvider() {
return [
['foo', 2000, 4000, true],
@@ -138,4 +159,41 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
['foo', 2000, 3816, true],
];
}
+
+ public function testSSO() {
+ static $sessionId = 'mySession1d';
+
+ $this->reflector->reflect($this->controller, __FUNCTION__);
+
+ $this->user->method('getBackendClassName')
+ ->willReturn('fictional_backend');
+ $this->userSession->method('getUser')
+ ->willReturn($this->user);
+
+ $this->session->method('get')
+ ->with('last-password-confirm')
+ ->willReturn(0);
+ $this->session->method('getId')
+ ->willReturn($sessionId);
+
+ $this->timeFactory->method('getTime')
+ ->willReturn(9876);
+
+ $token = $this->createMock(IToken::class);
+ $token->method('getScopeAsArray')
+ ->willReturn([IToken::SCOPE_SKIP_PASSWORD_VALIDATION => true]);
+ $this->tokenProvider->expects($this->once())
+ ->method('getToken')
+ ->with($sessionId)
+ ->willReturn($token);
+
+ $thrown = false;
+ try {
+ $this->middleware->beforeController($this->controller, __FUNCTION__);
+ } catch (NotConfirmedException) {
+ $thrown = true;
+ }
+
+ $this->assertSame(false, $thrown);
+ }
}
diff --git a/tests/lib/Authentication/Token/PublicKeyTokenTest.php b/tests/lib/Authentication/Token/PublicKeyTokenTest.php
index acbddebea35..cc8890002e9 100644
--- a/tests/lib/Authentication/Token/PublicKeyTokenTest.php
+++ b/tests/lib/Authentication/Token/PublicKeyTokenTest.php
@@ -9,11 +9,12 @@ declare(strict_types=1);
namespace Test\Authentication\Token;
use OC\Authentication\Token\PublicKeyToken;
+use OCP\Authentication\Token\IToken;
use Test\TestCase;
class PublicKeyTokenTest extends TestCase {
public function testSetScopeAsArray() {
- $scope = ['filesystem' => false];
+ $scope = [IToken::SCOPE_FILESYSTEM => false];
$token = new PublicKeyToken();
$token->setScope($scope);
$this->assertEquals(json_encode($scope), $token->getScope());
@@ -21,7 +22,7 @@ class PublicKeyTokenTest extends TestCase {
}
public function testDefaultScope() {
- $scope = ['filesystem' => true];
+ $scope = [IToken::SCOPE_FILESYSTEM => true];
$token = new PublicKeyToken();
$this->assertEquals($scope, $token->getScopeAsArray());
}
diff --git a/tests/lib/Lockdown/Filesystem/NoFSTest.php b/tests/lib/Lockdown/Filesystem/NoFSTest.php
index 08429228647..7a636fbaaaa 100644
--- a/tests/lib/Lockdown/Filesystem/NoFSTest.php
+++ b/tests/lib/Lockdown/Filesystem/NoFSTest.php
@@ -9,6 +9,7 @@ namespace Test\Lockdown\Filesystem;
use OC\Authentication\Token\PublicKeyToken;
use OC\Files\Filesystem;
use OC\Lockdown\Filesystem\NullStorage;
+use OCP\Authentication\Token\IToken;
use Test\Traits\UserTrait;
/**
@@ -20,7 +21,7 @@ class NoFSTest extends \Test\TestCase {
protected function tearDown(): void {
$token = new PublicKeyToken();
$token->setScope([
- 'filesystem' => true
+ IToken::SCOPE_FILESYSTEM => true
]);
\OC::$server->get('LockdownManager')->setToken($token);
parent::tearDown();
@@ -30,7 +31,7 @@ class NoFSTest extends \Test\TestCase {
parent::setUp();
$token = new PublicKeyToken();
$token->setScope([
- 'filesystem' => false
+ IToken::SCOPE_FILESYSTEM => false
]);
\OC::$server->get('LockdownManager')->setToken($token);
diff --git a/tests/lib/Lockdown/LockdownManagerTest.php b/tests/lib/Lockdown/LockdownManagerTest.php
index 5ff5a84e800..bb71a6e63de 100644
--- a/tests/lib/Lockdown/LockdownManagerTest.php
+++ b/tests/lib/Lockdown/LockdownManagerTest.php
@@ -8,6 +8,7 @@ namespace Test\Lockdown;
use OC\Authentication\Token\PublicKeyToken;
use OC\Lockdown\LockdownManager;
+use OCP\Authentication\Token\IToken;
use OCP\ISession;
use Test\TestCase;
@@ -29,7 +30,7 @@ class LockdownManagerTest extends TestCase {
public function testCanAccessFilesystemAllowed() {
$token = new PublicKeyToken();
- $token->setScope(['filesystem' => true]);
+ $token->setScope([IToken::SCOPE_FILESYSTEM => true]);
$manager = new LockdownManager($this->sessionCallback);
$manager->setToken($token);
$this->assertTrue($manager->canAccessFilesystem());
@@ -37,7 +38,7 @@ class LockdownManagerTest extends TestCase {
public function testCanAccessFilesystemNotAllowed() {
$token = new PublicKeyToken();
- $token->setScope(['filesystem' => false]);
+ $token->setScope([IToken::SCOPE_FILESYSTEM => false]);
$manager = new LockdownManager($this->sessionCallback);
$manager->setToken($token);
$this->assertFalse($manager->canAccessFilesystem());