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

Commit

Permalink
Allow tracking puppeted users for MAU
Browse files Browse the repository at this point in the history
Currently when puppeting another user, the user doing the puppeting is tracked for client ip's and MAU (if configured).

When tracking MAU is important, it becomes necessary to be possible to also track the client IP's and MAU of puppeted users. As an example a client that manages user creation and creation of tokens via the Synapse admin API, passing those tokens for the client to use.

This PR adds optional configuration to enable tracking of puppeted users into monthly active users. The default behaviour stays the same.

Signed-off-by: Jason Robinson <jasonr@matrix.org>
  • Loading branch information
jaywink committed Dec 10, 2021
1 parent 86e7a6d commit 9e90cc1
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog.d/11561.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add config flag `mau_track_puppeted_users` to allow tracking puppeted users in terms of monthly active users.
5 changes: 5 additions & 0 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,11 @@ manhole_settings:
# - medium: 'email'
# address: 'reserved_user@example.com'

# If enabled, puppeted users can also be tracked. By default when
# puppeting another user, the user who has created the access token
# for puppeting is tracked. If this is enabled, both requests are tracked.
#mau_track_puppeted_users: false

# Used by phonehome stats to group together related servers.
#server_context: context

Expand Down
13 changes: 13 additions & 0 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def __init__(self, hs: "HomeServer"):
self._track_appservice_user_ips = hs.config.appservice.track_appservice_user_ips
self._macaroon_secret_key = hs.config.key.macaroon_secret_key
self._force_tracing_for_users = hs.config.tracing.force_tracing_for_users
self._mau_track_puppeted_users = hs.config.server.mau_track_puppeted_users

async def check_user_in_room(
self,
Expand Down Expand Up @@ -208,6 +209,18 @@ async def get_user_by_req(
user_agent=user_agent,
device_id=device_id,
)
# Track also the puppeted user client IP if enabled and the user is puppeting
if (
user_info.user_id != user_info.token_owner
and self._mau_track_puppeted_users
):
await self.store.insert_client_ip(
user_id=user_info.user_id,
access_token=access_token,
ip=ip_addr,
user_agent=user_agent,
device_id=device_id,
)

if is_guest and not allow_guest:
raise AuthError(
Expand Down
6 changes: 6 additions & 0 deletions synapse/config/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ def read_config(self, config, **kwargs):

self.mau_trial_days = config.get("mau_trial_days", 0)
self.mau_limit_alerting = config.get("mau_limit_alerting", True)
self.mau_track_puppeted_users = config.get("mau_track_puppeted_users", False)

# How long to keep redacted events in the database in unredacted form
# before redacting them.
Expand Down Expand Up @@ -1128,6 +1129,11 @@ def generate_config_section(
# - medium: 'email'
# address: 'reserved_user@example.com'
# If enabled, puppeted users can also be tracked. By default when
# puppeting another user, the user who has created the access token
# for puppeting is tracked. If this is enabled, both requests are tracked.
#mau_track_puppeted_users: false
# Used by phonehome stats to group together related servers.
#server_context: context
Expand Down
33 changes: 33 additions & 0 deletions tests/api/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,39 @@ def test_get_user_by_req_appservice_valid_token_bad_user_id(self):
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
self.get_failure(self.auth.get_user_by_req(request), AuthError)

def test_get_user_by_req__puppeted_token__not_tracking_puppeted_mau(self):
self.store.get_user_by_access_token = simple_async_mock(
TokenLookupResult(
user_id="@baldrick:matrix.org",
device_id="device",
token_owner="@admin:matrix.org",
)
)
self.store.insert_client_ip = simple_async_mock(None)
request = Mock(args={})
request.getClientIP.return_value = "127.0.0.1"
request.args[b"access_token"] = [self.test_token]
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
self.get_success(self.auth.get_user_by_req(request))
self.store.insert_client_ip.assert_called_once()

def test_get_user_by_req__puppeted_token__tracking_puppeted_mau(self):
self.auth._mau_track_puppeted_users = True
self.store.get_user_by_access_token = simple_async_mock(
TokenLookupResult(
user_id="@baldrick:matrix.org",
device_id="device",
token_owner="@admin:matrix.org",
)
)
self.store.insert_client_ip = simple_async_mock(None)
request = Mock(args={})
request.getClientIP.return_value = "127.0.0.1"
request.args[b"access_token"] = [self.test_token]
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
self.get_success(self.auth.get_user_by_req(request))
self.assertEquals(self.store.insert_client_ip.call_count, 2)

def test_get_user_from_macaroon(self):
self.store.get_user_by_access_token = simple_async_mock(
TokenLookupResult(user_id="@baldrick:matrix.org", device_id="device")
Expand Down

0 comments on commit 9e90cc1

Please sign in to comment.