Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.

Commit bc04860

Browse files
committed
Make the access tokens TTL configurable
1 parent 73d33df commit bc04860

File tree

11 files changed

+155
-93
lines changed

11 files changed

+155
-93
lines changed

crates/cli/src/commands/server.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ use anyhow::Context;
1818
use clap::Parser;
1919
use itertools::Itertools;
2020
use mas_config::AppConfig;
21-
use mas_handlers::{AppState, CookieManager, HttpClientFactory, MatrixHomeserver, MetadataCache};
21+
use mas_handlers::{
22+
AppState, CookieManager, HttpClientFactory, MatrixHomeserver, MetadataCache, SiteConfig,
23+
};
2224
use mas_listener::{server::Server, shutdown::ShutdownStream};
2325
use mas_matrix_synapse::SynapseConnection;
2426
use mas_router::UrlBuilder;
@@ -137,6 +139,11 @@ impl Options {
137139
http_client_factory.clone(),
138140
);
139141

142+
let site_config = SiteConfig {
143+
access_token_ttl: config.hack.access_token_ttl,
144+
compat_token_ttl: config.hack.compat_token_ttl,
145+
};
146+
140147
// Explicitly the config to properly zeroize secret keys
141148
drop(config);
142149

@@ -159,6 +166,7 @@ impl Options {
159166
graphql_schema,
160167
http_client_factory,
161168
password_manager,
169+
site_config,
162170
conn_acquisition_histogram: None,
163171
};
164172
s.init_metrics()?;
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
1+
// Copyright 2023 The Matrix.org Foundation C.I.C.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -19,33 +19,42 @@ use schemars::JsonSchema;
1919
use serde::{Deserialize, Serialize};
2020
use serde_with::serde_as;
2121

22-
use super::ConfigurationSection;
22+
use crate::ConfigurationSection;
2323

24-
fn default_ttl() -> Duration {
25-
Duration::hours(1)
24+
fn default_token_ttl() -> Duration {
25+
Duration::minutes(5)
2626
}
2727

28-
/// Configuration related to Cross-Site Request Forgery protections
28+
/// Configuration sections for miscellaneous options
2929
#[serde_as]
30-
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
31-
pub struct CsrfConfig {
32-
/// Time-to-live of a CSRF token in seconds
30+
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)]
31+
pub struct HackConfig {
32+
/// Time-to-live of access tokens in seconds
3333
#[schemars(with = "u64", range(min = 60, max = 86400))]
34-
#[serde(default = "default_ttl")]
34+
#[serde(default = "default_token_ttl")]
3535
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
36-
pub ttl: Duration,
36+
pub access_token_ttl: Duration,
37+
38+
/// Time-to-live of compatibility access tokens in seconds
39+
#[schemars(with = "u64", range(min = 60, max = 86400))]
40+
#[serde(default = "default_token_ttl")]
41+
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
42+
pub compat_token_ttl: Duration,
3743
}
3844

39-
impl Default for CsrfConfig {
45+
impl Default for HackConfig {
4046
fn default() -> Self {
41-
Self { ttl: default_ttl() }
47+
Self {
48+
access_token_ttl: default_token_ttl(),
49+
compat_token_ttl: default_token_ttl(),
50+
}
4251
}
4352
}
4453

4554
#[async_trait]
46-
impl ConfigurationSection for CsrfConfig {
55+
impl ConfigurationSection for HackConfig {
4756
fn path() -> &'static str {
48-
"csrf"
57+
"hack"
4958
}
5059

5160
async fn generate<R>(_rng: R) -> anyhow::Result<Self>
@@ -59,29 +68,3 @@ impl ConfigurationSection for CsrfConfig {
5968
Self::default()
6069
}
6170
}
62-
63-
#[cfg(test)]
64-
mod tests {
65-
use figment::Jail;
66-
67-
use super::*;
68-
69-
#[test]
70-
fn load_config() {
71-
Jail::expect_with(|jail| {
72-
jail.create_file(
73-
"config.yaml",
74-
r#"
75-
csrf:
76-
ttl: 1800
77-
"#,
78-
)?;
79-
80-
let config = CsrfConfig::load_from_file("config.yaml")?;
81-
82-
assert_eq!(config.ttl, Duration::minutes(30));
83-
84-
Ok(())
85-
});
86-
}
87-
}

crates/config/src/sections/mod.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use schemars::JsonSchema;
1818
use serde::{Deserialize, Serialize};
1919

2020
mod clients;
21-
mod csrf;
2221
mod database;
2322
mod email;
23+
mod hack;
2424
mod http;
2525
mod matrix;
2626
mod passwords;
@@ -32,9 +32,9 @@ mod upstream_oauth2;
3232

3333
pub use self::{
3434
clients::{ClientAuthMethodConfig, ClientConfig, ClientsConfig},
35-
csrf::CsrfConfig,
3635
database::{ConnectConfig as DatabaseConnectConfig, DatabaseConfig},
3736
email::{EmailConfig, EmailSmtpMode, EmailTransportConfig},
37+
hack::HackConfig,
3838
http::{
3939
BindConfig as HttpBindConfig, HttpConfig, ListenerConfig as HttpListenerConfig,
4040
Resource as HttpResource, TlsConfig as HttpTlsConfig, UnixOrTcp,
@@ -81,10 +81,6 @@ pub struct RootConfig {
8181
#[serde(default)]
8282
pub templates: TemplatesConfig,
8383

84-
/// Configuration related to Cross-Site Request Forgery protections
85-
#[serde(default)]
86-
pub csrf: CsrfConfig,
87-
8884
/// Configuration related to sending emails
8985
#[serde(default)]
9086
pub email: EmailConfig,
@@ -106,6 +102,10 @@ pub struct RootConfig {
106102
/// Configuration related to upstream OAuth providers
107103
#[serde(default)]
108104
pub upstream_oauth2: UpstreamOAuth2Config,
105+
106+
/// Miscellaneous configuration options
107+
#[serde(default)]
108+
pub hack: HackConfig,
109109
}
110110

111111
#[async_trait]
@@ -124,13 +124,13 @@ impl ConfigurationSection for RootConfig {
124124
database: DatabaseConfig::generate(&mut rng).await?,
125125
telemetry: TelemetryConfig::generate(&mut rng).await?,
126126
templates: TemplatesConfig::generate(&mut rng).await?,
127-
csrf: CsrfConfig::generate(&mut rng).await?,
128127
email: EmailConfig::generate(&mut rng).await?,
129128
passwords: PasswordsConfig::generate(&mut rng).await?,
130129
secrets: SecretsConfig::generate(&mut rng).await?,
131130
matrix: MatrixConfig::generate(&mut rng).await?,
132131
policy: PolicyConfig::generate(&mut rng).await?,
133132
upstream_oauth2: UpstreamOAuth2Config::generate(&mut rng).await?,
133+
hack: HackConfig::generate(&mut rng).await?,
134134
})
135135
}
136136

@@ -142,12 +142,12 @@ impl ConfigurationSection for RootConfig {
142142
telemetry: TelemetryConfig::test(),
143143
templates: TemplatesConfig::test(),
144144
passwords: PasswordsConfig::test(),
145-
csrf: CsrfConfig::test(),
146145
email: EmailConfig::test(),
147146
secrets: SecretsConfig::test(),
148147
matrix: MatrixConfig::test(),
149148
policy: PolicyConfig::test(),
150149
upstream_oauth2: UpstreamOAuth2Config::test(),
150+
hack: HackConfig::test(),
151151
}
152152
}
153153
}
@@ -165,9 +165,6 @@ pub struct AppConfig {
165165
#[serde(default)]
166166
pub templates: TemplatesConfig,
167167

168-
#[serde(default)]
169-
pub csrf: CsrfConfig,
170-
171168
#[serde(default)]
172169
pub email: EmailConfig,
173170

@@ -180,6 +177,9 @@ pub struct AppConfig {
180177

181178
#[serde(default)]
182179
pub policy: PolicyConfig,
180+
181+
#[serde(default)]
182+
pub hack: HackConfig,
183183
}
184184

185185
#[async_trait]
@@ -196,12 +196,12 @@ impl ConfigurationSection for AppConfig {
196196
http: HttpConfig::generate(&mut rng).await?,
197197
database: DatabaseConfig::generate(&mut rng).await?,
198198
templates: TemplatesConfig::generate(&mut rng).await?,
199-
csrf: CsrfConfig::generate(&mut rng).await?,
200199
email: EmailConfig::generate(&mut rng).await?,
201200
passwords: PasswordsConfig::generate(&mut rng).await?,
202201
secrets: SecretsConfig::generate(&mut rng).await?,
203202
matrix: MatrixConfig::generate(&mut rng).await?,
204203
policy: PolicyConfig::generate(&mut rng).await?,
204+
hack: HackConfig::generate(&mut rng).await?,
205205
})
206206
}
207207

@@ -211,11 +211,11 @@ impl ConfigurationSection for AppConfig {
211211
database: DatabaseConfig::test(),
212212
templates: TemplatesConfig::test(),
213213
passwords: PasswordsConfig::test(),
214-
csrf: CsrfConfig::test(),
215214
email: EmailConfig::test(),
216215
secrets: SecretsConfig::test(),
217216
matrix: MatrixConfig::test(),
218217
policy: PolicyConfig::test(),
218+
hack: HackConfig::test(),
219219
}
220220
}
221221
}

crates/handlers/src/app_state.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ use opentelemetry::{
3434
use rand::SeedableRng;
3535
use sqlx::PgPool;
3636

37-
use crate::{passwords::PasswordManager, upstream_oauth2::cache::MetadataCache, MatrixHomeserver};
37+
use crate::{
38+
passwords::PasswordManager, site_config::SiteConfig, upstream_oauth2::cache::MetadataCache,
39+
MatrixHomeserver,
40+
};
3841

3942
#[derive(Clone)]
4043
pub struct AppState {
@@ -50,6 +53,7 @@ pub struct AppState {
5053
pub http_client_factory: HttpClientFactory,
5154
pub password_manager: PasswordManager,
5255
pub metadata_cache: MetadataCache,
56+
pub site_config: SiteConfig,
5357
pub conn_acquisition_histogram: Option<Histogram<u64>>,
5458
}
5559

@@ -199,6 +203,12 @@ impl FromRef<AppState> for MetadataCache {
199203
}
200204
}
201205

206+
impl FromRef<AppState> for SiteConfig {
207+
fn from_ref(input: &AppState) -> Self {
208+
input.site_config.clone()
209+
}
210+
}
211+
202212
#[async_trait]
203213
impl FromRequestParts<AppState> for BoxClock {
204214
type Rejection = Infallible;

crates/handlers/src/compat/login.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use thiserror::Error;
3232
use zeroize::Zeroizing;
3333

3434
use super::{MatrixError, MatrixHomeserver};
35-
use crate::{impl_from_error_for_route, passwords::PasswordManager};
35+
use crate::{impl_from_error_for_route, passwords::PasswordManager, site_config::SiteConfig};
3636

3737
#[derive(Debug, Serialize)]
3838
#[serde(tag = "type")]
@@ -210,6 +210,7 @@ pub(crate) async fn post(
210210
State(password_manager): State<PasswordManager>,
211211
mut repo: BoxRepository,
212212
State(homeserver): State<MatrixHomeserver>,
213+
State(site_config): State<SiteConfig>,
213214
Json(input): Json<RequestBody>,
214215
) -> Result<impl IntoResponse, RouteError> {
215216
let (session, user) = match (password_manager.is_enabled(), input.credentials) {
@@ -242,8 +243,7 @@ pub(crate) async fn post(
242243

243244
// If the client asked for a refreshable token, make it expire
244245
let expires_in = if input.refresh_token {
245-
// TODO: this should be configurable
246-
Some(Duration::minutes(5))
246+
Some(site_config.compat_token_ttl)
247247
} else {
248248
None
249249
};

crates/handlers/src/compat/refresh.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use axum::{response::IntoResponse, Json};
15+
use axum::{extract::State, response::IntoResponse, Json};
1616
use chrono::Duration;
1717
use hyper::StatusCode;
1818
use mas_data_model::{TokenFormatError, TokenType};
@@ -25,7 +25,7 @@ use serde_with::{serde_as, DurationMilliSeconds};
2525
use thiserror::Error;
2626

2727
use super::MatrixError;
28-
use crate::impl_from_error_for_route;
28+
use crate::{impl_from_error_for_route, site_config::SiteConfig};
2929

3030
#[derive(Debug, Deserialize)]
3131
pub struct RequestBody {
@@ -91,6 +91,7 @@ pub(crate) async fn post(
9191
mut rng: BoxRng,
9292
clock: BoxClock,
9393
mut repo: BoxRepository,
94+
State(site_config): State<SiteConfig>,
9495
Json(input): Json<RequestBody>,
9596
) -> Result<impl IntoResponse, RouteError> {
9697
let token_type = TokenType::check(&input.refresh_token)?;
@@ -128,7 +129,7 @@ pub(crate) async fn post(
128129
let new_refresh_token_str = TokenType::CompatRefreshToken.generate(&mut rng);
129130
let new_access_token_str = TokenType::CompatAccessToken.generate(&mut rng);
130131

131-
let expires_in = Duration::minutes(5);
132+
let expires_in = site_config.compat_token_ttl;
132133
let new_access_token = repo
133134
.compat_access_token()
134135
.add(

crates/handlers/src/lib.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub mod passwords;
6868
pub mod upstream_oauth2;
6969
mod views;
7070

71+
mod site_config;
7172
#[cfg(test)]
7273
mod test_utils;
7374

@@ -89,8 +90,10 @@ macro_rules! impl_from_error_for_route {
8990

9091
pub use mas_axum_utils::{cookies::CookieManager, http_client_factory::HttpClientFactory};
9192

92-
pub use self::{app_state::AppState, compat::MatrixHomeserver, graphql::schema as graphql_schema};
93-
pub use crate::upstream_oauth2::cache::MetadataCache;
93+
pub use self::{
94+
app_state::AppState, compat::MatrixHomeserver, graphql::schema as graphql_schema,
95+
site_config::SiteConfig, upstream_oauth2::cache::MetadataCache,
96+
};
9497

9598
pub fn healthcheck_router<S, B>() -> Router<S, B>
9699
where
@@ -169,6 +172,7 @@ where
169172
BoxRepository: FromRequestParts<S>,
170173
Encrypter: FromRef<S>,
171174
HttpClientFactory: FromRef<S>,
175+
SiteConfig: FromRef<S>,
172176
BoxClock: FromRequestParts<S>,
173177
BoxRng: FromRequestParts<S>,
174178
Policy: FromRequestParts<S>,
@@ -225,9 +229,10 @@ where
225229
<B as HttpBody>::Error: std::error::Error + Send + Sync,
226230
S: Clone + Send + Sync + 'static,
227231
UrlBuilder: FromRef<S>,
228-
BoxRepository: FromRequestParts<S>,
232+
SiteConfig: FromRef<S>,
229233
MatrixHomeserver: FromRef<S>,
230234
PasswordManager: FromRef<S>,
235+
BoxRepository: FromRequestParts<S>,
231236
BoxClock: FromRequestParts<S>,
232237
BoxRng: FromRequestParts<S>,
233238
{

0 commit comments

Comments
 (0)