Introduce compat login policy
This commit is contained in:
@@ -16,6 +16,7 @@ INPUTS := \
|
||||
client_registration/client_registration.rego \
|
||||
register/register.rego \
|
||||
authorization_grant/authorization_grant.rego \
|
||||
compat_login/compat_login.rego \
|
||||
email/email.rego
|
||||
|
||||
ifeq ($(DOCKER), 1)
|
||||
@@ -38,6 +39,7 @@ policy.wasm: $(INPUTS)
|
||||
-e "client_registration/violation" \
|
||||
-e "register/violation" \
|
||||
-e "authorization_grant/violation" \
|
||||
-e "compat_login/violation" \
|
||||
-e "email/violation" \
|
||||
$^
|
||||
tar xzf bundle.tar.gz /policy.wasm
|
||||
|
||||
61
policies/compat_login/compat_login.rego
Normal file
61
policies/compat_login/compat_login.rego
Normal file
@@ -0,0 +1,61 @@
|
||||
# Copyright 2025 Element Creations Ltd.
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
# Please see LICENSE files in the repository root for full details.
|
||||
|
||||
# METADATA
|
||||
# schemas:
|
||||
# - input: schema["compat_login_input"]
|
||||
package compat_login
|
||||
|
||||
import rego.v1
|
||||
|
||||
import data.common
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if {
|
||||
count(violation) == 0
|
||||
}
|
||||
|
||||
violation contains {"msg": sprintf(
|
||||
"Requester [%s] isn't allowed to do this action",
|
||||
[common.format_requester(input.requester)],
|
||||
)} if {
|
||||
common.requester_banned(input.requester, data.requester)
|
||||
}
|
||||
|
||||
violation contains {
|
||||
"code": "too-many-sessions",
|
||||
"msg": "user has too many active sessions (soft limit)",
|
||||
} if {
|
||||
# Only apply if session limits are enabled in the config
|
||||
data.session_limit != null
|
||||
|
||||
# This is a web-based interactive login
|
||||
# TODO not strictly correct...
|
||||
input.login_type == "m.login.sso"
|
||||
|
||||
# For web-based 'compat SSO' login, a violation occurs when the soft limit has already been
|
||||
# reached or exceeded.
|
||||
# We use the soft limit because the user will be able to interactively remove
|
||||
# sessions to return under the limit.
|
||||
data.session_limit.soft_limit <= input.session_counts.total
|
||||
}
|
||||
|
||||
violation contains {
|
||||
"code": "too-many-sessions",
|
||||
"msg": "user has too many active sessions (hard limit)",
|
||||
} if {
|
||||
# Only apply if session limits are enabled in the config
|
||||
data.session_limit != null
|
||||
|
||||
# This is not a web-based interactive login
|
||||
input.login_type == "m.login.password"
|
||||
|
||||
# For `m.login.password` login, a violation occurs when the hard limit has already been
|
||||
# reached or exceeded.
|
||||
# We don't use the soft limit because the user won't be able to interactively remove
|
||||
# sessions to return under the limit.
|
||||
data.session_limit.hard_limit <= input.session_counts.total
|
||||
}
|
||||
72
policies/compat_login/compat_login_test.rego
Normal file
72
policies/compat_login/compat_login_test.rego
Normal file
@@ -0,0 +1,72 @@
|
||||
# Copyright 2025 Element Creations Ltd.
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
# Please see LICENSE files in the repository root for full details.
|
||||
|
||||
package compat_login_test
|
||||
|
||||
import data.compat_login
|
||||
import rego.v1
|
||||
|
||||
user := {"username": "john"}
|
||||
|
||||
test_session_limiting_sso if {
|
||||
compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 1}
|
||||
with input.login_type as "m.login.sso"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 31}
|
||||
with input.login_type as "m.login.sso"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
not compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 32}
|
||||
with input.login_type as "m.login.sso"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
not compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 42}
|
||||
with input.login_type as "m.login.sso"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
not compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 65}
|
||||
with input.login_type as "m.login.sso"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
# No limit configured
|
||||
compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 1}
|
||||
with input.login_type as "m.login.sso"
|
||||
with data.session_limit as null
|
||||
}
|
||||
|
||||
test_session_limiting_password if {
|
||||
compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 1}
|
||||
with input.login_type as "m.login.password"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 63}
|
||||
with input.login_type as "m.login.password"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
not compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 64}
|
||||
with input.login_type as "m.login.password"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
not compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 65}
|
||||
with input.login_type as "m.login.password"
|
||||
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
|
||||
|
||||
# No limit configured
|
||||
compat_login.allow with input.user as user
|
||||
with input.session_counts as {"total": 1}
|
||||
with input.login_type as "m.login.password"
|
||||
with data.session_limit as null
|
||||
}
|
||||
88
policies/schema/compat_login_input.json
Normal file
88
policies/schema/compat_login_input.json
Normal file
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "CompatLoginInput",
|
||||
"description": "Input for the compatibility login policy.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"login_type",
|
||||
"requester",
|
||||
"session_counts",
|
||||
"user"
|
||||
],
|
||||
"properties": {
|
||||
"user": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"session_counts": {
|
||||
"description": "How many sessions the user has.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/SessionCounts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"login_type": {
|
||||
"$ref": "#/definitions/CompatLoginType"
|
||||
},
|
||||
"requester": {
|
||||
"$ref": "#/definitions/Requester"
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"SessionCounts": {
|
||||
"description": "Information about how many sessions the user has",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"compat",
|
||||
"oauth2",
|
||||
"personal",
|
||||
"total"
|
||||
],
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"oauth2": {
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"compat": {
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"personal": {
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0
|
||||
}
|
||||
}
|
||||
},
|
||||
"CompatLoginType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"m.login.sso",
|
||||
"m.login.password"
|
||||
]
|
||||
},
|
||||
"Requester": {
|
||||
"description": "Identity of the requester",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ip_address": {
|
||||
"description": "IP address of the entity making the request",
|
||||
"type": "string",
|
||||
"format": "ip"
|
||||
},
|
||||
"user_agent": {
|
||||
"description": "User agent of the entity making the request",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user