Skip to content

Commit 537e141

Browse files
authored
Support stable endpoint and scopes from the MSC3861 family (#18549)
This adds stable APIs for both MSC2965 and MSC2967
1 parent 68068de commit 537e141

File tree

6 files changed

+113
-153
lines changed

6 files changed

+113
-153
lines changed

changelog.d/18549.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support for the stable endpoint and scopes of [MSC3861](https://github.com/matrix-org/matrix-spec-proposals/pull/3861) & co.

synapse/api/auth/mas.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#
1414
#
1515
import logging
16-
from typing import TYPE_CHECKING, Optional
16+
from typing import TYPE_CHECKING, Optional, Set
1717
from urllib.parse import urlencode
1818

1919
from synapse._pydantic_compat import (
@@ -57,8 +57,10 @@
5757

5858
# Scope as defined by MSC2967
5959
# https://github.com/matrix-org/matrix-spec-proposals/pull/2967
60-
SCOPE_MATRIX_API = "urn:matrix:org.matrix.msc2967.client:api:*"
61-
SCOPE_MATRIX_DEVICE_PREFIX = "urn:matrix:org.matrix.msc2967.client:device:"
60+
UNSTABLE_SCOPE_MATRIX_API = "urn:matrix:org.matrix.msc2967.client:api:*"
61+
UNSTABLE_SCOPE_MATRIX_DEVICE_PREFIX = "urn:matrix:org.matrix.msc2967.client:device:"
62+
STABLE_SCOPE_MATRIX_API = "urn:matrix:client:api:*"
63+
STABLE_SCOPE_MATRIX_DEVICE_PREFIX = "urn:matrix:client:device:"
6264

6365

6466
class ServerMetadata(BaseModel):
@@ -334,7 +336,10 @@ async def get_user_by_access_token(
334336
scope = introspection_result.get_scope_set()
335337

336338
# Determine type of user based on presence of particular scopes
337-
if SCOPE_MATRIX_API not in scope:
339+
if (
340+
UNSTABLE_SCOPE_MATRIX_API not in scope
341+
and STABLE_SCOPE_MATRIX_API not in scope
342+
):
338343
raise InvalidClientTokenError(
339344
"Token doesn't grant access to the Matrix C-S API"
340345
)
@@ -366,19 +371,20 @@ async def get_user_by_access_token(
366371
# We only allow a single device_id in the scope, so we find them all in the
367372
# scope list, and raise if there are more than one. The OIDC server should be
368373
# the one enforcing valid scopes, so we raise a 500 if we find an invalid scope.
369-
device_ids = [
370-
tok[len(SCOPE_MATRIX_DEVICE_PREFIX) :]
371-
for tok in scope
372-
if tok.startswith(SCOPE_MATRIX_DEVICE_PREFIX)
373-
]
374+
device_ids: Set[str] = set()
375+
for tok in scope:
376+
if tok.startswith(UNSTABLE_SCOPE_MATRIX_DEVICE_PREFIX):
377+
device_ids.add(tok[len(UNSTABLE_SCOPE_MATRIX_DEVICE_PREFIX) :])
378+
elif tok.startswith(STABLE_SCOPE_MATRIX_DEVICE_PREFIX):
379+
device_ids.add(tok[len(STABLE_SCOPE_MATRIX_DEVICE_PREFIX) :])
374380

375381
if len(device_ids) > 1:
376382
raise AuthError(
377383
500,
378384
"Multiple device IDs in scope",
379385
)
380386

381-
device_id = device_ids[0] if device_ids else None
387+
device_id = next(iter(device_ids), None)
382388

383389
if device_id is not None:
384390
# Sanity check the device_id

synapse/api/auth/msc3861_delegated.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#
2121
import logging
2222
from dataclasses import dataclass
23-
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
23+
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Set
2424
from urllib.parse import urlencode
2525

2626
from authlib.oauth2 import ClientAuth
@@ -34,7 +34,6 @@
3434
AuthError,
3535
HttpResponseException,
3636
InvalidClientTokenError,
37-
OAuthInsufficientScopeError,
3837
SynapseError,
3938
UnrecognizedRequestError,
4039
)
@@ -63,9 +62,10 @@
6362

6463
# Scope as defined by MSC2967
6564
# https://github.com/matrix-org/matrix-spec-proposals/pull/2967
66-
SCOPE_MATRIX_API = "urn:matrix:org.matrix.msc2967.client:api:*"
67-
SCOPE_MATRIX_GUEST = "urn:matrix:org.matrix.msc2967.client:api:guest"
68-
SCOPE_MATRIX_DEVICE_PREFIX = "urn:matrix:org.matrix.msc2967.client:device:"
65+
UNSTABLE_SCOPE_MATRIX_API = "urn:matrix:org.matrix.msc2967.client:api:*"
66+
UNSTABLE_SCOPE_MATRIX_DEVICE_PREFIX = "urn:matrix:org.matrix.msc2967.client:device:"
67+
STABLE_SCOPE_MATRIX_API = "urn:matrix:client:api:*"
68+
STABLE_SCOPE_MATRIX_DEVICE_PREFIX = "urn:matrix:client:device:"
6969

7070
# Scope which allows access to the Synapse admin API
7171
SCOPE_SYNAPSE_ADMIN = "urn:synapse:admin:*"
@@ -444,9 +444,6 @@ async def _wrapped_get_user_by_req(
444444
if not self._is_access_token_the_admin_token(access_token):
445445
await self._record_request(request, requester)
446446

447-
if not allow_guest and requester.is_guest:
448-
raise OAuthInsufficientScopeError([SCOPE_MATRIX_API])
449-
450447
request.requester = requester
451448

452449
return requester
@@ -528,10 +525,11 @@ async def get_user_by_access_token(
528525
scope: List[str] = introspection_result.get_scope_list()
529526

530527
# Determine type of user based on presence of particular scopes
531-
has_user_scope = SCOPE_MATRIX_API in scope
532-
has_guest_scope = SCOPE_MATRIX_GUEST in scope
528+
has_user_scope = (
529+
UNSTABLE_SCOPE_MATRIX_API in scope or STABLE_SCOPE_MATRIX_API in scope
530+
)
533531

534-
if not has_user_scope and not has_guest_scope:
532+
if not has_user_scope:
535533
raise InvalidClientTokenError("No scope in token granting user rights")
536534

537535
# Match via the sub claim
@@ -579,19 +577,20 @@ async def get_user_by_access_token(
579577
# We only allow a single device_id in the scope, so we find them all in the
580578
# scope list, and raise if there are more than one. The OIDC server should be
581579
# the one enforcing valid scopes, so we raise a 500 if we find an invalid scope.
582-
device_ids = [
583-
tok[len(SCOPE_MATRIX_DEVICE_PREFIX) :]
584-
for tok in scope
585-
if tok.startswith(SCOPE_MATRIX_DEVICE_PREFIX)
586-
]
580+
device_ids: Set[str] = set()
581+
for tok in scope:
582+
if tok.startswith(UNSTABLE_SCOPE_MATRIX_DEVICE_PREFIX):
583+
device_ids.add(tok[len(UNSTABLE_SCOPE_MATRIX_DEVICE_PREFIX) :])
584+
elif tok.startswith(STABLE_SCOPE_MATRIX_DEVICE_PREFIX):
585+
device_ids.add(tok[len(STABLE_SCOPE_MATRIX_DEVICE_PREFIX) :])
587586

588587
if len(device_ids) > 1:
589588
raise AuthError(
590589
500,
591590
"Multiple device IDs in scope",
592591
)
593592

594-
device_id = device_ids[0] if device_ids else None
593+
device_id = next(iter(device_ids), None)
595594

596595
if device_id is not None:
597596
# Sanity check the device_id
@@ -617,5 +616,4 @@ async def get_user_by_access_token(
617616
user_id=user_id,
618617
device_id=device_id,
619618
scope=scope,
620-
is_guest=(has_guest_scope and not has_user_scope),
621619
)

synapse/rest/client/auth_metadata.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,17 @@ class AuthMetadataServlet(RestServlet):
7676
Advertises the OAuth 2.0 server metadata for the homeserver.
7777
"""
7878

79-
PATTERNS = client_patterns(
80-
"/org.matrix.msc2965/auth_metadata$",
81-
unstable=True,
82-
releases=(),
83-
)
79+
PATTERNS = [
80+
*client_patterns(
81+
"/auth_metadata$",
82+
releases=("v1",),
83+
),
84+
*client_patterns(
85+
"/org.matrix.msc2965/auth_metadata$",
86+
unstable=True,
87+
releases=(),
88+
),
89+
]
8490

8591
def __init__(self, hs: "HomeServer"):
8692
super().__init__()

0 commit comments

Comments
 (0)