test_jwks.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. # Copyright 2023 The Matrix.org Foundation C.I.C.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from typing import Dict
  15. from twisted.web.resource import Resource
  16. from synapse.rest.synapse.client import build_synapse_client_resource_tree
  17. from tests.unittest import HomeserverTestCase, override_config, skip_unless
  18. try:
  19. import authlib # noqa: F401
  20. HAS_AUTHLIB = True
  21. except ImportError:
  22. HAS_AUTHLIB = False
  23. @skip_unless(HAS_AUTHLIB, "requires authlib")
  24. class JWKSTestCase(HomeserverTestCase):
  25. """Test /_synapse/jwks JWKS data."""
  26. def create_resource_dict(self) -> Dict[str, Resource]:
  27. d = super().create_resource_dict()
  28. d.update(build_synapse_client_resource_tree(self.hs))
  29. return d
  30. def test_empty_jwks(self) -> None:
  31. """Test that the JWKS endpoint is not present by default."""
  32. channel = self.make_request("GET", "/_synapse/jwks")
  33. self.assertEqual(404, channel.code, channel.result)
  34. @override_config(
  35. {
  36. "disable_registration": True,
  37. "experimental_features": {
  38. "msc3861": {
  39. "enabled": True,
  40. "issuer": "https://issuer/",
  41. "client_id": "test-client-id",
  42. "client_auth_method": "client_secret_post",
  43. "client_secret": "secret",
  44. },
  45. },
  46. }
  47. )
  48. def test_empty_jwks_for_msc3861_client_secret_post(self) -> None:
  49. """Test that the JWKS endpoint is empty when plain auth is used."""
  50. channel = self.make_request("GET", "/_synapse/jwks")
  51. self.assertEqual(200, channel.code, channel.result)
  52. self.assertEqual({"keys": []}, channel.json_body)
  53. @override_config(
  54. {
  55. "disable_registration": True,
  56. "experimental_features": {
  57. "msc3861": {
  58. "enabled": True,
  59. "issuer": "https://issuer/",
  60. "client_id": "test-client-id",
  61. "client_auth_method": "private_key_jwt",
  62. "jwk": {
  63. "p": "-frVdP_tZ-J_nIR6HNMDq1N7aunwm51nAqNnhqIyuA8ikx7LlQED1tt2LD3YEvYyW8nxE2V95HlCRZXQPMiRJBFOsbmYkzl2t-MpavTaObB_fct_JqcRtdXddg4-_ihdjRDwUOreq_dpWh6MIKsC3UyekfkHmeEJg5YpOTL15j8",
  64. "kty": "RSA",
  65. "q": "oFw-Enr_YozQB1ab-kawn4jY3yHi8B1nSmYT0s8oTCflrmps5BFJfCkHL5ij3iY15z0o2m0N-jjB1oSJ98O4RayEEYNQlHnTNTl0kRIWzpoqblHUIxVcahIpP_xTovBJzwi8XXoLGqHOOMA-r40LSyVgP2Ut8D9qBwV6_UfT0LU",
  66. "d": "WFkDPYo4b4LIS64D_QtQfGGuAObPvc3HFfp9VZXyq3SJR58XZRHE0jqtlEMNHhOTgbMYS3w8nxPQ_qVzY-5hs4fIanwvB64mAoOGl0qMHO65DTD_WsGFwzYClJPBVniavkLE2Hmpu8IGe6lGliN8vREC6_4t69liY-XcN_ECboVtC2behKkLOEASOIMuS7YcKAhTJFJwkl1dqDlliEn5A4u4xy7nuWQz3juB1OFdKlwGA5dfhDNglhoLIwNnkLsUPPFO-WB5ZNEW35xxHOToxj4bShvDuanVA6mJPtTKjz0XibjB36bj_nF_j7EtbE2PdGJ2KevAVgElR4lqS4ISgQ",
  67. "e": "AQAB",
  68. "kid": "test",
  69. "qi": "cPfNk8l8W5exVNNea4d7QZZ8Qr8LgHghypYAxz8PQh1fNa8Ya1SNUDVzC2iHHhszxxA0vB9C7jGze8dBrvnzWYF1XvQcqNIVVgHhD57R1Nm3dj2NoHIKe0Cu4bCUtP8xnZQUN4KX7y4IIcgRcBWG1hT6DEYZ4BxqicnBXXNXAUI",
  70. "dp": "dKlMHvslV1sMBQaKWpNb3gPq0B13TZhqr3-E2_8sPlvJ3fD8P4CmwwnOn50JDuhY3h9jY5L06sBwXjspYISVv8hX-ndMLkEeF3lrJeA5S70D8rgakfZcPIkffm3tlf1Ok3v5OzoxSv3-67Df4osMniyYwDUBCB5Oq1tTx77xpU8",
  71. "dq": "S4ooU1xNYYcjl9FcuJEEMqKsRrAXzzSKq6laPTwIp5dDwt2vXeAm1a4eDHXC-6rUSZGt5PbqVqzV4s-cjnJMI8YYkIdjNg4NSE1Ac_YpeDl3M3Colb5CQlU7yUB7xY2bt0NOOFp9UJZYJrOo09mFMGjy5eorsbitoZEbVqS3SuE",
  72. "n": "nJbYKqFwnURKimaviyDFrNLD3gaKR1JW343Qem25VeZxoMq1665RHVoO8n1oBm4ClZdjIiZiVdpyqzD5-Ow12YQgQEf1ZHP3CCcOQQhU57Rh5XvScTe5IxYVkEW32IW2mp_CJ6WfjYpfeL4azarVk8H3Vr59d1rSrKTVVinVdZer9YLQyC_rWAQNtHafPBMrf6RYiNGV9EiYn72wFIXlLlBYQ9Fx7bfe1PaL6qrQSsZP3_rSpuvVdLh1lqGeCLR0pyclA9uo5m2tMyCXuuGQLbA_QJm5xEc7zd-WFdux2eXF045oxnSZ_kgQt-pdN7AxGWOVvwoTf9am6mSkEdv6iw",
  73. },
  74. },
  75. },
  76. }
  77. )
  78. def test_key_returned_for_msc3861_client_secret_post(self) -> None:
  79. """Test that the JWKS includes public part of JWK for private_key_jwt auth is used."""
  80. channel = self.make_request("GET", "/_synapse/jwks")
  81. self.assertEqual(200, channel.code, channel.result)
  82. self.assertEqual(
  83. {
  84. "keys": [
  85. {
  86. "kty": "RSA",
  87. "e": "AQAB",
  88. "kid": "test",
  89. "n": "nJbYKqFwnURKimaviyDFrNLD3gaKR1JW343Qem25VeZxoMq1665RHVoO8n1oBm4ClZdjIiZiVdpyqzD5-Ow12YQgQEf1ZHP3CCcOQQhU57Rh5XvScTe5IxYVkEW32IW2mp_CJ6WfjYpfeL4azarVk8H3Vr59d1rSrKTVVinVdZer9YLQyC_rWAQNtHafPBMrf6RYiNGV9EiYn72wFIXlLlBYQ9Fx7bfe1PaL6qrQSsZP3_rSpuvVdLh1lqGeCLR0pyclA9uo5m2tMyCXuuGQLbA_QJm5xEc7zd-WFdux2eXF045oxnSZ_kgQt-pdN7AxGWOVvwoTf9am6mSkEdv6iw",
  90. }
  91. ]
  92. },
  93. channel.json_body,
  94. )