Move the "email unsubscribe" resource, refactor the macaroon generator & simplify the access token verification logic. (#12986)

This simplifies the access token verification logic by removing the `rights`
parameter which was only ever used for the unsubscribe link in email
notifications. The latter has been moved under the `/_synapse` namespace,
since it is not a standard API.

This also makes the email verification link more secure, by embedding the
app_id and pushkey in the macaroon and verifying it. This prevents the user
from tampering the query parameters of that unsubscribe link.

Macaroon generation is refactored:

- Centralised all macaroon generation and verification logic to the
  `MacaroonGenerator`
- Moved to `synapse.utils`
- Changed the constructor to require only a `Clock`, hostname, and a secret key
  (instead of a full `Homeserver`).
- Added tests for all methods.
This commit is contained in:
Quentin Gliech 2022-06-14 15:12:08 +02:00 committed by GitHub
parent 09a3c5ce0b
commit fe1daad672
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 618 additions and 440 deletions

View file

@ -11,7 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Collection, Dict, List, Optional
from typing import Collection, Dict, List, Optional, cast
from unittest.mock import Mock
from twisted.internet import defer
@ -22,6 +22,8 @@ from synapse.api.room_versions import RoomVersions
from synapse.events import make_event_from_dict
from synapse.events.snapshot import EventContext
from synapse.state import StateHandler, StateResolutionHandler
from synapse.util import Clock
from synapse.util.macaroons import MacaroonGenerator
from tests import unittest
@ -190,13 +192,18 @@ class StateTestCase(unittest.TestCase):
"get_clock",
"get_state_resolution_handler",
"get_account_validity_handler",
"get_macaroon_generator",
"hostname",
]
)
clock = cast(Clock, MockClock())
hs.config = default_config("tesths", True)
hs.get_datastores.return_value = Mock(main=self.dummy_store)
hs.get_state_handler.return_value = None
hs.get_clock.return_value = MockClock()
hs.get_clock.return_value = clock
hs.get_macaroon_generator.return_value = MacaroonGenerator(
clock, "tesths", b"verysecret"
)
hs.get_auth.return_value = Auth(hs)
hs.get_state_resolution_handler = lambda: StateResolutionHandler(hs)
hs.get_storage_controllers.return_value = storage_controllers