RateLimitingPluginTest.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\DAV\Tests\unit\CalDAV\Security;
  8. use OC\Security\RateLimiting\Exception\RateLimitExceededException;
  9. use OC\Security\RateLimiting\Limiter;
  10. use OCA\DAV\CalDAV\CalDavBackend;
  11. use OCA\DAV\CalDAV\Security\RateLimitingPlugin;
  12. use OCA\DAV\Connector\Sabre\Exception\TooManyRequests;
  13. use OCP\IAppConfig;
  14. use OCP\IUser;
  15. use OCP\IUserManager;
  16. use PHPUnit\Framework\MockObject\MockObject;
  17. use Psr\Log\LoggerInterface;
  18. use Sabre\DAV\Exception\Forbidden;
  19. use Test\TestCase;
  20. class RateLimitingPluginTest extends TestCase {
  21. private Limiter|MockObject $limiter;
  22. private CalDavBackend|MockObject $caldavBackend;
  23. private IUserManager|MockObject $userManager;
  24. private LoggerInterface|MockObject $logger;
  25. private IAppConfig|MockObject $config;
  26. private string $userId = 'user123';
  27. private RateLimitingPlugin $plugin;
  28. protected function setUp(): void {
  29. parent::setUp();
  30. $this->limiter = $this->createMock(Limiter::class);
  31. $this->userManager = $this->createMock(IUserManager::class);
  32. $this->caldavBackend = $this->createMock(CalDavBackend::class);
  33. $this->logger = $this->createMock(LoggerInterface::class);
  34. $this->config = $this->createMock(IAppConfig::class);
  35. $this->plugin = new RateLimitingPlugin(
  36. $this->limiter,
  37. $this->userManager,
  38. $this->caldavBackend,
  39. $this->logger,
  40. $this->config,
  41. $this->userId,
  42. );
  43. }
  44. public function testNoUserObject(): void {
  45. $this->limiter->expects(self::never())
  46. ->method('registerUserRequest');
  47. $this->plugin->beforeBind('calendars/foo/cal');
  48. }
  49. public function testUnrelated(): void {
  50. $user = $this->createMock(IUser::class);
  51. $this->userManager->expects(self::once())
  52. ->method('get')
  53. ->with($this->userId)
  54. ->willReturn($user);
  55. $this->limiter->expects(self::never())
  56. ->method('registerUserRequest');
  57. $this->plugin->beforeBind('foo/bar');
  58. }
  59. public function testRegisterCalendarCreation(): void {
  60. $user = $this->createMock(IUser::class);
  61. $this->userManager->expects(self::once())
  62. ->method('get')
  63. ->with($this->userId)
  64. ->willReturn($user);
  65. $this->config
  66. ->method('getValueInt')
  67. ->with('dav')
  68. ->willReturnArgument(2);
  69. $this->limiter->expects(self::once())
  70. ->method('registerUserRequest')
  71. ->with(
  72. 'caldav-create-calendar',
  73. 10,
  74. 3600,
  75. $user,
  76. );
  77. $this->plugin->beforeBind('calendars/foo/cal');
  78. }
  79. public function testCalendarCreationRateLimitExceeded(): void {
  80. $user = $this->createMock(IUser::class);
  81. $this->userManager->expects(self::once())
  82. ->method('get')
  83. ->with($this->userId)
  84. ->willReturn($user);
  85. $this->config
  86. ->method('getValueInt')
  87. ->with('dav')
  88. ->willReturnArgument(2);
  89. $this->limiter->expects(self::once())
  90. ->method('registerUserRequest')
  91. ->with(
  92. 'caldav-create-calendar',
  93. 10,
  94. 3600,
  95. $user,
  96. )
  97. ->willThrowException(new RateLimitExceededException());
  98. $this->expectException(TooManyRequests::class);
  99. $this->plugin->beforeBind('calendars/foo/cal');
  100. }
  101. public function testCalendarLimitReached(): void {
  102. $user = $this->createMock(IUser::class);
  103. $this->userManager->expects(self::once())
  104. ->method('get')
  105. ->with($this->userId)
  106. ->willReturn($user);
  107. $user->method('getUID')->willReturn('user123');
  108. $this->config
  109. ->method('getValueInt')
  110. ->with('dav')
  111. ->willReturnArgument(2);
  112. $this->limiter->expects(self::once())
  113. ->method('registerUserRequest')
  114. ->with(
  115. 'caldav-create-calendar',
  116. 10,
  117. 3600,
  118. $user,
  119. );
  120. $this->caldavBackend->expects(self::once())
  121. ->method('getCalendarsForUserCount')
  122. ->with('principals/users/user123')
  123. ->willReturn(27);
  124. $this->caldavBackend->expects(self::once())
  125. ->method('getSubscriptionsForUserCount')
  126. ->with('principals/users/user123')
  127. ->willReturn(3);
  128. $this->expectException(Forbidden::class);
  129. $this->plugin->beforeBind('calendars/foo/cal');
  130. }
  131. public function testNoCalendarsSubscriptsLimit(): void {
  132. $user = $this->createMock(IUser::class);
  133. $this->userManager->expects(self::once())
  134. ->method('get')
  135. ->with($this->userId)
  136. ->willReturn($user);
  137. $user->method('getUID')->willReturn('user123');
  138. $this->config
  139. ->method('getValueInt')
  140. ->with('dav')
  141. ->willReturnCallback(function ($app, $key, $default) {
  142. switch ($key) {
  143. case 'maximumCalendarsSubscriptions':
  144. return -1;
  145. default:
  146. return $default;
  147. }
  148. });
  149. $this->limiter->expects(self::once())
  150. ->method('registerUserRequest')
  151. ->with(
  152. 'caldav-create-calendar',
  153. 10,
  154. 3600,
  155. $user,
  156. );
  157. $this->caldavBackend->expects(self::never())
  158. ->method('getCalendarsForUserCount')
  159. ->with('principals/users/user123')
  160. ->willReturn(27);
  161. $this->caldavBackend->expects(self::never())
  162. ->method('getSubscriptionsForUserCount')
  163. ->with('principals/users/user123')
  164. ->willReturn(3);
  165. $this->plugin->beforeBind('calendars/foo/cal');
  166. }
  167. }