mirror of
				https://github.com/nitnelave/lldap.git
				synced 2023-04-12 14:25:13 +00:00 
			
		
		
		
	Register clients' passwords using OPAQUE
This commit is contained in:
		
							parent
							
								
									8b73de0df7
								
							
						
					
					
						commit
						b77b34af09
					
				@ -76,40 +76,48 @@ where
 | 
				
			|||||||
    FetchService::fetch_with_options(request, get_default_options(), handler)
 | 
					    FetchService::fetch_with_options(request, get_default_options(), handler)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn call_server_json_with_error_message<CallbackResult, RB, Req>(
 | 
				
			||||||
 | 
					    url: &str,
 | 
				
			||||||
 | 
					    request: RB,
 | 
				
			||||||
 | 
					    callback: Callback<Result<CallbackResult>>,
 | 
				
			||||||
 | 
					    error_message: &'static str,
 | 
				
			||||||
 | 
					) -> Result<FetchTask>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    CallbackResult: serde::de::DeserializeOwned + 'static,
 | 
				
			||||||
 | 
					    RB: Into<RequestBody<Req>>,
 | 
				
			||||||
 | 
					    Req: Into<yew::format::Text>,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    call_server(
 | 
				
			||||||
 | 
					        url,
 | 
				
			||||||
 | 
					        request,
 | 
				
			||||||
 | 
					        callback,
 | 
				
			||||||
 | 
					        move |status: http::StatusCode, data: String| {
 | 
				
			||||||
 | 
					            if status.is_success() {
 | 
				
			||||||
 | 
					                serde_json::from_str(&data).map_err(|e| anyhow!("Could not parse response: {}", e))
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Err(anyhow!("{}[{}]: {}", error_message, status, data))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl HostService {
 | 
					impl HostService {
 | 
				
			||||||
    pub fn list_users(
 | 
					    pub fn list_users(
 | 
				
			||||||
        request: ListUsersRequest,
 | 
					        request: ListUsersRequest,
 | 
				
			||||||
        callback: Callback<Result<Vec<User>>>,
 | 
					        callback: Callback<Result<Vec<User>>>,
 | 
				
			||||||
    ) -> Result<FetchTask> {
 | 
					    ) -> Result<FetchTask> {
 | 
				
			||||||
        call_server("/api/users", &request, callback, |status, data: String| {
 | 
					        call_server_json_with_error_message("/api/users", &request, callback, "")
 | 
				
			||||||
            if status.is_success() {
 | 
					 | 
				
			||||||
                serde_json::from_str(&data).map_err(|e| anyhow!("Could not parse response: {}", e))
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                Err(anyhow!("[{}]: {}", status, data))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn login_start(
 | 
					    pub fn login_start(
 | 
				
			||||||
        request: login::ClientLoginStartRequest,
 | 
					        request: login::ClientLoginStartRequest,
 | 
				
			||||||
        callback: Callback<Result<Box<login::ServerLoginStartResponse>>>,
 | 
					        callback: Callback<Result<Box<login::ServerLoginStartResponse>>>,
 | 
				
			||||||
    ) -> Result<FetchTask> {
 | 
					    ) -> Result<FetchTask> {
 | 
				
			||||||
        call_server(
 | 
					        call_server_json_with_error_message(
 | 
				
			||||||
            "/auth/opaque/login/start",
 | 
					            "/auth/opaque/login/start",
 | 
				
			||||||
            &request,
 | 
					            &request,
 | 
				
			||||||
            callback,
 | 
					            callback,
 | 
				
			||||||
            |status, data: String| {
 | 
					            "Could not start authentication: ",
 | 
				
			||||||
                if status.is_success() {
 | 
					 | 
				
			||||||
                    serde_json::from_str(&data)
 | 
					 | 
				
			||||||
                        .map_err(|e| anyhow!("Could not parse response: {}", e))
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Err(anyhow!(
 | 
					 | 
				
			||||||
                        "Could not start authentication: [{}]: {}",
 | 
					 | 
				
			||||||
                        status,
 | 
					 | 
				
			||||||
                        data
 | 
					 | 
				
			||||||
                    ))
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -141,6 +149,36 @@ impl HostService {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn register_start(
 | 
				
			||||||
 | 
					        request: registration::ClientRegistrationStartRequest,
 | 
				
			||||||
 | 
					        callback: Callback<Result<Box<registration::ServerRegistrationStartResponse>>>,
 | 
				
			||||||
 | 
					    ) -> Result<FetchTask> {
 | 
				
			||||||
 | 
					        call_server_json_with_error_message(
 | 
				
			||||||
 | 
					            "/auth/opaque/registration/start",
 | 
				
			||||||
 | 
					            &request,
 | 
				
			||||||
 | 
					            callback,
 | 
				
			||||||
 | 
					            "Could not start registration: ",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn register_finish(
 | 
				
			||||||
 | 
					        request: registration::ClientRegistrationFinishRequest,
 | 
				
			||||||
 | 
					        callback: Callback<Result<()>>,
 | 
				
			||||||
 | 
					    ) -> Result<FetchTask> {
 | 
				
			||||||
 | 
					        call_server(
 | 
				
			||||||
 | 
					            "/auth/opaque/registration/finish",
 | 
				
			||||||
 | 
					            &request,
 | 
				
			||||||
 | 
					            callback,
 | 
				
			||||||
 | 
					            |status, data: String| {
 | 
				
			||||||
 | 
					                if status.is_success() {
 | 
				
			||||||
 | 
					                    Ok(())
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Err(anyhow!("Could finish registration: [{}]: {}", status, data))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn logout(callback: Callback<Result<()>>) -> Result<FetchTask> {
 | 
					    pub fn logout(callback: Callback<Result<()>>) -> Result<FetchTask> {
 | 
				
			||||||
        call_server(
 | 
					        call_server(
 | 
				
			||||||
            "/auth/logout",
 | 
					            "/auth/logout",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
use crate::api::HostService;
 | 
					use crate::api::HostService;
 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::{anyhow, Result};
 | 
				
			||||||
use lldap_model::*;
 | 
					use lldap_model::*;
 | 
				
			||||||
use yew::prelude::*;
 | 
					use yew::prelude::*;
 | 
				
			||||||
use yew::services::{fetch::FetchTask, ConsoleService};
 | 
					use yew::services::{fetch::FetchTask, ConsoleService};
 | 
				
			||||||
@ -13,6 +13,7 @@ pub struct CreateUserForm {
 | 
				
			|||||||
    route_dispatcher: RouteAgentDispatcher,
 | 
					    route_dispatcher: RouteAgentDispatcher,
 | 
				
			||||||
    node_ref: NodeRef,
 | 
					    node_ref: NodeRef,
 | 
				
			||||||
    error: Option<anyhow::Error>,
 | 
					    error: Option<anyhow::Error>,
 | 
				
			||||||
 | 
					    registration_start: Option<opaque::client::registration::ClientRegistration>,
 | 
				
			||||||
    // Used to keep the request alive long enough.
 | 
					    // Used to keep the request alive long enough.
 | 
				
			||||||
    _task: Option<FetchTask>,
 | 
					    _task: Option<FetchTask>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -20,19 +21,112 @@ pub struct CreateUserForm {
 | 
				
			|||||||
pub enum Msg {
 | 
					pub enum Msg {
 | 
				
			||||||
    CreateUserResponse(Result<()>),
 | 
					    CreateUserResponse(Result<()>),
 | 
				
			||||||
    SubmitForm,
 | 
					    SubmitForm,
 | 
				
			||||||
 | 
					    SuccessfulCreation,
 | 
				
			||||||
 | 
					    RegistrationStartResponse(Result<Box<registration::ServerRegistrationStartResponse>>),
 | 
				
			||||||
 | 
					    RegistrationFinishResponse(Result<()>),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::ptr_arg)]
 | 
				
			||||||
 | 
					fn not_empty(s: &String) -> bool {
 | 
				
			||||||
 | 
					    !s.is_empty()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl CreateUserForm {
 | 
					impl CreateUserForm {
 | 
				
			||||||
    fn create_user(&mut self, req: CreateUserRequest) {
 | 
					    fn handle_msg(&mut self, msg: <Self as Component>::Message) -> Result<()> {
 | 
				
			||||||
        match HostService::create_user(req, self.link.callback(Msg::CreateUserResponse)) {
 | 
					        match msg {
 | 
				
			||||||
            Ok(task) => self._task = Some(task),
 | 
					            Msg::SubmitForm => {
 | 
				
			||||||
            Err(e) => {
 | 
					                let req = CreateUserRequest {
 | 
				
			||||||
                self._task = None;
 | 
					                    user_id: get_element("username")
 | 
				
			||||||
                ConsoleService::log(format!("Error trying to create user: {}", e).as_str())
 | 
					                        .filter(not_empty)
 | 
				
			||||||
 | 
					                        .ok_or_else(|| anyhow!("Missing username"))?,
 | 
				
			||||||
 | 
					                    email: get_element("email")
 | 
				
			||||||
 | 
					                        .filter(not_empty)
 | 
				
			||||||
 | 
					                        .ok_or_else(|| anyhow!("Missing email"))?,
 | 
				
			||||||
 | 
					                    display_name: get_element("displayname").filter(not_empty),
 | 
				
			||||||
 | 
					                    first_name: get_element("firstname").filter(not_empty),
 | 
				
			||||||
 | 
					                    last_name: get_element("lastname").filter(not_empty),
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                self._task = Some(
 | 
				
			||||||
 | 
					                    HostService::create_user(req, self.link.callback(Msg::CreateUserResponse))
 | 
				
			||||||
 | 
					                        .map_err(|e| anyhow!("Error trying to create user: {}", e))?,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					            Msg::CreateUserResponse(r) => {
 | 
				
			||||||
 | 
					                if r.is_err() {
 | 
				
			||||||
 | 
					                    return r;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                let user_id = get_element("username")
 | 
				
			||||||
 | 
					                    .filter(not_empty)
 | 
				
			||||||
 | 
					                    .ok_or_else(|| anyhow!("Missing username"))?;
 | 
				
			||||||
 | 
					                if let Some(password) = get_element("password").filter(not_empty) {
 | 
				
			||||||
 | 
					                    // User was successfully created, let's register the password.
 | 
				
			||||||
 | 
					                    let mut rng = rand::rngs::OsRng;
 | 
				
			||||||
 | 
					                    let client_registration_start =
 | 
				
			||||||
 | 
					                        opaque::client::registration::start_registration(&password, &mut rng)?;
 | 
				
			||||||
 | 
					                    self.registration_start = Some(client_registration_start.state);
 | 
				
			||||||
 | 
					                    let req = registration::ClientRegistrationStartRequest {
 | 
				
			||||||
 | 
					                        username: user_id,
 | 
				
			||||||
 | 
					                        registration_start_request: client_registration_start.message,
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    self._task = Some(
 | 
				
			||||||
 | 
					                        HostService::register_start(
 | 
				
			||||||
 | 
					                            req,
 | 
				
			||||||
 | 
					                            self.link.callback(Msg::RegistrationStartResponse),
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                        .map_err(|e| anyhow!("Error trying to create user: {}", e))?,
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    self.update(Msg::SuccessfulCreation);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Msg::RegistrationStartResponse(response) => {
 | 
				
			||||||
 | 
					                debug_assert!(self.registration_start.is_some());
 | 
				
			||||||
 | 
					                let response = response?;
 | 
				
			||||||
 | 
					                let mut rng = rand::rngs::OsRng;
 | 
				
			||||||
 | 
					                let registration_upload = opaque::client::registration::finish_registration(
 | 
				
			||||||
 | 
					                    self.registration_start.take().unwrap(),
 | 
				
			||||||
 | 
					                    response.registration_response,
 | 
				
			||||||
 | 
					                    &mut rng,
 | 
				
			||||||
 | 
					                )?;
 | 
				
			||||||
 | 
					                let req = registration::ClientRegistrationFinishRequest {
 | 
				
			||||||
 | 
					                    server_data: response.server_data,
 | 
				
			||||||
 | 
					                    registration_upload: registration_upload.message,
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                self._task = Some(
 | 
				
			||||||
 | 
					                    HostService::register_finish(
 | 
				
			||||||
 | 
					                        req,
 | 
				
			||||||
 | 
					                        self.link.callback(Msg::RegistrationFinishResponse),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    .map_err(|e| anyhow!("Error trying to register user: {}", e))?,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Msg::RegistrationFinishResponse(response) => {
 | 
				
			||||||
 | 
					                if response.is_err() {
 | 
				
			||||||
 | 
					                    return response;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                self.update(Msg::SuccessfulCreation);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Msg::SuccessfulCreation => {
 | 
				
			||||||
 | 
					                self.route_dispatcher
 | 
				
			||||||
 | 
					                    .send(RouteRequest::ChangeRoute(Route::new_no_state(
 | 
				
			||||||
 | 
					                        "/list_users",
 | 
				
			||||||
 | 
					                    )));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					fn get_element(name: &str) -> Option<String> {
 | 
				
			||||||
 | 
					    use wasm_bindgen::JsCast;
 | 
				
			||||||
 | 
					    Some(
 | 
				
			||||||
 | 
					        web_sys::window()?
 | 
				
			||||||
 | 
					            .document()?
 | 
				
			||||||
 | 
					            .get_element_by_id(name)?
 | 
				
			||||||
 | 
					            .dyn_into::<web_sys::HtmlInputElement>()
 | 
				
			||||||
 | 
					            .ok()?
 | 
				
			||||||
 | 
					            .value(),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Component for CreateUserForm {
 | 
					impl Component for CreateUserForm {
 | 
				
			||||||
    type Message = Msg;
 | 
					    type Message = Msg;
 | 
				
			||||||
@ -44,42 +138,16 @@ impl Component for CreateUserForm {
 | 
				
			|||||||
            route_dispatcher: RouteAgentDispatcher::new(),
 | 
					            route_dispatcher: RouteAgentDispatcher::new(),
 | 
				
			||||||
            node_ref: NodeRef::default(),
 | 
					            node_ref: NodeRef::default(),
 | 
				
			||||||
            error: None,
 | 
					            error: None,
 | 
				
			||||||
 | 
					            registration_start: None,
 | 
				
			||||||
            _task: None,
 | 
					            _task: None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn update(&mut self, msg: Self::Message) -> ShouldRender {
 | 
					    fn update(&mut self, msg: Self::Message) -> ShouldRender {
 | 
				
			||||||
        match msg {
 | 
					        self.error = None;
 | 
				
			||||||
            Msg::SubmitForm => {
 | 
					        if let Err(e) = self.handle_msg(msg) {
 | 
				
			||||||
                use wasm_bindgen::JsCast;
 | 
					            ConsoleService::error(&e.to_string());
 | 
				
			||||||
                let document = web_sys::window().unwrap().document().unwrap();
 | 
					            self.error = Some(e);
 | 
				
			||||||
                let get_element = |name: &str| {
 | 
					 | 
				
			||||||
                    document
 | 
					 | 
				
			||||||
                        .get_element_by_id(name)
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .dyn_into::<web_sys::HtmlInputElement>()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .value()
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
                let req = CreateUserRequest {
 | 
					 | 
				
			||||||
                    user_id: get_element("username"),
 | 
					 | 
				
			||||||
                    email: get_element("email"),
 | 
					 | 
				
			||||||
                    display_name: Some(get_element("displayname")),
 | 
					 | 
				
			||||||
                    first_name: Some(get_element("firstname")),
 | 
					 | 
				
			||||||
                    last_name: Some(get_element("lastname")),
 | 
					 | 
				
			||||||
                    password: Some(get_element("password")),
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
                self.create_user(req);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Msg::CreateUserResponse(Ok(())) => {
 | 
					 | 
				
			||||||
                self.route_dispatcher
 | 
					 | 
				
			||||||
                    .send(RouteRequest::ChangeRoute(Route::new_no_state(
 | 
					 | 
				
			||||||
                        "/list_users",
 | 
					 | 
				
			||||||
                    )));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Msg::CreateUserResponse(Err(e)) => {
 | 
					 | 
				
			||||||
                ConsoleService::warn(&format!("Error listing users: {}", e));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        true
 | 
					        true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -42,6 +42,7 @@ pub mod login {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The messages for the 3-step OPAQUE registration process.
 | 
					/// The messages for the 3-step OPAQUE registration process.
 | 
				
			||||||
 | 
					/// It is used to reset a user's password.
 | 
				
			||||||
pub mod registration {
 | 
					pub mod registration {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -117,7 +118,6 @@ pub struct CreateUserRequest {
 | 
				
			|||||||
    pub display_name: Option<String>,
 | 
					    pub display_name: Option<String>,
 | 
				
			||||||
    pub first_name: Option<String>,
 | 
					    pub first_name: Option<String>,
 | 
				
			||||||
    pub last_name: Option<String>,
 | 
					    pub last_name: Option<String>,
 | 
				
			||||||
    pub password: Option<String>,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]
 | 
					#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,6 @@ use crate::infra::configuration::Configuration;
 | 
				
			|||||||
use async_trait::async_trait;
 | 
					use async_trait::async_trait;
 | 
				
			||||||
use futures_util::StreamExt;
 | 
					use futures_util::StreamExt;
 | 
				
			||||||
use futures_util::TryStreamExt;
 | 
					use futures_util::TryStreamExt;
 | 
				
			||||||
use lldap_model::opaque;
 | 
					 | 
				
			||||||
use sea_query::{Expr, Iden, Order, Query, SimpleExpr, Value};
 | 
					use sea_query::{Expr, Iden, Order, Query, SimpleExpr, Value};
 | 
				
			||||||
use sqlx::Row;
 | 
					use sqlx::Row;
 | 
				
			||||||
use std::collections::HashSet;
 | 
					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 {
 | 
					fn get_filter_expr(filter: RequestFilter) -> SimpleExpr {
 | 
				
			||||||
    use RequestFilter::*;
 | 
					    use RequestFilter::*;
 | 
				
			||||||
    fn get_repeated_filter(
 | 
					    fn get_repeated_filter(
 | 
				
			||||||
@ -178,7 +150,7 @@ impl BackendHandler for SqlBackendHandler {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn create_user(&self, request: CreateUserRequest) -> Result<()> {
 | 
					    async fn create_user(&self, request: CreateUserRequest) -> Result<()> {
 | 
				
			||||||
        let mut columns = vec![
 | 
					        let columns = vec![
 | 
				
			||||||
            Users::UserId,
 | 
					            Users::UserId,
 | 
				
			||||||
            Users::Email,
 | 
					            Users::Email,
 | 
				
			||||||
            Users::DisplayName,
 | 
					            Users::DisplayName,
 | 
				
			||||||
@ -186,7 +158,7 @@ impl BackendHandler for SqlBackendHandler {
 | 
				
			|||||||
            Users::LastName,
 | 
					            Users::LastName,
 | 
				
			||||||
            Users::CreationDate,
 | 
					            Users::CreationDate,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        let mut values = vec![
 | 
					        let values = vec![
 | 
				
			||||||
            request.user_id.clone().into(),
 | 
					            request.user_id.clone().into(),
 | 
				
			||||||
            request.email.into(),
 | 
					            request.email.into(),
 | 
				
			||||||
            request.display_name.map(Into::into).unwrap_or(Value::Null),
 | 
					            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),
 | 
					            request.last_name.map(Into::into).unwrap_or(Value::Null),
 | 
				
			||||||
            chrono::Utc::now().naive_utc().into(),
 | 
					            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()
 | 
					        let query = Query::insert()
 | 
				
			||||||
            .into_table(Users::Table)
 | 
					            .into_table(Users::Table)
 | 
				
			||||||
            .columns(columns)
 | 
					            .columns(columns)
 | 
				
			||||||
@ -271,12 +235,28 @@ mod tests {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn insert_user(handler: &SqlBackendHandler, name: &str, pass: &str) {
 | 
					    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
 | 
					        handler
 | 
				
			||||||
            .create_user(CreateUserRequest {
 | 
					            .registration_finish(registration::ClientRegistrationFinishRequest {
 | 
				
			||||||
                user_id: name.to_string(),
 | 
					                server_data: response.server_data,
 | 
				
			||||||
                email: "bob@bob.bob".to_string(),
 | 
					                registration_upload: registration_upload.message,
 | 
				
			||||||
                password: Some(pass.to_string()),
 | 
					 | 
				
			||||||
                ..Default::default()
 | 
					 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .await
 | 
					            .await
 | 
				
			||||||
            .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
 | 
				
			|||||||
@ -55,10 +55,16 @@ impl SqlBackendHandler {
 | 
				
			|||||||
                .and_where(Expr::col(Users::UserId).eq(username))
 | 
					                .and_where(Expr::col(Users::UserId).eq(username))
 | 
				
			||||||
                .to_string(DbQueryBuilder {});
 | 
					                .to_string(DbQueryBuilder {});
 | 
				
			||||||
            if let Some(row) = sqlx::query(&query).fetch_optional(&self.sql_pool).await? {
 | 
					            if let Some(row) = sqlx::query(&query).fetch_optional(&self.sql_pool).await? {
 | 
				
			||||||
                row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHash.to_string())
 | 
					                if let Some(bytes) =
 | 
				
			||||||
                    // If no password, always fail.
 | 
					                    row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHash.to_string())
 | 
				
			||||||
                    .ok_or_else(|| DomainError::AuthenticationError(username.to_string()))?
 | 
					                {
 | 
				
			||||||
 | 
					                    bytes
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // No password set.
 | 
				
			||||||
 | 
					                    return Ok(None);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
 | 
					                // No such user.
 | 
				
			||||||
                return Ok(None);
 | 
					                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 maybe_password_file = self.get_password_file_for_user(&request.username).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut rng = rand::rngs::OsRng;
 | 
					        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(
 | 
					        let start_response = opaque::server::login::start_login(
 | 
				
			||||||
            &mut rng,
 | 
					            &mut rng,
 | 
				
			||||||
            self.config.get_server_setup(),
 | 
					            self.config.get_server_setup(),
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,6 @@ async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration)
 | 
				
			|||||||
    handler
 | 
					    handler
 | 
				
			||||||
        .create_user(lldap_model::CreateUserRequest {
 | 
					        .create_user(lldap_model::CreateUserRequest {
 | 
				
			||||||
            user_id: config.ldap_user_dn.clone(),
 | 
					            user_id: config.ldap_user_dn.clone(),
 | 
				
			||||||
            password: Some(config.ldap_user_pass.clone()),
 | 
					 | 
				
			||||||
            ..Default::default()
 | 
					            ..Default::default()
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user