Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Add concept of authenticated_entity vs target_user
Browse files Browse the repository at this point in the history
  • Loading branch information
erikjohnston committed Oct 21, 2020
1 parent c238a54 commit 9edb5b3
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 8 deletions.
15 changes: 10 additions & 5 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ async def get_user_by_req(
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:
Expand All @@ -218,8 +219,9 @@ async def get_user_by_req(

# 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
)
Expand All @@ -228,7 +230,7 @@ async def get_user_by_req(

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,
Expand All @@ -242,8 +244,10 @@ async def get_user_by_req(
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)

Expand All @@ -254,6 +258,7 @@ async def get_user_by_req(
shadow_banned,
device_id,
app_service=app_service,
authenticated_entity=user_info.token_owner,
)
except KeyError:
raise MissingClientTokenError()
Expand Down
6 changes: 6 additions & 0 deletions synapse/http/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def __init__(self, channel, *args, **kw):
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.
Expand Down Expand Up @@ -269,6 +270,11 @@ def _finished_processing(self):
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
Expand Down
10 changes: 8 additions & 2 deletions synapse/storage/databases/main/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -353,9 +358,10 @@ def _query_for_auth(self, txn, token: str) -> Optional[TokenLookupResult]:
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 = ?
"""

Expand Down
17 changes: 17 additions & 0 deletions synapse/storage/databases/main/schema/delta/58/22puppet_token.sql
Original file line number Diff line number Diff line change
@@ -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;
19 changes: 18 additions & 1 deletion synapse/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class Requester(
"shadow_banned",
"device_id",
"app_service",
"authenticated_entity",
],
)
):
Expand Down Expand Up @@ -104,6 +105,7 @@ def serialize(self):
"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
Expand All @@ -129,6 +131,7 @@ def deserialize(store, input):
shadow_banned=input["shadow_banned"],
device_id=input["device_id"],
app_service=appservice,
authenticated_entity=input["authenticated_entity"],
)


Expand All @@ -139,6 +142,7 @@ def create_requester(
shadow_banned=False,
device_id=None,
app_service=None,
authenticated_entity=None,
):
"""
Create a new ``Requester`` object
Expand All @@ -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,
)


Expand Down

0 comments on commit 9edb5b3

Please sign in to comment.