You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
storage: test compat {session, access token, refresh token} repositories
This commit is contained in:
@ -23,3 +23,296 @@ pub use self::{
|
||||
session::{CompatSessionRepository, PgCompatSessionRepository},
|
||||
sso_login::{CompatSsoLoginRepository, PgCompatSsoLoginRepository},
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chrono::Duration;
|
||||
use mas_data_model::Device;
|
||||
use rand::SeedableRng;
|
||||
use rand_chacha::ChaChaRng;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::*;
|
||||
use crate::{user::UserRepository, Clock, PgRepository, Repository};
|
||||
|
||||
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
||||
async fn test_session_repository(pool: PgPool) {
|
||||
const FIRST_TOKEN: &str = "first_access_token";
|
||||
const SECOND_TOKEN: &str = "second_access_token";
|
||||
let mut rng = ChaChaRng::seed_from_u64(42);
|
||||
let clock = Clock::mock();
|
||||
let mut repo = PgRepository::from_pool(&pool).await.unwrap();
|
||||
|
||||
// Create a user
|
||||
let user = repo
|
||||
.user()
|
||||
.add(&mut rng, &clock, "john".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Start a compat session for that user
|
||||
let device = Device::generate(&mut rng);
|
||||
let device_str = device.as_str().to_owned();
|
||||
let session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(session.user_id, user.id);
|
||||
assert_eq!(session.device.as_str(), device_str);
|
||||
assert!(session.is_valid());
|
||||
assert!(!session.is_finished());
|
||||
|
||||
// Lookup the session and check it didn't change
|
||||
let session_lookup = repo
|
||||
.compat_session()
|
||||
.lookup(session.id)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("compat session not found");
|
||||
assert_eq!(session_lookup.id, session.id);
|
||||
assert_eq!(session_lookup.user_id, user.id);
|
||||
assert_eq!(session_lookup.device.as_str(), device_str);
|
||||
assert!(session_lookup.is_valid());
|
||||
assert!(!session_lookup.is_finished());
|
||||
|
||||
// Finish the session
|
||||
let session = repo.compat_session().finish(&clock, session).await.unwrap();
|
||||
assert!(!session.is_valid());
|
||||
assert!(session.is_finished());
|
||||
|
||||
// Reload the session and check again
|
||||
let session_lookup = repo
|
||||
.compat_session()
|
||||
.lookup(session.id)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("compat session not found");
|
||||
assert!(!session_lookup.is_valid());
|
||||
assert!(session_lookup.is_finished());
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
||||
async fn test_access_token_repository(pool: PgPool) {
|
||||
const FIRST_TOKEN: &str = "first_access_token";
|
||||
const SECOND_TOKEN: &str = "second_access_token";
|
||||
let mut rng = ChaChaRng::seed_from_u64(42);
|
||||
let clock = Clock::mock();
|
||||
let mut repo = PgRepository::from_pool(&pool).await.unwrap();
|
||||
|
||||
// Create a user
|
||||
let user = repo
|
||||
.user()
|
||||
.add(&mut rng, &clock, "john".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Start a compat session for that user
|
||||
let device = Device::generate(&mut rng);
|
||||
let session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Add an access token to that session
|
||||
let token = repo
|
||||
.compat_access_token()
|
||||
.add(
|
||||
&mut rng,
|
||||
&clock,
|
||||
&session,
|
||||
FIRST_TOKEN.to_owned(),
|
||||
Some(Duration::minutes(1)),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(token.session_id, session.id);
|
||||
assert_eq!(token.token, FIRST_TOKEN);
|
||||
|
||||
// Commit the txn and grab a new transaction, to test a conflict
|
||||
repo.save().await.unwrap();
|
||||
|
||||
{
|
||||
let mut repo = PgRepository::from_pool(&pool).await.unwrap();
|
||||
// Adding the same token a second time should conflict
|
||||
assert!(repo
|
||||
.compat_access_token()
|
||||
.add(
|
||||
&mut rng,
|
||||
&clock,
|
||||
&session,
|
||||
FIRST_TOKEN.to_owned(),
|
||||
Some(Duration::minutes(1)),
|
||||
)
|
||||
.await
|
||||
.is_err());
|
||||
repo.cancel().await.unwrap();
|
||||
}
|
||||
|
||||
// Grab a new repo
|
||||
let mut repo = PgRepository::from_pool(&pool).await.unwrap();
|
||||
|
||||
// Looking up via ID works
|
||||
let token_lookup = repo
|
||||
.compat_access_token()
|
||||
.lookup(token.id)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("compat access token not found");
|
||||
assert_eq!(token.id, token_lookup.id);
|
||||
assert_eq!(token_lookup.session_id, session.id);
|
||||
|
||||
// Looking up via the token value works
|
||||
let token_lookup = repo
|
||||
.compat_access_token()
|
||||
.find_by_token(FIRST_TOKEN)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("compat access token not found");
|
||||
assert_eq!(token.id, token_lookup.id);
|
||||
assert_eq!(token_lookup.session_id, session.id);
|
||||
|
||||
// Token is currently valid
|
||||
assert!(token.is_valid(clock.now()));
|
||||
|
||||
clock.advance(Duration::minutes(1));
|
||||
// Token should have expired
|
||||
assert!(!token.is_valid(clock.now()));
|
||||
|
||||
// Add a second access token, this time without expiration
|
||||
let token = repo
|
||||
.compat_access_token()
|
||||
.add(&mut rng, &clock, &session, SECOND_TOKEN.to_owned(), None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(token.session_id, session.id);
|
||||
assert_eq!(token.token, SECOND_TOKEN);
|
||||
|
||||
// Token is currently valid
|
||||
assert!(token.is_valid(clock.now()));
|
||||
|
||||
// Make it expire
|
||||
repo.compat_access_token()
|
||||
.expire(&clock, token)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Reload it
|
||||
let token = repo
|
||||
.compat_access_token()
|
||||
.find_by_token(SECOND_TOKEN)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("compat access token not found");
|
||||
|
||||
// Token is not valid anymore
|
||||
assert!(!token.is_valid(clock.now()));
|
||||
|
||||
repo.save().await.unwrap();
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
||||
async fn test_refresh_token_repository(pool: PgPool) {
|
||||
const ACCESS_TOKEN: &str = "access_token";
|
||||
const REFRESH_TOKEN: &str = "refresh_token";
|
||||
let mut rng = ChaChaRng::seed_from_u64(42);
|
||||
let clock = Clock::mock();
|
||||
let mut repo = PgRepository::from_pool(&pool).await.unwrap();
|
||||
|
||||
// Create a user
|
||||
let user = repo
|
||||
.user()
|
||||
.add(&mut rng, &clock, "john".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Start a compat session for that user
|
||||
let device = Device::generate(&mut rng);
|
||||
let session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Add an access token to that session
|
||||
let access_token = repo
|
||||
.compat_access_token()
|
||||
.add(&mut rng, &clock, &session, ACCESS_TOKEN.to_owned(), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let refresh_token = repo
|
||||
.compat_refresh_token()
|
||||
.add(
|
||||
&mut rng,
|
||||
&clock,
|
||||
&session,
|
||||
&access_token,
|
||||
REFRESH_TOKEN.to_owned(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(refresh_token.session_id, session.id);
|
||||
assert_eq!(refresh_token.access_token_id, access_token.id);
|
||||
assert_eq!(refresh_token.token, REFRESH_TOKEN);
|
||||
assert!(refresh_token.is_valid());
|
||||
assert!(!refresh_token.is_consumed());
|
||||
|
||||
// Look it up by ID and check everything matches
|
||||
let refresh_token_lookup = repo
|
||||
.compat_refresh_token()
|
||||
.lookup(refresh_token.id)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("refresh token not found");
|
||||
assert_eq!(refresh_token_lookup.id, refresh_token.id);
|
||||
assert_eq!(refresh_token_lookup.session_id, session.id);
|
||||
assert_eq!(refresh_token_lookup.access_token_id, access_token.id);
|
||||
assert_eq!(refresh_token_lookup.token, REFRESH_TOKEN);
|
||||
assert!(refresh_token_lookup.is_valid());
|
||||
assert!(!refresh_token_lookup.is_consumed());
|
||||
|
||||
// Look it up by token and check everything matches
|
||||
let refresh_token_lookup = repo
|
||||
.compat_refresh_token()
|
||||
.find_by_token(REFRESH_TOKEN)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("refresh token not found");
|
||||
assert_eq!(refresh_token_lookup.id, refresh_token.id);
|
||||
assert_eq!(refresh_token_lookup.session_id, session.id);
|
||||
assert_eq!(refresh_token_lookup.access_token_id, access_token.id);
|
||||
assert_eq!(refresh_token_lookup.token, REFRESH_TOKEN);
|
||||
assert!(refresh_token_lookup.is_valid());
|
||||
assert!(!refresh_token_lookup.is_consumed());
|
||||
|
||||
// Consume it
|
||||
let refresh_token = repo
|
||||
.compat_refresh_token()
|
||||
.consume(&clock, refresh_token)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(!refresh_token.is_valid());
|
||||
assert!(refresh_token.is_consumed());
|
||||
|
||||
// Reload it and check again
|
||||
let refresh_token_lookup = repo
|
||||
.compat_refresh_token()
|
||||
.find_by_token(REFRESH_TOKEN)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("refresh token not found");
|
||||
assert!(!refresh_token_lookup.is_valid());
|
||||
assert!(refresh_token_lookup.is_consumed());
|
||||
|
||||
// Consuming it again should not work
|
||||
assert!(repo
|
||||
.compat_refresh_token()
|
||||
.consume(&clock, refresh_token)
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
repo.save().await.unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -29,12 +29,12 @@ mod tests {
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::*;
|
||||
use crate::{Clock, PgRepository, Repository};
|
||||
use crate::{user::UserRepository, Clock, PgRepository, Repository};
|
||||
|
||||
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
||||
async fn test_repository(pool: PgPool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut rng = rand_chacha::ChaChaRng::seed_from_u64(42);
|
||||
let clock = Clock::default();
|
||||
let clock = Clock::mock();
|
||||
let mut repo = PgRepository::from_pool(&pool).await?;
|
||||
|
||||
// The provider list should be empty at the start
|
||||
@ -115,6 +115,12 @@ mod tests {
|
||||
.upstream_oauth_session()
|
||||
.complete_with_link(&clock, session, &link, None)
|
||||
.await?;
|
||||
// Reload the session
|
||||
let session = repo
|
||||
.upstream_oauth_session()
|
||||
.lookup(session.id)
|
||||
.await?
|
||||
.expect("session to be found in the database");
|
||||
assert!(session.is_completed());
|
||||
assert!(!session.is_consumed());
|
||||
assert_eq!(session.link_id(), Some(link.id));
|
||||
@ -123,8 +129,29 @@ mod tests {
|
||||
.upstream_oauth_session()
|
||||
.consume(&clock, session)
|
||||
.await?;
|
||||
// Reload the session
|
||||
let session = repo
|
||||
.upstream_oauth_session()
|
||||
.lookup(session.id)
|
||||
.await?
|
||||
.expect("session to be found in the database");
|
||||
assert!(session.is_consumed());
|
||||
|
||||
let user = repo.user().add(&mut rng, &clock, "john".to_owned()).await?;
|
||||
repo.upstream_oauth_link()
|
||||
.associate_to_user(&link, &user)
|
||||
.await?;
|
||||
|
||||
let links = repo
|
||||
.upstream_oauth_link()
|
||||
.list_paginated(&user, None, None, Some(10), None)
|
||||
.await?;
|
||||
assert!(!links.has_previous_page);
|
||||
assert!(!links.has_next_page);
|
||||
assert_eq!(links.edges.len(), 1);
|
||||
assert_eq!(links.edges[0].id, link.id);
|
||||
assert_eq!(links.edges[0].user_id, Some(user.id));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user