diff options
author | Arthur Schiwon <blizzz@arthur-schiwon.de> | 2024-06-07 11:25:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-07 11:25:36 +0200 |
commit | 98b5cdc43dfd62e1ceaca6b28ab607d66c1c168e (patch) | |
tree | d3ddc97b31be6814be82fc5150d6d0c983246475 | |
parent | ef01dc72c1c92bdde6145954fe2a029e90c61e60 (diff) | |
parent | f6d6efef3a26fc5524988cdfba780dce035cd61b (diff) | |
download | nextcloud-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
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()); |