diff options
author | Erik Johnston <erik@matrix.org> | 2020-10-21 14:07:59 +0100 |
---|---|---|
committer | Erik Johnston <erik@matrix.org> | 2020-10-21 16:53:40 +0100 |
commit | 9edb5b369eaacc76c22c2de8f0ec4cc5f818e586 (patch) | |
tree | 12af023bfc3031d80ca232e8ff1bec4f5dbd0668 | |
parent | Make get_user_by_access_token return a proper type (diff) | |
download | synapse-9edb5b369eaacc76c22c2de8f0ec4cc5f818e586.tar.xz |
Add concept of authenticated_entity vs target_user
-rw-r--r-- | synapse/api/auth.py | 15 | ||||
-rw-r--r-- | synapse/http/site.py | 6 | ||||
-rw-r--r-- | synapse/storage/databases/main/registration.py | 10 | ||||
-rw-r--r-- | synapse/storage/databases/main/schema/delta/58/22puppet_token.sql | 17 | ||||
-rw-r--r-- | synapse/types.py | 19 |
5 files changed, 59 insertions, 8 deletions
diff --git a/synapse/api/auth.py b/synapse/api/auth.py index a182ce22db..39d4ac33b4 100644 --- a/synapse/api/auth.py +++ b/synapse/api/auth.py @@ -195,6 +195,7 @@ class Auth: if user_id: request.authenticated_entity = user_id opentracing.set_tag("authenticated_entity", user_id) + opentracing.set_tag("target_user", user_id) opentracing.set_tag("appservice_id", app_service.id) if ip_addr and self._track_appservice_user_ips: @@ -218,8 +219,9 @@ class Auth: # Deny the request if the user account has expired. if self._account_validity.enabled and not allow_expired: - user_id = user.to_string() - if await self.store.is_account_expired(user_id, self.clock.time_msec()): + if await self.store.is_account_expired( + user_info.user_id, self.clock.time_msec() + ): raise AuthError( 403, "User account has expired", errcode=Codes.EXPIRED_ACCOUNT ) @@ -228,7 +230,7 @@ class Auth: if access_token and ip_addr: await self.store.insert_client_ip( - user_id=user.to_string(), + user_id=user_info.token_owner, access_token=access_token, ip=ip_addr, user_agent=user_agent, @@ -242,8 +244,10 @@ class Auth: errcode=Codes.GUEST_ACCESS_FORBIDDEN, ) - request.authenticated_entity = user.to_string() - opentracing.set_tag("authenticated_entity", user.to_string()) + request.authenticated_entity = user_info.token_owner + request.target_user = user_info.user_id + opentracing.set_tag("authenticated_entity", user_info.token_owner) + opentracing.set_tag("target_user", user_info.user_id) if device_id: opentracing.set_tag("device_id", device_id) @@ -254,6 +258,7 @@ class Auth: shadow_banned, device_id, app_service=app_service, + authenticated_entity=user_info.token_owner, ) except KeyError: raise MissingClientTokenError() diff --git a/synapse/http/site.py b/synapse/http/site.py index 6e79b47828..480c4d5e2f 100644 --- a/synapse/http/site.py +++ b/synapse/http/site.py @@ -55,6 +55,7 @@ class SynapseRequest(Request): self.site = channel.site self._channel = channel # this is used by the tests self.authenticated_entity = None + self.target_user = None self.start_time = 0.0 # we can't yet create the logcontext, as we don't know the method. @@ -269,6 +270,11 @@ class SynapseRequest(Request): if authenticated_entity is not None and isinstance(authenticated_entity, bytes): authenticated_entity = authenticated_entity.decode("utf-8", "replace") + if self.target_user: + authenticated_entity = "{} as {}".format( + authenticated_entity, self.target_user, + ) + # ...or could be raw utf-8 bytes in the User-Agent header. # N.B. if you don't do this, the logger explodes cryptically # with maximum recursion trying to log errors about diff --git a/synapse/storage/databases/main/registration.py b/synapse/storage/databases/main/registration.py index 6660a65b10..c4c2fa4f68 100644 --- a/synapse/storage/databases/main/registration.py +++ b/synapse/storage/databases/main/registration.py @@ -51,6 +51,11 @@ class TokenLookupResult: token_id = attr.ib(type=Optional[int], default=None) device_id = attr.ib(type=Optional[str], default=None) valid_until_ms = attr.ib(type=Optional[int], default=None) + token_owner = attr.ib(type=str) + + @token_owner.default + def _default_token_owner(self): + return self.user_id class RegistrationWorkerStore(CacheInvalidationWorkerStore): @@ -353,9 +358,10 @@ class RegistrationWorkerStore(CacheInvalidationWorkerStore): users.shadow_banned, access_tokens.id as token_id, access_tokens.device_id, - access_tokens.valid_until_ms + access_tokens.valid_until_ms, + access_tokens.user_id as token_owner FROM users - INNER JOIN access_tokens on users.name = access_tokens.user_id + INNER JOIN access_tokens on users.name = COALESCE(puppets_user_id, access_tokens.user_id) WHERE token = ? """ diff --git a/synapse/storage/databases/main/schema/delta/58/22puppet_token.sql b/synapse/storage/databases/main/schema/delta/58/22puppet_token.sql new file mode 100644 index 0000000000..00a9431a97 --- /dev/null +++ b/synapse/storage/databases/main/schema/delta/58/22puppet_token.sql @@ -0,0 +1,17 @@ +/* Copyright 2020 The Matrix.org Foundation C.I.C + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ + +-- Whether the access token is an admin token for controlling another user. +ALTER TABLE access_tokens ADD COLUMN puppets_user_id TEXT; diff --git a/synapse/types.py b/synapse/types.py index 5bde67cc07..7fb39038b3 100644 --- a/synapse/types.py +++ b/synapse/types.py @@ -74,6 +74,7 @@ class Requester( "shadow_banned", "device_id", "app_service", + "authenticated_entity", ], ) ): @@ -104,6 +105,7 @@ class Requester( "shadow_banned": self.shadow_banned, "device_id": self.device_id, "app_server_id": self.app_service.id if self.app_service else None, + "authenticated_entity": self.authenticated_entity, } @staticmethod @@ -129,6 +131,7 @@ class Requester( shadow_banned=input["shadow_banned"], device_id=input["device_id"], app_service=appservice, + authenticated_entity=input["authenticated_entity"], ) @@ -139,6 +142,7 @@ def create_requester( shadow_banned=False, device_id=None, app_service=None, + authenticated_entity=None, ): """ Create a new ``Requester`` object @@ -151,14 +155,27 @@ def create_requester( shadow_banned (bool): True if the user making this request is shadow-banned. device_id (str|None): device_id which was set at authentication time app_service (ApplicationService|None): the AS requesting on behalf of the user + authenticated_entity: The entity that authenticatd when making the request, + this is different than the user_id when an admin user or the server is + "puppeting" the user. Returns: Requester """ if not isinstance(user_id, UserID): user_id = UserID.from_string(user_id) + + if authenticated_entity is None: + authenticated_entity = user_id.to_string() + return Requester( - user_id, access_token_id, is_guest, shadow_banned, device_id, app_service + user_id, + access_token_id, + is_guest, + shadow_banned, + device_id, + app_service, + authenticated_entity, ) |