1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Lookup and save upstream links

This commit is contained in:
Quentin Gliech
2022-11-23 16:31:47 +01:00
parent e8c8d0bf8a
commit cde9187adc
6 changed files with 293 additions and 12 deletions

View File

@ -689,6 +689,45 @@
},
"query": "\n SELECT\n ue.user_email_id,\n ue.email AS \"user_email\",\n ue.created_at AS \"user_email_created_at\",\n ue.confirmed_at AS \"user_email_confirmed_at\"\n FROM user_emails ue\n\n WHERE ue.user_id = $1\n AND ue.email = $2\n "
},
"3a6de39a88ef93a91f3cc0465785bafd58ef7dbd4aae924a8bcfcefaf2f1a0d7": {
"describe": {
"columns": [
{
"name": "upstream_oauth_link_id",
"ordinal": 0,
"type_info": "Uuid"
},
{
"name": "user_id",
"ordinal": 1,
"type_info": "Uuid"
},
{
"name": "subject",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "created_at",
"ordinal": 3,
"type_info": "Timestamptz"
}
],
"nullable": [
false,
true,
false,
false
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
}
},
"query": "\n SELECT\n upstream_oauth_link_id,\n user_id,\n subject,\n created_at\n FROM upstream_oauth_links\n WHERE upstream_oauth_provider_id = $1\n AND subject = $2\n "
},
"3df0838b660466f69ee681337fe6753133748defb715e53c8381badcc3e8bca9": {
"describe": {
"columns": [
@ -954,6 +993,19 @@
},
"query": "\n INSERT INTO user_passwords (user_password_id, user_id, hashed_password, created_at)\n VALUES ($1, $2, $3, $4)\n "
},
"4b6a44d040a0dc849bb4e04abb11a181995b5847917605ef4c160389686a54f5": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Left": [
"Uuid",
"Timestamptz"
]
}
},
"query": "\n UPDATE upstream_oauth_authorization_sessions\n SET upstream_oauth_link_id = $1,\n completed_at = $2\n "
},
"4f8ec19f3f1bfe0268fe102a24e5a9fa542e77eccbebdce65e6deb1c197adf36": {
"describe": {
"columns": [
@ -2417,6 +2469,21 @@
},
"query": "\n DELETE FROM user_emails\n WHERE user_emails.user_email_id = $1\n "
},
"e1dc9dd2bf26a341050a53151bf51f7638448ccc2bd458bbdfe87cc22f086313": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Text",
"Timestamptz"
]
}
},
"query": "\n INSERT INTO upstream_oauth_links (\n upstream_oauth_link_id,\n upstream_oauth_provider_id,\n user_id,\n subject,\n created_at\n ) VALUES ($1, $2, NULL, $3, $4)\n "
},
"e446e37d48c8838ef2e0d0fd82f8f7b04893c84ad46747cdf193ebd83755ceb2": {
"describe": {
"columns": [],

View File

@ -0,0 +1,120 @@
// Copyright 2022 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::{DateTime, Utc};
use mas_data_model::{UpstreamOAuthLink, UpstreamOAuthProvider};
use rand::Rng;
use sqlx::PgExecutor;
use ulid::Ulid;
use uuid::Uuid;
use crate::{Clock, GenericLookupError};
struct LinkLookup {
upstream_oauth_link_id: Uuid,
user_id: Option<Uuid>,
subject: String,
created_at: DateTime<Utc>,
}
#[tracing::instrument(
skip_all,
fields(
upstream_oauth_link.subject = subject,
%upstream_oauth_provider.id,
%upstream_oauth_provider.issuer,
%upstream_oauth_provider.client_id,
),
err,
)]
pub async fn lookup_link_by_subject(
executor: impl PgExecutor<'_>,
upstream_oauth_provider: &UpstreamOAuthProvider,
subject: &str,
) -> Result<(UpstreamOAuthLink, Option<Ulid>), GenericLookupError> {
let res = sqlx::query_as!(
LinkLookup,
r#"
SELECT
upstream_oauth_link_id,
user_id,
subject,
created_at
FROM upstream_oauth_links
WHERE upstream_oauth_provider_id = $1
AND subject = $2
"#,
Uuid::from(upstream_oauth_provider.id),
subject,
)
.fetch_one(executor)
.await
.map_err(GenericLookupError::what("Upstream OAuth 2.0 link"))?;
Ok((
UpstreamOAuthLink {
id: Ulid::from(res.upstream_oauth_link_id),
subject: res.subject,
created_at: res.created_at,
},
res.user_id.map(Ulid::from),
))
}
#[tracing::instrument(
skip_all,
fields(
upstream_oauth_link.id,
upstream_oauth_link.subject = subject,
%upstream_oauth_provider.id,
%upstream_oauth_provider.issuer,
%upstream_oauth_provider.client_id,
),
err,
)]
pub async fn add_link(
executor: impl PgExecutor<'_>,
mut rng: impl Rng + Send,
clock: &Clock,
upstream_oauth_provider: &UpstreamOAuthProvider,
subject: String,
) -> Result<UpstreamOAuthLink, sqlx::Error> {
let created_at = clock.now();
let id = Ulid::from_datetime_with_source(created_at.into(), &mut rng);
tracing::Span::current().record("upstream_oauth_link.id", tracing::field::display(id));
sqlx::query!(
r#"
INSERT INTO upstream_oauth_links (
upstream_oauth_link_id,
upstream_oauth_provider_id,
user_id,
subject,
created_at
) VALUES ($1, $2, NULL, $3, $4)
"#,
Uuid::from(id),
Uuid::from(upstream_oauth_provider.id),
&subject,
created_at,
)
.execute(executor)
.await?;
Ok(UpstreamOAuthLink {
id,
subject,
created_at,
})
}

View File

@ -12,10 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
mod link;
mod provider;
mod session;
pub use self::{
link::{add_link, lookup_link_by_subject},
provider::{add_provider, lookup_provider, ProviderLookupError},
session::{add_session, lookup_session, SessionLookupError},
session::{add_session, complete_session, lookup_session, SessionLookupError},
};

View File

@ -13,7 +13,7 @@
// limitations under the License.
use chrono::{DateTime, Utc};
use mas_data_model::{UpstreamOAuthAuthorizationSession, UpstreamOAuthProvider};
use mas_data_model::{UpstreamOAuthAuthorizationSession, UpstreamOAuthLink, UpstreamOAuthProvider};
use rand::Rng;
use sqlx::PgExecutor;
use thiserror::Error;
@ -128,9 +128,9 @@ pub async fn lookup_session(
#[tracing::instrument(
skip_all,
fields(
upstream_oauth_provider.id = %provider.id,
upstream_oauth_provider.issuer = %provider.issuer,
upstream_oauth_provider.client_id = %provider.client_id,
%upstream_oauth_provider.id,
%upstream_oauth_provider.issuer,
%upstream_oauth_provider.client_id,
upstream_oauth_authorization_session.id,
),
err,
@ -139,7 +139,7 @@ pub async fn add_session(
executor: impl PgExecutor<'_>,
mut rng: impl Rng + Send,
clock: &Clock,
provider: &UpstreamOAuthProvider,
upstream_oauth_provider: &UpstreamOAuthProvider,
state: String,
code_challenge_verifier: Option<String>,
nonce: String,
@ -164,7 +164,7 @@ pub async fn add_session(
) VALUES ($1, $2, $3, $4, $5, $6, NULL)
"#,
Uuid::from(id),
Uuid::from(provider.id),
Uuid::from(upstream_oauth_provider.id),
&state,
code_challenge_verifier.as_deref(),
nonce,
@ -182,3 +182,35 @@ pub async fn add_session(
completed_at: None,
})
}
#[tracing::instrument(
skip_all,
fields(
%upstream_oauth_authorization_session.id,
%upstream_oauth_link.id,
),
err,
)]
pub async fn complete_session(
executor: impl PgExecutor<'_>,
clock: &Clock,
mut upstream_oauth_authorization_session: UpstreamOAuthAuthorizationSession,
upstream_oauth_link: &UpstreamOAuthLink,
) -> Result<UpstreamOAuthAuthorizationSession, sqlx::Error> {
let completed_at = clock.now();
sqlx::query!(
r#"
UPDATE upstream_oauth_authorization_sessions
SET upstream_oauth_link_id = $1,
completed_at = $2
"#,
Uuid::from(upstream_oauth_link.id),
completed_at,
)
.execute(executor)
.await?;
upstream_oauth_authorization_session.completed_at = Some(completed_at);
Ok(upstream_oauth_authorization_session)
}