1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

handlers: box the rng and clock, and extract it from the state

This commit is contained in:
Quentin Gliech
2023-01-18 17:32:54 +01:00
parent 8c585b20f0
commit 9005931e2a
52 changed files with 291 additions and 193 deletions

View File

@@ -27,7 +27,7 @@ use mas_policy::PolicyFactory;
use mas_router::{PostAuthAction, Route};
use mas_storage::{
oauth2::{OAuth2AuthorizationGrantRepository, OAuth2ClientRepository, OAuth2SessionRepository},
Repository,
BoxClock, BoxRng, Repository,
};
use mas_storage_pg::PgRepository;
use mas_templates::Templates;
@@ -70,7 +70,6 @@ impl IntoResponse for RouteError {
}
}
impl_from_error_for_route!(sqlx::Error);
impl_from_error_for_route!(mas_storage_pg::DatabaseError);
impl_from_error_for_route!(mas_policy::LoadError);
impl_from_error_for_route!(mas_policy::InstanciateError);
@@ -79,6 +78,8 @@ impl_from_error_for_route!(super::callback::IntoCallbackDestinationError);
impl_from_error_for_route!(super::callback::CallbackDestinationError);
pub(crate) async fn get(
rng: BoxRng,
clock: BoxClock,
State(policy_factory): State<Arc<PolicyFactory>>,
State(templates): State<Templates>,
State(pool): State<PgPool>,
@@ -108,7 +109,7 @@ pub(crate) async fn get(
return Ok((cookie_jar, mas_router::Login::and_then(continue_grant).go()).into_response());
};
match complete(grant, session, &policy_factory, repo).await {
match complete(rng, clock, grant, session, &policy_factory, repo).await {
Ok(params) => {
let res = callback_destination.go(&templates, params).await?;
Ok((cookie_jar, res).into_response())
@@ -149,7 +150,6 @@ pub enum GrantCompletionError {
NoSuchClient,
}
impl_from_error_for_route!(GrantCompletionError: sqlx::Error);
impl_from_error_for_route!(GrantCompletionError: mas_storage_pg::DatabaseError);
impl_from_error_for_route!(GrantCompletionError: super::callback::IntoCallbackDestinationError);
impl_from_error_for_route!(GrantCompletionError: mas_policy::LoadError);
@@ -157,13 +157,13 @@ impl_from_error_for_route!(GrantCompletionError: mas_policy::InstanciateError);
impl_from_error_for_route!(GrantCompletionError: mas_policy::EvaluationError);
pub(crate) async fn complete(
mut rng: BoxRng,
clock: BoxClock,
grant: AuthorizationGrant,
browser_session: BrowserSession,
policy_factory: &PolicyFactory,
mut repo: PgRepository,
) -> Result<AuthorizationResponse<Option<AccessTokenResponse>>, GrantCompletionError> {
let (clock, mut rng) = crate::clock_and_rng();
// Verify that the grant is in a pending stage
if !grant.stage.is_pending() {
return Err(GrantCompletionError::NotPending);

View File

@@ -27,7 +27,7 @@ use mas_policy::PolicyFactory;
use mas_router::{PostAuthAction, Route};
use mas_storage::{
oauth2::{OAuth2AuthorizationGrantRepository, OAuth2ClientRepository},
Repository,
BoxClock, BoxRng, Repository,
};
use mas_storage_pg::PgRepository;
use mas_templates::Templates;
@@ -91,7 +91,6 @@ impl IntoResponse for RouteError {
}
}
impl_from_error_for_route!(sqlx::Error);
impl_from_error_for_route!(mas_storage_pg::DatabaseError);
impl_from_error_for_route!(self::callback::CallbackDestinationError);
impl_from_error_for_route!(mas_policy::LoadError);
@@ -133,13 +132,14 @@ fn resolve_response_mode(
#[allow(clippy::too_many_lines)]
pub(crate) async fn get(
mut rng: BoxRng,
clock: BoxClock,
State(policy_factory): State<Arc<PolicyFactory>>,
State(templates): State<Templates>,
State(pool): State<PgPool>,
cookie_jar: PrivateCookieJar<Encrypter>,
Form(params): Form<Params>,
) -> Result<Response, RouteError> {
let (clock, mut rng) = crate::clock_and_rng();
let mut repo = PgRepository::from_pool(&pool).await?;
// First, figure out what client it is
@@ -334,7 +334,15 @@ pub(crate) async fn get(
// Else, we immediately try to complete the authorization grant
Some(user_session) if prompt.contains(&Prompt::None) => {
// With prompt=none, we should get back to the client immediately
match self::complete::complete(grant, user_session, &policy_factory, repo).await
match self::complete::complete(
rng,
clock,
grant,
user_session,
&policy_factory,
repo,
)
.await
{
Ok(params) => callback_destination.go(&templates, params).await?,
Err(GrantCompletionError::RequiresConsent) => {
@@ -373,7 +381,15 @@ pub(crate) async fn get(
Some(user_session) => {
let grant_id = grant.id;
// Else, we show the relevant reauth/consent page if necessary
match self::complete::complete(grant, user_session, &policy_factory, repo).await
match self::complete::complete(
rng,
clock,
grant,
user_session,
&policy_factory,
repo,
)
.await
{
Ok(params) => callback_destination.go(&templates, params).await?,
Err(

View File

@@ -30,7 +30,7 @@ use mas_policy::PolicyFactory;
use mas_router::{PostAuthAction, Route};
use mas_storage::{
oauth2::{OAuth2AuthorizationGrantRepository, OAuth2ClientRepository},
Clock, Repository,
BoxClock, BoxRng, Repository,
};
use mas_storage_pg::PgRepository;
use mas_templates::{ConsentContext, PolicyViolationContext, TemplateContext, Templates};
@@ -61,7 +61,6 @@ pub enum RouteError {
NoSuchClient,
}
impl_from_error_for_route!(sqlx::Error);
impl_from_error_for_route!(mas_templates::TemplateError);
impl_from_error_for_route!(mas_storage_pg::DatabaseError);
impl_from_error_for_route!(mas_policy::LoadError);
@@ -75,13 +74,14 @@ impl IntoResponse for RouteError {
}
pub(crate) async fn get(
mut rng: BoxRng,
clock: BoxClock,
State(policy_factory): State<Arc<PolicyFactory>>,
State(templates): State<Templates>,
State(pool): State<PgPool>,
cookie_jar: PrivateCookieJar<Encrypter>,
Path(grant_id): Path<Ulid>,
) -> Result<Response, RouteError> {
let (clock, mut rng) = crate::clock_and_rng();
let mut repo = PgRepository::from_pool(&pool).await?;
let (session_info, cookie_jar) = cookie_jar.session_info();
@@ -99,7 +99,7 @@ pub(crate) async fn get(
}
if let Some(session) = maybe_session {
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng);
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng);
let mut policy = policy_factory.instantiate().await?;
let res = policy
@@ -130,16 +130,17 @@ pub(crate) async fn get(
}
pub(crate) async fn post(
mut rng: BoxRng,
clock: BoxClock,
State(policy_factory): State<Arc<PolicyFactory>>,
State(pool): State<PgPool>,
cookie_jar: PrivateCookieJar<Encrypter>,
Path(grant_id): Path<Ulid>,
Form(form): Form<ProtectedForm<()>>,
) -> Result<Response, RouteError> {
let (clock, mut rng) = crate::clock_and_rng();
let mut repo = PgRepository::from_pool(&pool).await?;
cookie_jar.verify_form(clock.now(), form)?;
cookie_jar.verify_form(&clock, form)?;
let (session_info, cookie_jar) = cookie_jar.session_info();

View File

@@ -25,7 +25,7 @@ use mas_storage::{
compat::{CompatAccessTokenRepository, CompatRefreshTokenRepository, CompatSessionRepository},
oauth2::{OAuth2AccessTokenRepository, OAuth2RefreshTokenRepository, OAuth2SessionRepository},
user::{BrowserSessionRepository, UserRepository},
Clock, Repository, SystemClock,
BoxClock, Clock, Repository,
};
use mas_storage_pg::PgRepository;
use oauth2_types::{
@@ -97,7 +97,6 @@ impl IntoResponse for RouteError {
}
}
impl_from_error_for_route!(sqlx::Error);
impl_from_error_for_route!(mas_storage_pg::DatabaseError);
impl From<TokenFormatError> for RouteError {
@@ -125,12 +124,12 @@ const API_SCOPE: ScopeToken = ScopeToken::from_static("urn:matrix:org.matrix.msc
#[allow(clippy::too_many_lines)]
pub(crate) async fn post(
clock: BoxClock,
State(http_client_factory): State<HttpClientFactory>,
State(pool): State<PgPool>,
State(encrypter): State<Encrypter>,
client_authorization: ClientAuthorization<IntrospectionRequest>,
) -> Result<impl IntoResponse, RouteError> {
let clock = SystemClock::default();
let mut repo = PgRepository::from_pool(&pool).await?;
let client = client_authorization

View File

@@ -19,7 +19,7 @@ use hyper::StatusCode;
use mas_iana::oauth::OAuthClientAuthenticationMethod;
use mas_keystore::Encrypter;
use mas_policy::{PolicyFactory, Violation};
use mas_storage::{oauth2::OAuth2ClientRepository, Repository};
use mas_storage::{oauth2::OAuth2ClientRepository, BoxClock, BoxRng, Repository};
use mas_storage_pg::PgRepository;
use oauth2_types::{
errors::{ClientError, ClientErrorCode},
@@ -49,7 +49,6 @@ pub(crate) enum RouteError {
PolicyDenied(Vec<Violation>),
}
impl_from_error_for_route!(sqlx::Error);
impl_from_error_for_route!(mas_storage_pg::DatabaseError);
impl_from_error_for_route!(mas_policy::LoadError);
impl_from_error_for_route!(mas_policy::InstanciateError);
@@ -108,12 +107,13 @@ impl IntoResponse for RouteError {
#[tracing::instrument(skip_all, err)]
pub(crate) async fn post(
mut rng: BoxRng,
clock: BoxClock,
State(pool): State<PgPool>,
State(policy_factory): State<Arc<PolicyFactory>>,
State(encrypter): State<Encrypter>,
Json(body): Json<ClientMetadata>,
) -> Result<impl IntoResponse, RouteError> {
let (clock, mut rng) = crate::clock_and_rng();
info!(?body, "Client registration");
// Validate the body

View File

@@ -37,7 +37,7 @@ use mas_storage::{
OAuth2RefreshTokenRepository, OAuth2SessionRepository,
},
user::BrowserSessionRepository,
Clock, Repository,
BoxClock, BoxRng, Clock, Repository,
};
use mas_storage_pg::PgRepository;
use oauth2_types::{
@@ -151,7 +151,6 @@ impl IntoResponse for RouteError {
}
}
impl_from_error_for_route!(sqlx::Error);
impl_from_error_for_route!(mas_storage_pg::DatabaseError);
impl_from_error_for_route!(mas_keystore::WrongAlgorithmError);
impl_from_error_for_route!(mas_jose::claims::ClaimError);
@@ -160,6 +159,8 @@ impl_from_error_for_route!(mas_jose::jwt::JwtSignatureError);
#[tracing::instrument(skip_all, err)]
pub(crate) async fn post(
mut rng: BoxRng,
clock: BoxClock,
State(http_client_factory): State<HttpClientFactory>,
State(key_store): State<Keystore>,
State(url_builder): State<UrlBuilder>,
@@ -189,10 +190,19 @@ pub(crate) async fn post(
let reply = match form {
AccessTokenRequest::AuthorizationCode(grant) => {
authorization_code_grant(&grant, &client, &key_store, &url_builder, repo).await?
authorization_code_grant(
&mut rng,
&clock,
&grant,
&client,
&key_store,
&url_builder,
repo,
)
.await?
}
AccessTokenRequest::RefreshToken(grant) => {
refresh_token_grant(&grant, &client, repo).await?
refresh_token_grant(&mut rng, &clock, &grant, &client, repo).await?
}
_ => {
return Err(RouteError::InvalidGrant);
@@ -208,14 +218,14 @@ pub(crate) async fn post(
#[allow(clippy::too_many_lines)]
async fn authorization_code_grant(
mut rng: &mut BoxRng,
clock: &impl Clock,
grant: &AuthorizationCodeGrant,
client: &Client,
key_store: &Keystore,
url_builder: &UrlBuilder,
mut repo: PgRepository,
) -> Result<AccessTokenResponse, RouteError> {
let (clock, mut rng) = crate::clock_and_rng();
let authz_grant = repo
.oauth2_authorization_grant()
.find_by_code(&grant.code)
@@ -244,7 +254,7 @@ async fn authorization_code_grant(
.lookup(session_id)
.await?
.ok_or(RouteError::NoSuchOAuthSession)?;
repo.oauth2_session().finish(&clock, session).await?;
repo.oauth2_session().finish(clock, session).await?;
repo.save().await?;
}
@@ -302,12 +312,12 @@ async fn authorization_code_grant(
let access_token = repo
.oauth2_access_token()
.add(&mut rng, &clock, &session, access_token_str, ttl)
.add(&mut rng, clock, &session, access_token_str, ttl)
.await?;
let refresh_token = repo
.oauth2_refresh_token()
.add(&mut rng, &clock, &session, &access_token, refresh_token_str)
.add(&mut rng, clock, &session, &access_token, refresh_token_str)
.await?;
let id_token = if session.scope.contains(&scope::OPENID) {
@@ -357,7 +367,7 @@ async fn authorization_code_grant(
}
repo.oauth2_authorization_grant()
.exchange(&clock, authz_grant)
.exchange(clock, authz_grant)
.await?;
repo.save().await?;
@@ -366,12 +376,12 @@ async fn authorization_code_grant(
}
async fn refresh_token_grant(
mut rng: &mut BoxRng,
clock: &impl Clock,
grant: &RefreshTokenGrant,
client: &Client,
mut repo: PgRepository,
) -> Result<AccessTokenResponse, RouteError> {
let (clock, mut rng) = crate::clock_and_rng();
let refresh_token = repo
.oauth2_refresh_token()
.find_by_token(&grant.refresh_token)
@@ -399,14 +409,14 @@ async fn refresh_token_grant(
let new_access_token = repo
.oauth2_access_token()
.add(&mut rng, &clock, &session, access_token_str.clone(), ttl)
.add(&mut rng, clock, &session, access_token_str.clone(), ttl)
.await?;
let new_refresh_token = repo
.oauth2_refresh_token()
.add(
&mut rng,
&clock,
clock,
&session,
&new_access_token,
refresh_token_str,
@@ -415,13 +425,13 @@ async fn refresh_token_grant(
let refresh_token = repo
.oauth2_refresh_token()
.consume(&clock, refresh_token)
.consume(clock, refresh_token)
.await?;
if let Some(access_token_id) = refresh_token.access_token_id {
if let Some(access_token) = repo.oauth2_access_token().lookup(access_token_id).await? {
repo.oauth2_access_token()
.revoke(&clock, access_token)
.revoke(clock, access_token)
.await?;
}
}

View File

@@ -31,7 +31,7 @@ use mas_router::UrlBuilder;
use mas_storage::{
oauth2::OAuth2ClientRepository,
user::{BrowserSessionRepository, UserEmailRepository},
Clock, Repository,
BoxClock, BoxRng, Repository,
};
use mas_storage_pg::PgRepository;
use oauth2_types::scope;
@@ -79,7 +79,6 @@ pub enum RouteError {
NoSuchBrowserSession,
}
impl_from_error_for_route!(sqlx::Error);
impl_from_error_for_route!(mas_storage_pg::DatabaseError);
impl_from_error_for_route!(mas_keystore::WrongAlgorithmError);
impl_from_error_for_route!(mas_jose::jwt::JwtSignatureError);
@@ -99,15 +98,16 @@ impl IntoResponse for RouteError {
}
pub async fn get(
mut rng: BoxRng,
clock: BoxClock,
State(url_builder): State<UrlBuilder>,
State(pool): State<PgPool>,
State(key_store): State<Keystore>,
user_authorization: UserAuthorization,
) -> Result<Response, RouteError> {
let (clock, mut rng) = crate::clock_and_rng();
let mut repo = PgRepository::from_pool(&pool).await?;
let session = user_authorization.protected(&mut repo, clock.now()).await?;
let session = user_authorization.protected(&mut repo, &clock).await?;
let browser_session = repo
.browser_session()