Reject tokens with multiple device scopes
This commit is contained in:
parent
98afc57d59
commit
f739bde962
|
@ -303,13 +303,31 @@ class MSC3861DelegatedAuth(BaseAuth):
|
||||||
else:
|
else:
|
||||||
user_id = UserID.from_string(user_id_str)
|
user_id = UserID.from_string(user_id_str)
|
||||||
|
|
||||||
# Find device_id in scope
|
# Find device_ids in scope
|
||||||
device_id = None
|
# We only allow a single device_id in the scope, so we find them all in the
|
||||||
for tok in scope:
|
# scope list, and raise if there are more than one. The OIDC server should be
|
||||||
if tok.startswith(SCOPE_MATRIX_DEVICE_PREFIX):
|
# the one enforcing valid scopes, so we raise a 500 if we find an invalid scope.
|
||||||
device_id = tok[len(SCOPE_MATRIX_DEVICE_PREFIX) :]
|
device_ids = [
|
||||||
|
tok[len(SCOPE_MATRIX_DEVICE_PREFIX) :]
|
||||||
|
for tok in scope
|
||||||
|
if tok.startswith(SCOPE_MATRIX_DEVICE_PREFIX)
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(device_ids) > 1:
|
||||||
|
raise AuthError(
|
||||||
|
500,
|
||||||
|
"Multiple device IDs in scope",
|
||||||
|
)
|
||||||
|
|
||||||
|
device_id = device_ids[0] if device_ids else None
|
||||||
|
if device_id is not None:
|
||||||
|
# Sanity check the device_id
|
||||||
|
if len(device_id) > 255 or len(device_id) < 1:
|
||||||
|
raise AuthError(
|
||||||
|
500,
|
||||||
|
"Invalid device ID in scope",
|
||||||
|
)
|
||||||
|
|
||||||
if device_id:
|
|
||||||
# Create the device on the fly if it does not exist
|
# Create the device on the fly if it does not exist
|
||||||
try:
|
try:
|
||||||
await self.store.get_device(
|
await self.store.get_device(
|
||||||
|
|
|
@ -27,6 +27,7 @@ from signedjson.sign import sign_json
|
||||||
from twisted.test.proto_helpers import MemoryReactor
|
from twisted.test.proto_helpers import MemoryReactor
|
||||||
|
|
||||||
from synapse.api.errors import (
|
from synapse.api.errors import (
|
||||||
|
AuthError,
|
||||||
Codes,
|
Codes,
|
||||||
InvalidClientTokenError,
|
InvalidClientTokenError,
|
||||||
OAuthInsufficientScopeError,
|
OAuthInsufficientScopeError,
|
||||||
|
@ -68,8 +69,9 @@ INTROSPECTION_ENDPOINT = ISSUER + "introspect"
|
||||||
SYNAPSE_ADMIN_SCOPE = "urn:synapse:admin:*"
|
SYNAPSE_ADMIN_SCOPE = "urn:synapse:admin:*"
|
||||||
MATRIX_USER_SCOPE = "urn:matrix:org.matrix.msc2967.client:api:*"
|
MATRIX_USER_SCOPE = "urn:matrix:org.matrix.msc2967.client:api:*"
|
||||||
MATRIX_GUEST_SCOPE = "urn:matrix:org.matrix.msc2967.client:api:guest"
|
MATRIX_GUEST_SCOPE = "urn:matrix:org.matrix.msc2967.client:api:guest"
|
||||||
|
MATRIX_DEVICE_SCOPE_PREFIX = "urn:matrix:org.matrix.msc2967.client:device:"
|
||||||
DEVICE = "AABBCCDD"
|
DEVICE = "AABBCCDD"
|
||||||
MATRIX_DEVICE_SCOPE = "urn:matrix:org.matrix.msc2967.client:device:" + DEVICE
|
MATRIX_DEVICE_SCOPE = MATRIX_DEVICE_SCOPE_PREFIX + DEVICE
|
||||||
SUBJECT = "abc-def-ghi"
|
SUBJECT = "abc-def-ghi"
|
||||||
USERNAME = "test-user"
|
USERNAME = "test-user"
|
||||||
USER_ID = "@" + USERNAME + ":" + SERVER_NAME
|
USER_ID = "@" + USERNAME + ":" + SERVER_NAME
|
||||||
|
@ -344,6 +346,31 @@ class MSC3861OAuthDelegation(HomeserverTestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(requester.device_id, DEVICE)
|
self.assertEqual(requester.device_id, DEVICE)
|
||||||
|
|
||||||
|
def test_multiple_devices(self) -> None:
|
||||||
|
"""The handler should raise an error if multiple devices are found in the scope."""
|
||||||
|
|
||||||
|
self.http_client.request = simple_async_mock(
|
||||||
|
return_value=FakeResponse.json(
|
||||||
|
code=200,
|
||||||
|
payload={
|
||||||
|
"active": True,
|
||||||
|
"sub": SUBJECT,
|
||||||
|
"scope": " ".join(
|
||||||
|
[
|
||||||
|
MATRIX_USER_SCOPE,
|
||||||
|
f"{MATRIX_DEVICE_SCOPE_PREFIX}AABBCC",
|
||||||
|
f"{MATRIX_DEVICE_SCOPE_PREFIX}DDEEFF",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
"username": USERNAME,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
request = Mock(args={})
|
||||||
|
request.args[b"access_token"] = [b"mockAccessToken"]
|
||||||
|
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
|
||||||
|
self.get_failure(self.auth.get_user_by_req(request), AuthError)
|
||||||
|
|
||||||
def test_active_guest_not_allowed(self) -> None:
|
def test_active_guest_not_allowed(self) -> None:
|
||||||
"""The handler should return an insufficient scope error."""
|
"""The handler should return an insufficient scope error."""
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue