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
Database refactoring
This commit is contained in:
@ -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 }
|
||||
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
@ -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(¶ms)?;
|
||||
redirect_uri.set_query(Some(&query));
|
||||
|
@ -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?;
|
||||
|
@ -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?;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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?;
|
||||
|
@ -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)
|
||||
|
@ -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?;
|
||||
|
@ -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?;
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user