Skip to content

Commit 1ce2c39

Browse files
committed
Make policy depend on whether the login is interactive or not
1 parent 04951d9 commit 1ce2c39

File tree

6 files changed

+37
-8
lines changed

6 files changed

+37
-8
lines changed

crates/handlers/src/compat/login.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,7 @@ async fn token_login(
586586
let res = policy
587587
.evaluate_compat_login(mas_policy::CompatLoginInput {
588588
user: &browser_session.user,
589+
is_interactive: false,
589590
login_type: CompatLoginType::WebSso,
590591
session_replaced,
591592
session_counts,
@@ -714,6 +715,7 @@ async fn user_password_login(
714715
let res = policy
715716
.evaluate_compat_login(mas_policy::CompatLoginInput {
716717
user: &user,
718+
is_interactive: false,
717719
login_type: CompatLoginType::Password,
718720
session_replaced,
719721
session_counts,

crates/handlers/src/compat/login_sso_complete.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,11 @@ use mas_axum_utils::{
2020
csrf::{CsrfExt, ProtectedForm},
2121
};
2222
use mas_data_model::{BoxClock, BoxRng, Clock};
23-
use mas_policy::{Policy, ViolationCode, model::CompatLoginType};
23+
use mas_policy::{Policy, model::CompatLoginType};
2424
use mas_router::{CompatLoginSsoAction, UrlBuilder};
2525
use mas_storage::{BoxRepository, RepositoryAccess, compat::CompatSsoLoginRepository};
2626
use mas_templates::{
27-
CompatLoginPolicyViolationContext, CompatSsoContext, EmptyContext, ErrorContext,
28-
PolicyViolationContext, TemplateContext, Templates,
27+
CompatLoginPolicyViolationContext, CompatSsoContext, ErrorContext, TemplateContext, Templates,
2928
};
3029
use serde::{Deserialize, Serialize};
3130
use ulid::Ulid;
@@ -122,6 +121,7 @@ pub async fn get(
122121
let res = policy
123122
.evaluate_compat_login(mas_policy::CompatLoginInput {
124123
user: &session.user,
124+
is_interactive: true,
125125
login_type: CompatLoginType::WebSso,
126126
// TODO should we predict a replacement?
127127
session_replaced: false,
@@ -251,6 +251,7 @@ pub async fn post(
251251
let res = policy
252252
.evaluate_compat_login(mas_policy::CompatLoginInput {
253253
user: &session.user,
254+
is_interactive: true,
254255
login_type: CompatLoginType::WebSso,
255256
session_counts,
256257
// TODO should we predict a replacement?

crates/policy/src/model.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,15 @@ pub struct CompatLoginInput<'a> {
200200
/// Whether a session will be replaced by this login
201201
pub session_replaced: bool,
202202

203-
// TODO is this actually what we care about? Don't we care a bit more about whether we're in an
204-
// interactive context or a non-interactive context? (SSO type has both phases :()
203+
/// Whether the user is currently in an interactive context.
204+
/// For `m.login.password`: false
205+
/// For `m.login.sso`:
206+
/// - true when asking for consent,
207+
/// - false when actually performing the login (at which point we create the
208+
/// compat session, but it's too late to show a web page)
209+
pub is_interactive: bool,
210+
211+
// TODO I don't know if we should keep this anymore, not used by current policy
205212
pub login_type: CompatLoginType,
206213

207214
pub requester: Requester,

policies/compat_login/compat_login.rego

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ violation contains {
3333
data.session_limit != null
3434

3535
# This is a web-based interactive login
36-
# TODO not strictly correct...
37-
input.login_type == "m.login.sso"
36+
input.is_interactive
3837

3938
# Only apply if this login doesn't replace a session
4039
# (As then this login is not actually increasing the number of devices)
@@ -55,7 +54,7 @@ violation contains {
5554
data.session_limit != null
5655

5756
# This is not a web-based interactive login
58-
input.login_type == "m.login.password"
57+
not input.is_interactive
5958

6059
# Only apply if this login doesn't replace a session
6160
# (As then this login is not actually increasing the number of devices)

policies/compat_login/compat_login_test.rego

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,73 +10,86 @@ import rego.v1
1010

1111
user := {"username": "john"}
1212

13+
# Tests session limiting when using (the interactive part of) `m.login.sso`
1314
test_session_limiting_sso if {
1415
compat_login.allow with input.user as user
1516
with input.session_counts as {"total": 1}
17+
with input.is_interactive as true
1618
with input.login_type as "m.login.sso"
1719
with input.session_replaced as false
1820
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
1921

2022
compat_login.allow with input.user as user
2123
with input.session_counts as {"total": 31}
24+
with input.is_interactive as true
2225
with input.login_type as "m.login.sso"
2326
with input.session_replaced as false
2427
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
2528

2629
not compat_login.allow with input.user as user
2730
with input.session_counts as {"total": 32}
31+
with input.is_interactive as true
2832
with input.login_type as "m.login.sso"
2933
with input.session_replaced as false
3034
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
3135

3236
not compat_login.allow with input.user as user
3337
with input.session_counts as {"total": 42}
38+
with input.is_interactive as true
3439
with input.login_type as "m.login.sso"
3540
with input.session_replaced as false
3641
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
3742

3843
not compat_login.allow with input.user as user
3944
with input.session_counts as {"total": 65}
45+
with input.is_interactive as true
4046
with input.login_type as "m.login.sso"
4147
with input.session_replaced as false
4248
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
4349

4450
# No limit configured
4551
compat_login.allow with input.user as user
4652
with input.session_counts as {"total": 1}
53+
with input.is_interactive as true
4754
with input.login_type as "m.login.sso"
4855
with input.session_replaced as false
4956
with data.session_limit as null
5057
}
5158

59+
# Test session limiting when using `m.login.password`
5260
test_session_limiting_password if {
5361
compat_login.allow with input.user as user
5462
with input.session_counts as {"total": 1}
63+
with input.is_interactive as false
5564
with input.login_type as "m.login.password"
5665
with input.session_replaced as false
5766
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
5867

5968
compat_login.allow with input.user as user
6069
with input.session_counts as {"total": 63}
70+
with input.is_interactive as false
6171
with input.login_type as "m.login.password"
6272
with input.session_replaced as false
6373
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
6474

6575
not compat_login.allow with input.user as user
6676
with input.session_counts as {"total": 64}
77+
with input.is_interactive as false
6778
with input.login_type as "m.login.password"
6879
with input.session_replaced as false
6980
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
7081

7182
not compat_login.allow with input.user as user
7283
with input.session_counts as {"total": 65}
84+
with input.is_interactive as false
7385
with input.login_type as "m.login.password"
7486
with input.session_replaced as false
7587
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
7688

7789
# No limit configured
7890
compat_login.allow with input.user as user
7991
with input.session_counts as {"total": 1}
92+
with input.is_interactive as false
8093
with input.login_type as "m.login.password"
8194
with input.session_replaced as false
8295
with data.session_limit as null
@@ -85,12 +98,14 @@ test_session_limiting_password if {
8598
test_no_session_limiting_upon_replacement if {
8699
not compat_login.allow with input.user as user
87100
with input.session_counts as {"total": 65}
101+
with input.is_interactive as false
88102
with input.login_type as "m.login.password"
89103
with input.session_replaced as false
90104
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}
91105

92106
not compat_login.allow with input.user as user
93107
with input.session_counts as {"total": 65}
108+
with input.is_interactive as true
94109
with input.login_type as "m.login.sso"
95110
with input.session_replaced as false
96111
with data.session_limit as {"soft_limit": 32, "hard_limit": 64}

policies/schema/compat_login_input.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"description": "Input for the compatibility login policy.",
55
"type": "object",
66
"required": [
7+
"is_interactive",
78
"login_type",
89
"requester",
910
"session_counts",
@@ -27,6 +28,10 @@
2728
"description": "Whether a session will be replaced by this login",
2829
"type": "boolean"
2930
},
31+
"is_interactive": {
32+
"description": "Whether the user is currently in an interactive context. For `m.login.password`: false For `m.login.sso`: - true when asking for consent, - false when actually performing the login (at which point we create the compat session, but it's too late to show a web page)",
33+
"type": "boolean"
34+
},
3035
"login_type": {
3136
"$ref": "#/definitions/CompatLoginType"
3237
},

0 commit comments

Comments
 (0)