Register clients' passwords using OPAQUE
This commit is contained in:
committed by
nitnelave
parent
8b73de0df7
commit
e09c73efce
@@ -3,7 +3,6 @@ use crate::infra::configuration::Configuration;
|
||||
use async_trait::async_trait;
|
||||
use futures_util::StreamExt;
|
||||
use futures_util::TryStreamExt;
|
||||
use lldap_model::opaque;
|
||||
use sea_query::{Expr, Iden, Order, Query, SimpleExpr, Value};
|
||||
use sqlx::Row;
|
||||
use std::collections::HashSet;
|
||||
@@ -20,33 +19,6 @@ impl SqlBackendHandler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_password_file(
|
||||
clear_password: &str,
|
||||
server_setup: &opaque::server::ServerSetup,
|
||||
username: &str,
|
||||
) -> Result<opaque::server::ServerRegistration> {
|
||||
use opaque::{client, server};
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
let client_register_start_result =
|
||||
client::registration::start_registration(clear_password, &mut rng)?;
|
||||
|
||||
let server_register_start_result = server::registration::start_registration(
|
||||
server_setup,
|
||||
client_register_start_result.message,
|
||||
username,
|
||||
)?;
|
||||
|
||||
let client_registration_result = client::registration::finish_registration(
|
||||
client_register_start_result.state,
|
||||
server_register_start_result.message,
|
||||
&mut rng,
|
||||
)?;
|
||||
|
||||
Ok(server::registration::get_password_file(
|
||||
client_registration_result.message,
|
||||
))
|
||||
}
|
||||
|
||||
fn get_filter_expr(filter: RequestFilter) -> SimpleExpr {
|
||||
use RequestFilter::*;
|
||||
fn get_repeated_filter(
|
||||
@@ -178,7 +150,7 @@ impl BackendHandler for SqlBackendHandler {
|
||||
}
|
||||
|
||||
async fn create_user(&self, request: CreateUserRequest) -> Result<()> {
|
||||
let mut columns = vec![
|
||||
let columns = vec![
|
||||
Users::UserId,
|
||||
Users::Email,
|
||||
Users::DisplayName,
|
||||
@@ -186,7 +158,7 @@ impl BackendHandler for SqlBackendHandler {
|
||||
Users::LastName,
|
||||
Users::CreationDate,
|
||||
];
|
||||
let mut values = vec![
|
||||
let values = vec![
|
||||
request.user_id.clone().into(),
|
||||
request.email.into(),
|
||||
request.display_name.map(Into::into).unwrap_or(Value::Null),
|
||||
@@ -194,14 +166,6 @@ impl BackendHandler for SqlBackendHandler {
|
||||
request.last_name.map(Into::into).unwrap_or(Value::Null),
|
||||
chrono::Utc::now().naive_utc().into(),
|
||||
];
|
||||
if let Some(pass) = request.password {
|
||||
columns.push(Users::PasswordHash);
|
||||
values.push(
|
||||
get_password_file(&pass, self.config.get_server_setup(), &request.user_id)?
|
||||
.serialize()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
let query = Query::insert()
|
||||
.into_table(Users::Table)
|
||||
.columns(columns)
|
||||
@@ -271,12 +235,28 @@ mod tests {
|
||||
}
|
||||
|
||||
async fn insert_user(handler: &SqlBackendHandler, name: &str, pass: &str) {
|
||||
use crate::domain::opaque_handler::OpaqueHandler;
|
||||
insert_user_no_password(handler, name).await;
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
let client_registration_start =
|
||||
opaque::client::registration::start_registration(pass, &mut rng).unwrap();
|
||||
let response = handler
|
||||
.registration_start(registration::ClientRegistrationStartRequest {
|
||||
username: name.to_string(),
|
||||
registration_start_request: client_registration_start.message,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let registration_upload = opaque::client::registration::finish_registration(
|
||||
client_registration_start.state,
|
||||
response.registration_response,
|
||||
&mut rng,
|
||||
)
|
||||
.unwrap();
|
||||
handler
|
||||
.create_user(CreateUserRequest {
|
||||
user_id: name.to_string(),
|
||||
email: "bob@bob.bob".to_string(),
|
||||
password: Some(pass.to_string()),
|
||||
..Default::default()
|
||||
.registration_finish(registration::ClientRegistrationFinishRequest {
|
||||
server_data: response.server_data,
|
||||
registration_upload: registration_upload.message,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -55,10 +55,16 @@ impl SqlBackendHandler {
|
||||
.and_where(Expr::col(Users::UserId).eq(username))
|
||||
.to_string(DbQueryBuilder {});
|
||||
if let Some(row) = sqlx::query(&query).fetch_optional(&self.sql_pool).await? {
|
||||
row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHash.to_string())
|
||||
// If no password, always fail.
|
||||
.ok_or_else(|| DomainError::AuthenticationError(username.to_string()))?
|
||||
if let Some(bytes) =
|
||||
row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHash.to_string())
|
||||
{
|
||||
bytes
|
||||
} else {
|
||||
// No password set.
|
||||
return Ok(None);
|
||||
}
|
||||
} else {
|
||||
// No such user.
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
@@ -119,6 +125,7 @@ impl OpaqueHandler for SqlOpaqueHandler {
|
||||
let maybe_password_file = self.get_password_file_for_user(&request.username).await?;
|
||||
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
// Get the CredentialResponse for the user, or a dummy one if no user/no password.
|
||||
let start_response = opaque::server::login::start_login(
|
||||
&mut rng,
|
||||
self.config.get_server_setup(),
|
||||
|
||||
@@ -17,7 +17,6 @@ async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration)
|
||||
handler
|
||||
.create_user(lldap_model::CreateUserRequest {
|
||||
user_id: config.ldap_user_dn.clone(),
|
||||
password: Some(config.ldap_user_pass.clone()),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user