Files
letro-authentication-service/policies/compat_login/compat_login.rego
2025-12-01 11:51:51 +00:00

75 lines
2.2 KiB
Rego

# 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
is_interactive
# Only apply if this login doesn't replace a session
# (As then this login is not actually increasing the number of devices)
not input.session_replaced
# 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
not is_interactive
# Only apply if this login doesn't replace a session
# (As then this login is not actually increasing the number of devices)
not input.session_replaced
# 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
}
is_interactive if {
# Only `m.login.sso` (the interactive web form) is interactive;
# `m.login.password` and `m.login.token` (including the finalisation of an SSO login) are not
input.login.type == "m.login.sso"
}