test_rights.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # This file is part of Radicale Server - Calendar Server
  2. # Copyright © 2017-2019 Unrud <unrud@outlook.com>
  3. #
  4. # This library is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This library is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
  16. """
  17. Radicale tests with simple requests and rights.
  18. """
  19. import base64
  20. import os
  21. import shutil
  22. import tempfile
  23. from radicale import Application, config
  24. from radicale.tests.helpers import get_file_content
  25. from radicale.tests.test_base import BaseTest
  26. class TestBaseRightsRequests(BaseTest):
  27. """Tests basic requests with rights."""
  28. def setup(self):
  29. self.configuration = config.load()
  30. self.colpath = tempfile.mkdtemp()
  31. self.configuration.update({
  32. "storage": {"filesystem_folder": self.colpath},
  33. # Disable syncing to disk for better performance
  34. "internal": {"filesystem_fsync": "False"}}, "test", internal=True)
  35. def teardown(self):
  36. shutil.rmtree(self.colpath)
  37. def _test_rights(self, rights_type, user, path, mode, expected_status,
  38. with_auth=True):
  39. assert mode in ("r", "w")
  40. assert user in ("", "tmp")
  41. htpasswd_file_path = os.path.join(self.colpath, ".htpasswd")
  42. with open(htpasswd_file_path, "w") as f:
  43. f.write("tmp:bepo\nother:bepo")
  44. self.configuration.update({
  45. "rights": {"type": rights_type},
  46. "auth": {"type": "htpasswd" if with_auth else "none",
  47. "htpasswd_filename": htpasswd_file_path,
  48. "htpasswd_encryption": "plain"}}, "test")
  49. self.application = Application(self.configuration)
  50. for u in ("tmp", "other"):
  51. status, _, _ = self.request(
  52. "PROPFIND", "/%s" % u, HTTP_AUTHORIZATION="Basic %s" %
  53. base64.b64encode(("%s:bepo" % u).encode()).decode())
  54. assert status == 207
  55. status, _, _ = self.request(
  56. "PROPFIND" if mode == "r" else "PROPPATCH", path,
  57. HTTP_AUTHORIZATION="Basic %s" % base64.b64encode(
  58. ("tmp:bepo").encode()).decode() if user else "")
  59. assert status == expected_status
  60. def test_owner_only(self):
  61. self._test_rights("owner_only", "", "/", "r", 401)
  62. self._test_rights("owner_only", "", "/", "w", 401)
  63. self._test_rights("owner_only", "", "/tmp", "r", 401)
  64. self._test_rights("owner_only", "", "/tmp", "w", 401)
  65. self._test_rights("owner_only", "tmp", "/", "r", 207)
  66. self._test_rights("owner_only", "tmp", "/", "w", 403)
  67. self._test_rights("owner_only", "tmp", "/tmp", "r", 207)
  68. self._test_rights("owner_only", "tmp", "/tmp", "w", 207)
  69. self._test_rights("owner_only", "tmp", "/other", "r", 403)
  70. self._test_rights("owner_only", "tmp", "/other", "w", 403)
  71. def test_owner_only_without_auth(self):
  72. self._test_rights("owner_only", "", "/", "r", 207, False)
  73. self._test_rights("owner_only", "", "/", "w", 401, False)
  74. self._test_rights("owner_only", "", "/tmp", "r", 207, False)
  75. self._test_rights("owner_only", "", "/tmp", "w", 207, False)
  76. def test_owner_write(self):
  77. self._test_rights("owner_write", "", "/", "r", 401)
  78. self._test_rights("owner_write", "", "/", "w", 401)
  79. self._test_rights("owner_write", "", "/tmp", "r", 401)
  80. self._test_rights("owner_write", "", "/tmp", "w", 401)
  81. self._test_rights("owner_write", "tmp", "/", "r", 207)
  82. self._test_rights("owner_write", "tmp", "/", "w", 403)
  83. self._test_rights("owner_write", "tmp", "/tmp", "r", 207)
  84. self._test_rights("owner_write", "tmp", "/tmp", "w", 207)
  85. self._test_rights("owner_write", "tmp", "/other", "r", 207)
  86. self._test_rights("owner_write", "tmp", "/other", "w", 403)
  87. def test_owner_write_without_auth(self):
  88. self._test_rights("owner_write", "", "/", "r", 207, False)
  89. self._test_rights("owner_write", "", "/", "w", 401, False)
  90. self._test_rights("owner_write", "", "/tmp", "r", 207, False)
  91. self._test_rights("owner_write", "", "/tmp", "w", 207, False)
  92. def test_authenticated(self):
  93. self._test_rights("authenticated", "", "/", "r", 401)
  94. self._test_rights("authenticated", "", "/", "w", 401)
  95. self._test_rights("authenticated", "", "/tmp", "r", 401)
  96. self._test_rights("authenticated", "", "/tmp", "w", 401)
  97. self._test_rights("authenticated", "tmp", "/", "r", 207)
  98. self._test_rights("authenticated", "tmp", "/", "w", 207)
  99. self._test_rights("authenticated", "tmp", "/tmp", "r", 207)
  100. self._test_rights("authenticated", "tmp", "/tmp", "w", 207)
  101. self._test_rights("authenticated", "tmp", "/other", "r", 207)
  102. self._test_rights("authenticated", "tmp", "/other", "w", 207)
  103. def test_authenticated_without_auth(self):
  104. self._test_rights("authenticated", "", "/", "r", 207, False)
  105. self._test_rights("authenticated", "", "/", "w", 207, False)
  106. self._test_rights("authenticated", "", "/tmp", "r", 207, False)
  107. self._test_rights("authenticated", "", "/tmp", "w", 207, False)
  108. def test_from_file(self):
  109. rights_file_path = os.path.join(self.colpath, "rights")
  110. with open(rights_file_path, "w") as f:
  111. f.write("""\
  112. [owner]
  113. user: .+
  114. collection: %(login)s(/.*)?
  115. permissions: RrWw
  116. [custom]
  117. user: .*
  118. collection: custom(/.*)?
  119. permissions: Rr""")
  120. self.configuration.update(
  121. {"rights": {"file": rights_file_path}}, "test")
  122. self._test_rights("from_file", "", "/other", "r", 401)
  123. self._test_rights("from_file", "tmp", "/other", "r", 403)
  124. self._test_rights("from_file", "", "/custom/sub", "r", 404)
  125. self._test_rights("from_file", "tmp", "/custom/sub", "r", 404)
  126. self._test_rights("from_file", "", "/custom/sub", "w", 401)
  127. self._test_rights("from_file", "tmp", "/custom/sub", "w", 403)
  128. def test_custom(self):
  129. """Custom rights management."""
  130. self._test_rights("radicale.tests.custom.rights", "", "/", "r", 401)
  131. self._test_rights("radicale.tests.custom.rights", "", "/tmp", "r", 207)
  132. def test_collections_and_items(self):
  133. """Test rights for creation of collections, calendars and items.
  134. Collections are allowed at "/" and "/.../".
  135. Calendars/Address books are allowed at "/.../.../".
  136. Items are allowed at "/.../.../...".
  137. """
  138. self.application = Application(self.configuration)
  139. status, _, _ = self.request("MKCALENDAR", "/")
  140. assert status == 401
  141. status, _, _ = self.request("MKCALENDAR", "/user/")
  142. assert status == 401
  143. status, _, _ = self.request("MKCOL", "/user/")
  144. assert status == 201
  145. status, _, _ = self.request("MKCOL", "/user/calendar/")
  146. assert status == 401
  147. status, _, _ = self.request("MKCALENDAR", "/user/calendar/")
  148. assert status == 201
  149. status, _, _ = self.request("MKCOL", "/user/calendar/item")
  150. assert status == 401
  151. status, _, _ = self.request("MKCALENDAR", "/user/calendar/item")
  152. assert status == 401
  153. def test_put_collections_and_items(self):
  154. """Test rights for creation of calendars and items with PUT."""
  155. self.application = Application(self.configuration)
  156. status, _, _ = self.request(
  157. "PUT", "/user/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  158. assert status == 401
  159. status, _, _ = self.request("MKCOL", "/user/")
  160. assert status == 201
  161. status, _, _ = self.request(
  162. "PUT", "/user/calendar/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  163. assert status == 201
  164. event1 = get_file_content("event1.ics")
  165. status, _, _ = self.request(
  166. "PUT", "/user/calendar/event1.ics", event1)
  167. assert status == 201