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

Make the access tokens TTL configurable

This commit is contained in:
Quentin Gliech
2023-08-31 16:30:08 +02:00
parent 73d33dfccb
commit bc04860afb
11 changed files with 155 additions and 93 deletions

View File

@ -34,7 +34,10 @@ use opentelemetry::{
use rand::SeedableRng;
use sqlx::PgPool;
use crate::{passwords::PasswordManager, upstream_oauth2::cache::MetadataCache, MatrixHomeserver};
use crate::{
passwords::PasswordManager, site_config::SiteConfig, upstream_oauth2::cache::MetadataCache,
MatrixHomeserver,
};
#[derive(Clone)]
pub struct AppState {
@ -50,6 +53,7 @@ pub struct AppState {
pub http_client_factory: HttpClientFactory,
pub password_manager: PasswordManager,
pub metadata_cache: MetadataCache,
pub site_config: SiteConfig,
pub conn_acquisition_histogram: Option<Histogram<u64>>,
}
@ -199,6 +203,12 @@ impl FromRef<AppState> for MetadataCache {
}
}
impl FromRef<AppState> for SiteConfig {
fn from_ref(input: &AppState) -> Self {
input.site_config.clone()
}
}
#[async_trait]
impl FromRequestParts<AppState> for BoxClock {
type Rejection = Infallible;

View File

@ -32,7 +32,7 @@ use thiserror::Error;
use zeroize::Zeroizing;
use super::{MatrixError, MatrixHomeserver};
use crate::{impl_from_error_for_route, passwords::PasswordManager};
use crate::{impl_from_error_for_route, passwords::PasswordManager, site_config::SiteConfig};
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
@ -210,6 +210,7 @@ pub(crate) async fn post(
State(password_manager): State<PasswordManager>,
mut repo: BoxRepository,
State(homeserver): State<MatrixHomeserver>,
State(site_config): State<SiteConfig>,
Json(input): Json<RequestBody>,
) -> Result<impl IntoResponse, RouteError> {
let (session, user) = match (password_manager.is_enabled(), input.credentials) {
@ -242,8 +243,7 @@ pub(crate) async fn post(
// If the client asked for a refreshable token, make it expire
let expires_in = if input.refresh_token {
// TODO: this should be configurable
Some(Duration::minutes(5))
Some(site_config.compat_token_ttl)
} else {
None
};

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use axum::{response::IntoResponse, Json};
use axum::{extract::State, response::IntoResponse, Json};
use chrono::Duration;
use hyper::StatusCode;
use mas_data_model::{TokenFormatError, TokenType};
@ -25,7 +25,7 @@ use serde_with::{serde_as, DurationMilliSeconds};
use thiserror::Error;
use super::MatrixError;
use crate::impl_from_error_for_route;
use crate::{impl_from_error_for_route, site_config::SiteConfig};
#[derive(Debug, Deserialize)]
pub struct RequestBody {
@ -91,6 +91,7 @@ pub(crate) async fn post(
mut rng: BoxRng,
clock: BoxClock,
mut repo: BoxRepository,
State(site_config): State<SiteConfig>,
Json(input): Json<RequestBody>,
) -> Result<impl IntoResponse, RouteError> {
let token_type = TokenType::check(&input.refresh_token)?;
@ -128,7 +129,7 @@ pub(crate) async fn post(
let new_refresh_token_str = TokenType::CompatRefreshToken.generate(&mut rng);
let new_access_token_str = TokenType::CompatAccessToken.generate(&mut rng);
let expires_in = Duration::minutes(5);
let expires_in = site_config.compat_token_ttl;
let new_access_token = repo
.compat_access_token()
.add(

View File

@ -68,6 +68,7 @@ pub mod passwords;
pub mod upstream_oauth2;
mod views;
mod site_config;
#[cfg(test)]
mod test_utils;
@ -89,8 +90,10 @@ macro_rules! impl_from_error_for_route {
pub use mas_axum_utils::{cookies::CookieManager, http_client_factory::HttpClientFactory};
pub use self::{app_state::AppState, compat::MatrixHomeserver, graphql::schema as graphql_schema};
pub use crate::upstream_oauth2::cache::MetadataCache;
pub use self::{
app_state::AppState, compat::MatrixHomeserver, graphql::schema as graphql_schema,
site_config::SiteConfig, upstream_oauth2::cache::MetadataCache,
};
pub fn healthcheck_router<S, B>() -> Router<S, B>
where
@ -169,6 +172,7 @@ where
BoxRepository: FromRequestParts<S>,
Encrypter: FromRef<S>,
HttpClientFactory: FromRef<S>,
SiteConfig: FromRef<S>,
BoxClock: FromRequestParts<S>,
BoxRng: FromRequestParts<S>,
Policy: FromRequestParts<S>,
@ -225,9 +229,10 @@ where
<B as HttpBody>::Error: std::error::Error + Send + Sync,
S: Clone + Send + Sync + 'static,
UrlBuilder: FromRef<S>,
BoxRepository: FromRequestParts<S>,
SiteConfig: FromRef<S>,
MatrixHomeserver: FromRef<S>,
PasswordManager: FromRef<S>,
BoxRepository: FromRequestParts<S>,
BoxClock: FromRequestParts<S>,
BoxRng: FromRequestParts<S>,
{

View File

@ -47,7 +47,7 @@ use tracing::debug;
use url::Url;
use super::{generate_id_token, generate_token_pair};
use crate::impl_from_error_for_route;
use crate::{impl_from_error_for_route, site_config::SiteConfig};
#[serde_as]
#[skip_serializing_none]
@ -161,6 +161,7 @@ pub(crate) async fn post(
State(key_store): State<Keystore>,
State(url_builder): State<UrlBuilder>,
mut repo: BoxRepository,
State(site_config): State<SiteConfig>,
State(encrypter): State<Encrypter>,
client_authorization: ClientAuthorization<AccessTokenRequest>,
) -> Result<impl IntoResponse, RouteError> {
@ -191,12 +192,13 @@ pub(crate) async fn post(
&client,
&key_store,
&url_builder,
&site_config,
repo,
)
.await?
}
AccessTokenRequest::RefreshToken(grant) => {
refresh_token_grant(&mut rng, &clock, &grant, &client, repo).await?
refresh_token_grant(&mut rng, &clock, &grant, &client, &site_config, repo).await?
}
_ => {
return Err(RouteError::UnsupportedGrantType);
@ -220,6 +222,7 @@ async fn authorization_code_grant(
client: &Client,
key_store: &Keystore,
url_builder: &UrlBuilder,
site_config: &SiteConfig,
mut repo: BoxRepository,
) -> Result<(AccessTokenResponse, BoxRepository), RouteError> {
let authz_grant = repo
@ -312,7 +315,7 @@ async fn authorization_code_grant(
.get_last_authentication(&browser_session)
.await?;
let ttl = Duration::minutes(5);
let ttl = site_config.access_token_ttl;
let (access_token, refresh_token) =
generate_token_pair(&mut rng, clock, &mut repo, &session, ttl).await?;
@ -367,6 +370,7 @@ async fn refresh_token_grant(
clock: &impl Clock,
grant: &RefreshTokenGrant,
client: &Client,
site_config: &SiteConfig,
mut repo: BoxRepository,
) -> Result<(AccessTokenResponse, BoxRepository), RouteError> {
let refresh_token = repo
@ -390,7 +394,7 @@ async fn refresh_token_grant(
return Err(RouteError::InvalidGrant);
}
let ttl = Duration::minutes(5);
let ttl = site_config.access_token_ttl;
let (new_access_token, new_refresh_token) =
generate_token_pair(rng, clock, &mut repo, &session, ttl).await?;

View File

@ -0,0 +1,31 @@
// Copyright 2023 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.
use chrono::Duration;
/// Random site configuration we don't now where to put yet.
#[derive(Debug, Clone)]
pub struct SiteConfig {
pub access_token_ttl: Duration,
pub compat_token_ttl: Duration,
}
impl Default for SiteConfig {
fn default() -> Self {
Self {
access_token_ttl: Duration::minutes(5),
compat_token_ttl: Duration::minutes(5),
}
}
}

View File

@ -48,6 +48,7 @@ use url::Url;
use crate::{
app_state::ErrorWrapper,
passwords::{Hasher, PasswordManager},
site_config::SiteConfig,
upstream_oauth2::cache::MetadataCache,
MatrixHomeserver,
};
@ -76,6 +77,7 @@ pub(crate) struct TestState {
pub graphql_schema: mas_graphql::Schema,
pub http_client_factory: HttpClientFactory,
pub password_manager: PasswordManager,
pub site_config: SiteConfig,
pub clock: Arc<MockClock>,
pub rng: Arc<Mutex<ChaChaRng>>,
}
@ -133,6 +135,8 @@ impl TestState {
let http_client_factory = HttpClientFactory::new(10);
let site_config = SiteConfig::default();
let clock = Arc::new(MockClock::default());
let rng = Arc::new(Mutex::new(ChaChaRng::seed_from_u64(42)));
@ -160,6 +164,7 @@ impl TestState {
graphql_schema,
http_client_factory,
password_manager,
site_config,
clock,
rng,
})
@ -346,6 +351,12 @@ impl FromRef<TestState> for MetadataCache {
}
}
impl FromRef<TestState> for SiteConfig {
fn from_ref(input: &TestState) -> Self {
input.site_config.clone()
}
}
#[async_trait]
impl FromRequestParts<TestState> for BoxClock {
type Rejection = Infallible;