From a25c3d79bbbd11916438661e03292db8aedc39ad Mon Sep 17 00:00:00 2001 From: Danny Tatom Date: Fri, 20 Sep 2024 10:12:56 -0700 Subject: [PATCH] fix(authn): only create a user if the identifier doesn't already exist --- authn/src/handlers/hook.rs | 49 +++++++++++-------- db/.sqlx/lib.rs | 25 ++++++++++ ...9915f3a9c1fe0718133dec0d4d99ffc9e2e8d.json | 1 + ...e2a7556215d9f8af7d6738ce9f88ce0bf4879.json | 46 +++++++++++++++++ ...7b7d7e3636a48fc23d59b292b6a1cb158398d.json | 1 + ...02998f5a5f3722dff3d407b655c94d44e28de.json | 2 + ...567ba8acc7d853453a323a1c8bd1661861718.json | 1 + ...730a5dcc07cddbcae5823e1a1cf11f20d446f.json | 1 + ...f04ba8a3ad371b81a64acc47b6bb436952f44.json | 1 + ...a0677e44edd481daf0526bb3e4ac229e2838f.json | 2 + .../20240908190542_create_identifiers.up.sql | 6 +-- db/schema.sql | 4 +- db/sql/identifiers/get_by_value.sql | 1 + db/src/repos/identifiers.rs | 9 ++++ 14 files changed, 122 insertions(+), 27 deletions(-) create mode 100644 db/.sqlx/lib.rs create mode 100644 db/.sqlx/query-3e0695d175a688c042afb9afb48e2a7556215d9f8af7d6738ce9f88ce0bf4879.json create mode 100644 db/sql/identifiers/get_by_value.sql diff --git a/authn/src/handlers/hook.rs b/authn/src/handlers/hook.rs index 1873b1a..7e84b70 100644 --- a/authn/src/handlers/hook.rs +++ b/authn/src/handlers/hook.rs @@ -49,36 +49,43 @@ async fn handle_registration( let auth_session = serde_json::from_str::(&auth_session)?; - // Create the user and associated DID. - // ----------------------------------- + // Create the user and associated DID if they don't already exist. + // --------------------------------------------------------------- - state - .repos - .users - .create( - &CreateUser::builder() - .id(auth_session.user_id) - .service_id(auth_session.service_id) - .build(), - ) - .await?; - - state + let existing = state .repos .identifiers - .create( - &CreateIdentifier::builder() - .value(body.data.identifier.clone()) - .user_id(auth_session.user_id) - .build(), - ) + .get_by_value(&body.data.identifier) .await?; + if existing.is_none() { + state + .repos + .users + .create( + &CreateUser::builder() + .id(auth_session.user_id) + .service_id(auth_session.service_id) + .build(), + ) + .await?; + + state + .repos + .identifiers + .create( + &CreateIdentifier::builder() + .value(body.data.identifier.clone()) + .user_id(auth_session.user_id) + .build(), + ) + .await?; + } + // Complete the registration process. // ---------------------------------- // Send an event to the user's browser to let it know authentication is complete. - // // This event will be picked up by an event listener in the browser listening to the `wait` handler. state .redis_pub_client diff --git a/db/.sqlx/lib.rs b/db/.sqlx/lib.rs new file mode 100644 index 0000000..7ec19be --- /dev/null +++ b/db/.sqlx/lib.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +pub mod app; +mod crypto; +mod handlers; +mod state; +mod webhooks; + +const COOKIE_KEY: &str = "id"; +const REDIS_AUTH_KEY: &str = "auth"; +const REDIS_AUTH_HOOK_KEY: &str = "auth-hook"; +const REDIS_RESPONSE_RECEIVED_KEY: &str = "response-received"; + +#[derive(Serialize, Deserialize)] +pub(crate) struct AuthSessionData { + pub(crate) service_id: Uuid, + pub(crate) user_id: Uuid, +} + +#[derive(Serialize, Deserialize)] +pub(crate) struct AuthHookSessionData { + pub(crate) hook_id: Uuid, + pub(crate) user_session_id: Uuid, +} diff --git a/db/.sqlx/query-23db55b81f4dfac829b7e5327e49915f3a9c1fe0718133dec0d4d99ffc9e2e8d.json b/db/.sqlx/query-23db55b81f4dfac829b7e5327e49915f3a9c1fe0718133dec0d4d99ffc9e2e8d.json index 90b560f..a6d2b0c 100644 --- a/db/.sqlx/query-23db55b81f4dfac829b7e5327e49915f3a9c1fe0718133dec0d4d99ffc9e2e8d.json +++ b/db/.sqlx/query-23db55b81f4dfac829b7e5327e49915f3a9c1fe0718133dec0d4d99ffc9e2e8d.json @@ -21,6 +21,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } diff --git a/db/.sqlx/query-3e0695d175a688c042afb9afb48e2a7556215d9f8af7d6738ce9f88ce0bf4879.json b/db/.sqlx/query-3e0695d175a688c042afb9afb48e2a7556215d9f8af7d6738ce9f88ce0bf4879.json new file mode 100644 index 0000000..b22070f --- /dev/null +++ b/db/.sqlx/query-3e0695d175a688c042afb9afb48e2a7556215d9f8af7d6738ce9f88ce0bf4879.json @@ -0,0 +1,46 @@ +{ + "db_name": "PostgreSQL", + "query": "select * from identifiers where value = $1;\n", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "value", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 3, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "3e0695d175a688c042afb9afb48e2a7556215d9f8af7d6738ce9f88ce0bf4879" +} diff --git a/db/.sqlx/query-5eddd4e88b12c4985f250a57eca7b7d7e3636a48fc23d59b292b6a1cb158398d.json b/db/.sqlx/query-5eddd4e88b12c4985f250a57eca7b7d7e3636a48fc23d59b292b6a1cb158398d.json index 68f11e4..31b4d2a 100644 --- a/db/.sqlx/query-5eddd4e88b12c4985f250a57eca7b7d7e3636a48fc23d59b292b6a1cb158398d.json +++ b/db/.sqlx/query-5eddd4e88b12c4985f250a57eca7b7d7e3636a48fc23d59b292b6a1cb158398d.json @@ -21,6 +21,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } diff --git a/db/.sqlx/query-6f48db2b0e00fcbb72c41bf0de202998f5a5f3722dff3d407b655c94d44e28de.json b/db/.sqlx/query-6f48db2b0e00fcbb72c41bf0de202998f5a5f3722dff3d407b655c94d44e28de.json index 123be47..18e2780 100644 --- a/db/.sqlx/query-6f48db2b0e00fcbb72c41bf0de202998f5a5f3722dff3d407b655c94d44e28de.json +++ b/db/.sqlx/query-6f48db2b0e00fcbb72c41bf0de202998f5a5f3722dff3d407b655c94d44e28de.json @@ -21,6 +21,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } @@ -61,6 +62,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } diff --git a/db/.sqlx/query-70b2732d03b4f7831588b600bd2567ba8acc7d853453a323a1c8bd1661861718.json b/db/.sqlx/query-70b2732d03b4f7831588b600bd2567ba8acc7d853453a323a1c8bd1661861718.json index 2ac8edf..7dd273d 100644 --- a/db/.sqlx/query-70b2732d03b4f7831588b600bd2567ba8acc7d853453a323a1c8bd1661861718.json +++ b/db/.sqlx/query-70b2732d03b4f7831588b600bd2567ba8acc7d853453a323a1c8bd1661861718.json @@ -11,6 +11,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } diff --git a/db/.sqlx/query-788d7402d01f7ddfc6dfdcf1d68730a5dcc07cddbcae5823e1a1cf11f20d446f.json b/db/.sqlx/query-788d7402d01f7ddfc6dfdcf1d68730a5dcc07cddbcae5823e1a1cf11f20d446f.json index 2c5a58b..c81b145 100644 --- a/db/.sqlx/query-788d7402d01f7ddfc6dfdcf1d68730a5dcc07cddbcae5823e1a1cf11f20d446f.json +++ b/db/.sqlx/query-788d7402d01f7ddfc6dfdcf1d68730a5dcc07cddbcae5823e1a1cf11f20d446f.json @@ -21,6 +21,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } diff --git a/db/.sqlx/query-92525eeb0416a8d544b9f7a50bef04ba8a3ad371b81a64acc47b6bb436952f44.json b/db/.sqlx/query-92525eeb0416a8d544b9f7a50bef04ba8a3ad371b81a64acc47b6bb436952f44.json index ab645ec..04fd408 100644 --- a/db/.sqlx/query-92525eeb0416a8d544b9f7a50bef04ba8a3ad371b81a64acc47b6bb436952f44.json +++ b/db/.sqlx/query-92525eeb0416a8d544b9f7a50bef04ba8a3ad371b81a64acc47b6bb436952f44.json @@ -21,6 +21,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } diff --git a/db/.sqlx/query-f36efd4d9f41dc2ba3115bf6cc9a0677e44edd481daf0526bb3e4ac229e2838f.json b/db/.sqlx/query-f36efd4d9f41dc2ba3115bf6cc9a0677e44edd481daf0526bb3e4ac229e2838f.json index f932dc1..f937e02 100644 --- a/db/.sqlx/query-f36efd4d9f41dc2ba3115bf6cc9a0677e44edd481daf0526bb3e4ac229e2838f.json +++ b/db/.sqlx/query-f36efd4d9f41dc2ba3115bf6cc9a0677e44edd481daf0526bb3e4ac229e2838f.json @@ -21,6 +21,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } @@ -61,6 +62,7 @@ "name": "key_kind", "kind": { "Enum": [ + "api", "token" ] } diff --git a/db/migrations/20240908190542_create_identifiers.up.sql b/db/migrations/20240908190542_create_identifiers.up.sql index e3c60d7..fa34aea 100644 --- a/db/migrations/20240908190542_create_identifiers.up.sql +++ b/db/migrations/20240908190542_create_identifiers.up.sql @@ -1,13 +1,11 @@ -- Add up migration script here create table identifiers ( id uuid primary key default uuid_generate_v4(), - value text not null, + value text unique not null, user_id uuid not null references users(id) on delete cascade, created_at timestamptz not null default now(), - updated_at timestamptz not null default now(), - - unique (user_id, value) + updated_at timestamptz not null default now() ); create or replace trigger set_updated_at before update on identifiers diff --git a/db/schema.sql b/db/schema.sql index 8f38a2e..bdcf8fd 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -190,11 +190,11 @@ ALTER TABLE ONLY public.identifiers -- --- Name: identifiers identifiers_user_id_value_key; Type: CONSTRAINT; Schema: public; Owner: casper +-- Name: identifiers identifiers_value_key; Type: CONSTRAINT; Schema: public; Owner: casper -- ALTER TABLE ONLY public.identifiers - ADD CONSTRAINT identifiers_user_id_value_key UNIQUE (user_id, value); + ADD CONSTRAINT identifiers_value_key UNIQUE (value); -- diff --git a/db/sql/identifiers/get_by_value.sql b/db/sql/identifiers/get_by_value.sql new file mode 100644 index 0000000..65bd0e8 --- /dev/null +++ b/db/sql/identifiers/get_by_value.sql @@ -0,0 +1 @@ +select * from identifiers where value = $1; diff --git a/db/src/repos/identifiers.rs b/db/src/repos/identifiers.rs index d49a37f..5c2099e 100644 --- a/db/src/repos/identifiers.rs +++ b/db/src/repos/identifiers.rs @@ -8,6 +8,7 @@ use crate::models::identifier::{CreateIdentifier, Identifier}; #[mockall::automock] pub trait IdentifierRepo: Send + Sync { async fn create(&self, data: &CreateIdentifier) -> Result; + async fn get_by_value(&self, value: &str) -> Result>; } pub struct PgIdentifierRepo { @@ -34,4 +35,12 @@ impl IdentifierRepo for PgIdentifierRepo { Ok(identifier) } + + async fn get_by_value(&self, value: &str) -> Result> { + let identifier = query_file_as!(Identifier, "sql/identifiers/get_by_value.sql", value) + .fetch_optional(&self.pool) + .await?; + + Ok(identifier) + } }