diff --git a/crates/graphql/src/mutations/oauth2_session.rs b/crates/graphql/src/mutations/oauth2_session.rs index ba169067..a9b2d171 100644 --- a/crates/graphql/src/mutations/oauth2_session.rs +++ b/crates/graphql/src/mutations/oauth2_session.rs @@ -177,10 +177,9 @@ impl OAuth2SessionMutations { } let ttl = if permanent { - // XXX: that's lazy - Duration::days(365 * 50) + None } else { - Duration::minutes(5) + Some(Duration::minutes(5)) }; let access_token = repo .oauth2_access_token() diff --git a/crates/handlers/src/graphql/tests.rs b/crates/handlers/src/graphql/tests.rs index cf75ba5a..6033a7ed 100644 --- a/crates/handlers/src/graphql/tests.rs +++ b/crates/handlers/src/graphql/tests.rs @@ -13,7 +13,6 @@ // limitations under the License. use axum::http::Request; -use chrono::Duration; use hyper::StatusCode; use mas_data_model::{AccessToken, Client, TokenType, User}; use mas_router::SimpleRoute; @@ -106,13 +105,7 @@ async fn start_oauth_session( let access_token = repo .oauth2_access_token() - .add( - &mut rng, - &state.clock, - &session, - access_token_str, - Duration::minutes(5), - ) + .add(&mut rng, &state.clock, &session, access_token_str, None) .await .unwrap(); diff --git a/crates/handlers/src/oauth2/mod.rs b/crates/handlers/src/oauth2/mod.rs index 824741f6..62e84ff3 100644 --- a/crates/handlers/src/oauth2/mod.rs +++ b/crates/handlers/src/oauth2/mod.rs @@ -115,7 +115,7 @@ pub(crate) async fn generate_token_pair( let access_token = repo .oauth2_access_token() - .add(rng, clock, session, access_token_str, ttl) + .add(rng, clock, session, access_token_str, Some(ttl)) .await?; let refresh_token = repo diff --git a/crates/handlers/src/oauth2/token.rs b/crates/handlers/src/oauth2/token.rs index 7433163c..050ed65c 100644 --- a/crates/handlers/src/oauth2/token.rs +++ b/crates/handlers/src/oauth2/token.rs @@ -529,7 +529,7 @@ async fn client_credentials_grant( let access_token = repo .oauth2_access_token() - .add(rng, clock, &session, access_token_str, ttl) + .add(rng, clock, &session, access_token_str, Some(ttl)) .await?; let mut params = AccessTokenResponse::new(access_token.access_token).with_expires_in(ttl); diff --git a/crates/storage-pg/.sqlx/query-477f79556e5777b38feb85013b4f04dbb8230e4b0b0bcc45f669d7b8d0b91db4.json b/crates/storage-pg/.sqlx/query-477f79556e5777b38feb85013b4f04dbb8230e4b0b0bcc45f669d7b8d0b91db4.json index 6e9d1a96..bc6c2fb7 100644 --- a/crates/storage-pg/.sqlx/query-477f79556e5777b38feb85013b4f04dbb8230e4b0b0bcc45f669d7b8d0b91db4.json +++ b/crates/storage-pg/.sqlx/query-477f79556e5777b38feb85013b4f04dbb8230e4b0b0bcc45f669d7b8d0b91db4.json @@ -43,7 +43,7 @@ false, false, false, - false, + true, true, false ] diff --git a/crates/storage-pg/.sqlx/query-6554d3620a5f7fb0e85af44e8a21c2f2f3ebe4b805ec67aca4a2278a8ae16693.json b/crates/storage-pg/.sqlx/query-6554d3620a5f7fb0e85af44e8a21c2f2f3ebe4b805ec67aca4a2278a8ae16693.json deleted file mode 100644 index 492e1632..00000000 --- a/crates/storage-pg/.sqlx/query-6554d3620a5f7fb0e85af44e8a21c2f2f3ebe4b805ec67aca4a2278a8ae16693.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO oauth2_sessions\n ( oauth2_session_id\n , oauth2_client_id\n , scope_list\n , created_at\n )\n VALUES ($1, $2, $3, $4)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid", - "Uuid", - "TextArray", - "Timestamptz" - ] - }, - "nullable": [] - }, - "hash": "6554d3620a5f7fb0e85af44e8a21c2f2f3ebe4b805ec67aca4a2278a8ae16693" -} diff --git a/crates/storage-pg/.sqlx/query-dd16942318bf38d9a245b2c86fedd3cbd6b65e7a13465552d79cd3c022122fd4.json b/crates/storage-pg/.sqlx/query-dd16942318bf38d9a245b2c86fedd3cbd6b65e7a13465552d79cd3c022122fd4.json index ea706b41..c9bd7055 100644 --- a/crates/storage-pg/.sqlx/query-dd16942318bf38d9a245b2c86fedd3cbd6b65e7a13465552d79cd3c022122fd4.json +++ b/crates/storage-pg/.sqlx/query-dd16942318bf38d9a245b2c86fedd3cbd6b65e7a13465552d79cd3c022122fd4.json @@ -43,7 +43,7 @@ false, false, false, - false, + true, true, false ] diff --git a/crates/storage-pg/migrations/20230911091636_oauth2_token_expiration.sql b/crates/storage-pg/migrations/20230911091636_oauth2_token_expiration.sql new file mode 100644 index 00000000..beebb617 --- /dev/null +++ b/crates/storage-pg/migrations/20230911091636_oauth2_token_expiration.sql @@ -0,0 +1,19 @@ +-- 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. + +-- This makes the `expires_at` column nullable on the `oauth2_access_tokens`. +-- This is to allow permanent tokens to be created via the admin API. +ALTER TABLE oauth2_access_tokens + ALTER COLUMN expires_at DROP NOT NULL; + diff --git a/crates/storage-pg/src/oauth2/access_token.rs b/crates/storage-pg/src/oauth2/access_token.rs index 1161dbe5..71df24cf 100644 --- a/crates/storage-pg/src/oauth2/access_token.rs +++ b/crates/storage-pg/src/oauth2/access_token.rs @@ -42,7 +42,7 @@ struct OAuth2AccessTokenLookup { oauth2_session_id: Uuid, access_token: String, created_at: DateTime, - expires_at: DateTime, + expires_at: Option>, revoked_at: Option>, } @@ -59,7 +59,7 @@ impl From for AccessToken { session_id: value.oauth2_session_id.into(), access_token: value.access_token, created_at: value.created_at, - expires_at: Some(value.expires_at), + expires_at: value.expires_at, } } } @@ -146,10 +146,10 @@ impl<'c> OAuth2AccessTokenRepository for PgOAuth2AccessTokenRepository<'c> { clock: &dyn Clock, session: &Session, access_token: String, - expires_after: Duration, + expires_after: Option, ) -> Result { let created_at = clock.now(); - let expires_at = created_at + expires_after; + let expires_at = expires_after.map(|d| created_at + d); let id = Ulid::from_datetime_with_source(created_at.into(), rng); tracing::Span::current().record("access_token.id", tracing::field::display(id)); @@ -177,7 +177,7 @@ impl<'c> OAuth2AccessTokenRepository for PgOAuth2AccessTokenRepository<'c> { access_token, session_id: session.id, created_at, - expires_at: Some(expires_at), + expires_at, }) } diff --git a/crates/storage-pg/src/oauth2/mod.rs b/crates/storage-pg/src/oauth2/mod.rs index 6475df29..4e90a6eb 100644 --- a/crates/storage-pg/src/oauth2/mod.rs +++ b/crates/storage-pg/src/oauth2/mod.rs @@ -270,7 +270,7 @@ mod tests { &clock, &session, "aabbcc".to_owned(), - Duration::minutes(5), + Some(Duration::minutes(5)), ) .await .unwrap(); diff --git a/crates/storage/src/oauth2/access_token.rs b/crates/storage/src/oauth2/access_token.rs index 3fba2399..7b24aa16 100644 --- a/crates/storage/src/oauth2/access_token.rs +++ b/crates/storage/src/oauth2/access_token.rs @@ -66,7 +66,8 @@ pub trait OAuth2AccessTokenRepository: Send + Sync { /// * `clock`: The clock used to generate timestamps /// * `session`: The session the access token is associated with /// * `access_token`: The access token to add - /// * `expires_after`: The duration after which the access token expires + /// * `expires_after`: The duration after which the access token expires. If + /// [`None`] the access token never expires /// /// # Errors /// @@ -77,7 +78,7 @@ pub trait OAuth2AccessTokenRepository: Send + Sync { clock: &dyn Clock, session: &Session, access_token: String, - expires_after: Duration, + expires_after: Option, ) -> Result; /// Revoke an access token @@ -126,7 +127,7 @@ repository_impl!(OAuth2AccessTokenRepository: clock: &dyn Clock, session: &Session, access_token: String, - expires_after: Duration, + expires_after: Option, ) -> Result; async fn revoke(