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

Add experimental support for MSC3202: allowing application services to masquerade as specific devices. #11538

Merged
merged 18 commits into from
Dec 15, 2021
Merged
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a39ccfc
Expand return type of get_appservice_user_id to allow returning a dev…
reivilibre Dec 8, 2021
be8814f
Expand get_user_by_req to support handling a device ID
reivilibre Dec 8, 2021
7ea5022
Remove superfluous lines
reivilibre Dec 8, 2021
9551a3e
Remove early return because we need more logic here
reivilibre Dec 8, 2021
86ef692
Add get_device_opt which returns None instead of raising if it doesn'…
reivilibre Dec 8, 2021
d3b0be5
Allow masquerading as a device by specifying the device_id URI parameter
reivilibre Dec 8, 2021
8a078ce
Newsfile
reivilibre Dec 8, 2021
cc2bbcd
Switch to the 400 M_EXCLUSIVE error code for non-existent device IDs
reivilibre Dec 9, 2021
7e39806
Add a pair of tests for the ?device_id parameter for AS device masque…
reivilibre Dec 9, 2021
ae968ea
Add an experimental flag to control device masquerading
reivilibre Dec 9, 2021
11e2192
Update tests to enable experimental features
reivilibre Dec 9, 2021
63042ac
Use get_device (fixing in upstream develop)
reivilibre Dec 13, 2021
2becd52
TEMPORARY Revert "Use get_device (fixing in upstream develop)"
reivilibre Dec 13, 2021
405f3f9
Fix comment
reivilibre Dec 13, 2021
075a2b7
Merge branch 'develop' into rei/as_device_masquerading_msc3202
reivilibre Dec 13, 2021
15cb2f0
Use get_device
reivilibre Dec 13, 2021
24e3fad
Merge branch 'develop' into rei/as_device_masquerading_msc3202
reivilibre Dec 15, 2021
f35234a
Fix up: mock get_device in lieu of get_device_opt (since changes from…
reivilibre Dec 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions tests/api/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,67 @@ 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_appservice_valid_token_valid_device_id(self):
"""
Tests that when an application service passes the device_id URL parameter
with the ID of a valid device for the user in question,
the requester instance tracks that device ID.
"""
masquerading_user_id = b"@doppelganger:matrix.org"
masquerading_device_id = b"DOPPELDEVICE"
app_service = Mock(
token="foobar", url="a_url", sender=self.test_user, ip_range_whitelist=None
)
app_service.is_interested_in_user = Mock(return_value=True)
self.store.get_app_service_by_token = Mock(return_value=app_service)
# This just needs to return a truth-y value.
self.store.get_user_by_id = simple_async_mock({"is_guest": False})
self.store.get_user_by_access_token = simple_async_mock(None)
# This also needs to just return a truth-y value
self.store.get_device_opt = simple_async_mock({"hidden": False})

request = Mock(args={})
request.getClientIP.return_value = "127.0.0.1"
request.args[b"access_token"] = [self.test_token]
request.args[b"user_id"] = [masquerading_user_id]
request.args[b"org.matrix.msc3202.device_id"] = [masquerading_device_id]
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
requester = self.get_success(self.auth.get_user_by_req(request))
self.assertEquals(
requester.user.to_string(), masquerading_user_id.decode("utf8")
)
self.assertEquals(requester.device_id, masquerading_device_id.decode("utf8"))

def test_get_user_by_req_appservice_valid_token_invalid_device_id(self):
"""
Tests that when an application service passes the device_id URL parameter
with an ID that is not a valid device ID for the user in question,
the request fails with the appropriate error code.
"""
masquerading_user_id = b"@doppelganger:matrix.org"
masquerading_device_id = b"NOT_A_REAL_DEVICE_ID"
app_service = Mock(
token="foobar", url="a_url", sender=self.test_user, ip_range_whitelist=None
)
app_service.is_interested_in_user = Mock(return_value=True)
self.store.get_app_service_by_token = Mock(return_value=app_service)
# This just needs to return a truth-y value.
self.store.get_user_by_id = simple_async_mock({"is_guest": False})
self.store.get_user_by_access_token = simple_async_mock(None)
# This also needs to just return a truth-y value
self.store.get_device_opt = simple_async_mock(None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one needs to be falsey.


request = Mock(args={})
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
request.getClientIP.return_value = "127.0.0.1"
request.args[b"access_token"] = [self.test_token]
request.args[b"user_id"] = [masquerading_user_id]
request.args[b"org.matrix.msc3202.device_id"] = [masquerading_device_id]
request.requestHeaders.getRawHeaders = mock_getRawHeaders()

failure = self.get_failure(self.auth.get_user_by_req(request), AuthError)
self.assertEquals(failure.value.code, 400)
self.assertEquals(failure.value.errcode, Codes.EXCLUSIVE)

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