Skip to content

Commit e2a08d2

Browse files
committed
Only allow C-S device scopes when the C-S API scope has been requested
It'd be weird for a client to request a device on the client-server API but yet not request any client-server API scopes to use it with. By adding this restriction, we can then create a partial index on the oauth2_sessions table to quickly identify sessions that have C-S API scopes and use this as a proxy metric for how many sessions may have device scopes. This in turn makes it feasible to efficiently limit the number of 'devices' a user has, or more precisely: the number of sessions with client-server API access. We can't do the same for device scopes themselves because, other than nastiness like parsing the JSON stringification of the scope list, it's not feasible to identify device scopes within a Postgres index predicate. Part of: #4339
1 parent 532e4a4 commit e2a08d2

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

policies/authorization_grant/authorization_grant.rego

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,26 @@ uses_stable_scopes if {
9898
count({scope | some scope in scope_list; startswith(scope, "urn:matrix:client:")}) > 0
9999
}
100100

101+
has_device_scope if {
102+
scope_list := split(input.scope, " ")
103+
count({scope | some scope in scope_list; startswith(scope, "urn:matrix:client:device:")}) > 0
104+
}
105+
106+
has_device_scope if {
107+
scope_list := split(input.scope, " ")
108+
count({scope | some scope in scope_list; startswith(scope, "urn:matrix:org.matrix.msc2967.client:device:")}) > 0
109+
}
110+
111+
has_cs_api_scope if {
112+
scope_list := split(input.scope, " ")
113+
count({scope | some scope in scope_list; startswith(scope, "urn:matrix:client:api:")}) > 0
114+
}
115+
116+
has_cs_api_scope if {
117+
scope_list := split(input.scope, " ")
118+
count({scope | some scope in scope_list; startswith(scope, "urn:matrix:org.matrix.msc2967.client:api:")}) > 0
119+
}
120+
101121
# METADATA
102122
# entrypoint: true
103123
violation contains {"msg": msg} if {
@@ -116,6 +136,12 @@ violation contains {"msg": "only one device scope is allowed at a time"} if {
116136
count({scope | some scope in scope_list; startswith(scope, "urn:matrix:client:device:")}) > 1
117137
}
118138

139+
# Prevent the creation of C-S API devices for sessions that don't have C-S API access.
140+
violation contains {"msg": "device scopes are only allowed when the client-server API scope is requested"} if {
141+
has_device_scope
142+
not has_cs_api_scope
143+
}
144+
119145
violation contains {"msg": "request cannot mix unstable and stable scopes"} if {
120146
uses_stable_scopes
121147
uses_unstable_scopes

policies/authorization_grant/authorization_grant_test.rego

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,21 @@ test_stable_device_scopes if {
141141
# Not authorization_grant.allowed for the client credentials grant
142142
not authorization_grant.allow with input.client as client
143143
with input.grant_type as "client_credentials"
144-
with input.scope as "urn:matrix:client:device:AAbbCCdd01"
144+
with input.scope as "urn:matrix:client:api:* urn:matrix:client:device:AAbbCCdd01"
145+
}
146+
147+
test_device_scope_only_with_cs_api_scope if {
148+
not authorization_grant.allow with input.user as user
149+
with input.client as client
150+
with input.grant_type as "authorization_code"
151+
# Requested a device scope but no C-S API scope:
152+
with input.scope as "urn:matrix:client:device:AAbbCCdd01"
153+
154+
not authorization_grant.allow with input.user as user
155+
with input.client as client
156+
with input.grant_type as "authorization_code"
157+
# Requested a device scope but no C-S API scope:
158+
with input.scope as "urn:matrix:org.matrix.msc2967.client:device:AAbbCCdd01"
145159
}
146160

147161
test_mix_stable_and_unstable_scopes if {

0 commit comments

Comments
 (0)