From 45df1233e5e30b3ef81056f93039c5587b9dc6f2 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 20 Nov 2022 12:10:28 -0500 Subject: [PATCH] Complete the test suite for the authentication DB --- server/src/authentication.rs | 204 +++++++++++++++++++++++++++++++---- server/src/main.rs | 3 +- 2 files changed, 183 insertions(+), 24 deletions(-) diff --git a/server/src/authentication.rs b/server/src/authentication.rs index 327d213..4e7f16b 100644 --- a/server/src/authentication.rs +++ b/server/src/authentication.rs @@ -144,7 +144,7 @@ impl FromSql for Username { pub trait AuthenticationDB: Send + Sync { fn create_user(&mut self, username: Username) -> AppResult; - fn create_invitation(&mut self, user: UserId) -> AppResult; + fn create_invitation(&mut self, user: &UserId) -> AppResult; fn authenticate( &mut self, @@ -182,6 +182,10 @@ impl AuthenticationDB for MemoryAuth { #[cfg(test)] let _ = maybe_fail::(vec![])?; + if self.users.contains_key(&username) { + return Ok(Err(AuthenticationError::DuplicateUsername)); + } + let userid = UserId::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str()); self.users.insert(username.clone(), userid.clone()); self.inverse_users.insert(userid.clone(), username); @@ -189,7 +193,7 @@ impl AuthenticationDB for MemoryAuth { ok(userid) } - fn create_invitation(&mut self, user: UserId) -> AppResult { + fn create_invitation(&mut self, user: &UserId) -> AppResult { #[cfg(test)] let _ = maybe_fail::(vec![])?; @@ -199,7 +203,7 @@ impl AuthenticationDB for MemoryAuth { let invitation = Invitation::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str()); - self.invitations.insert(invitation.clone(), user); + self.invitations.insert(invitation.clone(), user.clone()); ok(invitation) } @@ -346,43 +350,197 @@ mod test { with_memory_db(test_case); } - #[test] - fn it_allows_multiple_invitations_per_user() { - unimplemented!() - } - #[test] fn it_exchanges_an_invitation_for_a_session() { - unimplemented!() - } - - #[test] - fn it_allows_multiple_sessions_per_user() { - unimplemented!() - } - - #[test] - fn it_disallows_invitation_reuse() { - unimplemented!() + fn test_case(mut authdb: Box) { + let username = Username::from("shephard"); + let userid = authdb + .create_user(username.clone()) + .expect("no fatal errors") + .expect("user to be created"); + let invitation = authdb + .create_invitation(&userid) + .expect("no fatal errors") + .expect("invitation to be created"); + let _ = authdb + .authenticate(invitation) + .expect("no fatal errors") + .expect("to receive a session token"); + } + with_memory_db(test_case); } #[test] fn it_identifies_a_user_by_session() { - unimplemented!() + fn test_case(mut authdb: Box) { + let shephard = Username::from("shephard"); + let garrus = Username::from("garrus"); + + let (shephard_session, shephard_id) = { + let userid = authdb.create_user(shephard.clone()).unwrap().unwrap(); + let invitation = authdb.create_invitation(&userid).unwrap().unwrap(); + (authdb.authenticate(invitation).unwrap().unwrap(), userid) + }; + + let (garrus_session, garrus_id) = { + let userid = authdb.create_user(garrus.clone()).unwrap().unwrap(); + let invitation = authdb.create_invitation(&userid).unwrap().unwrap(); + (authdb.authenticate(invitation).unwrap().unwrap(), userid) + }; + + assert_eq!( + authdb.validate_session(shephard_session).unwrap().unwrap(), + (shephard, shephard_id) + ); + assert_eq!( + authdb.validate_session(garrus_session).unwrap().unwrap(), + (garrus, garrus_id) + ); + } + with_memory_db(test_case); + } + + #[test] + fn it_allows_multiple_invitations_per_user() { + fn test_case(mut authdb: Box) { + let username = Username::from("shephard"); + let userid = authdb.create_user(username).unwrap().unwrap(); + let invite1 = authdb.create_invitation(&userid).unwrap().unwrap(); + let invite2 = authdb.create_invitation(&userid).unwrap().unwrap(); + + assert_ne!(invite1, invite2); + + authdb.authenticate(invite1).unwrap().unwrap(); + authdb.authenticate(invite2).unwrap().unwrap(); + } + with_memory_db(test_case); + } + + #[test] + fn it_allows_multiple_sessions_per_user() { + fn test_case(mut authdb: Box) { + let username = Username::from("shephard"); + let userid = authdb.create_user(username.clone()).unwrap().unwrap(); + let invite1 = authdb.create_invitation(&userid).unwrap().unwrap(); + let invite2 = authdb.create_invitation(&userid).unwrap().unwrap(); + + assert_ne!(invite1, invite2); + + let session1 = authdb.authenticate(invite1).unwrap().unwrap(); + let session2 = authdb.authenticate(invite2).unwrap().unwrap(); + + assert_ne!(session1, session2); + assert_eq!( + authdb.validate_session(session1).unwrap().unwrap(), + (username.clone(), userid.clone()) + ); + assert_eq!( + authdb.validate_session(session2).unwrap().unwrap(), + (username, userid) + ); + } + with_memory_db(test_case); + } + + #[test] + fn it_disallows_invitation_reuse() { + fn test_case(mut authdb: Box) { + let username = Username::from("shephard"); + let userid = authdb + .create_user(username.clone()) + .expect("no fatal errors") + .expect("user to be created"); + let invitation = authdb + .create_invitation(&userid) + .expect("no fatal errors") + .expect("invitation to be created"); + let _ = authdb + .authenticate(invitation.clone()) + .expect("no fatal errors") + .expect("to receive a session token"); + let reuse_result = authdb.authenticate(invitation).expect("no fatal errors"); + assert_eq!(reuse_result, Err(AuthenticationError::InvalidInvitation)); + } + with_memory_db(test_case); } #[test] fn it_deletes_a_user_and_invalidates_tokens() { - unimplemented!() + fn test_case(mut authdb: Box) { + let shephard = Username::from("shephard"); + let garrus = Username::from("garrus"); + + let (shephard_session, shephard_id) = { + let userid = authdb.create_user(shephard.clone()).unwrap().unwrap(); + let invitation = authdb.create_invitation(&userid).unwrap().unwrap(); + (authdb.authenticate(invitation).unwrap().unwrap(), userid) + }; + + let (garrus_invitation, garrus_id) = { + let userid = authdb.create_user(garrus.clone()).unwrap().unwrap(); + (authdb.create_invitation(&userid).unwrap().unwrap(), userid) + }; + + authdb.delete_user(shephard_id).unwrap().unwrap(); + assert_eq!( + authdb.validate_session(shephard_session).unwrap(), + Err(AuthenticationError::InvalidSession) + ); + + authdb.delete_user(garrus_id).unwrap().unwrap(); + assert_eq!( + authdb.authenticate(garrus_invitation).unwrap(), + Err(AuthenticationError::InvalidInvitation) + ); + } + with_memory_db(test_case); } #[test] fn it_deletes_a_session() { - unimplemented!() + fn test_case(mut authdb: Box) { + let username = Username::from("shephard"); + let userid = authdb + .create_user(username.clone()) + .expect("no fatal errors") + .expect("user to be created"); + let invitation = authdb + .create_invitation(&userid) + .expect("no fatal errors") + .expect("invitation to be created"); + let session = authdb.authenticate(invitation).unwrap().unwrap(); + + authdb.delete_session(session.clone()).unwrap().unwrap(); + assert_eq!( + authdb.validate_session(session).unwrap(), + Err(AuthenticationError::InvalidSession) + ); + } + with_memory_db(test_case); } #[test] fn it_deletes_an_invitation() { - unimplemented!() + fn test_case(mut authdb: Box) { + let username = Username::from("shephard"); + let userid = authdb + .create_user(username.clone()) + .expect("no fatal errors") + .expect("user to be created"); + let invitation = authdb + .create_invitation(&userid) + .expect("no fatal errors") + .expect("invitation to be created"); + + authdb + .delete_invitation(invitation.clone()) + .unwrap() + .unwrap(); + assert_eq!( + authdb.authenticate(invitation).unwrap(), + Err(AuthenticationError::InvalidInvitation) + ); + } + with_memory_db(test_case); } } diff --git a/server/src/main.rs b/server/src/main.rs index 220251f..547b424 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -87,6 +87,7 @@ struct MakeInvitationResponse { invitation: Invitation, } +/* fn make_invitation( auth_ctx: Arc>, ) -> impl Filter + Clone { @@ -104,6 +105,7 @@ fn make_invitation( } }) } +*/ #[derive(Deserialize)] struct AuthenticateParams { @@ -191,7 +193,6 @@ pub async fn main() { .or(echo_unauthenticated); */ let filter = make_user(auth_ctx.clone()) - .or(make_invitation(auth_ctx.clone())) .or(authenticate(auth_ctx.clone())) .or(echo_authenticated) .or(echo_unauthenticated);