test_auth.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2015, 2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import pymacaroons
  16. from twisted.internet import defer
  17. import synapse
  18. import synapse.api.errors
  19. from synapse.handlers.auth import AuthHandler
  20. from tests import unittest
  21. from tests.utils import setup_test_homeserver
  22. class AuthHandlers(object):
  23. def __init__(self, hs):
  24. self.auth_handler = AuthHandler(hs)
  25. class AuthTestCase(unittest.TestCase):
  26. @defer.inlineCallbacks
  27. def setUp(self):
  28. self.hs = yield setup_test_homeserver(handlers=None)
  29. self.hs.handlers = AuthHandlers(self.hs)
  30. self.auth_handler = self.hs.handlers.auth_handler
  31. self.macaroon_generator = self.hs.get_macaroon_generator()
  32. def test_token_is_a_macaroon(self):
  33. token = self.macaroon_generator.generate_access_token("some_user")
  34. # Check that we can parse the thing with pymacaroons
  35. macaroon = pymacaroons.Macaroon.deserialize(token)
  36. # The most basic of sanity checks
  37. if "some_user" not in macaroon.inspect():
  38. self.fail("some_user was not in %s" % macaroon.inspect())
  39. def test_macaroon_caveats(self):
  40. self.hs.clock.now = 5000
  41. token = self.macaroon_generator.generate_access_token("a_user")
  42. macaroon = pymacaroons.Macaroon.deserialize(token)
  43. def verify_gen(caveat):
  44. return caveat == "gen = 1"
  45. def verify_user(caveat):
  46. return caveat == "user_id = a_user"
  47. def verify_type(caveat):
  48. return caveat == "type = access"
  49. def verify_nonce(caveat):
  50. return caveat.startswith("nonce =")
  51. v = pymacaroons.Verifier()
  52. v.satisfy_general(verify_gen)
  53. v.satisfy_general(verify_user)
  54. v.satisfy_general(verify_type)
  55. v.satisfy_general(verify_nonce)
  56. v.verify(macaroon, self.hs.config.macaroon_secret_key)
  57. def test_short_term_login_token_gives_user_id(self):
  58. self.hs.clock.now = 1000
  59. token = self.macaroon_generator.generate_short_term_login_token(
  60. "a_user", 5000
  61. )
  62. self.assertEqual(
  63. "a_user",
  64. self.auth_handler.validate_short_term_login_token_and_get_user_id(
  65. token
  66. )
  67. )
  68. # when we advance the clock, the token should be rejected
  69. self.hs.clock.now = 6000
  70. with self.assertRaises(synapse.api.errors.AuthError):
  71. self.auth_handler.validate_short_term_login_token_and_get_user_id(
  72. token
  73. )
  74. def test_short_term_login_token_cannot_replace_user_id(self):
  75. token = self.macaroon_generator.generate_short_term_login_token(
  76. "a_user", 5000
  77. )
  78. macaroon = pymacaroons.Macaroon.deserialize(token)
  79. self.assertEqual(
  80. "a_user",
  81. self.auth_handler.validate_short_term_login_token_and_get_user_id(
  82. macaroon.serialize()
  83. )
  84. )
  85. # add another "user_id" caveat, which might allow us to override the
  86. # user_id.
  87. macaroon.add_first_party_caveat("user_id = b_user")
  88. with self.assertRaises(synapse.api.errors.AuthError):
  89. self.auth_handler.validate_short_term_login_token_and_get_user_id(
  90. macaroon.serialize()
  91. )