diff --git a/apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php b/apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php
index 1989ef5d4c128..2e4e6a3bf2cf3 100644
--- a/apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php
+++ b/apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php
@@ -11,6 +11,7 @@
use OCA\Provisioning_API\Middleware\Exceptions\NotSubAdminException;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\OCS\OCSException;
@@ -40,7 +41,7 @@ public function __construct(
*/
public function beforeController($controller, $methodName) {
// If AuthorizedAdminSetting, the check will be done in the SecurityMiddleware
- if (!$this->isAdmin && !$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->isSubAdmin && !$this->reflector->hasAnnotation('AuthorizedAdminSetting')) {
+ if (!$this->isAdmin && !$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->isSubAdmin && !$this->reflector->hasAnnotationOrAttribute('AuthorizedAdminSetting', AuthorizedAdminSetting::class)) {
throw new NotSubAdminException();
}
}
diff --git a/apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php b/apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php
index 0e84adca09f5b..0b55424a2558d 100644
--- a/apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php
+++ b/apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php
@@ -53,10 +53,14 @@ public function testBeforeController(bool $subadminRequired, bool $isAdmin, bool
);
$this->reflector->method('hasAnnotation')
- ->willReturnCallback(function ($annotation) use ($subadminRequired, $hasSettingAuthorizationAnnotation) {
+ ->willReturnCallback(function ($annotation) use ($subadminRequired) {
if ($annotation === 'NoSubAdminRequired') {
return !$subadminRequired;
}
+ return false;
+ });
+ $this->reflector->method('hasAnnotationOrAttribute')
+ ->willReturnCallback(function ($annotation, $attribute) use ($hasSettingAuthorizationAnnotation) {
if ($annotation === 'AuthorizedAdminSetting') {
return $hasSettingAuthorizationAnnotation;
}
diff --git a/apps/settings/lib/Middleware/SubadminMiddleware.php b/apps/settings/lib/Middleware/SubadminMiddleware.php
index d7be892d163c6..24d443a55d2f6 100644
--- a/apps/settings/lib/Middleware/SubadminMiddleware.php
+++ b/apps/settings/lib/Middleware/SubadminMiddleware.php
@@ -14,6 +14,7 @@
use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Middleware;
use OCP\Group\ISubAdmin;
@@ -44,7 +45,7 @@ private function isSubAdmin(): bool {
#[Override]
public function beforeController(Controller $controller, string $methodName): void {
- if (!$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->reflector->hasAnnotation('AuthorizedAdminSetting')) {
+ if (!$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->reflector->hasAnnotationOrAttribute('AuthorizedAdminSetting', AuthorizedAdminSetting::class)) {
if (!$this->isSubAdmin()) {
throw new NotAdminException($this->l10n->t('Logged in account must be a sub admin'));
}
diff --git a/apps/settings/tests/Middleware/SubadminMiddlewareTest.php b/apps/settings/tests/Middleware/SubadminMiddlewareTest.php
index 37cfb5ccc5969..489359c34693e 100644
--- a/apps/settings/tests/Middleware/SubadminMiddlewareTest.php
+++ b/apps/settings/tests/Middleware/SubadminMiddlewareTest.php
@@ -14,6 +14,7 @@
use OC\AppFramework\Utility\ControllerMethodReflector;
use OCA\Settings\Middleware\SubadminMiddleware;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Group\ISubAdmin;
use OCP\IL10N;
@@ -62,11 +63,16 @@ public function testBeforeControllerAsUserWithoutAnnotation(): void {
$this->expectException(NotAdminException::class);
$this->reflector
- ->expects($this->exactly(2))
+ ->expects($this->exactly(1))
->method('hasAnnotation')
->willReturnMap([
['NoSubAdminRequired', false],
- ['AuthorizedAdminSetting', false],
+ ]);
+ $this->reflector
+ ->expects($this->exactly(1))
+ ->method('hasAnnotationOrAttribute')
+ ->willReturnMap([
+ ['AuthorizedAdminSetting', AuthorizedAdminSetting::class, false],
]);
$this->subAdminManager
@@ -94,11 +100,16 @@ public function testBeforeControllerWithAnnotation(): void {
public function testBeforeControllerAsSubAdminWithoutAnnotation(): void {
$this->reflector
- ->expects($this->exactly(2))
+ ->expects($this->exactly(1))
->method('hasAnnotation')
->willReturnMap([
['NoSubAdminRequired', false],
- ['AuthorizedAdminSetting', false],
+ ]);
+ $this->reflector
+ ->expects($this->exactly(1))
+ ->method('hasAnnotationOrAttribute')
+ ->willReturnMap([
+ ['AuthorizedAdminSetting', AuthorizedAdminSetting::class, false],
]);
$this->subAdminManager
diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml
index 47edd7bbcc739..635292944d245 100644
--- a/build/psalm-baseline.xml
+++ b/build/psalm-baseline.xml
@@ -1552,9 +1552,6 @@
-
-
-
@@ -2097,9 +2094,6 @@
-
-
-
diff --git a/core/Middleware/TwoFactorMiddleware.php b/core/Middleware/TwoFactorMiddleware.php
index 02f8ab8dad316..ffbcc2ce3da64 100644
--- a/core/Middleware/TwoFactorMiddleware.php
+++ b/core/Middleware/TwoFactorMiddleware.php
@@ -11,7 +11,6 @@
use Exception;
use OC\AppFramework\Http\Attributes\TwoFactorSetUpDoneRequired;
-use OC\AppFramework\Middleware\MiddlewareUtils;
use OC\Authentication\Exceptions\TwoFactorAuthRequiredException;
use OC\Authentication\Exceptions\UserAlreadyLoggedInException;
use OC\Authentication\TwoFactorAuth\Manager;
@@ -23,6 +22,7 @@
use OCP\AppFramework\Http\Attribute\NoTwoFactorRequired;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Middleware;
+use OCP\AppFramework\Utility\IControllerMethodReflector;
use OCP\Authentication\TwoFactorAuth\ALoginSetupController;
use OCP\IRequest;
use OCP\ISession;
@@ -36,7 +36,7 @@ public function __construct(
private Session $userSession,
private ISession $session,
private IURLGenerator $urlGenerator,
- private MiddlewareUtils $middlewareUtils,
+ private IControllerMethodReflector $reflector,
private IRequest $request,
) {
}
@@ -46,9 +46,7 @@ public function __construct(
* @param string $methodName
*/
public function beforeController($controller, $methodName) {
- $reflectionMethod = new ReflectionMethod($controller, $methodName);
-
- if ($this->middlewareUtils->hasAnnotationOrAttribute($reflectionMethod, 'NoTwoFactorRequired', NoTwoFactorRequired::class)) {
+ if ($this->reflector->hasAnnotationOrAttribute('NoTwoFactorRequired', NoTwoFactorRequired::class)) {
// Route handler explicitly marked to work without finished 2FA are
// not blocked
return;
@@ -59,6 +57,7 @@ public function beforeController($controller, $methodName) {
return;
}
+ $reflectionMethod = new ReflectionMethod($controller, $methodName);
if ($controller instanceof TwoFactorChallengeController
&& $this->userSession->getUser() !== null
&& !$reflectionMethod->getAttributes(TwoFactorSetUpDoneRequired::class)) {
diff --git a/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php b/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php
index 115a823598367..658a120320e2f 100644
--- a/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php
+++ b/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php
@@ -18,7 +18,6 @@
use OCP\ISession;
use OCP\IUserSession;
use Psr\Log\LoggerInterface;
-use ReflectionMethod;
// Will close the session if the user session is ephemeral.
// Happens when the user logs in via the login flow v2.
@@ -61,12 +60,7 @@ public function beforeController(Controller $controller, string $methodName) {
return;
}
- $reflectionMethod = new ReflectionMethod($controller, $methodName);
- if (!empty($reflectionMethod->getAttributes(PublicPage::class))) {
- return;
- }
-
- if ($this->reflector->hasAnnotation('PublicPage')) {
+ if ($this->reflector->hasAnnotationOrAttribute('PublicPage', PublicPage::class)) {
return;
}
diff --git a/lib/private/AppFramework/Middleware/MiddlewareUtils.php b/lib/private/AppFramework/Middleware/MiddlewareUtils.php
index 94ac2d1f44c91..de5abf6c2467c 100644
--- a/lib/private/AppFramework/Middleware/MiddlewareUtils.php
+++ b/lib/private/AppFramework/Middleware/MiddlewareUtils.php
@@ -31,19 +31,10 @@ public function __construct(
* @param ReflectionMethod $reflectionMethod
* @param ?string $annotationName
* @param class-string $attributeClass
- * @return boolean
+ * @deprecated 34.0.0 call directly on the reflector
*/
public function hasAnnotationOrAttribute(ReflectionMethod $reflectionMethod, ?string $annotationName, string $attributeClass): bool {
- if (!empty($reflectionMethod->getAttributes($attributeClass))) {
- return true;
- }
-
- if ($annotationName && $this->reflector->hasAnnotation($annotationName)) {
- $this->logger->debug($reflectionMethod->getDeclaringClass()->getName() . '::' . $reflectionMethod->getName() . ' uses the @' . $annotationName . ' annotation and should use the #[' . $attributeClass . '] attribute instead');
- return true;
- }
-
- return false;
+ return $this->reflector->hasAnnotationOrAttribute($annotationName, $attributeClass);
}
/**
diff --git a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
index ce997d1701600..60b925876b1e2 100644
--- a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
@@ -46,9 +46,7 @@ public function __construct(
* @throws NotConfirmedException
*/
public function beforeController(Controller $controller, string $methodName) {
- $reflectionMethod = new ReflectionMethod($controller, $methodName);
-
- if (!$this->needsPasswordConfirmation($reflectionMethod)) {
+ if (!$this->needsPasswordConfirmation()) {
return;
}
@@ -79,6 +77,7 @@ public function beforeController(Controller $controller, string $methodName) {
return;
}
+ $reflectionMethod = new ReflectionMethod($controller, $methodName);
if ($this->isPasswordConfirmationStrict($reflectionMethod)) {
$authHeader = $this->request->getHeader('Authorization');
if (!str_starts_with(strtolower($authHeader), 'basic ')) {
@@ -101,18 +100,8 @@ public function beforeController(Controller $controller, string $methodName) {
}
}
- private function needsPasswordConfirmation(ReflectionMethod $reflectionMethod): bool {
- $attributes = $reflectionMethod->getAttributes(PasswordConfirmationRequired::class);
- if (!empty($attributes)) {
- return true;
- }
-
- if ($this->reflector->hasAnnotation('PasswordConfirmationRequired')) {
- $this->logger->debug($reflectionMethod->getDeclaringClass()->getName() . '::' . $reflectionMethod->getName() . ' uses the @' . 'PasswordConfirmationRequired' . ' annotation and should use the #[PasswordConfirmationRequired] attribute instead');
- return true;
- }
-
- return false;
+ private function needsPasswordConfirmation(): bool {
+ return $this->reflector->hasAnnotationOrAttribute('PasswordConfirmationRequired', PasswordConfirmationRequired::class);
}
private function isPasswordConfirmationStrict(ReflectionMethod $reflectionMethod): bool {
diff --git a/lib/private/AppFramework/Middleware/SessionMiddleware.php b/lib/private/AppFramework/Middleware/SessionMiddleware.php
index 5b2ef81089830..c1cff28ce782f 100644
--- a/lib/private/AppFramework/Middleware/SessionMiddleware.php
+++ b/lib/private/AppFramework/Middleware/SessionMiddleware.php
@@ -14,7 +14,6 @@
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\ISession;
-use ReflectionMethod;
class SessionMiddleware extends Middleware {
public function __construct(
@@ -28,18 +27,7 @@ public function __construct(
* @param string $methodName
*/
public function beforeController($controller, $methodName) {
- /**
- * 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) {
+ if ($this->reflector->hasAnnotationOrAttribute('UseSession', UseSession::class)) {
$this->session->reopen();
}
}
@@ -51,18 +39,7 @@ public function beforeController($controller, $methodName) {
* @return Response
*/
public function afterController($controller, $methodName, Response $response) {
- /**
- * 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) {
+ if ($this->reflector->hasAnnotationOrAttribute('UseSession', UseSession::class)) {
$this->session->close();
}
diff --git a/lib/private/AppFramework/Utility/ControllerMethodReflector.php b/lib/private/AppFramework/Utility/ControllerMethodReflector.php
index b63be92dc3bee..1d30ff2e1376c 100644
--- a/lib/private/AppFramework/Utility/ControllerMethodReflector.php
+++ b/lib/private/AppFramework/Utility/ControllerMethodReflector.php
@@ -9,28 +9,39 @@
namespace OC\AppFramework\Utility;
use OCP\AppFramework\Utility\IControllerMethodReflector;
+use Psr\Log\LoggerInterface;
/**
* Reads and parses annotations from doc comments
*/
class ControllerMethodReflector implements IControllerMethodReflector {
- public $annotations = [];
- private $types = [];
- private $parameters = [];
+ public array $annotations = [];
+ private array $types = [];
+ private array $parameters = [];
private array $ranges = [];
private int $startLine = 0;
private string $file = '';
+ private ?\ReflectionMethod $reflectionMethod = null;
+
+ public function __construct(
+ private readonly LoggerInterface $logger,
+ ) {
+ }
/**
* @param object $object an object or classname
* @param string $method the method which we want to inspect
*/
public function reflect($object, string $method) {
- $reflection = new \ReflectionMethod($object, $method);
- $this->startLine = $reflection->getStartLine();
- $this->file = $reflection->getFileName();
+ $this->annotations = [];
+ $this->types = [];
+ $this->parameters = [];
+ $this->ranges = [];
+ $this->reflectionMethod = new \ReflectionMethod($object, $method);
+ $this->startLine = $this->reflectionMethod->getStartLine();
+ $this->file = $this->reflectionMethod->getFileName();
- $docs = $reflection->getDocComment();
+ $docs = $this->reflectionMethod->getDocComment();
if ($docs !== false) {
// extract everything prefixed by @ and first letter uppercase
@@ -69,7 +80,7 @@ public function reflect($object, string $method) {
}
}
- foreach ($reflection->getParameters() as $param) {
+ foreach ($this->reflectionMethod->getParameters() as $param) {
// extract type information from PHP 7 scalar types and prefer them over phpdoc annotations
$type = $param->getType();
if ($type instanceof \ReflectionNamedType) {
@@ -114,6 +125,24 @@ public function getParameters(): array {
return $this->parameters;
}
+ /**
+ * @template T
+ *
+ * @param class-string $attributeClass
+ */
+ public function hasAnnotationOrAttribute(?string $annotationName, string $attributeClass): bool {
+ if (!empty($this->reflectionMethod->getAttributes($attributeClass))) {
+ return true;
+ }
+
+ if ($annotationName && $this->hasAnnotation($annotationName)) {
+ $this->logger->debug($this->reflectionMethod->getDeclaringClass()->getName() . '::' . $this->reflectionMethod->getName() . ' uses the @' . $annotationName . ' annotation and should use the #[' . $attributeClass . '] attribute instead');
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Check if a method contains an annotation
* @param string $name the name of the annotation
diff --git a/lib/public/AppFramework/Utility/IControllerMethodReflector.php b/lib/public/AppFramework/Utility/IControllerMethodReflector.php
index 95d7fbebb561d..d4e36e310e084 100644
--- a/lib/public/AppFramework/Utility/IControllerMethodReflector.php
+++ b/lib/public/AppFramework/Utility/IControllerMethodReflector.php
@@ -11,22 +11,13 @@
/**
* Interface ControllerMethodReflector
*
- * Reads and parses annotations from doc comments
+ * You can inject this interface in your Middleware, and it will be prefilled with information related to the called controller method
+ *
+ * Reads and parses annotations from doc comments (deprecated) and PHP attributes
*
* @since 8.0.0
- * @deprecated 22.0.0 will be obsolete with native attributes in PHP8
- * @see https://help.nextcloud.com/t/how-should-we-use-php8-attributes/104278
*/
interface IControllerMethodReflector {
- /**
- * @param object $object an object or classname
- * @param string $method the method which we want to inspect
- * @return void
- * @since 8.0.0
- * @deprecated 17.0.0 Reflect should not be called multiple times and only be used internally. This will be removed in Nextcloud 18
- */
- public function reflect($object, string $method);
-
/**
* Inspects the PHPDoc parameters for types
*
@@ -56,4 +47,15 @@ public function getParameters(): array;
* @see https://help.nextcloud.com/t/how-should-we-use-php8-attributes/104278
*/
public function hasAnnotation(string $name): bool;
+
+ /**
+ * @template T
+ *
+ * Check if a method contains an annotation or an attribute.
+ * Log a debug line if the annotation is used.
+ *
+ * @param class-string $attributeClass
+ * @since 34.0.0
+ */
+ public function hasAnnotationOrAttribute(?string $annotationName, string $attributeClass): bool;
}
diff --git a/tests/Core/Middleware/TwoFactorMiddlewareTest.php b/tests/Core/Middleware/TwoFactorMiddlewareTest.php
index 062b1d94b5ea9..9d4a98b07d0ad 100644
--- a/tests/Core/Middleware/TwoFactorMiddlewareTest.php
+++ b/tests/Core/Middleware/TwoFactorMiddlewareTest.php
@@ -10,7 +10,6 @@
use OC\AppFramework\Http\Attributes\TwoFactorSetUpDoneRequired;
use OC\AppFramework\Http\Request;
-use OC\AppFramework\Middleware\MiddlewareUtils;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OC\Authentication\Exceptions\TwoFactorAuthRequiredException;
use OC\Authentication\Exceptions\UserAlreadyLoggedInException;
@@ -102,7 +101,7 @@ protected function setUp(): void {
$this->createMock(IConfig::class)
);
- $this->middleware = new TwoFactorMiddleware($this->twoFactorManager, $this->userSession, $this->session, $this->urlGenerator, new MiddlewareUtils($this->reflector, $this->logger), $this->request);
+ $this->middleware = new TwoFactorMiddleware($this->twoFactorManager, $this->userSession, $this->session, $this->urlGenerator, $this->reflector, $this->request);
}
public function testBeforeControllerNotLoggedIn(): void {
diff --git a/tests/lib/AppFramework/Http/DispatcherTest.php b/tests/lib/AppFramework/Http/DispatcherTest.php
index 1743474358b0c..03a1242dd1fef 100644
--- a/tests/lib/AppFramework/Http/DispatcherTest.php
+++ b/tests/lib/AppFramework/Http/DispatcherTest.php
@@ -123,7 +123,7 @@ protected function setUp(): void {
$this->request = $this->createMock(Request::class);
- $this->reflector = new ControllerMethodReflector();
+ $this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->dispatcher = new Dispatcher(
$this->http,
diff --git a/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php
index 0bf99390c22e8..e386cb82d2cfa 100644
--- a/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php
@@ -30,7 +30,7 @@ class BruteForceMiddlewareTest extends TestCase {
protected function setUp(): void {
parent::setUp();
- $this->reflector = new ControllerMethodReflector();
+ $this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->throttler = $this->createMock(IThrottler::class);
$this->request = $this->createMock(IRequest::class);
$this->logger = $this->createMock(LoggerInterface::class);
diff --git a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php
index 97541612429e0..0b47174553f47 100644
--- a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php
@@ -33,7 +33,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
protected function setUp(): void {
parent::setUp();
- $this->reflector = new ControllerMethodReflector();
+ $this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->session = $this->createMock(Session::class);
$this->throttler = $this->createMock(IThrottler::class);
$this->logger = $this->createMock(LoggerInterface::class);
@@ -79,6 +79,7 @@ public function testNoAnnotationNoCORSHEADER(): void {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
+ $this->reflector->reflect($this->controller, __FUNCTION__);
$middleware = new CORSMiddleware($request, new MiddlewareUtils($this->reflector, $this->logger), $this->session, $this->throttler);
$response = $middleware->afterController($this->controller, __FUNCTION__, new Response());
@@ -300,6 +301,7 @@ public function testAfterExceptionWithSecurityExceptionNoStatus(): void {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
+ $this->reflector->reflect($this->controller, __FUNCTION__);
$middleware = new CORSMiddleware($request, new MiddlewareUtils($this->reflector, $this->logger), $this->session, $this->throttler);
$response = $middleware->afterException($this->controller, __FUNCTION__, new SecurityException('A security exception'));
@@ -316,6 +318,7 @@ public function testAfterExceptionWithSecurityExceptionWithStatus(): void {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
+ $this->reflector->reflect($this->controller, __FUNCTION__);
$middleware = new CORSMiddleware($request, new MiddlewareUtils($this->reflector, $this->logger), $this->session, $this->throttler);
$response = $middleware->afterException($this->controller, __FUNCTION__, new SecurityException('A security exception', 501));
@@ -335,6 +338,7 @@ public function testAfterExceptionWithRegularException(): void {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
+ $this->reflector->reflect($this->controller, __FUNCTION__);
$middleware = new CORSMiddleware($request, new MiddlewareUtils($this->reflector, $this->logger), $this->session, $this->throttler);
$middleware->afterException($this->controller, __FUNCTION__, new \Exception('A regular exception'));
}
diff --git a/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
index 90e801ca47174..e0d1c254c9dbf 100644
--- a/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
@@ -45,7 +45,7 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
private Manager $userManager;
protected function setUp(): void {
- $this->reflector = new ControllerMethodReflector();
+ $this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->session = $this->createMock(ISession::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->user = $this->createMock(IUser::class);
diff --git a/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php
index cf2a569f911e3..beb9424424f7b 100644
--- a/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php
@@ -45,7 +45,7 @@ protected function setUp(): void {
$this->request = $this->createMock(IRequest::class);
$this->userSession = $this->createMock(IUserSession::class);
- $this->reflector = new ControllerMethodReflector();
+ $this->reflector = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->limiter = $this->createMock(Limiter::class);
$this->session = $this->createMock(ISession::class);
$this->appConfig = $this->createMock(IAppConfig::class);
diff --git a/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php
index ebcd3d4613b46..f554df1ad5d76 100644
--- a/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php
@@ -61,8 +61,9 @@ public function testBeforeControllerIndexHasAnnotation(): void {
$this->request->method('getScriptName')
->willReturn('/index.php');
- $this->reflector->method('hasAnnotation')
- ->with('NoSameSiteCookieRequired')
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotationOrAttribute')
+ ->with('NoSameSiteCookieRequired', NoSameSiteCookieRequired::class)
->willReturn(true);
$this->middleware->beforeController(new HasAnnotationController('foo', $this->request), 'foo');
@@ -73,8 +74,9 @@ public function testBeforeControllerIndexNoAnnotationPassingCheck(): void {
$this->request->method('getScriptName')
->willReturn('/index.php');
- $this->reflector->method('hasAnnotation')
- ->with('NoSameSiteCookieRequired')
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotationOrAttribute')
+ ->with('NoSameSiteCookieRequired', NoSameSiteCookieRequired::class)
->willReturn(false);
$this->request->method('passesLaxCookieCheck')
@@ -90,8 +92,9 @@ public function testBeforeControllerIndexNoAnnotationFailingCheck(): void {
$this->request->method('getScriptName')
->willReturn('/index.php');
- $this->reflector->method('hasAnnotation')
- ->with('NoSameSiteCookieRequired')
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotationOrAttribute')
+ ->with('NoSameSiteCookieRequired', NoSameSiteCookieRequired::class)
->willReturn(false);
$this->request->method('passesLaxCookieCheck')
diff --git a/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php
index 62886edd7b276..b47144621898e 100644
--- a/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php
@@ -72,7 +72,7 @@ protected function setUp(): void {
'test',
$this->request
);
- $this->reader = new ControllerMethodReflector();
+ $this->reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$this->logger = $this->createMock(LoggerInterface::class);
$this->navigationManager = $this->createMock(INavigationManager::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
@@ -433,6 +433,7 @@ public function testCsrfOcsController(string $controllerClass, bool $hasOcsApiHe
->willReturn(true);
$controller = new $controllerClass('test', $this->request);
+ $this->reader->reflect($controller, 'foo');
try {
$this->middleware->beforeController($controller, 'foo');
diff --git a/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php b/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php
index 234696ddcf1f1..bc612c30316d8 100644
--- a/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php
@@ -11,6 +11,7 @@
use OC\AppFramework\Middleware\SessionMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
use OCP\ISession;
@@ -19,8 +20,8 @@
use Test\TestCase;
class SessionMiddlewareTest extends TestCase {
- private ControllerMethodReflector|MockObject $reflector;
- private ISession|MockObject $session;
+ private ControllerMethodReflector&MockObject $reflector;
+ private ISession&MockObject $session;
private Controller $controller;
private SessionMiddleware $middleware;
@@ -39,70 +40,39 @@ protected function setUp(): void {
public function testSessionNotClosedOnBeforeController(): void {
$this->configureSessionMock(0, 1);
$this->reflector->expects(self::once())
- ->method('hasAnnotation')
- ->with('UseSession')
+ ->method('hasAnnotationOrAttribute')
+ ->with('UseSession', UseSession::class)
->willReturn(true);
$this->middleware->beforeController($this->controller, 'withAnnotation');
}
- public function testSessionNotClosedOnBeforeControllerWithAttribute(): void {
- $this->configureSessionMock(0, 1);
- $this->reflector->expects(self::once())
- ->method('hasAnnotation')
- ->with('UseSession')
- ->willReturn(false);
-
- $this->middleware->beforeController($this->controller, 'withAttribute');
- }
-
public function testSessionClosedOnAfterController(): void {
$this->configureSessionMock(1);
$this->reflector->expects(self::once())
- ->method('hasAnnotation')
- ->with('UseSession')
+ ->method('hasAnnotationOrAttribute')
+ ->with('UseSession', UseSession::class)
->willReturn(true);
$this->middleware->afterController($this->controller, 'withAnnotation', new Response());
}
- public function testSessionClosedOnAfterControllerWithAttribute(): void {
- $this->configureSessionMock(1);
- $this->reflector->expects(self::once())
- ->method('hasAnnotation')
- ->with('UseSession')
- ->willReturn(true);
-
- $this->middleware->afterController($this->controller, 'withAttribute', new Response());
- }
-
public function testSessionReopenedAndClosedOnBeforeController(): void {
$this->configureSessionMock(1, 1);
$this->reflector->expects(self::exactly(2))
- ->method('hasAnnotation')
- ->with('UseSession')
+ ->method('hasAnnotationOrAttribute')
+ ->with('UseSession', UseSession::class)
->willReturn(true);
$this->middleware->beforeController($this->controller, 'withAnnotation');
$this->middleware->afterController($this->controller, 'withAnnotation', new Response());
}
- public function testSessionReopenedAndClosedOnBeforeControllerWithAttribute(): void {
- $this->configureSessionMock(1, 1);
- $this->reflector->expects(self::exactly(2))
- ->method('hasAnnotation')
- ->with('UseSession')
- ->willReturn(false);
-
- $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')
+ ->method('hasAnnotationOrAttribute')
+ ->with('UseSession', UseSession::class)
->willReturn(false);
$this->middleware->beforeController($this->controller, 'without');
@@ -111,8 +81,8 @@ public function testSessionClosedOnBeforeController(): void {
public function testSessionNotClosedOnAfterController(): void {
$this->configureSessionMock(0);
$this->reflector->expects(self::once())
- ->method('hasAnnotation')
- ->with('UseSession')
+ ->method('hasAnnotationOrAttribute')
+ ->with('UseSession', UseSession::class)
->willReturn(false);
$this->middleware->afterController($this->controller, 'without', new Response());
diff --git a/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php b/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php
index 0d95dcac45fc6..56e3070f5dc68 100644
--- a/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php
+++ b/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php
@@ -9,6 +9,7 @@
namespace Test\AppFramework\Utility;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use Psr\Log\LoggerInterface;
class BaseController {
/**
@@ -69,7 +70,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase {
* @Annotation
*/
public function testReadAnnotation(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadAnnotation'
@@ -82,7 +83,7 @@ public function testReadAnnotation(): void {
* @Annotation(parameter=value)
*/
public function testGetAnnotationParameterSingle(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
self::class,
__FUNCTION__
@@ -95,7 +96,7 @@ public function testGetAnnotationParameterSingle(): void {
* @Annotation(parameter1=value1, parameter2=value2,parameter3=value3)
*/
public function testGetAnnotationParameterMultiple(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
self::class,
__FUNCTION__
@@ -111,7 +112,7 @@ public function testGetAnnotationParameterMultiple(): void {
* @param test
*/
public function testReadAnnotationNoLowercase(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadAnnotationNoLowercase'
@@ -127,7 +128,7 @@ public function testReadAnnotationNoLowercase(): void {
* @param int $test
*/
public function testReadTypeIntAnnotations(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadTypeIntAnnotations'
@@ -145,7 +146,7 @@ public function arguments3($a, float $b, int $c, $d) {
}
public function testReadTypeIntAnnotationsScalarTypes(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'arguments3'
@@ -163,7 +164,7 @@ public function testReadTypeIntAnnotationsScalarTypes(): void {
* @param double $test something special
*/
public function testReadTypeDoubleAnnotations(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadTypeDoubleAnnotations'
@@ -177,7 +178,7 @@ public function testReadTypeDoubleAnnotations(): void {
* @param string $foo
*/
public function testReadTypeWhitespaceAnnotations(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'testReadTypeWhitespaceAnnotations'
@@ -190,7 +191,7 @@ public function testReadTypeWhitespaceAnnotations(): void {
public function arguments($arg, $arg2 = 'hi') {
}
public function testReflectParameters(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'arguments'
@@ -203,7 +204,7 @@ public function testReflectParameters(): void {
public function arguments2($arg) {
}
public function testReflectParameters2(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect(
'\Test\AppFramework\Utility\ControllerMethodReflectorTest',
'arguments2'
@@ -214,7 +215,7 @@ public function testReflectParameters2(): void {
public function testInheritance(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test');
$this->assertTrue($reader->hasAnnotation('Annotation'));
@@ -222,7 +223,7 @@ public function testInheritance(): void {
public function testInheritanceOverride(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test2');
$this->assertTrue($reader->hasAnnotation('NoAnnotation'));
@@ -231,14 +232,14 @@ public function testInheritanceOverride(): void {
public function testInheritanceOverrideNoDocblock(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test3');
$this->assertFalse($reader->hasAnnotation('Annotation'));
}
public function testRangeDetectionPsalm(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test4');
$rangeInfo1 = $reader->getRange('rangedOne');
@@ -259,7 +260,7 @@ public function testRangeDetectionPsalm(): void {
}
public function testRangeDetectionNative(): void {
- $reader = new ControllerMethodReflector();
+ $reader = new ControllerMethodReflector(\OCP\Server::get(LoggerInterface::class));
$reader->reflect('Test\AppFramework\Utility\EndController', 'test5');
$rangeInfo1 = $reader->getRange('rangedOne');