test_rights.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. # This file is part of Radicale Server - Calendar Server
  2. # Copyright © 2017-2018 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 .helpers import get_file_content
  25. from .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["storage"]["filesystem_folder"] = self.colpath
  32. # Disable syncing to disk for better performance
  33. self.configuration["internal"]["filesystem_fsync"] = "False"
  34. def teardown(self):
  35. shutil.rmtree(self.colpath)
  36. def _test_rights(self, rights_type, user, path, mode, expected_status,
  37. with_auth=True):
  38. assert mode in ("r", "w")
  39. assert user in ("", "tmp")
  40. htpasswd_file_path = os.path.join(self.colpath, ".htpasswd")
  41. with open(htpasswd_file_path, "w") as f:
  42. f.write("tmp:bepo\nother:bepo")
  43. self.configuration["rights"]["type"] = rights_type
  44. if with_auth:
  45. self.configuration["auth"]["type"] = "htpasswd"
  46. self.configuration["auth"]["htpasswd_filename"] = htpasswd_file_path
  47. self.configuration["auth"]["htpasswd_encryption"] = "plain"
  48. self.application = Application(self.configuration)
  49. for u in ("tmp", "other"):
  50. status, _, _ = self.request(
  51. "PROPFIND", "/%s" % u, HTTP_AUTHORIZATION="Basic %s" %
  52. base64.b64encode(("%s:bepo" % u).encode()).decode())
  53. assert status == 207
  54. status, _, _ = self.request(
  55. "PROPFIND" if mode == "r" else "PROPPATCH", path,
  56. HTTP_AUTHORIZATION="Basic %s" % base64.b64encode(
  57. ("tmp:bepo").encode()).decode() if user else "")
  58. assert status == expected_status
  59. def test_owner_only(self):
  60. self._test_rights("owner_only", "", "/", "r", 401)
  61. self._test_rights("owner_only", "", "/", "w", 401)
  62. self._test_rights("owner_only", "", "/tmp", "r", 401)
  63. self._test_rights("owner_only", "", "/tmp", "w", 401)
  64. self._test_rights("owner_only", "tmp", "/", "r", 207)
  65. self._test_rights("owner_only", "tmp", "/", "w", 403)
  66. self._test_rights("owner_only", "tmp", "/tmp", "r", 207)
  67. self._test_rights("owner_only", "tmp", "/tmp", "w", 207)
  68. self._test_rights("owner_only", "tmp", "/other", "r", 403)
  69. self._test_rights("owner_only", "tmp", "/other", "w", 403)
  70. def test_owner_only_without_auth(self):
  71. self._test_rights("owner_only", "", "/", "r", 207, False)
  72. self._test_rights("owner_only", "", "/", "w", 401, False)
  73. self._test_rights("owner_only", "", "/tmp", "r", 207, False)
  74. self._test_rights("owner_only", "", "/tmp", "w", 207, False)
  75. def test_owner_write(self):
  76. self._test_rights("owner_write", "", "/", "r", 401)
  77. self._test_rights("owner_write", "", "/", "w", 401)
  78. self._test_rights("owner_write", "", "/tmp", "r", 401)
  79. self._test_rights("owner_write", "", "/tmp", "w", 401)
  80. self._test_rights("owner_write", "tmp", "/", "r", 207)
  81. self._test_rights("owner_write", "tmp", "/", "w", 403)
  82. self._test_rights("owner_write", "tmp", "/tmp", "r", 207)
  83. self._test_rights("owner_write", "tmp", "/tmp", "w", 207)
  84. self._test_rights("owner_write", "tmp", "/other", "r", 207)
  85. self._test_rights("owner_write", "tmp", "/other", "w", 403)
  86. def test_owner_write_without_auth(self):
  87. self._test_rights("owner_write", "", "/", "r", 207, False)
  88. self._test_rights("owner_write", "", "/", "w", 401, False)
  89. self._test_rights("owner_write", "", "/tmp", "r", 207, False)
  90. self._test_rights("owner_write", "", "/tmp", "w", 207, False)
  91. def test_authenticated(self):
  92. self._test_rights("authenticated", "", "/", "r", 401)
  93. self._test_rights("authenticated", "", "/", "w", 401)
  94. self._test_rights("authenticated", "", "/tmp", "r", 401)
  95. self._test_rights("authenticated", "", "/tmp", "w", 401)
  96. self._test_rights("authenticated", "tmp", "/", "r", 207)
  97. self._test_rights("authenticated", "tmp", "/", "w", 207)
  98. self._test_rights("authenticated", "tmp", "/tmp", "r", 207)
  99. self._test_rights("authenticated", "tmp", "/tmp", "w", 207)
  100. self._test_rights("authenticated", "tmp", "/other", "r", 207)
  101. self._test_rights("authenticated", "tmp", "/other", "w", 207)
  102. def test_authenticated_without_auth(self):
  103. self._test_rights("authenticated", "", "/", "r", 207, False)
  104. self._test_rights("authenticated", "", "/", "w", 207, False)
  105. self._test_rights("authenticated", "", "/tmp", "r", 207, False)
  106. self._test_rights("authenticated", "", "/tmp", "w", 207, False)
  107. def test_from_file(self):
  108. rights_file_path = os.path.join(self.colpath, "rights")
  109. with open(rights_file_path, "w") as f:
  110. f.write("""\
  111. [owner]
  112. user: .+
  113. collection: %(login)s(/.*)?
  114. permissions: RrWw
  115. [custom]
  116. user: .*
  117. collection: custom(/.*)?
  118. permissions: Rr""")
  119. self.configuration["rights"]["file"] = rights_file_path
  120. self._test_rights("from_file", "", "/other", "r", 401)
  121. self._test_rights("from_file", "tmp", "/other", "r", 403)
  122. self._test_rights("from_file", "", "/custom/sub", "r", 404)
  123. self._test_rights("from_file", "tmp", "/custom/sub", "r", 404)
  124. self._test_rights("from_file", "", "/custom/sub", "w", 401)
  125. self._test_rights("from_file", "tmp", "/custom/sub", "w", 403)
  126. def test_custom(self):
  127. """Custom rights management."""
  128. self._test_rights("tests.custom.rights", "", "/", "r", 401)
  129. self._test_rights("tests.custom.rights", "", "/tmp", "r", 207)
  130. def test_collections_and_items(self):
  131. """Test rights for creation of collections, calendars and items.
  132. Collections are allowed at "/" and "/.../".
  133. Calendars/Address books are allowed at "/.../.../".
  134. Items are allowed at "/.../.../...".
  135. """
  136. self.application = Application(self.configuration)
  137. status, _, _ = self.request("MKCALENDAR", "/")
  138. assert status == 401
  139. status, _, _ = self.request("MKCALENDAR", "/user/")
  140. assert status == 401
  141. status, _, _ = self.request("MKCOL", "/user/")
  142. assert status == 201
  143. status, _, _ = self.request("MKCOL", "/user/calendar/")
  144. assert status == 401
  145. status, _, _ = self.request("MKCALENDAR", "/user/calendar/")
  146. assert status == 201
  147. status, _, _ = self.request("MKCOL", "/user/calendar/item")
  148. assert status == 401
  149. status, _, _ = self.request("MKCALENDAR", "/user/calendar/item")
  150. assert status == 401
  151. def test_put_collections_and_items(self):
  152. """Test rights for creation of calendars and items with PUT."""
  153. self.application = Application(self.configuration)
  154. status, _, _ = self.request(
  155. "PUT", "/user/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  156. assert status == 401
  157. status, _, _ = self.request("MKCOL", "/user/")
  158. assert status == 201
  159. status, _, _ = self.request(
  160. "PUT", "/user/calendar/", "BEGIN:VCALENDAR\r\nEND:VCALENDAR")
  161. assert status == 201
  162. event1 = get_file_content("event1.ics")
  163. status, _, _ = self.request(
  164. "PUT", "/user/calendar/event1.ics", event1)
  165. assert status == 201