Merge pull request #36363 from nextcloud/feat/app-framework/usesession-attribute

feat(app-framework): Add UseSession attribute to replace annotation
This commit is contained in:
Christoph Wurst 2023-01-27 16:59:14 +01:00 коммит произвёл GitHub
Родитель df0bb9165d 20e00cdf17
Коммит 7269766e05
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 189 добавлений и 72 удалений

Просмотреть файл

@ -41,6 +41,7 @@ use OCA\OAuth2\Db\AccessTokenMapper;
use OCA\OAuth2\Db\ClientMapper; use OCA\OAuth2\Db\ClientMapper;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\StandaloneTemplateResponse; use OCP\AppFramework\Http\StandaloneTemplateResponse;
use OCP\Defaults; use OCP\Defaults;
@ -126,8 +127,8 @@ class ClientFlowLoginController extends Controller {
/** /**
* @PublicPage * @PublicPage
* @NoCSRFRequired * @NoCSRFRequired
* @UseSession
*/ */
#[UseSession]
public function showAuthPickerPage(string $clientIdentifier = '', string $user = '', int $direct = 0): StandaloneTemplateResponse { public function showAuthPickerPage(string $clientIdentifier = '', string $user = '', int $direct = 0): StandaloneTemplateResponse {
$clientName = $this->getClientName(); $clientName = $this->getClientName();
$client = null; $client = null;
@ -193,8 +194,8 @@ class ClientFlowLoginController extends Controller {
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired * @NoCSRFRequired
* @NoSameSiteCookieRequired * @NoSameSiteCookieRequired
* @UseSession
*/ */
#[UseSession]
public function grantPage(string $stateToken = '', public function grantPage(string $stateToken = '',
string $clientIdentifier = '', string $clientIdentifier = '',
int $direct = 0): StandaloneTemplateResponse { int $direct = 0): StandaloneTemplateResponse {
@ -243,10 +244,10 @@ class ClientFlowLoginController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @UseSession
* *
* @return Http\RedirectResponse|Response * @return Http\RedirectResponse|Response
*/ */
#[UseSession]
public function generateAppPassword(string $stateToken, public function generateAppPassword(string $stateToken,
string $clientIdentifier = '') { string $clientIdentifier = '') {
if (!$this->isValidToken($stateToken)) { if (!$this->isValidToken($stateToken)) {

Просмотреть файл

@ -33,6 +33,7 @@ use OC\Core\Exception\LoginFlowV2NotFoundException;
use OC\Core\Service\LoginFlowV2Service; use OC\Core\Service\LoginFlowV2Service;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\Response;
@ -97,8 +98,8 @@ class ClientFlowLoginV2Controller extends Controller {
/** /**
* @NoCSRFRequired * @NoCSRFRequired
* @PublicPage * @PublicPage
* @UseSession
*/ */
#[UseSession]
public function landing(string $token, $user = ''): Response { public function landing(string $token, $user = ''): Response {
if (!$this->loginFlowV2Service->startLoginFlow($token)) { if (!$this->loginFlowV2Service->startLoginFlow($token)) {
return $this->loginTokenForbiddenResponse(); return $this->loginTokenForbiddenResponse();
@ -114,8 +115,8 @@ class ClientFlowLoginV2Controller extends Controller {
/** /**
* @NoCSRFRequired * @NoCSRFRequired
* @PublicPage * @PublicPage
* @UseSession
*/ */
#[UseSession]
public function showAuthPickerPage($user = ''): StandaloneTemplateResponse { public function showAuthPickerPage($user = ''): StandaloneTemplateResponse {
try { try {
$flow = $this->getFlowByLoginToken(); $flow = $this->getFlowByLoginToken();
@ -145,10 +146,10 @@ class ClientFlowLoginV2Controller extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @UseSession
* @NoCSRFRequired * @NoCSRFRequired
* @NoSameSiteCookieRequired * @NoSameSiteCookieRequired
*/ */
#[UseSession]
public function grantPage(string $stateToken): StandaloneTemplateResponse { public function grantPage(string $stateToken): StandaloneTemplateResponse {
if (!$this->isValidStateToken($stateToken)) { if (!$this->isValidStateToken($stateToken)) {
return $this->stateTokenForbiddenResponse(); return $this->stateTokenForbiddenResponse();
@ -222,8 +223,8 @@ class ClientFlowLoginV2Controller extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @UseSession
*/ */
#[UseSession]
public function generateAppPassword(string $stateToken): Response { public function generateAppPassword(string $stateToken): Response {
if (!$this->isValidStateToken($stateToken)) { if (!$this->isValidStateToken($stateToken)) {
return $this->stateTokenForbiddenResponse(); return $this->stateTokenForbiddenResponse();

Просмотреть файл

@ -43,6 +43,7 @@ use OC\User\Session;
use OC_App; use OC_App;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\TemplateResponse;
@ -105,10 +106,10 @@ class LoginController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @UseSession
* *
* @return RedirectResponse * @return RedirectResponse
*/ */
#[UseSession]
public function logout() { public function logout() {
$loginToken = $this->request->getCookie('nc_token'); $loginToken = $this->request->getCookie('nc_token');
if (!is_null($loginToken)) { if (!is_null($loginToken)) {
@ -134,13 +135,13 @@ class LoginController extends Controller {
/** /**
* @PublicPage * @PublicPage
* @NoCSRFRequired * @NoCSRFRequired
* @UseSession
* *
* @param string $user * @param string $user
* @param string $redirect_url * @param string $redirect_url
* *
* @return TemplateResponse|RedirectResponse * @return TemplateResponse|RedirectResponse
*/ */
#[UseSession]
public function showLoginForm(string $user = null, string $redirect_url = null): Http\Response { public function showLoginForm(string $user = null, string $redirect_url = null): Http\Response {
if ($this->userSession->isLoggedIn()) { if ($this->userSession->isLoggedIn()) {
return new RedirectResponse($this->urlGenerator->linkToDefaultPageUrl()); return new RedirectResponse($this->urlGenerator->linkToDefaultPageUrl());
@ -283,12 +284,12 @@ class LoginController extends Controller {
/** /**
* @PublicPage * @PublicPage
* @UseSession
* @NoCSRFRequired * @NoCSRFRequired
* @BruteForceProtection(action=login) * @BruteForceProtection(action=login)
* *
* @return RedirectResponse * @return RedirectResponse
*/ */
#[UseSession]
public function tryLogin(Chain $loginChain, public function tryLogin(Chain $loginChain,
string $user, string $user,
string $password, string $password,
@ -368,12 +369,12 @@ class LoginController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @UseSession
* @BruteForceProtection(action=sudo) * @BruteForceProtection(action=sudo)
* *
* @license GNU AGPL version 3 or any later version * @license GNU AGPL version 3 or any later version
* *
*/ */
#[UseSession]
public function confirmPassword(string $password): DataResponse { public function confirmPassword(string $password): DataResponse {
$loginName = $this->userSession->getLoginName(); $loginName = $this->userSession->getLoginName();
$loginResult = $this->userManager->checkPassword($loginName, $password); $loginResult = $this->userManager->checkPassword($loginName, $password);

Просмотреть файл

@ -28,6 +28,7 @@ namespace OC\Core\Controller;
use OC\Authentication\TwoFactorAuth\Manager; use OC\Authentication\TwoFactorAuth\Manager;
use OC_User; use OC_User;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\StandaloneTemplateResponse; use OCP\AppFramework\Http\StandaloneTemplateResponse;
use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin; use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin;
@ -110,13 +111,13 @@ class TwoFactorChallengeController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired * @NoCSRFRequired
* @UseSession
* @TwoFactorSetUpDoneRequired * @TwoFactorSetUpDoneRequired
* *
* @param string $challengeProviderId * @param string $challengeProviderId
* @param string $redirect_url * @param string $redirect_url
* @return StandaloneTemplateResponse|RedirectResponse * @return StandaloneTemplateResponse|RedirectResponse
*/ */
#[UseSession]
public function showChallenge($challengeProviderId, $redirect_url) { public function showChallenge($challengeProviderId, $redirect_url) {
$user = $this->userSession->getUser(); $user = $this->userSession->getUser();
$providerSet = $this->twoFactorManager->getProviderSet($user); $providerSet = $this->twoFactorManager->getProviderSet($user);
@ -161,7 +162,6 @@ class TwoFactorChallengeController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired * @NoCSRFRequired
* @UseSession
* @TwoFactorSetUpDoneRequired * @TwoFactorSetUpDoneRequired
* *
* @UserRateThrottle(limit=5, period=100) * @UserRateThrottle(limit=5, period=100)
@ -171,6 +171,7 @@ class TwoFactorChallengeController extends Controller {
* @param string $redirect_url * @param string $redirect_url
* @return RedirectResponse * @return RedirectResponse
*/ */
#[UseSession]
public function solveChallenge($challengeProviderId, $challenge, $redirect_url = null) { public function solveChallenge($challengeProviderId, $challenge, $redirect_url = null) {
$user = $this->userSession->getUser(); $user = $this->userSession->getUser();
$provider = $this->twoFactorManager->getProvider($user, $challengeProviderId); $provider = $this->twoFactorManager->getProvider($user, $challengeProviderId);

Просмотреть файл

@ -33,6 +33,7 @@ use OC\Authentication\WebAuthn\Manager;
use OC\URLGenerator; use OC\URLGenerator;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest; use OCP\IRequest;
use OCP\ISession; use OCP\ISession;
@ -63,8 +64,8 @@ class WebAuthnController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @PublicPage * @PublicPage
* @UseSession
*/ */
#[UseSession]
public function startAuthentication(string $loginName): JSONResponse { public function startAuthentication(string $loginName): JSONResponse {
$this->logger->debug('Starting WebAuthn login'); $this->logger->debug('Starting WebAuthn login');
@ -87,8 +88,8 @@ class WebAuthnController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
* @PublicPage * @PublicPage
* @UseSession
*/ */
#[UseSession]
public function finishAuthentication(string $data): JSONResponse { public function finishAuthentication(string $data): JSONResponse {
$this->logger->debug('Validating WebAuthn login'); $this->logger->debug('Validating WebAuthn login');

Просмотреть файл

@ -35,6 +35,7 @@ return array(
'OCP\\AppFramework\\Db\\QBMapper' => $baseDir . '/lib/public/AppFramework/Db/QBMapper.php', 'OCP\\AppFramework\\Db\\QBMapper' => $baseDir . '/lib/public/AppFramework/Db/QBMapper.php',
'OCP\\AppFramework\\Db\\TTransactional' => $baseDir . '/lib/public/AppFramework/Db/TTransactional.php', 'OCP\\AppFramework\\Db\\TTransactional' => $baseDir . '/lib/public/AppFramework/Db/TTransactional.php',
'OCP\\AppFramework\\Http' => $baseDir . '/lib/public/AppFramework/Http.php', 'OCP\\AppFramework\\Http' => $baseDir . '/lib/public/AppFramework/Http.php',
'OCP\\AppFramework\\Http\\Attribute\\UseSession' => $baseDir . '/lib/public/AppFramework/Http/Attribute/UseSession.php',
'OCP\\AppFramework\\Http\\ContentSecurityPolicy' => $baseDir . '/lib/public/AppFramework/Http/ContentSecurityPolicy.php', 'OCP\\AppFramework\\Http\\ContentSecurityPolicy' => $baseDir . '/lib/public/AppFramework/Http/ContentSecurityPolicy.php',
'OCP\\AppFramework\\Http\\DataDisplayResponse' => $baseDir . '/lib/public/AppFramework/Http/DataDisplayResponse.php', 'OCP\\AppFramework\\Http\\DataDisplayResponse' => $baseDir . '/lib/public/AppFramework/Http/DataDisplayResponse.php',
'OCP\\AppFramework\\Http\\DataDownloadResponse' => $baseDir . '/lib/public/AppFramework/Http/DataDownloadResponse.php', 'OCP\\AppFramework\\Http\\DataDownloadResponse' => $baseDir . '/lib/public/AppFramework/Http/DataDownloadResponse.php',

Просмотреть файл

@ -68,6 +68,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\AppFramework\\Db\\QBMapper' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/QBMapper.php', 'OCP\\AppFramework\\Db\\QBMapper' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/QBMapper.php',
'OCP\\AppFramework\\Db\\TTransactional' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/TTransactional.php', 'OCP\\AppFramework\\Db\\TTransactional' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/TTransactional.php',
'OCP\\AppFramework\\Http' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http.php', 'OCP\\AppFramework\\Http' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http.php',
'OCP\\AppFramework\\Http\\Attribute\\UseSession' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/UseSession.php',
'OCP\\AppFramework\\Http\\ContentSecurityPolicy' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/ContentSecurityPolicy.php', 'OCP\\AppFramework\\Http\\ContentSecurityPolicy' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/ContentSecurityPolicy.php',
'OCP\\AppFramework\\Http\\DataDisplayResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/DataDisplayResponse.php', 'OCP\\AppFramework\\Http\\DataDisplayResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/DataDisplayResponse.php',
'OCP\\AppFramework\\Http\\DataDownloadResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/DataDownloadResponse.php', 'OCP\\AppFramework\\Http\\DataDownloadResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/DataDownloadResponse.php',

Просмотреть файл

@ -1,4 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, ownCloud, Inc.
* *
@ -27,9 +30,11 @@ namespace OC\AppFramework\Middleware;
use OC\AppFramework\Utility\ControllerMethodReflector; use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware; use OCP\AppFramework\Middleware;
use OCP\ISession; use OCP\ISession;
use ReflectionMethod;
class SessionMiddleware extends Middleware { class SessionMiddleware extends Middleware {
/** @var ControllerMethodReflector */ /** @var ControllerMethodReflector */
@ -49,8 +54,18 @@ class SessionMiddleware extends Middleware {
* @param string $methodName * @param string $methodName
*/ */
public function beforeController($controller, $methodName) { public function beforeController($controller, $methodName) {
$useSession = $this->reflector->hasAnnotation('UseSession'); /**
if ($useSession) { * Annotation deprecated with Nextcloud 26
*/
$hasAnnotation = $this->reflector->hasAnnotation('UseSession');
if ($hasAnnotation) {
$this->session->reopen();
return;
}
$reflectionMethod = new ReflectionMethod($controller, $methodName);
$hasAttribute = !empty($reflectionMethod->getAttributes(UseSession::class));
if ($hasAttribute) {
$this->session->reopen(); $this->session->reopen();
} }
} }
@ -62,10 +77,21 @@ class SessionMiddleware extends Middleware {
* @return Response * @return Response
*/ */
public function afterController($controller, $methodName, Response $response) { public function afterController($controller, $methodName, Response $response) {
$useSession = $this->reflector->hasAnnotation('UseSession'); /**
if ($useSession) { * Annotation deprecated with Nextcloud 26
*/
$hasAnnotation = $this->reflector->hasAnnotation('UseSession');
if ($hasAnnotation) {
$this->session->close();
return $response;
}
$reflectionMethod = new ReflectionMethod($controller, $methodName);
$hasAttribute = !empty($reflectionMethod->getAttributes(UseSession::class));
if ($hasAttribute) {
$this->session->close(); $this->session->close();
} }
return $response; return $response;
} }
} }

Просмотреть файл

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/*
* @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OCP\AppFramework\Http\Attribute;
use Attribute;
/**
* Attribute for controller methods that need to read/write PHP session data
*
* @since 26.0.0
*/
#[Attribute]
class UseSession {
}

Просмотреть файл

@ -1,4 +1,7 @@
<?php <?php
declare(strict_types=1);
/** /**
* ownCloud - App Framework * ownCloud - App Framework
* *
@ -14,84 +17,128 @@ namespace Test\AppFramework\Middleware;
use OC\AppFramework\Middleware\SessionMiddleware; use OC\AppFramework\Middleware\SessionMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector; use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\Response;
use OCP\IRequest;
use OCP\ISession;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
class SessionMiddlewareTest extends \Test\TestCase { class SessionMiddlewareTest extends TestCase {
/** @var ControllerMethodReflector */ private ControllerMethodReflector|MockObject $reflector;
private $reflector; private ISession|MockObject $session;
private Controller $controller;
/** @var Controller */ private SessionMiddleware $middleware;
private $controller;
protected function setUp(): void { protected function setUp(): void {
parent::setUp(); parent::setUp();
$this->reflector = new ControllerMethodReflector(); $this->reflector = $this->createMock(ControllerMethodReflector::class);
$this->controller = $this->createMock(Controller::class); $this->session = $this->createMock(ISession::class);
$this->controller = new class('app', $this->createMock(IRequest::class)) extends Controller {
/**
* @UseSession
*/
public function withAnnotation() {
}
#[UseSession]
public function withAttribute() {
}
public function without() {
}
};
$this->middleware = new SessionMiddleware(
$this->reflector,
$this->session,
);
} }
/** public function testSessionNotClosedOnBeforeController(): void {
* @UseSession $this->configureSessionMock(0, 1);
*/ $this->reflector->expects(self::once())
public function testSessionNotClosedOnBeforeController() { ->method('hasAnnotation')
$session = $this->getSessionMock(0, 1); ->with('UseSession')
->willReturn(true);
$this->reflector->reflect($this, __FUNCTION__); $this->middleware->beforeController($this->controller, 'withAnnotation');
$middleware = new SessionMiddleware($this->reflector, $session);
$middleware->beforeController($this->controller, __FUNCTION__);
} }
/** public function testSessionNotClosedOnBeforeControllerWithAttribute(): void {
* @UseSession $this->configureSessionMock(0, 1);
*/ $this->reflector->expects(self::once())
public function testSessionClosedOnAfterController() { ->method('hasAnnotation')
$session = $this->getSessionMock(1); ->with('UseSession')
->willReturn(false);
$this->reflector->reflect($this, __FUNCTION__); $this->middleware->beforeController($this->controller, 'withAttribute');
$middleware = new SessionMiddleware($this->reflector, $session);
$middleware->afterController($this->controller, __FUNCTION__, new Response());
} }
/** public function testSessionClosedOnAfterController(): void {
* @UseSession $this->configureSessionMock(1);
*/ $this->reflector->expects(self::once())
public function testSessionReopenedAndClosedOnBeforeController() { ->method('hasAnnotation')
$session = $this->getSessionMock(1, 1); ->with('UseSession')
->willReturn(true);
$this->reflector->reflect($this, __FUNCTION__); $this->middleware->afterController($this->controller, 'withAnnotation', new Response());
$middleware = new SessionMiddleware($this->reflector, $session);
$middleware->beforeController($this->controller, __FUNCTION__);
$middleware->afterController($this->controller, __FUNCTION__, new Response());
} }
public function testSessionClosedOnBeforeController() { public function testSessionClosedOnAfterControllerWithAttribute(): void {
$session = $this->getSessionMock(0); $this->configureSessionMock(1);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->willReturn(true);
$this->reflector->reflect($this, __FUNCTION__); $this->middleware->afterController($this->controller, 'withAttribute', new Response());
$middleware = new SessionMiddleware($this->reflector, $session);
$middleware->beforeController($this->controller, __FUNCTION__);
} }
public function testSessionNotClosedOnAfterController() { public function testSessionReopenedAndClosedOnBeforeController(): void {
$session = $this->getSessionMock(0); $this->configureSessionMock(1, 1);
$this->reflector->expects(self::exactly(2))
->method('hasAnnotation')
->with('UseSession')
->willReturn(true);
$this->reflector->reflect($this, __FUNCTION__); $this->middleware->beforeController($this->controller, 'withAnnotation');
$middleware = new SessionMiddleware($this->reflector, $session); $this->middleware->afterController($this->controller, 'withAnnotation', new Response());
$middleware->afterController($this->controller, __FUNCTION__, new Response());
} }
/** public function testSessionReopenedAndClosedOnBeforeControllerWithAttribute(): void {
* @return mixed $this->configureSessionMock(1, 1);
*/ $this->reflector->expects(self::exactly(2))
private function getSessionMock(int $expectedCloseCount, int $expectedReopenCount = 0) { ->method('hasAnnotation')
$session = $this->getMockBuilder('\OC\Session\Memory') ->with('UseSession')
->disableOriginalConstructor() ->willReturn(false);
->getMock();
$session->expects($this->exactly($expectedCloseCount)) $this->middleware->beforeController($this->controller, 'withAttribute');
$this->middleware->afterController($this->controller, 'withAttribute', new Response());
}
public function testSessionClosedOnBeforeController(): void {
$this->configureSessionMock(0);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->willReturn(false);
$this->middleware->beforeController($this->controller, 'without');
}
public function testSessionNotClosedOnAfterController(): void {
$this->configureSessionMock(0);
$this->reflector->expects(self::once())
->method('hasAnnotation')
->with('UseSession')
->willReturn(false);
$this->middleware->afterController($this->controller, 'without', new Response());
}
private function configureSessionMock(int $expectedCloseCount, int $expectedReopenCount = 0): void {
$this->session->expects($this->exactly($expectedCloseCount))
->method('close'); ->method('close');
$session->expects($this->exactly($expectedReopenCount)) $this->session->expects($this->exactly($expectedReopenCount))
->method('reopen'); ->method('reopen');
return $session;
} }
} }