refactor auth_repo to server_app
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use nkode_rs::nkode_core::keypad::Keypad;
|
use nkode_rs::nkode_core::keypad::Keypad;
|
||||||
use crate::shared::models::app::{OpaqueAPI, AuthAPI, CodeLoginData, CodeLoginSession, Icon, IconID, KeyLoginSession, ICON_ID_SIZE, LoginSession};
|
use crate::shared::models::app::{OpaqueAPI, AuthAPI, CodeLoginData, CodeLoggedInSession, Icon, IconID, KeyLoggedInSession, ICON_ID_SIZE, LoggedInSession};
|
||||||
use crate::shared::models::email::Email;
|
use crate::shared::models::email::Email;
|
||||||
use crate::shared::models::opaque::{OpaqueLoginSession, UserSecretKey};
|
use crate::shared::models::opaque::{OpaqueLoginSession, UserSecretKey};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@@ -50,7 +50,7 @@ pub struct ClientAppKeyLoggedIn<S: OpaqueAPI> {
|
|||||||
api: S,
|
api: S,
|
||||||
email: Email,
|
email: Email,
|
||||||
user_secret_key: UserSecretKey,
|
user_secret_key: UserSecretKey,
|
||||||
key_login: KeyLoginSession,
|
key_login: KeyLoggedInSession,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <S: OpaqueAPI + AuthAPI> ClientAppKeyLoggedIn<S> {
|
impl <S: OpaqueAPI + AuthAPI> ClientAppKeyLoggedIn<S> {
|
||||||
@@ -104,7 +104,7 @@ pub struct ClientAppCodeRegister<S: OpaqueAPI> {
|
|||||||
api: S,
|
api: S,
|
||||||
email: Email,
|
email: Email,
|
||||||
user_secret_key: UserSecretKey,
|
user_secret_key: UserSecretKey,
|
||||||
key_login: KeyLoginSession,
|
key_login: KeyLoggedInSession,
|
||||||
icon_nonce: Nonce,
|
icon_nonce: Nonce,
|
||||||
icons: Vec<Icon>,
|
icons: Vec<Icon>,
|
||||||
keypad: Keypad,
|
keypad: Keypad,
|
||||||
@@ -156,7 +156,7 @@ impl <S: OpaqueAPI>ClientAppCodeLogin<S> {
|
|||||||
).unwrap().to_vec()
|
).unwrap().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn login(&self, selected_keys: &Vec<usize>) -> Result<CodeLoginSession, String> {
|
pub async fn login(&self, selected_keys: &Vec<usize>) -> Result<CodeLoggedInSession, String> {
|
||||||
let passcode = self.cipher.decipher(selected_keys, self.keypad.indices(), &self.mask).map_err(|e| format!("invalid keys: {e}"))?;
|
let passcode = self.cipher.decipher(selected_keys, self.keypad.indices(), &self.mask).map_err(|e| format!("invalid keys: {e}"))?;
|
||||||
self.api.login_code(&self.email, &passcode).await
|
self.api.login_code(&self.email, &passcode).await
|
||||||
}
|
}
|
||||||
@@ -186,31 +186,33 @@ where
|
|||||||
self.opaque_key_register.register(&auth_data).await.map_err(|e| format!("error: {}", e))
|
self.opaque_key_register.register(&auth_data).await.map_err(|e| format!("error: {}", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoginSession, data: &CodeLoginData) -> Result<(), String> {
|
async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoggedInSession, data: &CodeLoginData) -> Result<(), String> {
|
||||||
let auth_data = AuthenticationData::from_code(email.as_str(), passcode);
|
let auth_data = AuthenticationData::from_code(email.as_str(), passcode);
|
||||||
self.opaque_code_register.register(&auth_data).await.map_err(|e| format!("error: {}", e))
|
self.opaque_code_register.register(&auth_data).await.map_err(|e| format!("error: {}", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoginSession, String> {
|
async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoggedInSession, String> {
|
||||||
let auth_data = AuthenticationData::from_secret_key(&email.as_str(), secret_key.as_slice());
|
let auth_data = AuthenticationData::from_secret_key(&email.as_str(), secret_key.as_slice());
|
||||||
let session_key = self.opaque_key_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?;
|
let session_key = self.opaque_key_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?;
|
||||||
Ok(KeyLoginSession(
|
todo!()
|
||||||
LoginSession {
|
// Ok(KeyLoggedInSession(
|
||||||
email: email.clone(),
|
// LoggedInSession {
|
||||||
session_key
|
// email: email.clone(),
|
||||||
}
|
// session_key
|
||||||
))
|
// }
|
||||||
|
// ))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String> {
|
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoggedInSession, String> {
|
||||||
let auth_data = AuthenticationData::from_code(email.as_str(), passcode);
|
let auth_data = AuthenticationData::from_code(email.as_str(), passcode);
|
||||||
let session_key = self.opaque_code_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?;
|
let session_key = self.opaque_code_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?;
|
||||||
Ok(CodeLoginSession(
|
todo!()
|
||||||
LoginSession {
|
// Ok(CodeLoggedInSession(
|
||||||
email: email.clone(),
|
// LoggedInSession {
|
||||||
session_key
|
// email: email.clone(),
|
||||||
}
|
// session_key
|
||||||
))
|
// }
|
||||||
|
// ))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +225,7 @@ where
|
|||||||
{
|
{
|
||||||
async fn get_new_icons(
|
async fn get_new_icons(
|
||||||
&self,
|
&self,
|
||||||
key_login_session: &KeyLoginSession,
|
key_login_session: &KeyLoggedInSession,
|
||||||
) -> Result<Vec<Icon>, String> {
|
) -> Result<Vec<Icon>, String> {
|
||||||
self.nkode_api
|
self.nkode_api
|
||||||
.get_new_icons(key_login_session)
|
.get_new_icons(key_login_session)
|
||||||
@@ -232,14 +234,14 @@ where
|
|||||||
|
|
||||||
async fn get_login_data(
|
async fn get_login_data(
|
||||||
&self,
|
&self,
|
||||||
key_login_session: &KeyLoginSession,
|
key_login_session: &KeyLoggedInSession,
|
||||||
) -> Result<CodeLoginData, String> {
|
) -> Result<CodeLoginData, String> {
|
||||||
self.nkode_api
|
self.nkode_api
|
||||||
.get_login_data(key_login_session)
|
.get_login_data(key_login_session)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String> {
|
async fn is_code_registered(&self, key_login_session: &KeyLoggedInSession) -> Result<bool, String> {
|
||||||
self.nkode_api.is_code_registered(key_login_session).await
|
self.nkode_api.is_code_registered(key_login_session).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use opaque_ke::{
|
|||||||
CredentialFinalization, CredentialRequest,
|
CredentialFinalization, CredentialRequest,
|
||||||
RegistrationRequest,
|
RegistrationRequest,
|
||||||
};
|
};
|
||||||
|
use crate::shared::models::app::LoggedInSession;
|
||||||
use crate::shared::models::opaque::{OpaqueRegisterSession, OpaqueLoginSession, NKodeCipherSuite, PasswordFile, OpaqueSessionKey};
|
use crate::shared::models::opaque::{OpaqueRegisterSession, OpaqueLoginSession, NKodeCipherSuite, PasswordFile, OpaqueSessionKey};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -81,7 +82,7 @@ pub trait ServerConnectionLogin {
|
|||||||
&self,
|
&self,
|
||||||
session_id: &Uuid,
|
session_id: &Uuid,
|
||||||
message: &CredentialFinalization<NKodeCipherSuite>,
|
message: &CredentialFinalization<NKodeCipherSuite>,
|
||||||
) -> Result<OpaqueSessionKey, ClientAuthError>;
|
) -> Result<LoggedInSession, ClientAuthError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
use uuid::Uuid;
|
||||||
|
use opaque_ke::{CredentialFinalization, CredentialRequest, RegistrationRequest, ServerLogin, ServerLoginParameters, ServerRegistration};
|
||||||
|
use opaque_ke::argon2::password_hash::rand_core::OsRng;
|
||||||
|
use nkode_rs::from_bytes::FromBytes;
|
||||||
|
use crate::server::models::CredKind;
|
||||||
|
use crate::server::repository::opaque_repo::{AuthRepoError, OpaqueDatabaseRepo, OpaqueSessionRepo};
|
||||||
|
use crate::server::repository::user_repo::UserRepo;
|
||||||
|
use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession, LoggedInSession};
|
||||||
|
use crate::shared::models::email::Email;
|
||||||
|
use crate::shared::models::opaque::{NKodeCipherSuite, NKodeServerSetup, OpaqueLoginSession, OpaqueRegisterSession, OpaqueSessionKey, PasswordFile};
|
||||||
|
|
||||||
|
pub struct ServerApp<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo, U: UserRepo> {
|
||||||
|
server_setup: NKodeServerSetup,
|
||||||
|
opaque_db: R,
|
||||||
|
opaque_sess: S,
|
||||||
|
user_db: U,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo, U: UserRepo> ServerApp<R, S, U> {
|
||||||
|
pub fn new(server_setup: NKodeServerSetup, opaque_db: R, opaque_sess: S, user_db: U) -> Self {
|
||||||
|
Self { server_setup, opaque_db, opaque_sess, user_db}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn reg_start<K: CredKind>(
|
||||||
|
&mut self,
|
||||||
|
identifier: &[u8],
|
||||||
|
request: RegistrationRequest<NKodeCipherSuite>,
|
||||||
|
) -> Result<OpaqueRegisterSession, String> {
|
||||||
|
K::prereq_for_register(&self.opaque_db, identifier)
|
||||||
|
.map_err(|e| format!("registration prereq failed: {e:?}"))?;
|
||||||
|
let start = ServerRegistration::<NKodeCipherSuite>::start(
|
||||||
|
&self.server_setup,
|
||||||
|
request,
|
||||||
|
identifier,
|
||||||
|
).map_err(|e| format!("opaque reg start: {e:?}"))?;
|
||||||
|
let cache = self.opaque_sess
|
||||||
|
.new_reg_session(identifier)
|
||||||
|
.map_err(|e| format!("reg cache: {e}"))?;
|
||||||
|
|
||||||
|
Ok(OpaqueRegisterSession { session_id: cache.session_id, response: start.message })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn reg_finish<K: CredKind>(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
password_file: PasswordFile,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let sess = self.opaque_sess
|
||||||
|
.get_reg_session(session_id)
|
||||||
|
.map_err(|e| format!("get reg session: {e}"))?;
|
||||||
|
K::prereq_for_register(&self.opaque_db, sess.identifier.as_slice())
|
||||||
|
.map_err(|e| format!("registration prereq failed: {e:?}"))?;
|
||||||
|
K::set_password_file(&mut self.opaque_db, sess.identifier.as_slice(), password_file)
|
||||||
|
.map_err(|e| format!("repo write: {e:?}"))?;
|
||||||
|
self.opaque_sess
|
||||||
|
.clear_reg_session(session_id)
|
||||||
|
.map_err(|e| format!("clear reg session: {e}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn login_start<K: CredKind>(
|
||||||
|
&mut self,
|
||||||
|
identifier: &[u8],
|
||||||
|
request: CredentialRequest<NKodeCipherSuite>,
|
||||||
|
) -> Result<OpaqueLoginSession, String> {
|
||||||
|
let password_file = K::get_password_file(&self.opaque_db, identifier)
|
||||||
|
.map_err(|e| format!("repo read: {e:?}"))?;
|
||||||
|
|
||||||
|
let password_file =
|
||||||
|
ServerRegistration::<NKodeCipherSuite>::deserialize(password_file.as_slice())
|
||||||
|
.map_err(|e| format!("pf deserialize: {e:?}"))?;
|
||||||
|
let mut server_rng = OsRng;
|
||||||
|
let start = ServerLogin::start(
|
||||||
|
&mut server_rng,
|
||||||
|
&self.server_setup,
|
||||||
|
Some(password_file),
|
||||||
|
request,
|
||||||
|
identifier,
|
||||||
|
ServerLoginParameters::default(),
|
||||||
|
).map_err(|e| format!("opaque login start: {e:?}"))?;
|
||||||
|
let cache = self.opaque_sess
|
||||||
|
.new_login_session(identifier, start.state)
|
||||||
|
.map_err(|e| format!("login cache: {e}"))?;
|
||||||
|
Ok(OpaqueLoginSession { session_id: cache.session_id, response: start.message })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn login_finish(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
finalize: CredentialFinalization<NKodeCipherSuite>,
|
||||||
|
) -> Result<LoggedInSession, String> {
|
||||||
|
let cache = self.opaque_sess
|
||||||
|
.get_login_session(session_id)
|
||||||
|
.map_err(|e| format!("get login session: {e}"))?;
|
||||||
|
|
||||||
|
let finish = cache.server_login
|
||||||
|
.finish(finalize, ServerLoginParameters::default())
|
||||||
|
.map_err(|e| format!("opaque login finish: {e:?}"))?;
|
||||||
|
|
||||||
|
self.opaque_sess
|
||||||
|
.clear_login_session(session_id)
|
||||||
|
.map_err(|e| format!("clear login session: {e}"))?;
|
||||||
|
let session_key = OpaqueSessionKey::from_bytes(&finish.session_key.to_vec()).unwrap();
|
||||||
|
Ok(LoggedInSession{
|
||||||
|
session_id: Uuid::new_v4(),
|
||||||
|
email: Email::from_bytes(cache.identifiers.as_slice()).unwrap(),
|
||||||
|
session_key
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn key_login_finish(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
finalize: CredentialFinalization<NKodeCipherSuite>,
|
||||||
|
) -> Result<KeyLoggedInSession, String> {
|
||||||
|
let session = KeyLoggedInSession(self.login_finish(session_id, finalize).await?);
|
||||||
|
self.user_db.set_key_session(session.clone())?;
|
||||||
|
Ok(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn code_login_finish(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
finalize: CredentialFinalization<NKodeCipherSuite>,
|
||||||
|
) -> Result<CodeLoggedInSession, String> {
|
||||||
|
let session = CodeLoggedInSession(self.login_finish(session_id, finalize).await?);
|
||||||
|
self.user_db.set_code_session(session.clone())?;
|
||||||
|
Ok(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_key_session(&mut self, session_id: &Uuid) -> Result<KeyLoggedInSession, String> {
|
||||||
|
self.user_db.get_key_session(session_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_code_session(&mut self, session_id: &Uuid) -> Result<CodeLoggedInSession, String> {
|
||||||
|
self.user_db.get_code_session(session_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_code_login_data(&mut self, email: &Email) -> Result<CodeLoginData, String> {
|
||||||
|
self.user_db.get_code_login_data(email)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_code_login_data(&mut self, email: Email, data: CodeLoginData) -> Result<(), String> {
|
||||||
|
self.user_db.set_code_login_data(email, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Key;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Code;
|
||||||
|
|
||||||
|
impl CredKind for Key {
|
||||||
|
fn has<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> bool {
|
||||||
|
repo.has_key(id)
|
||||||
|
}
|
||||||
|
fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError> {
|
||||||
|
repo.get_key_passcode_file(id)
|
||||||
|
}
|
||||||
|
fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError> {
|
||||||
|
repo.new_key(id, pf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CredKind for Code {
|
||||||
|
fn has<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> bool {
|
||||||
|
repo.has_code(id)
|
||||||
|
}
|
||||||
|
fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError> {
|
||||||
|
repo.get_code_passcode_file(id)
|
||||||
|
}
|
||||||
|
fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError> {
|
||||||
|
repo.new_code(id, pf)
|
||||||
|
}
|
||||||
|
fn prereq_for_register<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<(), AuthRepoError> {
|
||||||
|
if repo.has_key(id) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(AuthRepoError::KeyNotRegistered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod repository;
|
pub mod repository;
|
||||||
pub mod opaque;
|
mod models;
|
||||||
|
|||||||
24
src/server/models.rs
Normal file
24
src/server/models.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
use uuid::Uuid;
|
||||||
|
use opaque_ke::ServerLogin;
|
||||||
|
use crate::server::repository::opaque_repo::{AuthRepoError, OpaqueDatabaseRepo};
|
||||||
|
use crate::shared::models::opaque::{NKodeCipherSuite, PasswordFile};
|
||||||
|
|
||||||
|
pub struct RegCache {
|
||||||
|
pub session_id: Uuid,
|
||||||
|
pub identifier: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LoginCache {
|
||||||
|
pub session_id: Uuid,
|
||||||
|
pub identifiers: Vec<u8>,
|
||||||
|
pub server_login: ServerLogin<NKodeCipherSuite>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CredKind {
|
||||||
|
fn has<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> bool;
|
||||||
|
fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError>;
|
||||||
|
fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError>;
|
||||||
|
fn prereq_for_register<R: OpaqueDatabaseRepo>(_repo: &R, _id: &[u8]) -> Result<(), AuthRepoError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
use nkode_rs::from_bytes::FromBytes;
|
|
||||||
use opaque_ke::{
|
|
||||||
rand::rngs::OsRng, CredentialFinalization, CredentialRequest,
|
|
||||||
RegistrationRequest, ServerLogin, ServerLoginParameters,
|
|
||||||
ServerRegistration,
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
use crate::shared::models::opaque::{OpaqueLoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, OpaqueRegisterSession};
|
|
||||||
use crate::server::repository::opaque::repos::{OpaqueDatabaseRepo, AuthRepoError, OpaqueSessionRepo};
|
|
||||||
|
|
||||||
pub struct RegCache {
|
|
||||||
pub session_id: Uuid,
|
|
||||||
pub identifier: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LoginCache {
|
|
||||||
pub session_id: Uuid,
|
|
||||||
pub identifiers: Vec<u8>,
|
|
||||||
pub server_login: ServerLogin<NKodeCipherSuite>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CredKind {
|
|
||||||
fn has<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> bool;
|
|
||||||
fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError>;
|
|
||||||
fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError>;
|
|
||||||
fn prereq_for_register<R: OpaqueDatabaseRepo>(_repo: &R, _id: &[u8]) -> Result<(), AuthRepoError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Key;
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Code;
|
|
||||||
|
|
||||||
impl CredKind for Key {
|
|
||||||
fn has<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> bool {
|
|
||||||
repo.has_key(id)
|
|
||||||
}
|
|
||||||
fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError> {
|
|
||||||
repo.get_key_passcode_file(id)
|
|
||||||
}
|
|
||||||
fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError> {
|
|
||||||
repo.new_key(id, pf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CredKind for Code {
|
|
||||||
fn has<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> bool {
|
|
||||||
repo.has_code(id)
|
|
||||||
}
|
|
||||||
fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError> {
|
|
||||||
repo.get_code_passcode_file(id)
|
|
||||||
}
|
|
||||||
fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError> {
|
|
||||||
repo.new_code(id, pf)
|
|
||||||
}
|
|
||||||
fn prereq_for_register<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<(), AuthRepoError> {
|
|
||||||
if repo.has_key(id) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(AuthRepoError::KeyNotRegistered)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OpaqueAuth<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> {
|
|
||||||
server_setup: NKodeServerSetup,
|
|
||||||
user_repo: R,
|
|
||||||
session: S,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
|
|
||||||
pub fn new(server_setup: NKodeServerSetup, user_repo: R, session: S) -> Self {
|
|
||||||
Self { server_setup, user_repo, session }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn reg_start<K: CredKind>(
|
|
||||||
&mut self,
|
|
||||||
identifier: &[u8],
|
|
||||||
request: RegistrationRequest<NKodeCipherSuite>,
|
|
||||||
) -> Result<OpaqueRegisterSession, String> {
|
|
||||||
K::prereq_for_register(&self.user_repo, identifier)
|
|
||||||
.map_err(|e| format!("registration prereq failed: {e:?}"))?;
|
|
||||||
let start = ServerRegistration::<NKodeCipherSuite>::start(
|
|
||||||
&self.server_setup,
|
|
||||||
request,
|
|
||||||
identifier,
|
|
||||||
).map_err(|e| format!("opaque reg start: {e:?}"))?;
|
|
||||||
let cache = self.session
|
|
||||||
.new_reg_session(identifier)
|
|
||||||
.map_err(|e| format!("reg cache: {e}"))?;
|
|
||||||
|
|
||||||
Ok(OpaqueRegisterSession { session_id: cache.session_id, response: start.message })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn reg_finish<K: CredKind>(
|
|
||||||
&mut self,
|
|
||||||
session_id: &Uuid,
|
|
||||||
password_file: PasswordFile,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let sess = self.session
|
|
||||||
.get_reg_session(session_id)
|
|
||||||
.map_err(|e| format!("get reg session: {e}"))?;
|
|
||||||
K::prereq_for_register(&self.user_repo, sess.identifier.as_slice())
|
|
||||||
.map_err(|e| format!("registration prereq failed: {e:?}"))?;
|
|
||||||
K::set_password_file(&mut self.user_repo, sess.identifier.as_slice(), password_file)
|
|
||||||
.map_err(|e| format!("repo write: {e:?}"))?;
|
|
||||||
self.session
|
|
||||||
.clear_reg_session(session_id)
|
|
||||||
.map_err(|e| format!("clear reg session: {e}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn login_start<K: CredKind>(
|
|
||||||
&mut self,
|
|
||||||
identifier: &[u8],
|
|
||||||
request: CredentialRequest<NKodeCipherSuite>,
|
|
||||||
) -> Result<OpaqueLoginSession, String> {
|
|
||||||
let password_file = K::get_password_file(&self.user_repo, identifier)
|
|
||||||
.map_err(|e| format!("repo read: {e:?}"))?;
|
|
||||||
|
|
||||||
let password_file =
|
|
||||||
ServerRegistration::<NKodeCipherSuite>::deserialize(password_file.as_slice())
|
|
||||||
.map_err(|e| format!("pf deserialize: {e:?}"))?;
|
|
||||||
let mut server_rng = OsRng;
|
|
||||||
let start = ServerLogin::start(
|
|
||||||
&mut server_rng,
|
|
||||||
&self.server_setup,
|
|
||||||
Some(password_file),
|
|
||||||
request,
|
|
||||||
identifier,
|
|
||||||
ServerLoginParameters::default(),
|
|
||||||
).map_err(|e| format!("opaque login start: {e:?}"))?;
|
|
||||||
let cache = self.session
|
|
||||||
.new_login_session(identifier, start.state)
|
|
||||||
.map_err(|e| format!("login cache: {e}"))?;
|
|
||||||
Ok(OpaqueLoginSession { session_id: cache.session_id, response: start.message })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn login_finish<K: CredKind>(
|
|
||||||
&mut self,
|
|
||||||
session_id: &Uuid,
|
|
||||||
finalize: CredentialFinalization<NKodeCipherSuite>,
|
|
||||||
) -> Result<OpaqueSessionKey, String> {
|
|
||||||
let cache = self.session
|
|
||||||
.get_login_session(session_id)
|
|
||||||
.map_err(|e| format!("get login session: {e}"))?;
|
|
||||||
|
|
||||||
let finish = cache.server_login
|
|
||||||
.finish(finalize, ServerLoginParameters::default())
|
|
||||||
.map_err(|e| format!("opaque login finish: {e:?}"))?;
|
|
||||||
|
|
||||||
self.session
|
|
||||||
.clear_login_session(session_id)
|
|
||||||
.map_err(|e| format!("clear login session: {e}"))?;
|
|
||||||
|
|
||||||
Ok(OpaqueSessionKey::from_bytes(&finish.session_key.to_vec()).unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::shared::models::opaque::PasswordFile;
|
use crate::shared::models::opaque::PasswordFile;
|
||||||
use crate::server::repository::opaque::repos::{OpaqueDatabaseRepo, AuthRepoError};
|
use crate::server::repository::opaque_repo::{OpaqueDatabaseRepo, AuthRepoError};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct InMemoryAuthRepo {
|
pub struct InMemoryOpaqueDB {
|
||||||
key_entries: HashMap<KeyID, PasswordFile>,
|
key_entries: HashMap<KeyID, PasswordFile>,
|
||||||
code_entries: HashMap<CodeID, PasswordFile>,
|
code_entries: HashMap<CodeID, PasswordFile>,
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ pub struct KeyID(Vec<u8>);
|
|||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct CodeID(Vec<u8>);
|
pub struct CodeID(Vec<u8>);
|
||||||
|
|
||||||
impl InMemoryAuthRepo {
|
impl InMemoryOpaqueDB {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ impl InMemoryAuthRepo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpaqueDatabaseRepo for InMemoryAuthRepo {
|
impl OpaqueDatabaseRepo for InMemoryOpaqueDB {
|
||||||
fn new_key(
|
fn new_key(
|
||||||
&mut self,
|
&mut self,
|
||||||
identifier: &[u8],
|
identifier: &[u8],
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::server::opaque::{LoginCache, RegCache};
|
|
||||||
use opaque_ke::ServerLogin;
|
use opaque_ke::ServerLogin;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use crate::server::models::{LoginCache, RegCache};
|
||||||
use crate::shared::models::opaque::NKodeCipherSuite;
|
use crate::shared::models::opaque::NKodeCipherSuite;
|
||||||
use crate::server::repository::opaque::repos::OpaqueSessionRepo;
|
use crate::server::repository::opaque_repo::OpaqueSessionRepo;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct InMemoryAuthSession {
|
pub struct InMemoryOpaqueSession {
|
||||||
reg_sessions: HashMap<Uuid, RegCache>,
|
reg_sessions: HashMap<Uuid, RegCache>,
|
||||||
login_sessions: HashMap<Uuid, LoginCache>,
|
login_sessions: HashMap<Uuid, LoginCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InMemoryAuthSession {
|
impl InMemoryOpaqueSession {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpaqueSessionRepo for InMemoryAuthSession {
|
impl OpaqueSessionRepo for InMemoryOpaqueSession {
|
||||||
fn new_reg_session(&mut self, identifier: &[u8]) -> Result<RegCache, String> {
|
fn new_reg_session(&mut self, identifier: &[u8]) -> Result<RegCache, String> {
|
||||||
let cache = RegCache {
|
let cache = RegCache {
|
||||||
session_id: Uuid::new_v4(),
|
session_id: Uuid::new_v4(),
|
||||||
100
src/server/repository/in_memory/in_memory_transport.rs
Normal file
100
src/server/repository/in_memory/in_memory_transport.rs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use uuid::Uuid;
|
||||||
|
use opaque_ke::{CredentialFinalization, CredentialRequest, RegistrationRequest};
|
||||||
|
use crate::shared::models::opaque::{NKodeCipherSuite, NKodeServerSetup, OpaqueLoginSession, OpaqueRegisterSession, PasswordFile};
|
||||||
|
use crate::client::opaque::{ClientAuthError, ServerConnectionLogin, ServerConnectionRegister};
|
||||||
|
use crate::server::app::{Code, Key};
|
||||||
|
use crate::server::app::ServerApp;
|
||||||
|
use crate::server::models::CredKind;
|
||||||
|
use crate::server::repository::in_memory::in_memory_opaque_db::InMemoryOpaqueDB;
|
||||||
|
use crate::server::repository::in_memory::in_memory_opaque_session::InMemoryOpaqueSession;
|
||||||
|
use crate::server::repository::in_memory::in_memory_user_db::InMemoryUserDB;
|
||||||
|
use crate::shared::models::app::LoggedInSession;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct InMemoryServer<K: CredKind> {
|
||||||
|
auth_db: Arc<Mutex<ServerApp<InMemoryOpaqueDB, InMemoryOpaqueSession, InMemoryUserDB>>>,
|
||||||
|
_kind: PhantomData<K>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: CredKind> InMemoryServer<K> {
|
||||||
|
pub fn new(server_setup: NKodeServerSetup) -> Self {
|
||||||
|
Self {
|
||||||
|
auth_db: Arc::new(Mutex::new(
|
||||||
|
ServerApp::new(
|
||||||
|
server_setup,
|
||||||
|
InMemoryOpaqueDB::new(),
|
||||||
|
InMemoryOpaqueSession::new(),
|
||||||
|
InMemoryUserDB::new()
|
||||||
|
)
|
||||||
|
)),
|
||||||
|
_kind: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type InMemoryKeyServer = InMemoryServer<Key>;
|
||||||
|
pub type InMemoryCodeServer = InMemoryServer<Code>;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<K> ServerConnectionRegister for InMemoryServer<K>
|
||||||
|
where
|
||||||
|
K: CredKind + Sync,
|
||||||
|
{
|
||||||
|
async fn start(
|
||||||
|
&self,
|
||||||
|
identifier: &[u8],
|
||||||
|
message: &RegistrationRequest<NKodeCipherSuite>,
|
||||||
|
) -> Result<OpaqueRegisterSession, ClientAuthError> {
|
||||||
|
// Server API takes ownership; client trait gives us a reference.
|
||||||
|
// opaque-ke request types are typically Clone; if not, you'll need to adjust signatures.
|
||||||
|
self.auth_db.lock().await
|
||||||
|
.reg_start::<K>(identifier, message.clone())
|
||||||
|
.await
|
||||||
|
.map_err(|e| ClientAuthError::Transport(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn finish(
|
||||||
|
&self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
password_file: PasswordFile,
|
||||||
|
) -> Result<(), ClientAuthError> {
|
||||||
|
self.auth_db.lock().await
|
||||||
|
.reg_finish::<K>(session_id, password_file)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ClientAuthError::Transport(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<K> ServerConnectionLogin for InMemoryServer<K>
|
||||||
|
where
|
||||||
|
K: CredKind + Send + Sync,
|
||||||
|
{
|
||||||
|
async fn start(
|
||||||
|
&self,
|
||||||
|
identifier: &[u8],
|
||||||
|
request: &CredentialRequest<NKodeCipherSuite>,
|
||||||
|
) -> Result<OpaqueLoginSession, ClientAuthError> {
|
||||||
|
self.auth_db.lock().await
|
||||||
|
.login_start::<K>(identifier, request.clone())
|
||||||
|
.await
|
||||||
|
.map_err(|e| ClientAuthError::Transport(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn finish(
|
||||||
|
&self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
message: &CredentialFinalization<NKodeCipherSuite>,
|
||||||
|
) -> Result<LoggedInSession, ClientAuthError> {
|
||||||
|
Ok(self
|
||||||
|
.auth_db.lock().await
|
||||||
|
.login_finish(session_id, message.clone())
|
||||||
|
.await
|
||||||
|
.map_err(|e| ClientAuthError::Transport(e))?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/server/repository/in_memory/in_memory_user_db.rs
Normal file
67
src/server/repository/in_memory/in_memory_user_db.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use uuid::Uuid;
|
||||||
|
use crate::server::repository::user_repo::UserRepo;
|
||||||
|
use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession};
|
||||||
|
use crate::shared::models::email::Email;
|
||||||
|
|
||||||
|
pub struct InMemoryUserDB {
|
||||||
|
key_session: HashMap<Uuid, KeyLoggedInSession>,
|
||||||
|
code_session: HashMap<Uuid, CodeLoggedInSession>,
|
||||||
|
code_data: HashMap<Email, CodeLoginData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InMemoryUserDB {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
key_session: HashMap::new(),
|
||||||
|
code_session: HashMap::new(),
|
||||||
|
code_data: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InMemoryUserDB {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserRepo for InMemoryUserDB {
|
||||||
|
fn get_key_session(&mut self, session_id: &Uuid) -> Result<KeyLoggedInSession, String> {
|
||||||
|
self.key_session
|
||||||
|
.get(&session_id)
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| format!("key session not found for session_id={}", session_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_code_session(&mut self, session_id: &Uuid) -> Result<CodeLoggedInSession, String> {
|
||||||
|
self.code_session
|
||||||
|
.get(&session_id)
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| format!("code session not found for session_id={}", session_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_key_session(&mut self, session: KeyLoggedInSession) -> Result<(), String> {
|
||||||
|
// Assumes KeyLoggedInSession has a session_id: Uuid field (common pattern)
|
||||||
|
self.key_session.insert(session.0.session_id, session);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_code_session(&mut self, session: CodeLoggedInSession) -> Result<(), String> {
|
||||||
|
// Assumes CodeLoggedInSession has a session_id: Uuid field (common pattern)
|
||||||
|
self.code_session.insert(session.0.session_id, session);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_code_login_data(&mut self, email: Email, data: CodeLoginData) -> Result<(), String> {
|
||||||
|
self.code_data.insert(email, data);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_code_login_data(&mut self, email: &Email) -> Result<CodeLoginData, String> {
|
||||||
|
self.code_data
|
||||||
|
.get(email)
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| "code login data not found for email".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/server/repository/in_memory/mod.rs
Normal file
4
src/server/repository/in_memory/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub mod in_memory_opaque_db;
|
||||||
|
pub mod in_memory_transport;
|
||||||
|
pub mod in_memory_opaque_session;
|
||||||
|
mod in_memory_user_db;
|
||||||
@@ -1 +1,3 @@
|
|||||||
pub mod opaque;
|
pub mod in_memory;
|
||||||
|
pub mod opaque_repo;
|
||||||
|
pub mod user_repo;
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
use async_trait::async_trait;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use tokio::sync::Mutex;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use uuid::Uuid;
|
|
||||||
use opaque_ke::{CredentialFinalization, CredentialRequest, RegistrationRequest};
|
|
||||||
use crate::shared::models::opaque::{OpaqueLoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, OpaqueRegisterSession};
|
|
||||||
use crate::client::opaque::{ClientAuthError, ServerConnectionLogin, ServerConnectionRegister};
|
|
||||||
use crate::server::opaque::{OpaqueAuth, CredKind, Key, Code};
|
|
||||||
use crate::server::repository::opaque::in_memory::in_memory_auth_repo::InMemoryAuthRepo;
|
|
||||||
use crate::server::repository::opaque::in_memory::in_memory_auth_session::InMemoryAuthSession;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct InMemoryServer<K: CredKind> {
|
|
||||||
auth: Arc<Mutex<OpaqueAuth<InMemoryAuthRepo, InMemoryAuthSession>>>,
|
|
||||||
_kind: PhantomData<K>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K: CredKind> InMemoryServer<K> {
|
|
||||||
pub fn new(server_setup: NKodeServerSetup) -> Self {
|
|
||||||
Self {
|
|
||||||
auth: Arc::new(Mutex::new(OpaqueAuth::new(server_setup, InMemoryAuthRepo::new(), InMemoryAuthSession::new()))),
|
|
||||||
_kind: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type InMemoryKeyServer = InMemoryServer<Key>;
|
|
||||||
pub type InMemoryCodeServer = InMemoryServer<Code>;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<K> ServerConnectionRegister for InMemoryServer<K>
|
|
||||||
where
|
|
||||||
K: CredKind + Sync,
|
|
||||||
{
|
|
||||||
async fn start(
|
|
||||||
&self,
|
|
||||||
identifier: &[u8],
|
|
||||||
message: &RegistrationRequest<NKodeCipherSuite>,
|
|
||||||
) -> Result<OpaqueRegisterSession, ClientAuthError> {
|
|
||||||
// Server API takes ownership; client trait gives us a reference.
|
|
||||||
// opaque-ke request types are typically Clone; if not, you'll need to adjust signatures.
|
|
||||||
self.auth.lock().await
|
|
||||||
.reg_start::<K>(identifier, message.clone())
|
|
||||||
.await
|
|
||||||
.map_err(|e| ClientAuthError::Transport(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn finish(
|
|
||||||
&self,
|
|
||||||
session_id: &Uuid,
|
|
||||||
password_file: PasswordFile,
|
|
||||||
) -> Result<(), ClientAuthError> {
|
|
||||||
self.auth.lock().await
|
|
||||||
.reg_finish::<K>(session_id, password_file)
|
|
||||||
.await
|
|
||||||
.map_err(|e| ClientAuthError::Transport(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<K> ServerConnectionLogin for InMemoryServer<K>
|
|
||||||
where
|
|
||||||
K: CredKind + Send + Sync,
|
|
||||||
{
|
|
||||||
async fn start(
|
|
||||||
&self,
|
|
||||||
identifier: &[u8],
|
|
||||||
request: &CredentialRequest<NKodeCipherSuite>,
|
|
||||||
) -> Result<OpaqueLoginSession, ClientAuthError> {
|
|
||||||
self.auth.lock().await
|
|
||||||
.login_start::<K>(identifier, request.clone())
|
|
||||||
.await
|
|
||||||
.map_err(|e| ClientAuthError::Transport(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn finish(
|
|
||||||
&self,
|
|
||||||
session_id: &Uuid,
|
|
||||||
message: &CredentialFinalization<NKodeCipherSuite>,
|
|
||||||
) -> Result<OpaqueSessionKey, ClientAuthError> {
|
|
||||||
// Server computes its own session key too; we just need it to validate and complete.
|
|
||||||
let key = self
|
|
||||||
.auth.lock().await
|
|
||||||
.login_finish::<K>(session_id, message.clone())
|
|
||||||
.await
|
|
||||||
.map_err(|e| ClientAuthError::Transport(e))?;
|
|
||||||
|
|
||||||
Ok(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub struct InMemSharedServer<K> {
|
|
||||||
// inner: Arc<Mutex<OpaqueAuth<InMemoryAuthRepo, InMemoryAuthSession>>>,
|
|
||||||
// _k: PhantomData<K>,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl<K> InMemSharedServer<K> {
|
|
||||||
// pub fn new(inner: Arc<Mutex<OpaqueAuth<InMemoryAuthRepo, InMemoryAuthSession>>>) -> Self {
|
|
||||||
// Self { inner, _k: PhantomData }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #[async_trait::async_trait]
|
|
||||||
// impl<K> ServerConnectionRegister for InMemSharedServer<K>
|
|
||||||
// where
|
|
||||||
// K: CredKind + Send + Sync,
|
|
||||||
// {
|
|
||||||
// async fn start(
|
|
||||||
// &mut self,
|
|
||||||
// identifier: &[u8],
|
|
||||||
// message: &RegistrationRequest<NKodeCipherSuite>,
|
|
||||||
// ) -> Result<RegisterSession, ClientAuthError> {
|
|
||||||
// let mut guard = self.inner.lock().await;
|
|
||||||
// guard
|
|
||||||
// .reg_start::<K>(identifier, message.clone())
|
|
||||||
// .await
|
|
||||||
// .map_err(ClientAuthError::Transport)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn finish(
|
|
||||||
// &mut self,
|
|
||||||
// session_id: &Uuid,
|
|
||||||
// password_file: PasswordFile,
|
|
||||||
// ) -> Result<(), ClientAuthError> {
|
|
||||||
// let mut guard = self.inner.lock().await;
|
|
||||||
// guard
|
|
||||||
// .reg_finish::<K>(session_id, password_file)
|
|
||||||
// .await
|
|
||||||
// .map_err(ClientAuthError::Transport)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #[async_trait::async_trait]
|
|
||||||
// impl<K> ServerConnectionLogin for InMemSharedServer<K>
|
|
||||||
// where
|
|
||||||
// K: CredKind + Send + Sync,
|
|
||||||
// {
|
|
||||||
// async fn start(
|
|
||||||
// &mut self,
|
|
||||||
// identifier: &[u8],
|
|
||||||
// request: &CredentialRequest<NKodeCipherSuite>,
|
|
||||||
// ) -> Result<LoginSession, ClientAuthError> {
|
|
||||||
// let mut guard = self.inner.lock().await;
|
|
||||||
// guard
|
|
||||||
// .login_start::<K>(identifier, request.clone())
|
|
||||||
// .await
|
|
||||||
// .map_err(ClientAuthError::Transport)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn finish(
|
|
||||||
// &mut self,
|
|
||||||
// session_id: &Uuid,
|
|
||||||
// message: &CredentialFinalization<NKodeCipherSuite>,
|
|
||||||
// ) -> Result<OpaqueSessionKey, ClientAuthError> {
|
|
||||||
// let mut guard = self.inner.lock().await;
|
|
||||||
// let key = guard
|
|
||||||
// .login_finish::<K>(session_id, message.clone())
|
|
||||||
// .await
|
|
||||||
// .map_err(ClientAuthError::Transport)?;
|
|
||||||
// Ok(key)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
pub mod in_memory_auth_repo;
|
|
||||||
pub mod in_memory_transport;
|
|
||||||
pub mod in_memory_auth_session;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
pub mod in_memory;
|
|
||||||
pub mod repos;
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use opaque_ke::ServerLogin;
|
use opaque_ke::ServerLogin;
|
||||||
|
use crate::server::models::{LoginCache, RegCache};
|
||||||
use crate::shared::models::opaque::{NKodeCipherSuite, PasswordFile};
|
use crate::shared::models::opaque::{NKodeCipherSuite, PasswordFile};
|
||||||
use crate::server::opaque::{LoginCache, RegCache};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AuthRepoError {
|
pub enum AuthRepoError {
|
||||||
UserExists,
|
UserExists,
|
||||||
14
src/server/repository/user_repo.rs
Normal file
14
src/server/repository/user_repo.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use uuid::Uuid;
|
||||||
|
use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession};
|
||||||
|
use crate::shared::models::email::Email;
|
||||||
|
|
||||||
|
pub trait UserRepo {
|
||||||
|
fn get_key_session(&mut self, session_id: &Uuid) -> Result<KeyLoggedInSession, String>;
|
||||||
|
fn get_code_session(&mut self, session_id: &Uuid) -> Result<CodeLoggedInSession, String>;
|
||||||
|
|
||||||
|
fn set_key_session(&mut self, session: KeyLoggedInSession) -> Result<(), String>;
|
||||||
|
fn set_code_session(&mut self, session: CodeLoggedInSession) -> Result<(), String>;
|
||||||
|
|
||||||
|
fn set_code_login_data(&mut self, email: Email, data: CodeLoginData) -> Result<(), String>;
|
||||||
|
fn get_code_login_data(&mut self, email: &Email) -> Result<CodeLoginData, String>;
|
||||||
|
}
|
||||||
@@ -4,15 +4,23 @@ use serde::{Deserialize, Serialize};
|
|||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use nkode_rs::from_bytes::FromBytes;
|
use nkode_rs::from_bytes::FromBytes;
|
||||||
use nkode_rs::nkode_core::policy::NKodePolicy;
|
use nkode_rs::nkode_core::policy::NKodePolicy;
|
||||||
|
use uuid::Uuid;
|
||||||
use crate::shared::models::email::Email;
|
use crate::shared::models::email::Email;
|
||||||
use crate::shared::models::opaque::{OpaqueSessionKey, UserSecretKey};
|
use crate::shared::models::opaque::{OpaqueSessionKey, UserSecretKey};
|
||||||
pub struct LoginSession {
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct LoggedInSession {
|
||||||
|
pub(crate) session_id: Uuid,
|
||||||
pub(crate) email: Email,
|
pub(crate) email: Email,
|
||||||
pub(crate) session_key: OpaqueSessionKey,
|
pub(crate) session_key: OpaqueSessionKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct KeyLoginSession(pub(crate) LoginSession);
|
#[derive(Debug, Clone)]
|
||||||
pub struct CodeLoginSession(pub(crate) LoginSession);
|
pub struct KeyLoggedInSession(pub(crate) LoggedInSession);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CodeLoggedInSession(pub(crate) LoggedInSession);
|
||||||
|
|
||||||
pub const ICON_ID_SIZE: usize = 32;
|
pub const ICON_ID_SIZE: usize = 32;
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
@@ -53,16 +61,16 @@ pub struct CodeLoginData {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait OpaqueAPI {
|
pub trait OpaqueAPI {
|
||||||
async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String>;
|
async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String>;
|
||||||
async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoginSession, data: &CodeLoginData) -> Result<(), String>;
|
async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoggedInSession, data: &CodeLoginData) -> Result<(), String>;
|
||||||
async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoginSession, String>;
|
async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoggedInSession, String>;
|
||||||
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String>;
|
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoggedInSession, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AuthAPI {
|
pub trait AuthAPI {
|
||||||
async fn get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result<Vec<Icon>, String>;
|
async fn get_new_icons(&self, key_login_session: &KeyLoggedInSession) -> Result<Vec<Icon>, String>;
|
||||||
async fn get_login_data(&self, key_login_session: &KeyLoginSession) -> Result<CodeLoginData, String>;
|
async fn get_login_data(&self, key_login_session: &KeyLoggedInSession) -> Result<CodeLoginData, String>;
|
||||||
async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String>;
|
async fn is_code_registered(&self, key_login_session: &KeyLoggedInSession) -> Result<bool, String>;
|
||||||
async fn get_policy(&self) -> Result<NKodePolicy, String>;
|
async fn get_policy(&self) -> Result<NKodePolicy, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ impl FromBytes<USER_KEY_SIZE> for UserSecretKey {
|
|||||||
|
|
||||||
const OPAQUE_SESSION_KEY_SIZE: usize = 64;
|
const OPAQUE_SESSION_KEY_SIZE: usize = 64;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct OpaqueSessionKey(Zeroizing<[u8; OPAQUE_SESSION_KEY_SIZE]>);
|
pub struct OpaqueSessionKey(Zeroizing<[u8; OPAQUE_SESSION_KEY_SIZE]>);
|
||||||
|
|
||||||
impl FromBytes<OPAQUE_SESSION_KEY_SIZE> for OpaqueSessionKey {
|
impl FromBytes<OPAQUE_SESSION_KEY_SIZE> for OpaqueSessionKey {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use opaque_ke::rand::rngs::OsRng;
|
use opaque_ke::rand::rngs::OsRng;
|
||||||
use nkode_protocol::client::opaque::{AuthenticationData, ClientAuthError, OpaqueAuthLogin, OpaqueAuthRegister};
|
use nkode_protocol::client::opaque::{AuthenticationData, ClientAuthError, OpaqueAuthLogin, OpaqueAuthRegister};
|
||||||
use nkode_protocol::shared::models::opaque::NKodeServerSetup;
|
use nkode_protocol::shared::models::opaque::NKodeServerSetup;
|
||||||
use nkode_protocol::server::repository::opaque::in_memory::in_memory_transport::{InMemoryCodeServer, InMemoryKeyServer};
|
use nkode_protocol::server::repository::in_memory::in_memory_transport::{InMemoryCodeServer, InMemoryKeyServer};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn opaque_key_registration_and_login_roundtrip() {
|
async fn opaque_key_registration_and_login_roundtrip() {
|
||||||
@@ -15,7 +15,6 @@ async fn opaque_key_registration_and_login_roundtrip() {
|
|||||||
let _ =login_reg.login(&auth_data)
|
let _ =login_reg.login(&auth_data)
|
||||||
.await
|
.await
|
||||||
.expect("login should succeed");
|
.expect("login should succeed");
|
||||||
// assert!(!session_key.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
Reference in New Issue
Block a user