mirror of
https://github.com/element-hq/matrix-authentication-service.git
synced 2026-08-27 22:34:21 +00:00
Persist raw downstream query parameters on oauth2_authorization_grants
Captures the raw query parameters from the downstream OAuth2 authorization request, so they can later be referenced from templated upstream authorization parameters. Existing call sites pass an empty map; a follow-up commit will wire the downstream authorization handler to to capture the real query parameters.
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use mas_iana::oauth::PkceCodeChallengeMethod;
|
||||
use oauth2_types::{
|
||||
@@ -155,6 +157,9 @@ pub struct AuthorizationGrant {
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub login_hint: Option<String>,
|
||||
pub locale: Option<String>,
|
||||
/// Raw query parameters from the downstream authorization request, used
|
||||
/// to template the parameters forwarded to the upstream provider.
|
||||
pub raw_parameters: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for AuthorizationGrant {
|
||||
@@ -229,6 +234,7 @@ impl AuthorizationGrant {
|
||||
created_at: now,
|
||||
login_hint: Some(String::from("mxid:@example-user:example.com")),
|
||||
locale: Some(String::from("fr")),
|
||||
raw_parameters: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +260,7 @@ pub(crate) async fn get(
|
||||
response_type.has_id_token(),
|
||||
params.auth.login_hint,
|
||||
Some(locale.to_string()),
|
||||
std::collections::BTreeMap::new(),
|
||||
)
|
||||
.await?;
|
||||
let continue_grant = PostAuthAction::continue_grant(grant.id);
|
||||
|
||||
@@ -1073,6 +1073,7 @@ mod tests {
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
std::collections::BTreeMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -1173,6 +1174,7 @@ mod tests {
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
std::collections::BTreeMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO oauth2_authorization_grants (\n oauth2_authorization_grant_id,\n oauth2_client_id,\n redirect_uri,\n scope,\n state,\n nonce,\n response_mode,\n code_challenge,\n code_challenge_method,\n response_type_code,\n response_type_id_token,\n authorization_code,\n login_hint,\n locale,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)\n ",
|
||||
"query": "\n INSERT INTO oauth2_authorization_grants (\n oauth2_authorization_grant_id,\n oauth2_client_id,\n redirect_uri,\n scope,\n state,\n nonce,\n response_mode,\n code_challenge,\n code_challenge_method,\n response_type_code,\n response_type_id_token,\n authorization_code,\n login_hint,\n locale,\n raw_parameters,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -19,10 +19,11 @@
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Jsonb",
|
||||
"Timestamptz"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7a0641df5058927c5cd67d4cdaa59fe609112afbabcbfcc0e7f96c1e531b6567"
|
||||
"hash": "041c4ddff9b40ff5ba16c9aa1dd9c721998de6e5798e4423df9063519ee5ac4d"
|
||||
}
|
||||
+8
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT oauth2_authorization_grant_id\n , created_at\n , cancelled_at\n , fulfilled_at\n , exchanged_at\n , scope\n , state\n , redirect_uri\n , response_mode\n , nonce\n , oauth2_client_id\n , authorization_code\n , response_type_code\n , response_type_id_token\n , code_challenge\n , code_challenge_method\n , login_hint\n , locale\n , oauth2_session_id\n FROM\n oauth2_authorization_grants\n\n WHERE oauth2_authorization_grant_id = $1\n ",
|
||||
"query": "\n SELECT oauth2_authorization_grant_id\n , created_at\n , cancelled_at\n , fulfilled_at\n , exchanged_at\n , scope\n , state\n , redirect_uri\n , response_mode\n , nonce\n , oauth2_client_id\n , authorization_code\n , response_type_code\n , response_type_id_token\n , code_challenge\n , code_challenge_method\n , login_hint\n , locale\n , raw_parameters AS \"raw_parameters: Json<BTreeMap<String, String>>\"\n , oauth2_session_id\n FROM\n oauth2_authorization_grants\n\n WHERE oauth2_authorization_grant_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -95,6 +95,11 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "raw_parameters: Json<BTreeMap<String, String>>",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"name": "oauth2_session_id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
@@ -123,8 +128,9 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "c960f4f5571ee68816c49898125979f3c78c2caca52cb4b8dc9880e669a1f23e"
|
||||
"hash": "2bdf2e1ed7e207d0165b59153b274ea2941055fdbb6b5a6989b229a2fd68925c"
|
||||
}
|
||||
+8
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT oauth2_authorization_grant_id\n , created_at\n , cancelled_at\n , fulfilled_at\n , exchanged_at\n , scope\n , state\n , redirect_uri\n , response_mode\n , nonce\n , oauth2_client_id\n , authorization_code\n , response_type_code\n , response_type_id_token\n , code_challenge\n , code_challenge_method\n , login_hint\n , locale\n , oauth2_session_id\n FROM\n oauth2_authorization_grants\n\n WHERE authorization_code = $1\n ",
|
||||
"query": "\n SELECT oauth2_authorization_grant_id\n , created_at\n , cancelled_at\n , fulfilled_at\n , exchanged_at\n , scope\n , state\n , redirect_uri\n , response_mode\n , nonce\n , oauth2_client_id\n , authorization_code\n , response_type_code\n , response_type_id_token\n , code_challenge\n , code_challenge_method\n , login_hint\n , locale\n , raw_parameters AS \"raw_parameters: Json<BTreeMap<String, String>>\"\n , oauth2_session_id\n FROM\n oauth2_authorization_grants\n\n WHERE authorization_code = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -95,6 +95,11 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "raw_parameters: Json<BTreeMap<String, String>>",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"name": "oauth2_session_id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
@@ -123,8 +128,9 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "8ef27901b96b73826a431ad6c5fabecc18c36d8cdba8db3b47953855fa5c9035"
|
||||
"hash": "47ddb26cbdb3410ef80020c7835ecad9b9ca26452915553dfd6c37b3dccae710"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
-- Copyright 2026 New Vector Ltd.
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
-- Please see LICENSE files in the repository root for full details.
|
||||
|
||||
-- Capture the raw query parameters from the downstream OAuth2 authorization
|
||||
-- request, so the upstream OAuth2 provider authorization handler can
|
||||
-- reference them from templated `additional_authorization_parameters`.
|
||||
ALTER TABLE "oauth2_authorization_grants"
|
||||
ADD COLUMN "raw_parameters" JSONB;
|
||||
@@ -5,6 +5,8 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
use mas_data_model::{
|
||||
@@ -14,7 +16,7 @@ use mas_iana::oauth::PkceCodeChallengeMethod;
|
||||
use mas_storage::oauth2::OAuth2AuthorizationGrantRepository;
|
||||
use oauth2_types::{requests::ResponseMode, scope::Scope};
|
||||
use rand::RngCore;
|
||||
use sqlx::PgConnection;
|
||||
use sqlx::{PgConnection, types::Json};
|
||||
use ulid::Ulid;
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
@@ -54,6 +56,7 @@ struct GrantLookup {
|
||||
code_challenge_method: Option<String>,
|
||||
login_hint: Option<String>,
|
||||
locale: Option<String>,
|
||||
raw_parameters: Option<Json<BTreeMap<String, String>>>,
|
||||
oauth2_client_id: Uuid,
|
||||
oauth2_session_id: Option<Uuid>,
|
||||
}
|
||||
@@ -164,6 +167,7 @@ impl TryFrom<GrantLookup> for AuthorizationGrant {
|
||||
response_type_id_token: value.response_type_id_token,
|
||||
login_hint: value.login_hint,
|
||||
locale: value.locale,
|
||||
raw_parameters: value.raw_parameters.map(|Json(x)| x).unwrap_or_default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -197,6 +201,7 @@ impl OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantRepository
|
||||
response_type_id_token: bool,
|
||||
login_hint: Option<String>,
|
||||
locale: Option<String>,
|
||||
raw_parameters: BTreeMap<String, String>,
|
||||
) -> Result<AuthorizationGrant, Self::Error> {
|
||||
let code_challenge = code
|
||||
.as_ref()
|
||||
@@ -229,10 +234,11 @@ impl OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantRepository
|
||||
authorization_code,
|
||||
login_hint,
|
||||
locale,
|
||||
raw_parameters,
|
||||
created_at
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||||
"#,
|
||||
Uuid::from(id),
|
||||
Uuid::from(client.id),
|
||||
@@ -248,6 +254,7 @@ impl OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantRepository
|
||||
code_str,
|
||||
login_hint,
|
||||
locale,
|
||||
Json(&raw_parameters) as _,
|
||||
created_at,
|
||||
)
|
||||
.traced()
|
||||
@@ -268,6 +275,7 @@ impl OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantRepository
|
||||
response_type_id_token,
|
||||
login_hint,
|
||||
locale,
|
||||
raw_parameters,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -302,6 +310,7 @@ impl OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantRepository
|
||||
, code_challenge_method
|
||||
, login_hint
|
||||
, locale
|
||||
, raw_parameters AS "raw_parameters: Json<BTreeMap<String, String>>"
|
||||
, oauth2_session_id
|
||||
FROM
|
||||
oauth2_authorization_grants
|
||||
@@ -352,6 +361,7 @@ impl OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantRepository
|
||||
, code_challenge_method
|
||||
, login_hint
|
||||
, locale
|
||||
, raw_parameters AS "raw_parameters: Json<BTreeMap<String, String>>"
|
||||
, oauth2_session_id
|
||||
FROM
|
||||
oauth2_authorization_grants
|
||||
|
||||
@@ -120,6 +120,10 @@ mod tests {
|
||||
assert_eq!(grant, None);
|
||||
|
||||
// Create an authorization grant
|
||||
let raw_parameters = std::collections::BTreeMap::from([
|
||||
("client_id".to_owned(), "client".to_owned()),
|
||||
("foo".to_owned(), "bar".to_owned()),
|
||||
]);
|
||||
let grant = repo
|
||||
.oauth2_authorization_grant()
|
||||
.add(
|
||||
@@ -138,10 +142,12 @@ mod tests {
|
||||
true,
|
||||
None,
|
||||
None,
|
||||
raw_parameters.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(grant.is_pending());
|
||||
assert_eq!(grant.raw_parameters, raw_parameters);
|
||||
|
||||
// Lookup the same grant by id
|
||||
let grant_lookup = repo
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use mas_data_model::{AuthorizationCode, AuthorizationGrant, Client, Clock, Session};
|
||||
use oauth2_types::{requests::ResponseMode, scope::Scope};
|
||||
@@ -42,6 +44,9 @@ pub trait OAuth2AuthorizationGrantRepository: Send + Sync {
|
||||
/// * `login_hint`: The `login_hint` the client sent, if set
|
||||
/// * `locale`: The locale the detected when the user asked for the
|
||||
/// authorization grant
|
||||
/// * `raw_parameters`: The raw query parameters of the authorization
|
||||
/// request, used to template the parameters forwarded to the upstream
|
||||
/// provider
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@@ -61,6 +66,7 @@ pub trait OAuth2AuthorizationGrantRepository: Send + Sync {
|
||||
response_type_id_token: bool,
|
||||
login_hint: Option<String>,
|
||||
locale: Option<String>,
|
||||
raw_parameters: BTreeMap<String, String>,
|
||||
) -> Result<AuthorizationGrant, Self::Error>;
|
||||
|
||||
/// Lookup an authorization grant by its ID
|
||||
@@ -169,6 +175,7 @@ repository_impl!(OAuth2AuthorizationGrantRepository:
|
||||
response_type_id_token: bool,
|
||||
login_hint: Option<String>,
|
||||
locale: Option<String>,
|
||||
raw_parameters: BTreeMap<String, String>,
|
||||
) -> Result<AuthorizationGrant, Self::Error>;
|
||||
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<AuthorizationGrant>, Self::Error>;
|
||||
|
||||
Reference in New Issue
Block a user