1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Save which user session created a compat session

This also exposes the user session in the GraphQL API, and allow
filtering on browser session ID on the app session list.
This commit is contained in:
Quentin Gliech
2024-02-21 10:59:18 +01:00
parent 03b6ad7138
commit ed5893eb20
21 changed files with 432 additions and 51 deletions

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT compat_session_id\n , device_id\n , user_id\n , created_at\n , finished_at\n , is_synapse_admin\n , last_active_at\n , last_active_ip as \"last_active_ip: IpAddr\"\n FROM compat_sessions\n WHERE compat_session_id = $1\n ",
"query": "\n SELECT compat_session_id\n , device_id\n , user_id\n , user_session_id\n , created_at\n , finished_at\n , is_synapse_admin\n , last_active_at\n , last_active_ip as \"last_active_ip: IpAddr\"\n FROM compat_sessions\n WHERE compat_session_id = $1\n ",
"describe": {
"columns": [
{
@ -20,26 +20,31 @@
},
{
"ordinal": 3,
"name": "user_session_id",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"ordinal": 5,
"name": "finished_at",
"type_info": "Timestamptz"
},
{
"ordinal": 5,
"ordinal": 6,
"name": "is_synapse_admin",
"type_info": "Bool"
},
{
"ordinal": 6,
"ordinal": 7,
"name": "last_active_at",
"type_info": "Timestamptz"
},
{
"ordinal": 7,
"ordinal": 8,
"name": "last_active_ip: IpAddr",
"type_info": "Inet"
}
@ -53,6 +58,7 @@
false,
false,
false,
true,
false,
true,
false,
@ -60,5 +66,5 @@
true
]
},
"hash": "23c03635d6433099a4353ba0c80b88737724edb16315832891550e29088d02bf"
"hash": "04e25c9267bf2eb143a6445345229081e7b386743a93b3833ef8ad9d09972f3b"
}

View File

@ -0,0 +1,19 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO compat_sessions \n (compat_session_id, user_id, device_id,\n user_session_id, created_at, is_synapse_admin)\n VALUES ($1, $2, $3, $4, $5, $6)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Text",
"Uuid",
"Timestamptz",
"Bool"
]
},
"nullable": []
},
"hash": "4070549b235e059eaeccc4751b480ccb30ad5b62d933b4efb03491124a9361ad"
}

View File

@ -1,18 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO compat_sessions (compat_session_id, user_id, device_id, created_at, is_synapse_admin)\n VALUES ($1, $2, $3, $4, $5)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Text",
"Timestamptz",
"Bool"
]
},
"nullable": []
},
"hash": "cff3ac0fff62ffdc5640fce08c2ffabc1d89202561b736c5d03b501dfcd8d886"
}

View File

@ -0,0 +1,19 @@
-- Copyright 2024 The Matrix.org Foundation C.I.C.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- Adds an optional link between the compatibility sessions and the user sessions
ALTER TABLE compat_sessions
ADD COLUMN user_session_id UUID
REFERENCES user_sessions (user_session_id)
ON DELETE SET NULL;

View File

@ -102,11 +102,12 @@ impl TryFrom<AppSessionLookup> for AppSession {
last_active_ip,
} = value;
let user_session_id = user_session_id.map(Ulid::from);
match (
compat_session_id,
oauth2_session_id,
oauth2_client_id,
user_session_id,
user_id,
scope_list,
device_id,
@ -116,7 +117,6 @@ impl TryFrom<AppSessionLookup> for AppSession {
Some(compat_session_id),
None,
None,
None,
Some(user_id),
None,
Some(device_id),
@ -140,6 +140,7 @@ impl TryFrom<AppSessionLookup> for AppSession {
state,
user_id: user_id.into(),
device,
user_session_id,
created_at,
is_synapse_admin,
last_active_at,
@ -153,7 +154,6 @@ impl TryFrom<AppSessionLookup> for AppSession {
None,
Some(oauth2_session_id),
Some(oauth2_client_id),
user_session_id,
user_id,
Some(scope_list),
None,
@ -180,7 +180,7 @@ impl TryFrom<AppSessionLookup> for AppSession {
created_at,
client_id: oauth2_client_id.into(),
user_id: user_id.map(Ulid::from),
user_session_id: user_session_id.map(Ulid::from),
user_session_id,
scope,
last_active_at,
last_active_ip,
@ -269,6 +269,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
Expr::col((OAuth2Sessions::Table, OAuth2Sessions::FinishedAt)).is_not_null()
}
}))
.and_where_option(filter.browser_session().map(|browser_session| {
Expr::col((OAuth2Sessions::Table, OAuth2Sessions::UserSessionId))
.eq(Uuid::from(browser_session.id))
}))
.and_where_option(filter.device().map(|device| {
Expr::val(device.to_scope_token().to_string()).eq(PgFunc::any(Expr::col((
OAuth2Sessions::Table,
@ -288,7 +292,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
)
.expr_as(Expr::cust("NULL"), AppSessionLookupIden::Oauth2SessionId)
.expr_as(Expr::cust("NULL"), AppSessionLookupIden::Oauth2ClientId)
.expr_as(Expr::cust("NULL"), AppSessionLookupIden::UserSessionId)
.expr_as(
Expr::col((CompatSessions::Table, CompatSessions::UserSessionId)),
AppSessionLookupIden::UserSessionId,
)
.expr_as(
Expr::col((CompatSessions::Table, CompatSessions::UserId)),
AppSessionLookupIden::UserId,
@ -329,6 +336,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
Expr::col((CompatSessions::Table, CompatSessions::FinishedAt)).is_not_null()
}
}))
.and_where_option(filter.browser_session().map(|browser_session| {
Expr::col((CompatSessions::Table, CompatSessions::UserSessionId))
.eq(Uuid::from(browser_session.id))
}))
.and_where_option(filter.device().map(|device| {
Expr::col((CompatSessions::Table, CompatSessions::DeviceId)).eq(device.to_string())
}))
@ -385,6 +396,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
Expr::col((OAuth2Sessions::Table, OAuth2Sessions::FinishedAt)).is_not_null()
}
}))
.and_where_option(filter.browser_session().map(|browser_session| {
Expr::col((OAuth2Sessions::Table, OAuth2Sessions::UserSessionId))
.eq(Uuid::from(browser_session.id))
}))
.and_where_option(filter.device().map(|device| {
Expr::val(device.to_scope_token().to_string()).eq(PgFunc::any(Expr::col((
OAuth2Sessions::Table,
@ -406,6 +421,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
Expr::col((CompatSessions::Table, CompatSessions::FinishedAt)).is_not_null()
}
}))
.and_where_option(filter.browser_session().map(|browser_session| {
Expr::col((CompatSessions::Table, CompatSessions::UserSessionId))
.eq(Uuid::from(browser_session.id))
}))
.and_where_option(filter.device().map(|device| {
Expr::col((CompatSessions::Table, CompatSessions::DeviceId)).eq(device.to_string())
}))
@ -493,7 +512,7 @@ mod tests {
let device = Device::generate(&mut rng);
let compat_session = repo
.compat_session()
.add(&mut rng, &clock, &user, device.clone(), false)
.add(&mut rng, &clock, &user, device.clone(), None, false)
.await
.unwrap();

View File

@ -87,7 +87,7 @@ mod tests {
let device_str = device.as_str().to_owned();
let session = repo
.compat_session()
.add(&mut rng, &clock, &user, device.clone(), false)
.add(&mut rng, &clock, &user, device.clone(), None, false)
.await
.unwrap();
assert_eq!(session.user_id, user.id);
@ -203,7 +203,7 @@ mod tests {
let device = Device::generate(&mut rng);
let sso_login_session = repo
.compat_session()
.add(&mut rng, &clock, &user, device, false)
.add(&mut rng, &clock, &user, device, None, false)
.await
.unwrap();
@ -291,7 +291,7 @@ mod tests {
let device = Device::generate(&mut rng);
let session = repo
.compat_session()
.add(&mut rng, &clock, &user, device, false)
.add(&mut rng, &clock, &user, device, None, false)
.await
.unwrap();
@ -411,7 +411,7 @@ mod tests {
let device = Device::generate(&mut rng);
let session = repo
.compat_session()
.add(&mut rng, &clock, &user, device, false)
.add(&mut rng, &clock, &user, device, None, false)
.await
.unwrap();
@ -584,7 +584,7 @@ mod tests {
let device = Device::generate(&mut rng);
let session = repo
.compat_session()
.add(&mut rng, &clock, &user, device, false)
.add(&mut rng, &clock, &user, device, None, false)
.await
.unwrap();

View File

@ -17,7 +17,8 @@ use std::net::IpAddr;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use mas_data_model::{
CompatSession, CompatSessionState, CompatSsoLogin, CompatSsoLoginState, Device, User,
BrowserSession, CompatSession, CompatSessionState, CompatSsoLogin, CompatSsoLoginState, Device,
User,
};
use mas_storage::{
compat::{CompatSessionFilter, CompatSessionRepository},
@ -55,6 +56,7 @@ struct CompatSessionLookup {
compat_session_id: Uuid,
device_id: String,
user_id: Uuid,
user_session_id: Option<Uuid>,
created_at: DateTime<Utc>,
finished_at: Option<DateTime<Utc>>,
is_synapse_admin: bool,
@ -83,6 +85,7 @@ impl TryFrom<CompatSessionLookup> for CompatSession {
id,
state,
user_id: value.user_id.into(),
user_session_id: value.user_session_id.map(Ulid::from),
device,
created_at: value.created_at,
is_synapse_admin: value.is_synapse_admin,
@ -100,6 +103,7 @@ struct CompatSessionAndSsoLoginLookup {
compat_session_id: Uuid,
device_id: String,
user_id: Uuid,
user_session_id: Option<Uuid>,
created_at: DateTime<Utc>,
finished_at: Option<DateTime<Utc>>,
is_synapse_admin: bool,
@ -135,6 +139,7 @@ impl TryFrom<CompatSessionAndSsoLoginLookup> for (CompatSession, Option<CompatSs
state,
user_id: value.user_id.into(),
device,
user_session_id: value.user_session_id.map(Ulid::from),
created_at: value.created_at,
is_synapse_admin: value.is_synapse_admin,
last_active_at: value.last_active_at,
@ -214,6 +219,7 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
SELECT compat_session_id
, device_id
, user_id
, user_session_id
, created_at
, finished_at
, is_synapse_admin
@ -251,6 +257,7 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
clock: &dyn Clock,
user: &User,
device: Device,
browser_session: Option<&BrowserSession>,
is_synapse_admin: bool,
) -> Result<CompatSession, Self::Error> {
let created_at = clock.now();
@ -259,12 +266,15 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
sqlx::query!(
r#"
INSERT INTO compat_sessions (compat_session_id, user_id, device_id, created_at, is_synapse_admin)
VALUES ($1, $2, $3, $4, $5)
INSERT INTO compat_sessions
(compat_session_id, user_id, device_id,
user_session_id, created_at, is_synapse_admin)
VALUES ($1, $2, $3, $4, $5, $6)
"#,
Uuid::from(id),
Uuid::from(user.id),
device.as_str(),
browser_session.map(|s| Uuid::from(s.id)),
created_at,
is_synapse_admin,
)
@ -277,6 +287,7 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
state: CompatSessionState::default(),
user_id: user.id,
device,
user_session_id: browser_session.map(|s| s.id),
created_at,
is_synapse_admin,
last_active_at: None,
@ -350,6 +361,10 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
Expr::col((CompatSessions::Table, CompatSessions::UserId)),
CompatSessionAndSsoLoginLookupIden::UserId,
)
.expr_as(
Expr::col((CompatSessions::Table, CompatSessions::UserSessionId)),
CompatSessionAndSsoLoginLookupIden::UserSessionId,
)
.expr_as(
Expr::col((CompatSessions::Table, CompatSessions::CreatedAt)),
CompatSessionAndSsoLoginLookupIden::CreatedAt,

View File

@ -53,6 +53,7 @@ pub enum CompatSessions {
CompatSessionId,
UserId,
DeviceId,
UserSessionId,
CreatedAt,
FinishedAt,
IsSynapseAdmin,