mirror of
				https://github.com/nitnelave/lldap.git
				synced 2023-04-12 14:25:13 +00:00 
			
		
		
		
	Implement password checking using opaque
This commit is contained in:
		
							parent
							
								
									86bfd37b70
								
							
						
					
					
						commit
						3c916a2530
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -12,3 +12,6 @@
 | 
				
			|||||||
*.db
 | 
					*.db
 | 
				
			||||||
*.db-shm
 | 
					*.db-shm
 | 
				
			||||||
*.db-wal
 | 
					*.db-wal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Server private key
 | 
				
			||||||
 | 
					server_key
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										75
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										75
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -698,6 +698,72 @@ dependencies = [
 | 
				
			|||||||
 "zeroize",
 | 
					 "zeroize",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "darling"
 | 
				
			||||||
 | 
					version = "0.12.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "darling_core",
 | 
				
			||||||
 | 
					 "darling_macro",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "darling_core"
 | 
				
			||||||
 | 
					version = "0.12.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "fnv",
 | 
				
			||||||
 | 
					 "ident_case",
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "strsim",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "darling_macro"
 | 
				
			||||||
 | 
					version = "0.12.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "darling_core",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "derive_builder"
 | 
				
			||||||
 | 
					version = "0.10.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "derive_builder_macro",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "derive_builder_core"
 | 
				
			||||||
 | 
					version = "0.10.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "darling",
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "derive_builder_macro"
 | 
				
			||||||
 | 
					version = "0.10.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "derive_builder_core",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "derive_more"
 | 
					name = "derive_more"
 | 
				
			||||||
version = "0.99.14"
 | 
					version = "0.99.14"
 | 
				
			||||||
@ -1088,6 +1154,12 @@ version = "1.4.1"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
 | 
					checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "ident_case"
 | 
				
			||||||
 | 
					version = "1.0.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "idna"
 | 
					name = "idna"
 | 
				
			||||||
version = "0.2.3"
 | 
					version = "0.2.3"
 | 
				
			||||||
@ -1253,6 +1325,7 @@ dependencies = [
 | 
				
			|||||||
 "chrono",
 | 
					 "chrono",
 | 
				
			||||||
 "clap",
 | 
					 "clap",
 | 
				
			||||||
 "cron",
 | 
					 "cron",
 | 
				
			||||||
 | 
					 "derive_builder",
 | 
				
			||||||
 "figment",
 | 
					 "figment",
 | 
				
			||||||
 "futures",
 | 
					 "futures",
 | 
				
			||||||
 "futures-util",
 | 
					 "futures-util",
 | 
				
			||||||
@ -1263,8 +1336,8 @@ dependencies = [
 | 
				
			|||||||
 "lldap_model",
 | 
					 "lldap_model",
 | 
				
			||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "mockall",
 | 
					 "mockall",
 | 
				
			||||||
 | 
					 "opaque-ke",
 | 
				
			||||||
 "rand 0.8.3",
 | 
					 "rand 0.8.3",
 | 
				
			||||||
 "rust-argon2",
 | 
					 | 
				
			||||||
 "sea-query",
 | 
					 "sea-query",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 | 
				
			|||||||
@ -12,11 +12,11 @@ actix-server = "2.0.0-beta.3"
 | 
				
			|||||||
actix-service = "2.0.0"
 | 
					actix-service = "2.0.0"
 | 
				
			||||||
actix-web = "4.0.0-beta.3"
 | 
					actix-web = "4.0.0-beta.3"
 | 
				
			||||||
anyhow = "*"
 | 
					anyhow = "*"
 | 
				
			||||||
rust-argon2 = "0.8"
 | 
					 | 
				
			||||||
async-trait = "0.1"
 | 
					async-trait = "0.1"
 | 
				
			||||||
chrono = { version = "*", features = [ "serde" ]}
 | 
					chrono = { version = "*", features = [ "serde" ]}
 | 
				
			||||||
clap = "3.0.0-beta.2"
 | 
					clap = "3.0.0-beta.2"
 | 
				
			||||||
cron = "*"
 | 
					cron = "*"
 | 
				
			||||||
 | 
					derive_builder = "0.10.2"
 | 
				
			||||||
futures = "*"
 | 
					futures = "*"
 | 
				
			||||||
futures-util = "*"
 | 
					futures-util = "*"
 | 
				
			||||||
hmac = "0.10"
 | 
					hmac = "0.10"
 | 
				
			||||||
@ -25,6 +25,7 @@ jwt = "0.13"
 | 
				
			|||||||
ldap3_server = "*"
 | 
					ldap3_server = "*"
 | 
				
			||||||
lldap_model = { path = "model" }
 | 
					lldap_model = { path = "model" }
 | 
				
			||||||
log = "*"
 | 
					log = "*"
 | 
				
			||||||
 | 
					opaque-ke = "0.5"
 | 
				
			||||||
serde = "*"
 | 
					serde = "*"
 | 
				
			||||||
serde_json = "1"
 | 
					serde_json = "1"
 | 
				
			||||||
sha2 = "0.9"
 | 
					sha2 = "0.9"
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,41 @@ pub enum AuthenticationError {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub type AuthenticationResult<T> = std::result::Result<T, AuthenticationError>;
 | 
					pub type AuthenticationResult<T> = std::result::Result<T, AuthenticationError>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Wrapper around an opaque KeyPair to have type-checked public and private keys.
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct KeyPair(pub opaque_ke::keypair::KeyPair<<DefaultSuite as CipherSuite>::Group>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct PublicKey<'a>(&'a opaque_ke::keypair::Key);
 | 
				
			||||||
 | 
					pub struct PrivateKey<'a>(&'a opaque_ke::keypair::Key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl <'a> std::ops::Deref for PublicKey<'a> {
 | 
				
			||||||
 | 
					    type Target = &'a opaque_ke::keypair::Key;
 | 
				
			||||||
 | 
					    fn deref(&self) -> &Self::Target {
 | 
				
			||||||
 | 
					        &self.0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl <'a> std::ops::Deref for PrivateKey<'a> {
 | 
				
			||||||
 | 
					    type Target = &'a opaque_ke::keypair::Key;
 | 
				
			||||||
 | 
					    fn deref(&self) -> &Self::Target {
 | 
				
			||||||
 | 
					        &self.0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl KeyPair {
 | 
				
			||||||
 | 
					    pub fn private(&self) -> PrivateKey<'_> {
 | 
				
			||||||
 | 
					        PrivateKey(self.0.private())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn public(&self) -> PublicKey<'_> {
 | 
				
			||||||
 | 
					        PublicKey(self.0.public())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn from_private_key_slice(input: &[u8]) -> std::result::Result<Self, opaque_ke::errors::InternalPakeError> {
 | 
				
			||||||
 | 
					        opaque_ke::keypair::KeyPair::<<DefaultSuite as CipherSuite>::Group>::from_private_key_slice(input).map(Self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A wrapper around argon2 to provide the [`opaque_ke::slow_hash::SlowHash`] trait.
 | 
					/// A wrapper around argon2 to provide the [`opaque_ke::slow_hash::SlowHash`] trait.
 | 
				
			||||||
pub struct ArgonHasher;
 | 
					pub struct ArgonHasher;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,11 +91,11 @@ impl CipherSuite for DefaultSuite {
 | 
				
			|||||||
/// deserialized using the type's `deserialize` method.
 | 
					/// deserialized using the type's `deserialize` method.
 | 
				
			||||||
#[cfg(feature = "opaque_client")]
 | 
					#[cfg(feature = "opaque_client")]
 | 
				
			||||||
pub mod client {
 | 
					pub mod client {
 | 
				
			||||||
    use super::*;
 | 
					    pub use super::*;
 | 
				
			||||||
    /// Methods to register a new user, from the client side.
 | 
					    /// Methods to register a new user, from the client side.
 | 
				
			||||||
    pub mod registration {
 | 
					    pub mod registration {
 | 
				
			||||||
        use super::*;
 | 
					        pub use super::*;
 | 
				
			||||||
        use opaque_ke::{
 | 
					        pub use opaque_ke::{
 | 
				
			||||||
            ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationFinishResult,
 | 
					            ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationFinishResult,
 | 
				
			||||||
            ClientRegistrationStartResult, RegistrationResponse,
 | 
					            ClientRegistrationStartResult, RegistrationResponse,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@ -91,8 +126,8 @@ pub mod client {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Methods to login, from the client side.
 | 
					    /// Methods to login, from the client side.
 | 
				
			||||||
    pub mod login {
 | 
					    pub mod login {
 | 
				
			||||||
        use super::*;
 | 
					        pub use super::*;
 | 
				
			||||||
        use opaque_ke::{
 | 
					        pub use opaque_ke::{
 | 
				
			||||||
            ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult,
 | 
					            ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult,
 | 
				
			||||||
            ClientLoginStartParameters, ClientLoginStartResult, CredentialResponse,
 | 
					            ClientLoginStartParameters, ClientLoginStartResult, CredentialResponse,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@ -123,24 +158,24 @@ pub mod client {
 | 
				
			|||||||
/// intermediate results must be sent to the client using the serialized `.message`.
 | 
					/// intermediate results must be sent to the client using the serialized `.message`.
 | 
				
			||||||
#[cfg(feature = "opaque_server")]
 | 
					#[cfg(feature = "opaque_server")]
 | 
				
			||||||
pub mod server {
 | 
					pub mod server {
 | 
				
			||||||
    use super::*;
 | 
					    pub use super::*;
 | 
				
			||||||
    use opaque_ke::{keypair::Key, ServerRegistration};
 | 
					    pub use opaque_ke::ServerRegistration;
 | 
				
			||||||
    /// Methods to register a new user, from the server side.
 | 
					    /// Methods to register a new user, from the server side.
 | 
				
			||||||
    pub mod registration {
 | 
					    pub mod registration {
 | 
				
			||||||
        use super::*;
 | 
					        pub use super::*;
 | 
				
			||||||
        use opaque_ke::{RegistrationRequest, RegistrationUpload, ServerRegistrationStartResult};
 | 
					        pub use opaque_ke::{RegistrationRequest, RegistrationUpload, ServerRegistrationStartResult};
 | 
				
			||||||
        /// Start a registration process, from a request sent by the client.
 | 
					        /// Start a registration process, from a request sent by the client.
 | 
				
			||||||
        ///
 | 
					        ///
 | 
				
			||||||
        /// The result must be kept for the next step.
 | 
					        /// The result must be kept for the next step.
 | 
				
			||||||
        pub fn start_registration<R: RngCore + CryptoRng>(
 | 
					        pub fn start_registration<R: RngCore + CryptoRng>(
 | 
				
			||||||
            rng: &mut R,
 | 
					            rng: &mut R,
 | 
				
			||||||
            registration_request: RegistrationRequest<DefaultSuite>,
 | 
					            registration_request: RegistrationRequest<DefaultSuite>,
 | 
				
			||||||
            server_public_key: &Key,
 | 
					            server_public_key: PublicKey<'_>,
 | 
				
			||||||
        ) -> AuthenticationResult<ServerRegistrationStartResult<DefaultSuite>> {
 | 
					        ) -> AuthenticationResult<ServerRegistrationStartResult<DefaultSuite>> {
 | 
				
			||||||
            Ok(ServerRegistration::<DefaultSuite>::start(
 | 
					            Ok(ServerRegistration::<DefaultSuite>::start(
 | 
				
			||||||
                rng,
 | 
					                rng,
 | 
				
			||||||
                registration_request,
 | 
					                registration_request,
 | 
				
			||||||
                server_public_key,
 | 
					                *server_public_key,
 | 
				
			||||||
            )?)
 | 
					            )?)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -155,8 +190,8 @@ pub mod server {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Methods to handle user login, from the server-side.
 | 
					    /// Methods to handle user login, from the server-side.
 | 
				
			||||||
    pub mod login {
 | 
					    pub mod login {
 | 
				
			||||||
        use super::*;
 | 
					        pub use super::*;
 | 
				
			||||||
        use opaque_ke::{
 | 
					        pub use opaque_ke::{
 | 
				
			||||||
            CredentialFinalization, CredentialRequest, ServerLogin, ServerLoginFinishResult,
 | 
					            CredentialFinalization, CredentialRequest, ServerLogin, ServerLoginFinishResult,
 | 
				
			||||||
            ServerLoginStartParameters, ServerLoginStartResult,
 | 
					            ServerLoginStartParameters, ServerLoginStartResult,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@ -167,13 +202,13 @@ pub mod server {
 | 
				
			|||||||
        pub fn start_login<R: RngCore + CryptoRng>(
 | 
					        pub fn start_login<R: RngCore + CryptoRng>(
 | 
				
			||||||
            rng: &mut R,
 | 
					            rng: &mut R,
 | 
				
			||||||
            password_file: ServerRegistration<DefaultSuite>,
 | 
					            password_file: ServerRegistration<DefaultSuite>,
 | 
				
			||||||
            server_private_key: &Key,
 | 
					            server_private_key: PrivateKey<'_>,
 | 
				
			||||||
            credential_request: CredentialRequest<DefaultSuite>,
 | 
					            credential_request: CredentialRequest<DefaultSuite>,
 | 
				
			||||||
        ) -> AuthenticationResult<ServerLoginStartResult<DefaultSuite>> {
 | 
					        ) -> AuthenticationResult<ServerLoginStartResult<DefaultSuite>> {
 | 
				
			||||||
            Ok(ServerLogin::start(
 | 
					            Ok(ServerLogin::start(
 | 
				
			||||||
                rng,
 | 
					                rng,
 | 
				
			||||||
                password_file,
 | 
					                password_file,
 | 
				
			||||||
                server_private_key,
 | 
					                *server_private_key,
 | 
				
			||||||
                credential_request,
 | 
					                credential_request,
 | 
				
			||||||
                ServerLoginStartParameters::default(),
 | 
					                ServerLoginStartParameters::default(),
 | 
				
			||||||
            )?)
 | 
					            )?)
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,8 @@ pub enum Error {
 | 
				
			|||||||
    AuthenticationError(String),
 | 
					    AuthenticationError(String),
 | 
				
			||||||
    #[error("Database error: `{0}`")]
 | 
					    #[error("Database error: `{0}`")]
 | 
				
			||||||
    DatabaseError(#[from] sqlx::Error),
 | 
					    DatabaseError(#[from] sqlx::Error),
 | 
				
			||||||
 | 
					    #[error("Authentication protocol error for `{0}`")]
 | 
				
			||||||
 | 
					    AuthenticationProtocolError(#[from] lldap_model::opaque::AuthenticationError),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type Result<T> = std::result::Result<T, Error>;
 | 
					pub type Result<T> = std::result::Result<T, Error>;
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ 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 log::*;
 | 
					use log::*;
 | 
				
			||||||
use sea_query::{Expr, Iden, Order, Query, SimpleExpr, Value};
 | 
					use sea_query::{Expr, Iden, Order, Query, SimpleExpr, Value};
 | 
				
			||||||
use sqlx::Row;
 | 
					use sqlx::Row;
 | 
				
			||||||
@ -20,31 +21,55 @@ impl SqlBackendHandler {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn get_password_config(pepper: &str) -> argon2::Config {
 | 
					fn get_password_file(
 | 
				
			||||||
    argon2::Config {
 | 
					    clear_password: &str,
 | 
				
			||||||
        secret: pepper.as_bytes(),
 | 
					    server_public_key: opaque::PublicKey<'_>,
 | 
				
			||||||
        ..Default::default()
 | 
					) -> Result<opaque::server::ServerRegistration<opaque::DefaultSuite>> {
 | 
				
			||||||
    }
 | 
					    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(
 | 
				
			||||||
 | 
					        &mut rng,
 | 
				
			||||||
 | 
					        client_register_start_result.message,
 | 
				
			||||||
 | 
					        server_public_key,
 | 
				
			||||||
 | 
					    )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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(
 | 
				
			||||||
 | 
					        server_register_start_result.state,
 | 
				
			||||||
 | 
					        client_registration_result.message,
 | 
				
			||||||
 | 
					    )?)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn hash_password(clear_password: &str, salt: &str, pepper: &str) -> String {
 | 
					fn passwords_match(
 | 
				
			||||||
    let config = get_password_config(pepper);
 | 
					    password_file_bytes: &[u8],
 | 
				
			||||||
    argon2::hash_encoded(clear_password.as_bytes(), salt.as_bytes(), &config)
 | 
					    clear_password: &str,
 | 
				
			||||||
        .map_err(|e| anyhow::anyhow!("Error encoding password: {}", e))
 | 
					    server_private_key: opaque::PrivateKey<'_>,
 | 
				
			||||||
        .unwrap()
 | 
					) -> Result<()> {
 | 
				
			||||||
}
 | 
					    use opaque::{client, client::login::*, server, server::login::*, DefaultSuite};
 | 
				
			||||||
 | 
					    let mut rng = rand::rngs::OsRng;
 | 
				
			||||||
 | 
					    let client_login_start_result = client::login::start_login(clear_password, &mut rng)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn passwords_match(encrypted_password: &str, clear_password: &str, pepper: &str) -> bool {
 | 
					    let password_file = ServerRegistration::<DefaultSuite>::deserialize(password_file_bytes)
 | 
				
			||||||
    argon2::verify_encoded_ext(
 | 
					        .map_err(opaque::AuthenticationError::ProtocolError)?;
 | 
				
			||||||
        encrypted_password,
 | 
					    let server_login_start_result = server::login::start_login(
 | 
				
			||||||
        clear_password.as_bytes(),
 | 
					        &mut rng,
 | 
				
			||||||
        pepper.as_bytes(),
 | 
					        password_file,
 | 
				
			||||||
        /*additional_data=*/ b"",
 | 
					        server_private_key,
 | 
				
			||||||
    )
 | 
					        client_login_start_result.message,
 | 
				
			||||||
    .unwrap_or_else(|e| {
 | 
					    )?;
 | 
				
			||||||
        log::error!("Error checking password: {}", e);
 | 
					    finish_login(
 | 
				
			||||||
        false
 | 
					        client_login_start_result.state,
 | 
				
			||||||
    })
 | 
					        server_login_start_result.message,
 | 
				
			||||||
 | 
					    )?;
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn get_filter_expr(filter: RequestFilter) -> SimpleExpr {
 | 
					fn get_filter_expr(filter: RequestFilter) -> SimpleExpr {
 | 
				
			||||||
@ -85,14 +110,14 @@ impl BackendHandler for SqlBackendHandler {
 | 
				
			|||||||
            .and_where(Expr::col(Users::UserId).eq(request.name.as_str()))
 | 
					            .and_where(Expr::col(Users::UserId).eq(request.name.as_str()))
 | 
				
			||||||
            .to_string(DbQueryBuilder {});
 | 
					            .to_string(DbQueryBuilder {});
 | 
				
			||||||
        if let Ok(row) = sqlx::query(&query).fetch_one(&self.sql_pool).await {
 | 
					        if let Ok(row) = sqlx::query(&query).fetch_one(&self.sql_pool).await {
 | 
				
			||||||
            if passwords_match(
 | 
					            if let Err(e) = passwords_match(
 | 
				
			||||||
                &row.get::<String, _>(&*Users::PasswordHash.to_string()),
 | 
					                &row.get::<Vec<u8>, _>(&*Users::PasswordHash.to_string()),
 | 
				
			||||||
                &request.password,
 | 
					                &request.password,
 | 
				
			||||||
                &self.config.secret_pepper,
 | 
					                self.config.get_server_keys().private(),
 | 
				
			||||||
            ) {
 | 
					            ) {
 | 
				
			||||||
                return Ok(());
 | 
					                debug!(r#"Invalid password for "{}": {}"#, request.name, e);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                debug!(r#"Invalid password for "{}""#, request.name);
 | 
					                return Ok(());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            debug!(r#"No user found for "{}""#, request.name);
 | 
					            debug!(r#"No user found for "{}""#, request.name);
 | 
				
			||||||
@ -208,16 +233,9 @@ impl BackendHandler for SqlBackendHandler {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn create_user(&self, request: CreateUserRequest) -> Result<()> {
 | 
					    async fn create_user(&self, request: CreateUserRequest) -> Result<()> {
 | 
				
			||||||
        use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng};
 | 
					        let password_hash =
 | 
				
			||||||
        // TODO: Initialize the rng only once. Maybe Arc<Cell>?
 | 
					            get_password_file(&request.password, self.config.get_server_keys().public())?
 | 
				
			||||||
        let mut rng = SmallRng::from_entropy();
 | 
					                .serialize();
 | 
				
			||||||
        let salt: String = std::iter::repeat(())
 | 
					 | 
				
			||||||
            .map(|()| rng.sample(Alphanumeric))
 | 
					 | 
				
			||||||
            .map(char::from)
 | 
					 | 
				
			||||||
            .take(32)
 | 
					 | 
				
			||||||
            .collect();
 | 
					 | 
				
			||||||
        // The salt is included in the password hash.
 | 
					 | 
				
			||||||
        let password_hash = hash_password(&request.password, &salt, &self.config.secret_pepper);
 | 
					 | 
				
			||||||
        let query = Query::insert()
 | 
					        let query = Query::insert()
 | 
				
			||||||
            .into_table(Users::Table)
 | 
					            .into_table(Users::Table)
 | 
				
			||||||
            .columns(vec![
 | 
					            .columns(vec![
 | 
				
			||||||
@ -283,6 +301,14 @@ impl BackendHandler for SqlBackendHandler {
 | 
				
			|||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use crate::domain::sql_tables::init_table;
 | 
					    use crate::domain::sql_tables::init_table;
 | 
				
			||||||
 | 
					    use crate::infra::configuration::ConfigurationBuilder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn get_default_config() -> Configuration {
 | 
				
			||||||
 | 
					        ConfigurationBuilder::default()
 | 
				
			||||||
 | 
					            .verbose(true)
 | 
				
			||||||
 | 
					            .build()
 | 
				
			||||||
 | 
					            .unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn get_in_memory_db() -> Pool {
 | 
					    async fn get_in_memory_db() -> Pool {
 | 
				
			||||||
        PoolOptions::new().connect("sqlite::memory:").await.unwrap()
 | 
					        PoolOptions::new().connect("sqlite::memory:").await.unwrap()
 | 
				
			||||||
@ -328,11 +354,11 @@ mod tests {
 | 
				
			|||||||
    #[tokio::test]
 | 
					    #[tokio::test]
 | 
				
			||||||
    async fn test_bind_admin() {
 | 
					    async fn test_bind_admin() {
 | 
				
			||||||
        let sql_pool = get_in_memory_db().await;
 | 
					        let sql_pool = get_in_memory_db().await;
 | 
				
			||||||
        let config = Configuration {
 | 
					        let config = ConfigurationBuilder::default()
 | 
				
			||||||
            ldap_user_dn: "admin".to_string(),
 | 
					            .ldap_user_dn("admin".to_string())
 | 
				
			||||||
            ldap_user_pass: "test".to_string(),
 | 
					            .ldap_user_pass("test".to_string())
 | 
				
			||||||
            ..Default::default()
 | 
					            .build()
 | 
				
			||||||
        };
 | 
					            .unwrap();
 | 
				
			||||||
        let handler = SqlBackendHandler::new(config, sql_pool);
 | 
					        let handler = SqlBackendHandler::new(config, sql_pool);
 | 
				
			||||||
        handler
 | 
					        handler
 | 
				
			||||||
            .bind(BindRequest {
 | 
					            .bind(BindRequest {
 | 
				
			||||||
@ -343,24 +369,10 @@ mod tests {
 | 
				
			|||||||
            .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					 | 
				
			||||||
    fn test_argon() {
 | 
					 | 
				
			||||||
        let password = b"password";
 | 
					 | 
				
			||||||
        let salt = b"randomsalt";
 | 
					 | 
				
			||||||
        let pepper = b"pepper";
 | 
					 | 
				
			||||||
        let config = argon2::Config {
 | 
					 | 
				
			||||||
            secret: pepper,
 | 
					 | 
				
			||||||
            ..Default::default()
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        let hash = argon2::hash_encoded(password, salt, &config).unwrap();
 | 
					 | 
				
			||||||
        let matches = argon2::verify_encoded_ext(&hash, password, pepper, b"").unwrap();
 | 
					 | 
				
			||||||
        assert!(matches);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[tokio::test]
 | 
					    #[tokio::test]
 | 
				
			||||||
    async fn test_bind_user() {
 | 
					    async fn test_bind_user() {
 | 
				
			||||||
        let sql_pool = get_initialized_db().await;
 | 
					        let sql_pool = get_initialized_db().await;
 | 
				
			||||||
        let config = Configuration::default();
 | 
					        let config = get_default_config();
 | 
				
			||||||
        let handler = SqlBackendHandler::new(config, sql_pool.clone());
 | 
					        let handler = SqlBackendHandler::new(config, sql_pool.clone());
 | 
				
			||||||
        insert_user(&handler, "bob", "bob00").await;
 | 
					        insert_user(&handler, "bob", "bob00").await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -390,7 +402,7 @@ mod tests {
 | 
				
			|||||||
    #[tokio::test]
 | 
					    #[tokio::test]
 | 
				
			||||||
    async fn test_list_users() {
 | 
					    async fn test_list_users() {
 | 
				
			||||||
        let sql_pool = get_initialized_db().await;
 | 
					        let sql_pool = get_initialized_db().await;
 | 
				
			||||||
        let config = Configuration::default();
 | 
					        let config = get_default_config();
 | 
				
			||||||
        let handler = SqlBackendHandler::new(config, sql_pool);
 | 
					        let handler = SqlBackendHandler::new(config, sql_pool);
 | 
				
			||||||
        insert_user(&handler, "bob", "bob00").await;
 | 
					        insert_user(&handler, "bob", "bob00").await;
 | 
				
			||||||
        insert_user(&handler, "patrick", "pass").await;
 | 
					        insert_user(&handler, "patrick", "pass").await;
 | 
				
			||||||
@ -455,7 +467,7 @@ mod tests {
 | 
				
			|||||||
    #[tokio::test]
 | 
					    #[tokio::test]
 | 
				
			||||||
    async fn test_list_groups() {
 | 
					    async fn test_list_groups() {
 | 
				
			||||||
        let sql_pool = get_initialized_db().await;
 | 
					        let sql_pool = get_initialized_db().await;
 | 
				
			||||||
        let config = Configuration::default();
 | 
					        let config = get_default_config();
 | 
				
			||||||
        let handler = SqlBackendHandler::new(config, sql_pool.clone());
 | 
					        let handler = SqlBackendHandler::new(config, sql_pool.clone());
 | 
				
			||||||
        insert_user(&handler, "bob", "bob00").await;
 | 
					        insert_user(&handler, "bob", "bob00").await;
 | 
				
			||||||
        insert_user(&handler, "patrick", "pass").await;
 | 
					        insert_user(&handler, "patrick", "pass").await;
 | 
				
			||||||
@ -484,7 +496,7 @@ mod tests {
 | 
				
			|||||||
    #[tokio::test]
 | 
					    #[tokio::test]
 | 
				
			||||||
    async fn test_get_user_groups() {
 | 
					    async fn test_get_user_groups() {
 | 
				
			||||||
        let sql_pool = get_initialized_db().await;
 | 
					        let sql_pool = get_initialized_db().await;
 | 
				
			||||||
        let config = Configuration::default();
 | 
					        let config = get_default_config();
 | 
				
			||||||
        let handler = SqlBackendHandler::new(config, sql_pool.clone());
 | 
					        let handler = SqlBackendHandler::new(config, sql_pool.clone());
 | 
				
			||||||
        insert_user(&handler, "bob", "bob00").await;
 | 
					        insert_user(&handler, "bob", "bob00").await;
 | 
				
			||||||
        insert_user(&handler, "patrick", "pass").await;
 | 
					        insert_user(&handler, "patrick", "pass").await;
 | 
				
			||||||
@ -519,7 +531,7 @@ mod tests {
 | 
				
			|||||||
    #[tokio::test]
 | 
					    #[tokio::test]
 | 
				
			||||||
    async fn test_delete_user() {
 | 
					    async fn test_delete_user() {
 | 
				
			||||||
        let sql_pool = get_initialized_db().await;
 | 
					        let sql_pool = get_initialized_db().await;
 | 
				
			||||||
        let config = Configuration::default();
 | 
					        let config = get_default_config();
 | 
				
			||||||
        let handler = SqlBackendHandler::new(config, sql_pool.clone());
 | 
					        let handler = SqlBackendHandler::new(config, sql_pool.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        insert_user(&handler, "val", "s3np4i").await;
 | 
					        insert_user(&handler, "val", "s3np4i").await;
 | 
				
			||||||
 | 
				
			|||||||
@ -54,11 +54,7 @@ pub async fn init_table(pool: &Pool) -> sqlx::Result<()> {
 | 
				
			|||||||
            .col(ColumnDef::new(Users::LastName).string_len(255))
 | 
					            .col(ColumnDef::new(Users::LastName).string_len(255))
 | 
				
			||||||
            .col(ColumnDef::new(Users::Avatar).binary())
 | 
					            .col(ColumnDef::new(Users::Avatar).binary())
 | 
				
			||||||
            .col(ColumnDef::new(Users::CreationDate).date_time().not_null())
 | 
					            .col(ColumnDef::new(Users::CreationDate).date_time().not_null())
 | 
				
			||||||
            .col(
 | 
					            .col(ColumnDef::new(Users::PasswordHash).binary().not_null())
 | 
				
			||||||
                ColumnDef::new(Users::PasswordHash)
 | 
					 | 
				
			||||||
                    .string_len(255)
 | 
					 | 
				
			||||||
                    .not_null(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .col(ColumnDef::new(Users::TotpSecret).string_len(64))
 | 
					            .col(ColumnDef::new(Users::TotpSecret).string_len(64))
 | 
				
			||||||
            .col(ColumnDef::new(Users::MfaType).string_len(64))
 | 
					            .col(ColumnDef::new(Users::MfaType).string_len(64))
 | 
				
			||||||
            .to_string(DbQueryBuilder {}),
 | 
					            .to_string(DbQueryBuilder {}),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,45 +1,61 @@
 | 
				
			|||||||
use anyhow::Result;
 | 
					use anyhow::{anyhow, Result};
 | 
				
			||||||
use figment::{
 | 
					use figment::{
 | 
				
			||||||
    providers::{Env, Format, Serialized, Toml},
 | 
					    providers::{Env, Format, Serialized, Toml},
 | 
				
			||||||
    Figment,
 | 
					    Figment,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					use lldap_model::{opaque, opaque::KeyPair};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::infra::cli::CLIOpts;
 | 
					use crate::infra::cli::CLIOpts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
 | 
					#[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)]
 | 
				
			||||||
 | 
					#[builder(
 | 
				
			||||||
 | 
					    pattern = "owned",
 | 
				
			||||||
 | 
					    default = "Configuration::default()",
 | 
				
			||||||
 | 
					    build_fn(name = "private_build", validate = "Self::validate")
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
pub struct Configuration {
 | 
					pub struct Configuration {
 | 
				
			||||||
    pub ldap_port: u16,
 | 
					    pub ldap_port: u16,
 | 
				
			||||||
    pub ldaps_port: u16,
 | 
					    pub ldaps_port: u16,
 | 
				
			||||||
    pub http_port: u16,
 | 
					    pub http_port: u16,
 | 
				
			||||||
    pub secret_pepper: String,
 | 
					 | 
				
			||||||
    pub jwt_secret: String,
 | 
					    pub jwt_secret: String,
 | 
				
			||||||
    pub ldap_base_dn: String,
 | 
					    pub ldap_base_dn: String,
 | 
				
			||||||
    pub ldap_user_dn: String,
 | 
					    pub ldap_user_dn: String,
 | 
				
			||||||
    pub ldap_user_pass: String,
 | 
					    pub ldap_user_pass: String,
 | 
				
			||||||
    pub database_url: String,
 | 
					    pub database_url: String,
 | 
				
			||||||
    pub verbose: bool,
 | 
					    pub verbose: bool,
 | 
				
			||||||
 | 
					    pub key_file: String,
 | 
				
			||||||
 | 
					    #[serde(skip)]
 | 
				
			||||||
 | 
					    #[builder(field(private), setter(strip_option))]
 | 
				
			||||||
 | 
					    server_keys: Option<KeyPair>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for Configuration {
 | 
					impl ConfigurationBuilder {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    #[cfg(test)]
 | 
				
			||||||
        Configuration {
 | 
					    pub fn build(self) -> Result<Configuration> {
 | 
				
			||||||
            ldap_port: 3890,
 | 
					        let server_keys = get_server_keys(
 | 
				
			||||||
            ldaps_port: 6360,
 | 
					            &self
 | 
				
			||||||
            http_port: 17170,
 | 
					                .key_file
 | 
				
			||||||
            secret_pepper: String::from("secretsecretpepper"),
 | 
					                .as_deref()
 | 
				
			||||||
            jwt_secret: String::from("secretjwtsecret"),
 | 
					                .unwrap_or("server_key"),
 | 
				
			||||||
            ldap_base_dn: String::from("dc=example,dc=com"),
 | 
					        )?;
 | 
				
			||||||
            // cn=admin,dc=example,dc=com
 | 
					        Ok(self.server_keys(server_keys).private_build()?)
 | 
				
			||||||
            ldap_user_dn: String::from("admin"),
 | 
					    }
 | 
				
			||||||
            ldap_user_pass: String::from("password"),
 | 
					
 | 
				
			||||||
            database_url: String::from("sqlite://users.db?mode=rwc"),
 | 
					    fn validate(&self) -> Result<(), String> {
 | 
				
			||||||
            verbose: false,
 | 
					        if self.server_keys.is_none() {
 | 
				
			||||||
 | 
					            Err("Don't use `private_build`, use `build` instead".to_string())
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Ok(())
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Configuration {
 | 
					impl Configuration {
 | 
				
			||||||
 | 
					    pub fn get_server_keys(&self) -> &KeyPair {
 | 
				
			||||||
 | 
					        self.server_keys.as_ref().unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn merge_with_cli(mut self: Configuration, cli_opts: CLIOpts) -> Configuration {
 | 
					    fn merge_with_cli(mut self: Configuration, cli_opts: CLIOpts) -> Configuration {
 | 
				
			||||||
        if cli_opts.verbose {
 | 
					        if cli_opts.verbose {
 | 
				
			||||||
            self.verbose = true;
 | 
					            self.verbose = true;
 | 
				
			||||||
@ -55,6 +71,45 @@ impl Configuration {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub(super) fn default() -> Self {
 | 
				
			||||||
 | 
					        Configuration {
 | 
				
			||||||
 | 
					            ldap_port: 3890,
 | 
				
			||||||
 | 
					            ldaps_port: 6360,
 | 
				
			||||||
 | 
					            http_port: 17170,
 | 
				
			||||||
 | 
					            jwt_secret: String::from("secretjwtsecret"),
 | 
				
			||||||
 | 
					            ldap_base_dn: String::from("dc=example,dc=com"),
 | 
				
			||||||
 | 
					            // cn=admin,dc=example,dc=com
 | 
				
			||||||
 | 
					            ldap_user_dn: String::from("admin"),
 | 
				
			||||||
 | 
					            ldap_user_pass: String::from("password"),
 | 
				
			||||||
 | 
					            database_url: String::from("sqlite://users.db?mode=rwc"),
 | 
				
			||||||
 | 
					            verbose: false,
 | 
				
			||||||
 | 
					            key_file: String::from("server_key"),
 | 
				
			||||||
 | 
					            server_keys: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn get_server_keys(file_path: &str) -> Result<KeyPair> {
 | 
				
			||||||
 | 
					    use opaque_ke::ciphersuite::CipherSuite;
 | 
				
			||||||
 | 
					    use std::path::Path;
 | 
				
			||||||
 | 
					    let path = Path::new(file_path);
 | 
				
			||||||
 | 
					    if path.exists() {
 | 
				
			||||||
 | 
					        let bytes = std::fs::read(file_path)
 | 
				
			||||||
 | 
					            .map_err(|e| anyhow!("Could not read key file `{}`: {}", file_path, e))?;
 | 
				
			||||||
 | 
					        Ok(KeyPair::from_private_key_slice(&bytes)?)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        let mut rng = rand::rngs::OsRng;
 | 
				
			||||||
 | 
					        let keypair = opaque::DefaultSuite::generate_random_keypair(&mut rng);
 | 
				
			||||||
 | 
					        std::fs::write(path, keypair.private().as_slice()).map_err(|e| {
 | 
				
			||||||
 | 
					            anyhow!(
 | 
				
			||||||
 | 
					                "Could not write the generated server keys to file `{}`: {}",
 | 
				
			||||||
 | 
					                file_path,
 | 
				
			||||||
 | 
					                e
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        })?;
 | 
				
			||||||
 | 
					        Ok(KeyPair(keypair))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn init(cli_opts: CLIOpts) -> Result<Configuration> {
 | 
					pub fn init(cli_opts: CLIOpts) -> Result<Configuration> {
 | 
				
			||||||
@ -65,6 +120,7 @@ pub fn init(cli_opts: CLIOpts) -> Result<Configuration> {
 | 
				
			|||||||
        .merge(Env::prefixed("LLDAP_"))
 | 
					        .merge(Env::prefixed("LLDAP_"))
 | 
				
			||||||
        .extract()?;
 | 
					        .extract()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let config = config.merge_with_cli(cli_opts);
 | 
					    let mut config = config.merge_with_cli(cli_opts);
 | 
				
			||||||
 | 
					    config.server_keys = Some(get_server_keys(&config.key_file)?);
 | 
				
			||||||
    Ok(config)
 | 
					    Ok(config)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,9 @@ async fn index(req: HttpRequest) -> actix_web::Result<NamedFile> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub(crate) fn error_to_http_response(error: DomainError) -> HttpResponse {
 | 
					pub(crate) fn error_to_http_response(error: DomainError) -> HttpResponse {
 | 
				
			||||||
    match error {
 | 
					    match error {
 | 
				
			||||||
        DomainError::AuthenticationError(_) => HttpResponse::Unauthorized(),
 | 
					        DomainError::AuthenticationError(_) | DomainError::AuthenticationProtocolError(_) => {
 | 
				
			||||||
 | 
					            HttpResponse::Unauthorized()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        DomainError::DatabaseError(_) => HttpResponse::InternalServerError(),
 | 
					        DomainError::DatabaseError(_) => HttpResponse::InternalServerError(),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    .body(error.to_string())
 | 
					    .body(error.to_string())
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user