diff --git a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php index 4453f5a7d4b4f..f1ca9b48d2112 100644 --- a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php @@ -73,6 +73,13 @@ public function beforeController($controller, $methodName) { $user = array_key_exists('PHP_AUTH_USER', $this->request->server) ? $this->request->server['PHP_AUTH_USER'] : null; $pass = array_key_exists('PHP_AUTH_PW', $this->request->server) ? $this->request->server['PHP_AUTH_PW'] : null; + // Allow Bearer token authentication for CORS requests + // Bearer tokens are stateless and don't require CSRF protection + $authorizationHeader = $this->request->getHeader('Authorization'); + if (!empty($authorizationHeader) && str_starts_with($authorizationHeader, 'Bearer ')) { + return; + } + // Allow to use the current session if a CSRF token is provided if ($this->request->passesCSRFCheck()) { return; diff --git a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php index c325ae638fb96..0dad23e92ec91 100644 --- a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php @@ -341,4 +341,37 @@ public function testAfterExceptionWithRegularException(): void { $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); $middleware->afterException($this->controller, __FUNCTION__, new \Exception('A regular exception')); } + + public static function dataCORSShouldAllowBearerAuth(): array { + return [ + ['testCORSShouldNeverAllowCookieAuth'], + ['testCORSShouldNeverAllowCookieAuthAttribute'], + ['testCORSAttributeShouldNeverAllowCookieAuth'], + ['testCORSAttributeShouldNeverAllowCookieAuthAttribute'], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldAllowBearerAuth')] + public function testCORSShouldAllowBearerAuth(string $method): void { + $request = new Request( + [ + 'server' => [ + 'HTTP_AUTHORIZATION' => 'Bearer test-token-123' + ] + ], + $this->createMock(IRequestId::class), + $this->createMock(IConfig::class) + ); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); + $this->session->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(true); + $this->session->expects($this->never()) + ->method('logout'); + $this->session->expects($this->never()) + ->method('logClientIn'); + + $middleware->beforeController($this->controller, $method); + } }