Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(authn): only create a user if the identifier doesn't already exist #69

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions authn/src/handlers/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,36 +49,43 @@ async fn handle_registration(

let auth_session = serde_json::from_str::<AuthSessionData>(&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
Expand Down
25 changes: 25 additions & 0 deletions db/.sqlx/lib.rs
Original file line number Diff line number Diff line change
@@ -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,
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions db/migrations/20240908190542_create_identifiers.up.sql
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions db/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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);


--
Expand Down
1 change: 1 addition & 0 deletions db/sql/identifiers/get_by_value.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
select * from identifiers where value = $1;
9 changes: 9 additions & 0 deletions db/src/repos/identifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::models::identifier::{CreateIdentifier, Identifier};
#[mockall::automock]
pub trait IdentifierRepo: Send + Sync {
async fn create(&self, data: &CreateIdentifier) -> Result<Identifier>;
async fn get_by_value(&self, value: &str) -> Result<Option<Identifier>>;
}

pub struct PgIdentifierRepo {
Expand All @@ -34,4 +35,12 @@ impl IdentifierRepo for PgIdentifierRepo {

Ok(identifier)
}

async fn get_by_value(&self, value: &str) -> Result<Option<Identifier>> {
let identifier = query_file_as!(Identifier, "sql/identifiers/get_by_value.sql", value)
.fetch_optional(&self.pool)
.await?;

Ok(identifier)
}
}