1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-29 22:01:14 +03:00

Database refactoring

This commit is contained in:
Quentin Gliech
2022-10-21 11:25:38 +02:00
parent 0571c36da9
commit e2142f9cd4
79 changed files with 3070 additions and 3833 deletions

View File

@ -45,6 +45,7 @@ url = { version = "2.3.1", features = ["serde"] }
mime = "0.3.16"
rand = "0.8.5"
headers = "0.3.8"
ulid = "1.0.0"
oauth2-types = { path = "../oauth2-types" }
mas-axum-utils = { path = "../axum-utils", default-features = false }

View File

@ -259,12 +259,15 @@ async fn token_login(
match login.state {
CompatSsoLoginState::Pending => {
tracing::error!(
login.data,
compat_sso_login.id = %login.data,
"Exchanged a token for a login that was not fullfilled yet"
);
return Err(RouteError::InvalidLoginToken);
}
CompatSsoLoginState::Fullfilled { fullfilled_at, .. } => {
CompatSsoLoginState::Fulfilled {
fulfilled_at: fullfilled_at,
..
} => {
if now > fullfilled_at + Duration::seconds(30) {
return Err(RouteError::LoginTookTooLong);
}
@ -273,7 +276,7 @@ async fn token_login(
if now > exchanged_at + Duration::seconds(30) {
// TODO: log that session out
tracing::error!(
login.data,
compat_sso_login.id = %login.data,
"Login token exchanged a second time more than 30s after"
);
}

View File

@ -33,6 +33,7 @@ use mas_templates::{CompatSsoContext, ErrorContext, TemplateContext, Templates};
use rand::thread_rng;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use ulid::Ulid;
#[derive(Serialize)]
struct AllParams<'s> {
@ -52,7 +53,7 @@ pub async fn get(
State(pool): State<PgPool>,
State(templates): State<Templates>,
cookie_jar: PrivateCookieJar<Encrypter>,
Path(id): Path<i64>,
Path(id): Path<Ulid>,
Query(params): Query<Params>,
) -> Result<Response, FancyError> {
let mut conn = pool.acquire().await?;
@ -116,7 +117,7 @@ pub async fn post(
State(pool): State<PgPool>,
State(templates): State<Templates>,
cookie_jar: PrivateCookieJar<Encrypter>,
Path(id): Path<i64>,
Path(id): Path<Ulid>,
Query(params): Query<Params>,
Form(form): Form<ProtectedForm<()>>,
) -> Result<Response, FancyError> {
@ -178,7 +179,7 @@ pub async fn post(
let params = AllParams {
existing_params,
login_token: &login.token,
login_token: &login.login_token,
};
let query = serde_urlencoded::to_string(&params)?;
redirect_uri.set_query(Some(&query));

View File

@ -17,9 +17,8 @@ use chrono::Duration;
use hyper::StatusCode;
use mas_data_model::{TokenFormatError, TokenType};
use mas_storage::compat::{
add_compat_access_token, add_compat_refresh_token, expire_compat_access_token,
lookup_active_compat_refresh_token, replace_compat_refresh_token,
CompatRefreshTokenLookupError,
add_compat_access_token, add_compat_refresh_token, consume_compat_refresh_token,
expire_compat_access_token, lookup_active_compat_refresh_token, CompatRefreshTokenLookupError,
};
use rand::thread_rng;
use serde::{Deserialize, Serialize};
@ -125,7 +124,7 @@ pub(crate) async fn post(
add_compat_refresh_token(&mut txn, &session, &new_access_token, new_refresh_token_str)
.await?;
replace_compat_refresh_token(&mut txn, &refresh_token, &new_refresh_token).await?;
consume_compat_refresh_token(&mut txn, refresh_token).await?;
expire_compat_access_token(&mut txn, access_token).await?;
txn.commit().await?;

View File

@ -38,6 +38,7 @@ use mas_templates::Templates;
use oauth2_types::requests::{AccessTokenResponse, AuthorizationResponse};
use sqlx::{PgPool, Postgres, Transaction};
use thiserror::Error;
use ulid::Ulid;
use super::callback::{
CallbackDestination, CallbackDestinationError, IntoCallbackDestinationError,
@ -109,7 +110,7 @@ pub(crate) async fn get(
State(templates): State<Templates>,
State(pool): State<PgPool>,
cookie_jar: PrivateCookieJar<Encrypter>,
Path(grant_id): Path<i64>,
Path(grant_id): Path<Ulid>,
) -> Result<Response, RouteError> {
let mut txn = pool.begin().await?;

View File

@ -36,6 +36,7 @@ use mas_storage::oauth2::{
use mas_templates::{ConsentContext, PolicyViolationContext, TemplateContext, Templates};
use sqlx::PgPool;
use thiserror::Error;
use ulid::Ulid;
#[derive(Debug, Error)]
pub enum RouteError {
@ -54,7 +55,7 @@ pub(crate) async fn get(
State(templates): State<Templates>,
State(pool): State<PgPool>,
cookie_jar: PrivateCookieJar<Encrypter>,
Path(grant_id): Path<i64>,
Path(grant_id): Path<Ulid>,
) -> Result<Response, RouteError> {
let mut conn = pool
.acquire()
@ -115,7 +116,7 @@ pub(crate) async fn post(
State(policy_factory): State<Arc<PolicyFactory>>,
State(pool): State<PgPool>,
cookie_jar: PrivateCookieJar<Encrypter>,
Path(grant_id): Path<i64>,
Path(grant_id): Path<Ulid>,
Form(form): Form<ProtectedForm<()>>,
) -> Result<Response, RouteError> {
let mut txn = pool

View File

@ -24,10 +24,10 @@ use oauth2_types::{
ClientMetadata, ClientMetadataVerificationError, ClientRegistrationResponse, Localized,
},
};
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use sqlx::PgPool;
use thiserror::Error;
use tracing::info;
use ulid::Ulid;
#[derive(Debug, Error)]
pub(crate) enum RouteError {
@ -127,18 +127,14 @@ pub(crate) async fn post(
let mut txn = pool.begin().await?;
// Let's generate a random client ID
let client_id: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(10)
.map(char::from)
.collect();
let client_id = Ulid::new();
insert_client(
&mut txn,
&client_id,
client_id,
metadata.redirect_uris(),
None,
&metadata.response_types(),
//&metadata.response_types(),
metadata.grant_types(),
contacts,
metadata
@ -162,7 +158,7 @@ pub(crate) async fn post(
txn.commit().await?;
let response = ClientRegistrationResponse {
client_id,
client_id: client_id.to_string(),
client_secret: None,
client_id_issued_at: None,
client_secret_expires_at: None,

View File

@ -36,7 +36,7 @@ use mas_storage::{
client::ClientFetchError,
end_oauth_session,
refresh_token::{
add_refresh_token, lookup_active_refresh_token, replace_refresh_token,
add_refresh_token, consume_refresh_token, lookup_active_refresh_token,
RefreshTokenLookupError,
},
},
@ -311,10 +311,10 @@ async fn authorization_code_grant(
)
};
let access_token = add_access_token(&mut txn, session, &access_token_str, ttl).await?;
let access_token = add_access_token(&mut txn, session, access_token_str.clone(), ttl).await?;
let _refresh_token =
add_refresh_token(&mut txn, session, access_token, &refresh_token_str).await?;
add_refresh_token(&mut txn, session, access_token, refresh_token_str.clone()).await?;
let id_token = if session.scope.contains(&scope::OPENID) {
let mut claims = HashMap::new();
@ -391,20 +391,21 @@ async fn refresh_token_grant(
)
};
let new_access_token = add_access_token(&mut txn, &session, &access_token_str, ttl).await?;
let new_access_token =
add_access_token(&mut txn, &session, access_token_str.clone(), ttl).await?;
let new_refresh_token =
add_refresh_token(&mut txn, &session, new_access_token, &refresh_token_str).await?;
add_refresh_token(&mut txn, &session, new_access_token, refresh_token_str).await?;
replace_refresh_token(&mut txn, &refresh_token, &new_refresh_token).await?;
consume_refresh_token(&mut txn, &refresh_token).await?;
if let Some(access_token) = refresh_token.access_token {
revoke_access_token(&mut txn, &access_token).await?;
revoke_access_token(&mut txn, access_token).await?;
}
let params = AccessTokenResponse::new(access_token_str)
.with_expires_in(ttl)
.with_refresh_token(refresh_token_str)
.with_refresh_token(new_refresh_token.refresh_token)
.with_scope(session.scope);
txn.commit().await?;

View File

@ -86,7 +86,7 @@ pub(crate) async fn post(
return Ok((cookie_jar, login.go()).into_response());
};
let user_email = add_user_email(&mut txn, &session.user, &form.email).await?;
let user_email = add_user_email(&mut txn, &session.user, form.email).await?;
let next = mas_router::AccountVerifyEmail::new(user_email.data);
let next = if let Some(action) = query.post_auth_action {
next.and_then(action)

View File

@ -17,6 +17,7 @@ use axum::{
response::{Html, IntoResponse, Response},
};
use axum_extra::extract::PrivateCookieJar;
use chrono::Duration;
use lettre::{message::Mailbox, Address};
use mas_axum_utils::{
csrf::{CsrfExt, ProtectedForm},
@ -101,7 +102,8 @@ async fn start_email_verification(
let address: Address = user_email.email.parse()?;
let verification = add_user_email_verification_code(executor, user_email, code).await?;
let verification =
add_user_email_verification_code(executor, user_email, Duration::hours(8), code).await?;
// And send the verification email
let mailbox = Mailbox::new(Some(user.username.clone()), address);
@ -111,7 +113,7 @@ async fn start_email_verification(
mailer.send_verification_email(mailbox, &context).await?;
info!(
email.id = verification.email.data,
email.id = %verification.email.data,
"Verification email sent"
);
Ok(())
@ -141,7 +143,7 @@ pub(crate) async fn post(
match form {
ManagementForm::Add { email } => {
let user_email = add_user_email(&mut txn, &session.user, &email).await?;
let user_email = add_user_email(&mut txn, &session.user, email).await?;
let next = mas_router::AccountVerifyEmail::new(user_email.data);
start_email_verification(&mailer, &mut txn, &session.user, user_email).await?;
txn.commit().await?;

View File

@ -17,7 +17,6 @@ use axum::{
response::{Html, IntoResponse, Response},
};
use axum_extra::extract::PrivateCookieJar;
use chrono::Duration;
use mas_axum_utils::{
csrf::{CsrfExt, ProtectedForm},
FancyError, SessionInfoExt,
@ -31,6 +30,7 @@ use mas_storage::user::{
use mas_templates::{EmailVerificationPageContext, TemplateContext, Templates};
use serde::Deserialize;
use sqlx::PgPool;
use ulid::Ulid;
use crate::views::shared::OptionalPostAuthAction;
@ -43,7 +43,7 @@ pub(crate) async fn get(
State(templates): State<Templates>,
State(pool): State<PgPool>,
Query(query): Query<OptionalPostAuthAction>,
Path(id): Path<i64>,
Path(id): Path<Ulid>,
cookie_jar: PrivateCookieJar<Encrypter>,
) -> Result<Response, FancyError> {
let mut conn = pool.acquire().await?;
@ -81,7 +81,7 @@ pub(crate) async fn post(
State(pool): State<PgPool>,
cookie_jar: PrivateCookieJar<Encrypter>,
Query(query): Query<OptionalPostAuthAction>,
Path(id): Path<i64>,
Path(id): Path<Ulid>,
Form(form): Form<ProtectedForm<CodeForm>>,
) -> Result<Response, FancyError> {
let mut txn = pool.begin().await?;
@ -105,9 +105,7 @@ pub(crate) async fn post(
}
// TODO: make those 8 hours configurable
let verification =
lookup_user_email_verification_code(&mut txn, email, &form.code, Duration::hours(8))
.await?;
let verification = lookup_user_email_verification_code(&mut txn, email, &form.code).await?;
// TODO: display nice errors if the code was already consumed or expired
let verification = consume_email_verification(&mut txn, verification).await?;

View File

@ -22,6 +22,7 @@ use axum::{
response::{Html, IntoResponse, Response},
};
use axum_extra::extract::PrivateCookieJar;
use chrono::Duration;
use lettre::{message::Mailbox, Address};
use mas_axum_utils::{
csrf::{CsrfExt, CsrfToken, ProtectedForm},
@ -181,7 +182,7 @@ pub(crate) async fn post(
let pfh = Argon2::default();
let user = register_user(&mut txn, pfh, &form.username, &form.password).await?;
let user_email = add_user_email(&mut txn, &user, &form.email).await?;
let user_email = add_user_email(&mut txn, &user, form.email).await?;
// First, generate a code
let range = Uniform::<u32>::from(0..1_000_000);
@ -189,7 +190,8 @@ pub(crate) async fn post(
let address: Address = user_email.email.parse()?;
let verification = add_user_email_verification_code(&mut txn, user_email, code).await?;
let verification =
add_user_email_verification_code(&mut txn, user_email, Duration::hours(8), code).await?;
// And send the verification email
let mailbox = Mailbox::new(Some(user.username.clone()), address);