mirror of
				https://github.com/nitnelave/lldap.git
				synced 2023-04-12 14:25:13 +00:00 
			
		
		
		
	Update opaque and implement it without DB
This commit is contained in:
		
							parent
							
								
									f12abb35d3
								
							
						
					
					
						commit
						00ab0ba564
					
				
							
								
								
									
										65
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										65
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -728,6 +728,22 @@ dependencies = [
 | 
				
			|||||||
 "subtle",
 | 
					 "subtle",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crypto-mac"
 | 
				
			||||||
 | 
					version = "0.11.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "generic-array",
 | 
				
			||||||
 | 
					 "subtle",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "ct-codecs"
 | 
				
			||||||
 | 
					version = "1.1.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "curve25519-dalek"
 | 
					name = "curve25519-dalek"
 | 
				
			||||||
version = "3.1.0"
 | 
					version = "3.1.0"
 | 
				
			||||||
@ -737,6 +753,7 @@ dependencies = [
 | 
				
			|||||||
 "byteorder",
 | 
					 "byteorder",
 | 
				
			||||||
 "digest",
 | 
					 "digest",
 | 
				
			||||||
 "rand_core 0.5.1",
 | 
					 "rand_core 0.5.1",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 "subtle",
 | 
					 "subtle",
 | 
				
			||||||
 "zeroize",
 | 
					 "zeroize",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
@ -1056,6 +1073,7 @@ version = "0.14.4"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
 | 
					checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 "typenum",
 | 
					 "typenum",
 | 
				
			||||||
 "version_check",
 | 
					 "version_check",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
@ -1210,12 +1228,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "hkdf"
 | 
					name = "hkdf"
 | 
				
			||||||
version = "0.10.0"
 | 
					version = "0.11.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f"
 | 
					checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "digest",
 | 
					 "digest",
 | 
				
			||||||
 "hmac",
 | 
					 "hmac 0.11.0",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -1224,7 +1242,17 @@ version = "0.10.1"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
 | 
					checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "crypto-mac",
 | 
					 "crypto-mac 0.10.0",
 | 
				
			||||||
 | 
					 "digest",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "hmac"
 | 
				
			||||||
 | 
					version = "0.11.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "crypto-mac 0.11.0",
 | 
				
			||||||
 "digest",
 | 
					 "digest",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1324,9 +1352,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			|||||||
checksum = "86e46349d67dc03bdbdb28da0337a355a53ca1d5156452722c36fe21d0e6389b"
 | 
					checksum = "86e46349d67dc03bdbdb28da0337a355a53ca1d5156452722c36fe21d0e6389b"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "base64",
 | 
					 "base64",
 | 
				
			||||||
 "crypto-mac",
 | 
					 "crypto-mac 0.10.0",
 | 
				
			||||||
 "digest",
 | 
					 "digest",
 | 
				
			||||||
 "hmac",
 | 
					 "hmac 0.10.1",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 "sha2",
 | 
					 "sha2",
 | 
				
			||||||
@ -1419,6 +1447,8 @@ dependencies = [
 | 
				
			|||||||
 "actix-web-httpauth",
 | 
					 "actix-web-httpauth",
 | 
				
			||||||
 "anyhow",
 | 
					 "anyhow",
 | 
				
			||||||
 "async-trait",
 | 
					 "async-trait",
 | 
				
			||||||
 | 
					 "base64",
 | 
				
			||||||
 | 
					 "bincode",
 | 
				
			||||||
 "chrono",
 | 
					 "chrono",
 | 
				
			||||||
 "clap",
 | 
					 "clap",
 | 
				
			||||||
 "cron",
 | 
					 "cron",
 | 
				
			||||||
@ -1426,7 +1456,7 @@ dependencies = [
 | 
				
			|||||||
 "figment",
 | 
					 "figment",
 | 
				
			||||||
 "futures",
 | 
					 "futures",
 | 
				
			||||||
 "futures-util",
 | 
					 "futures-util",
 | 
				
			||||||
 "hmac",
 | 
					 "hmac 0.10.1",
 | 
				
			||||||
 "http",
 | 
					 "http",
 | 
				
			||||||
 "jwt",
 | 
					 "jwt",
 | 
				
			||||||
 "ldap3_server",
 | 
					 "ldap3_server",
 | 
				
			||||||
@ -1434,6 +1464,7 @@ dependencies = [
 | 
				
			|||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "mockall",
 | 
					 "mockall",
 | 
				
			||||||
 "opaque-ke",
 | 
					 "opaque-ke",
 | 
				
			||||||
 | 
					 "orion",
 | 
				
			||||||
 "rand 0.8.3",
 | 
					 "rand 0.8.3",
 | 
				
			||||||
 "sea-query",
 | 
					 "sea-query",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
@ -1804,8 +1835,8 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "opaque-ke"
 | 
					name = "opaque-ke"
 | 
				
			||||||
version = "0.5.1-pre.1"
 | 
					version = "0.6.0-pre.1"
 | 
				
			||||||
source = "git+https://github.com/novifinancial/opaque-ke?rev=98f1821897cd2800e5bffb2a70541056145e99cc#98f1821897cd2800e5bffb2a70541056145e99cc"
 | 
					source = "git+https://github.com/novifinancial/opaque-ke?rev=eb59676a940b15f77871aefe1e46d7b5bf85f40a#eb59676a940b15f77871aefe1e46d7b5bf85f40a"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "base64",
 | 
					 "base64",
 | 
				
			||||||
 "curve25519-dalek",
 | 
					 "curve25519-dalek",
 | 
				
			||||||
@ -1814,7 +1845,7 @@ dependencies = [
 | 
				
			|||||||
 "generic-array",
 | 
					 "generic-array",
 | 
				
			||||||
 "generic-bytes",
 | 
					 "generic-bytes",
 | 
				
			||||||
 "hkdf",
 | 
					 "hkdf",
 | 
				
			||||||
 "hmac",
 | 
					 "hmac 0.11.0",
 | 
				
			||||||
 "rand 0.8.3",
 | 
					 "rand 0.8.3",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "subtle",
 | 
					 "subtle",
 | 
				
			||||||
@ -1871,6 +1902,18 @@ dependencies = [
 | 
				
			|||||||
 "thiserror",
 | 
					 "thiserror",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "orion"
 | 
				
			||||||
 | 
					version = "0.16.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "118f94b4ca56d1eb99466a26a216b87fad822a51af8b308264c88a9337eb0a15"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "ct-codecs",
 | 
				
			||||||
 | 
					 "getrandom 0.2.3",
 | 
				
			||||||
 | 
					 "subtle",
 | 
				
			||||||
 | 
					 "zeroize",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "os_str_bytes"
 | 
					name = "os_str_bytes"
 | 
				
			||||||
version = "2.4.0"
 | 
					version = "2.4.0"
 | 
				
			||||||
@ -2525,7 +2568,7 @@ dependencies = [
 | 
				
			|||||||
 "generic-array",
 | 
					 "generic-array",
 | 
				
			||||||
 "hashlink",
 | 
					 "hashlink",
 | 
				
			||||||
 "hex",
 | 
					 "hex",
 | 
				
			||||||
 "hmac",
 | 
					 "hmac 0.10.1",
 | 
				
			||||||
 "itoa",
 | 
					 "itoa",
 | 
				
			||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
 "libsqlite3-sys",
 | 
					 "libsqlite3-sys",
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,8 @@ actix-service = "2.0.0"
 | 
				
			|||||||
actix-web = "4.0.0-beta.3"
 | 
					actix-web = "4.0.0-beta.3"
 | 
				
			||||||
anyhow = "*"
 | 
					anyhow = "*"
 | 
				
			||||||
async-trait = "0.1"
 | 
					async-trait = "0.1"
 | 
				
			||||||
 | 
					base64 = "0.13"
 | 
				
			||||||
 | 
					bincode = "1.3"
 | 
				
			||||||
chrono = { version = "*", features = [ "serde" ]}
 | 
					chrono = { version = "*", features = [ "serde" ]}
 | 
				
			||||||
clap = "3.0.0-beta.2"
 | 
					clap = "3.0.0-beta.2"
 | 
				
			||||||
cron = "*"
 | 
					cron = "*"
 | 
				
			||||||
@ -28,6 +30,7 @@ jwt = "0.13"
 | 
				
			|||||||
ldap3_server = "*"
 | 
					ldap3_server = "*"
 | 
				
			||||||
lldap_model = { path = "model" }
 | 
					lldap_model = { path = "model" }
 | 
				
			||||||
log = "*"
 | 
					log = "*"
 | 
				
			||||||
 | 
					orion = "0.16"
 | 
				
			||||||
serde = "*"
 | 
					serde = "*"
 | 
				
			||||||
serde_json = "1"
 | 
					serde_json = "1"
 | 
				
			||||||
sha2 = "0.9"
 | 
					sha2 = "0.9"
 | 
				
			||||||
@ -45,7 +48,7 @@ rand = { version = "0.8", features = ["small_rng", "getrandom"] }
 | 
				
			|||||||
# TODO: update to 0.6 when out.
 | 
					# TODO: update to 0.6 when out.
 | 
				
			||||||
[dependencies.opaque-ke]
 | 
					[dependencies.opaque-ke]
 | 
				
			||||||
git = "https://github.com/novifinancial/opaque-ke"
 | 
					git = "https://github.com/novifinancial/opaque-ke"
 | 
				
			||||||
rev = "98f1821897cd2800e5bffb2a70541056145e99cc"
 | 
					rev = "eb59676a940b15f77871aefe1e46d7b5bf85f40a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies.sqlx]
 | 
					[dependencies.sqlx]
 | 
				
			||||||
version = "0.5.1"
 | 
					version = "0.5.1"
 | 
				
			||||||
 | 
				
			|||||||
@ -92,7 +92,7 @@ impl LoginForm {
 | 
				
			|||||||
                    Ok(l) => l,
 | 
					                    Ok(l) => l,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                let req = login::ClientLoginFinishRequest {
 | 
					                let req = login::ClientLoginFinishRequest {
 | 
				
			||||||
                    login_key: res.login_key,
 | 
					                    server_data: res.server_data,
 | 
				
			||||||
                    credential_finalization: login_finish.message,
 | 
					                    credential_finalization: login_finish.message,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                self.call_backend(
 | 
					                self.call_backend(
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ thiserror = "*"
 | 
				
			|||||||
# TODO: update to 0.6 when out.
 | 
					# TODO: update to 0.6 when out.
 | 
				
			||||||
[dependencies.opaque-ke]
 | 
					[dependencies.opaque-ke]
 | 
				
			||||||
git = "https://github.com/novifinancial/opaque-ke"
 | 
					git = "https://github.com/novifinancial/opaque-ke"
 | 
				
			||||||
rev = "98f1821897cd2800e5bffb2a70541056145e99cc"
 | 
					rev = "eb59676a940b15f77871aefe1e46d7b5bf85f40a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies.chrono]
 | 
					[dependencies.chrono]
 | 
				
			||||||
version = "*"
 | 
					version = "*"
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,12 @@ pub struct BindRequest {
 | 
				
			|||||||
pub mod login {
 | 
					pub mod login {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[derive(Serialize, Deserialize, Clone)]
 | 
				
			||||||
 | 
					    pub struct ServerData {
 | 
				
			||||||
 | 
					        pub username: String,
 | 
				
			||||||
 | 
					        pub server_login: opaque::server::login::ServerLogin,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[derive(Serialize, Deserialize, Clone)]
 | 
					    #[derive(Serialize, Deserialize, Clone)]
 | 
				
			||||||
    pub struct ClientLoginStartRequest {
 | 
					    pub struct ClientLoginStartRequest {
 | 
				
			||||||
        pub username: String,
 | 
					        pub username: String,
 | 
				
			||||||
@ -22,15 +28,15 @@ pub mod login {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    #[derive(Serialize, Deserialize, Clone)]
 | 
					    #[derive(Serialize, Deserialize, Clone)]
 | 
				
			||||||
    pub struct ServerLoginStartResponse {
 | 
					    pub struct ServerLoginStartResponse {
 | 
				
			||||||
        /// A randomly-generated temporary key that corresponds to this login attempt.
 | 
					        /// Base64, encrypted ServerData to be passed back to the server.
 | 
				
			||||||
        pub login_key: String,
 | 
					        pub server_data: String,
 | 
				
			||||||
        pub credential_response: opaque::client::login::CredentialResponse,
 | 
					        pub credential_response: opaque::client::login::CredentialResponse,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[derive(Serialize, Deserialize, Clone)]
 | 
					    #[derive(Serialize, Deserialize, Clone)]
 | 
				
			||||||
    pub struct ClientLoginFinishRequest {
 | 
					    pub struct ClientLoginFinishRequest {
 | 
				
			||||||
        /// The key returned by the server in the previous step.
 | 
					        /// Encrypted ServerData from the previous step.
 | 
				
			||||||
        pub login_key: String,
 | 
					        pub server_data: String,
 | 
				
			||||||
        pub credential_finalization: opaque::client::login::CredentialFinalization,
 | 
					        pub credential_finalization: opaque::client::login::CredentialFinalization,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -39,6 +45,11 @@ pub mod login {
 | 
				
			|||||||
pub mod registration {
 | 
					pub mod registration {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[derive(Serialize, Deserialize, Clone)]
 | 
				
			||||||
 | 
					    pub struct ServerData {
 | 
				
			||||||
 | 
					        pub username: String,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[derive(Serialize, Deserialize, Clone)]
 | 
					    #[derive(Serialize, Deserialize, Clone)]
 | 
				
			||||||
    pub struct ClientRegistrationStartRequest {
 | 
					    pub struct ClientRegistrationStartRequest {
 | 
				
			||||||
        pub username: String,
 | 
					        pub username: String,
 | 
				
			||||||
@ -47,15 +58,15 @@ pub mod registration {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    #[derive(Serialize, Deserialize, Clone)]
 | 
					    #[derive(Serialize, Deserialize, Clone)]
 | 
				
			||||||
    pub struct ServerRegistrationStartResponse {
 | 
					    pub struct ServerRegistrationStartResponse {
 | 
				
			||||||
        /// A randomly-generated temporary key that corresponds to this registration attempt.
 | 
					        /// Base64, encrypted ServerData to be passed back to the server.
 | 
				
			||||||
        pub registration_key: String,
 | 
					        pub server_data: String,
 | 
				
			||||||
        pub registration_response: opaque::client::registration::RegistrationResponse,
 | 
					        pub registration_response: opaque::client::registration::RegistrationResponse,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[derive(Serialize, Deserialize, Clone)]
 | 
					    #[derive(Serialize, Deserialize, Clone)]
 | 
				
			||||||
    pub struct ClientRegistrationFinishRequest {
 | 
					    pub struct ClientRegistrationFinishRequest {
 | 
				
			||||||
        /// The key returned by the server in the previous step.
 | 
					        /// Encrypted ServerData from the previous step.
 | 
				
			||||||
        pub registration_key: String,
 | 
					        pub server_data: String,
 | 
				
			||||||
        pub registration_upload: opaque::server::registration::RegistrationUpload,
 | 
					        pub registration_upload: opaque::server::registration::RegistrationUpload,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -100,18 +100,14 @@ pub mod client {
 | 
				
			|||||||
        pub type ClientLoginStartResult = opaque_ke::ClientLoginStartResult<DefaultSuite>;
 | 
					        pub type ClientLoginStartResult = opaque_ke::ClientLoginStartResult<DefaultSuite>;
 | 
				
			||||||
        pub type CredentialResponse = opaque_ke::CredentialResponse<DefaultSuite>;
 | 
					        pub type CredentialResponse = opaque_ke::CredentialResponse<DefaultSuite>;
 | 
				
			||||||
        pub type CredentialFinalization = opaque_ke::CredentialFinalization<DefaultSuite>;
 | 
					        pub type CredentialFinalization = opaque_ke::CredentialFinalization<DefaultSuite>;
 | 
				
			||||||
        pub use opaque_ke::{ClientLoginFinishParameters, ClientLoginStartParameters};
 | 
					        pub use opaque_ke::ClientLoginFinishParameters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Initiate the login negotiation.
 | 
					        /// Initiate the login negotiation.
 | 
				
			||||||
        pub fn start_login<R: RngCore + CryptoRng>(
 | 
					        pub fn start_login<R: RngCore + CryptoRng>(
 | 
				
			||||||
            password: &str,
 | 
					            password: &str,
 | 
				
			||||||
            rng: &mut R,
 | 
					            rng: &mut R,
 | 
				
			||||||
        ) -> AuthenticationResult<ClientLoginStartResult> {
 | 
					        ) -> AuthenticationResult<ClientLoginStartResult> {
 | 
				
			||||||
            Ok(ClientLogin::start(
 | 
					            Ok(ClientLogin::start(rng, password.as_bytes())?)
 | 
				
			||||||
                rng,
 | 
					 | 
				
			||||||
                password.as_bytes(),
 | 
					 | 
				
			||||||
                ClientLoginStartParameters::default(),
 | 
					 | 
				
			||||||
            )?)
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Finalize the client login negotiation.
 | 
					        /// Finalize the client login negotiation.
 | 
				
			||||||
@ -130,6 +126,7 @@ pub mod client {
 | 
				
			|||||||
pub mod server {
 | 
					pub mod server {
 | 
				
			||||||
    pub use super::*;
 | 
					    pub use super::*;
 | 
				
			||||||
    pub type ServerRegistration = opaque_ke::ServerRegistration<DefaultSuite>;
 | 
					    pub type ServerRegistration = opaque_ke::ServerRegistration<DefaultSuite>;
 | 
				
			||||||
 | 
					    pub type ServerSetup = opaque_ke::ServerSetup<DefaultSuite>;
 | 
				
			||||||
    /// 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 {
 | 
				
			||||||
        pub use super::*;
 | 
					        pub use super::*;
 | 
				
			||||||
@ -140,24 +137,21 @@ pub mod server {
 | 
				
			|||||||
        /// 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(
 | 
				
			||||||
            rng: &mut R,
 | 
					            server_setup: &ServerSetup,
 | 
				
			||||||
            registration_request: RegistrationRequest,
 | 
					            registration_request: RegistrationRequest,
 | 
				
			||||||
            server_public_key: &PublicKey,
 | 
					            username: &str,
 | 
				
			||||||
        ) -> AuthenticationResult<ServerRegistrationStartResult> {
 | 
					        ) -> AuthenticationResult<ServerRegistrationStartResult> {
 | 
				
			||||||
            Ok(ServerRegistration::start(
 | 
					            Ok(ServerRegistration::start(
 | 
				
			||||||
                rng,
 | 
					                server_setup,
 | 
				
			||||||
                registration_request,
 | 
					                registration_request,
 | 
				
			||||||
                server_public_key,
 | 
					                username.as_bytes(),
 | 
				
			||||||
            )?)
 | 
					            )?)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Finish to register a new user, and get the data to store in the database.
 | 
					        /// Finish to register a new user, and get the data to store in the database.
 | 
				
			||||||
        pub fn get_password_file(
 | 
					        pub fn get_password_file(registration_upload: RegistrationUpload) -> ServerRegistration {
 | 
				
			||||||
            registration_start: ServerRegistration,
 | 
					            ServerRegistration::finish(registration_upload)
 | 
				
			||||||
            registration_upload: RegistrationUpload,
 | 
					 | 
				
			||||||
        ) -> AuthenticationResult<ServerRegistration> {
 | 
					 | 
				
			||||||
            Ok(registration_start.finish(registration_upload)?)
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -176,15 +170,17 @@ pub mod server {
 | 
				
			|||||||
        /// The result must be kept for the next step.
 | 
					        /// The result must be kept for the next step.
 | 
				
			||||||
        pub fn start_login<R: RngCore + CryptoRng>(
 | 
					        pub fn start_login<R: RngCore + CryptoRng>(
 | 
				
			||||||
            rng: &mut R,
 | 
					            rng: &mut R,
 | 
				
			||||||
            password_file: ServerRegistration,
 | 
					            server_setup: &ServerSetup,
 | 
				
			||||||
            server_private_key: &PrivateKey,
 | 
					            password_file: Option<ServerRegistration>,
 | 
				
			||||||
            credential_request: CredentialRequest,
 | 
					            credential_request: CredentialRequest,
 | 
				
			||||||
 | 
					            username: &str,
 | 
				
			||||||
        ) -> AuthenticationResult<ServerLoginStartResult> {
 | 
					        ) -> AuthenticationResult<ServerLoginStartResult> {
 | 
				
			||||||
            Ok(ServerLogin::start(
 | 
					            Ok(ServerLogin::start(
 | 
				
			||||||
                rng,
 | 
					                rng,
 | 
				
			||||||
 | 
					                server_setup,
 | 
				
			||||||
                password_file,
 | 
					                password_file,
 | 
				
			||||||
                server_private_key,
 | 
					 | 
				
			||||||
                credential_request,
 | 
					                credential_request,
 | 
				
			||||||
 | 
					                username.as_bytes(),
 | 
				
			||||||
                ServerLoginStartParameters::default(),
 | 
					                ServerLoginStartParameters::default(),
 | 
				
			||||||
            )?)
 | 
					            )?)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,12 @@ pub enum DomainError {
 | 
				
			|||||||
    DatabaseError(#[from] sqlx::Error),
 | 
					    DatabaseError(#[from] sqlx::Error),
 | 
				
			||||||
    #[error("Authentication protocol error for `{0}`")]
 | 
					    #[error("Authentication protocol error for `{0}`")]
 | 
				
			||||||
    AuthenticationProtocolError(#[from] lldap_model::opaque::AuthenticationError),
 | 
					    AuthenticationProtocolError(#[from] lldap_model::opaque::AuthenticationError),
 | 
				
			||||||
 | 
					    #[error("Unknown crypto error: `{0}`")]
 | 
				
			||||||
 | 
					    UnknownCryptoError(#[from] orion::errors::UnknownCryptoError),
 | 
				
			||||||
 | 
					    #[error("Binary serialization error: `{0}`")]
 | 
				
			||||||
 | 
					    BinarySerializationError(#[from] bincode::Error),
 | 
				
			||||||
 | 
					    #[error("Invalid base64: `{0}`")]
 | 
				
			||||||
 | 
					    Base64DecodeError(#[from] base64::DecodeError),
 | 
				
			||||||
    #[error("Internal error: `{0}`")]
 | 
					    #[error("Internal error: `{0}`")]
 | 
				
			||||||
    InternalError(String),
 | 
					    InternalError(String),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,8 @@ impl SqlBackendHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub fn get_password_file(
 | 
					pub fn get_password_file(
 | 
				
			||||||
    clear_password: &str,
 | 
					    clear_password: &str,
 | 
				
			||||||
    server_public_key: &opaque::PublicKey,
 | 
					    server_setup: &opaque::server::ServerSetup,
 | 
				
			||||||
 | 
					    username: &str,
 | 
				
			||||||
) -> Result<opaque::server::ServerRegistration> {
 | 
					) -> Result<opaque::server::ServerRegistration> {
 | 
				
			||||||
    use opaque::{client, server};
 | 
					    use opaque::{client, server};
 | 
				
			||||||
    let mut rng = rand::rngs::OsRng;
 | 
					    let mut rng = rand::rngs::OsRng;
 | 
				
			||||||
@ -30,9 +31,9 @@ pub fn get_password_file(
 | 
				
			|||||||
        client::registration::start_registration(clear_password, &mut rng)?;
 | 
					        client::registration::start_registration(clear_password, &mut rng)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let server_register_start_result = server::registration::start_registration(
 | 
					    let server_register_start_result = server::registration::start_registration(
 | 
				
			||||||
        &mut rng,
 | 
					        server_setup,
 | 
				
			||||||
        client_register_start_result.message,
 | 
					        client_register_start_result.message,
 | 
				
			||||||
        server_public_key,
 | 
					        username,
 | 
				
			||||||
    )?;
 | 
					    )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let client_registration_result = client::registration::finish_registration(
 | 
					    let client_registration_result = client::registration::finish_registration(
 | 
				
			||||||
@ -42,9 +43,8 @@ pub fn get_password_file(
 | 
				
			|||||||
    )?;
 | 
					    )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(server::registration::get_password_file(
 | 
					    Ok(server::registration::get_password_file(
 | 
				
			||||||
        server_register_start_result.state,
 | 
					 | 
				
			||||||
        client_registration_result.message,
 | 
					        client_registration_result.message,
 | 
				
			||||||
    )?)
 | 
					    ))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn get_filter_expr(filter: RequestFilter) -> SimpleExpr {
 | 
					fn get_filter_expr(filter: RequestFilter) -> SimpleExpr {
 | 
				
			||||||
@ -187,7 +187,7 @@ impl BackendHandler for SqlBackendHandler {
 | 
				
			|||||||
            Users::CreationDate,
 | 
					            Users::CreationDate,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        let mut values = vec![
 | 
					        let mut values = vec![
 | 
				
			||||||
            request.user_id.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),
 | 
				
			||||||
            request.first_name.map(Into::into).unwrap_or(Value::Null),
 | 
					            request.first_name.map(Into::into).unwrap_or(Value::Null),
 | 
				
			||||||
@ -197,7 +197,7 @@ impl BackendHandler for SqlBackendHandler {
 | 
				
			|||||||
        if let Some(pass) = request.password {
 | 
					        if let Some(pass) = request.password {
 | 
				
			||||||
            columns.push(Users::PasswordHash);
 | 
					            columns.push(Users::PasswordHash);
 | 
				
			||||||
            values.push(
 | 
					            values.push(
 | 
				
			||||||
                get_password_file(&pass, self.config.get_server_keys().public())?
 | 
					                get_password_file(&pass, self.config.get_server_setup(), &request.user_id)?
 | 
				
			||||||
                    .serialize()
 | 
					                    .serialize()
 | 
				
			||||||
                    .into(),
 | 
					                    .into(),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
				
			|||||||
@ -5,25 +5,16 @@ use super::{
 | 
				
			|||||||
use async_trait::async_trait;
 | 
					use async_trait::async_trait;
 | 
				
			||||||
use lldap_model::{opaque, BindRequest};
 | 
					use lldap_model::{opaque, BindRequest};
 | 
				
			||||||
use log::*;
 | 
					use log::*;
 | 
				
			||||||
use rand::{CryptoRng, RngCore};
 | 
					 | 
				
			||||||
use sea_query::{Expr, Iden, Query};
 | 
					use sea_query::{Expr, Iden, Query};
 | 
				
			||||||
use sqlx::Row;
 | 
					use sqlx::Row;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SqlOpaqueHandler = SqlBackendHandler;
 | 
					type SqlOpaqueHandler = SqlBackendHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn generate_random_id<R: RngCore + CryptoRng>(rng: &mut R) -> String {
 | 
					 | 
				
			||||||
    use rand::{distributions::Alphanumeric, Rng};
 | 
					 | 
				
			||||||
    std::iter::repeat(())
 | 
					 | 
				
			||||||
        .map(|()| rng.sample(Alphanumeric))
 | 
					 | 
				
			||||||
        .map(char::from)
 | 
					 | 
				
			||||||
        .take(32)
 | 
					 | 
				
			||||||
        .collect()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn passwords_match(
 | 
					fn passwords_match(
 | 
				
			||||||
    password_file_bytes: &[u8],
 | 
					    password_file_bytes: &[u8],
 | 
				
			||||||
    clear_password: &str,
 | 
					    clear_password: &str,
 | 
				
			||||||
    server_private_key: &opaque::PrivateKey,
 | 
					    server_setup: &opaque::server::ServerSetup,
 | 
				
			||||||
 | 
					    username: &str,
 | 
				
			||||||
) -> Result<()> {
 | 
					) -> Result<()> {
 | 
				
			||||||
    use opaque::{client, server};
 | 
					    use opaque::{client, server};
 | 
				
			||||||
    let mut rng = rand::rngs::OsRng;
 | 
					    let mut rng = rand::rngs::OsRng;
 | 
				
			||||||
@ -33,9 +24,10 @@ fn passwords_match(
 | 
				
			|||||||
        .map_err(opaque::AuthenticationError::ProtocolError)?;
 | 
					        .map_err(opaque::AuthenticationError::ProtocolError)?;
 | 
				
			||||||
    let server_login_start_result = server::login::start_login(
 | 
					    let server_login_start_result = server::login::start_login(
 | 
				
			||||||
        &mut rng,
 | 
					        &mut rng,
 | 
				
			||||||
        password_file,
 | 
					        server_setup,
 | 
				
			||||||
        server_private_key,
 | 
					        Some(password_file),
 | 
				
			||||||
        client_login_start_result.message,
 | 
					        client_login_start_result.message,
 | 
				
			||||||
 | 
					        username,
 | 
				
			||||||
    )?;
 | 
					    )?;
 | 
				
			||||||
    client::login::finish_login(
 | 
					    client::login::finish_login(
 | 
				
			||||||
        client_login_start_result.state,
 | 
					        client_login_start_result.state,
 | 
				
			||||||
@ -44,6 +36,40 @@ fn passwords_match(
 | 
				
			|||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SqlBackendHandler {
 | 
				
			||||||
 | 
					    fn get_orion_secret_key(&self) -> Result<orion::aead::SecretKey> {
 | 
				
			||||||
 | 
					        Ok(orion::aead::SecretKey::from_slice(
 | 
				
			||||||
 | 
					            self.config.get_server_keys().private(),
 | 
				
			||||||
 | 
					        )?)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn get_password_file_for_user(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        username: &str,
 | 
				
			||||||
 | 
					    ) -> Result<Option<opaque::server::ServerRegistration>> {
 | 
				
			||||||
 | 
					        // Fetch the previously registered password file from the DB.
 | 
				
			||||||
 | 
					        let password_file_bytes = {
 | 
				
			||||||
 | 
					            let query = Query::select()
 | 
				
			||||||
 | 
					                .column(Users::PasswordHash)
 | 
				
			||||||
 | 
					                .from(Users::Table)
 | 
				
			||||||
 | 
					                .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()))?
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return Ok(None);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        opaque::server::ServerRegistration::deserialize(&password_file_bytes)
 | 
				
			||||||
 | 
					            .map(Option::Some)
 | 
				
			||||||
 | 
					            .map_err(|_| {
 | 
				
			||||||
 | 
					                DomainError::InternalError(format!("Corrupted password file for {}", username))
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[async_trait]
 | 
					#[async_trait]
 | 
				
			||||||
impl LoginHandler for SqlBackendHandler {
 | 
					impl LoginHandler for SqlBackendHandler {
 | 
				
			||||||
    async fn bind(&self, request: BindRequest) -> Result<()> {
 | 
					    async fn bind(&self, request: BindRequest) -> Result<()> {
 | 
				
			||||||
@ -67,7 +93,8 @@ impl LoginHandler for SqlBackendHandler {
 | 
				
			|||||||
                if let Err(e) = passwords_match(
 | 
					                if let Err(e) = passwords_match(
 | 
				
			||||||
                    &password_hash,
 | 
					                    &password_hash,
 | 
				
			||||||
                    &request.password,
 | 
					                    &request.password,
 | 
				
			||||||
                    self.config.get_server_keys().private(),
 | 
					                    self.config.get_server_setup(),
 | 
				
			||||||
 | 
					                    &request.name,
 | 
				
			||||||
                ) {
 | 
					                ) {
 | 
				
			||||||
                    debug!(r#"Invalid password for "{}": {}"#, request.name, e);
 | 
					                    debug!(r#"Invalid password for "{}": {}"#, request.name, e);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
@ -89,99 +116,44 @@ impl OpaqueHandler for SqlOpaqueHandler {
 | 
				
			|||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        request: login::ClientLoginStartRequest,
 | 
					        request: login::ClientLoginStartRequest,
 | 
				
			||||||
    ) -> Result<login::ServerLoginStartResponse> {
 | 
					    ) -> Result<login::ServerLoginStartResponse> {
 | 
				
			||||||
        // Fetch the previously registered password file from the DB.
 | 
					        let maybe_password_file = self.get_password_file_for_user(&request.username).await?;
 | 
				
			||||||
        let password_file_bytes = {
 | 
					 | 
				
			||||||
            let query = Query::select()
 | 
					 | 
				
			||||||
                .column(Users::PasswordHash)
 | 
					 | 
				
			||||||
                .from(Users::Table)
 | 
					 | 
				
			||||||
                .and_where(Expr::col(Users::UserId).eq(request.username.as_str()))
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {});
 | 
					 | 
				
			||||||
            sqlx::query(&query)
 | 
					 | 
				
			||||||
                .fetch_one(&self.sql_pool)
 | 
					 | 
				
			||||||
                .await?
 | 
					 | 
				
			||||||
                .get::<Option<Vec<u8>>, _>(&*Users::PasswordHash.to_string())
 | 
					 | 
				
			||||||
                // If no password, always fail.
 | 
					 | 
				
			||||||
                .ok_or_else(|| DomainError::AuthenticationError(request.username.clone()))?
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        let password_file = opaque::server::ServerRegistration::deserialize(&password_file_bytes)
 | 
					 | 
				
			||||||
            .map_err(|_| {
 | 
					 | 
				
			||||||
            DomainError::InternalError(format!("Corrupted password file for {}", request.username))
 | 
					 | 
				
			||||||
        })?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut rng = rand::rngs::OsRng;
 | 
					        let mut rng = rand::rngs::OsRng;
 | 
				
			||||||
        let start_response = opaque::server::login::start_login(
 | 
					        let start_response = opaque::server::login::start_login(
 | 
				
			||||||
            &mut rng,
 | 
					            &mut rng,
 | 
				
			||||||
            password_file,
 | 
					            self.config.get_server_setup(),
 | 
				
			||||||
            self.config.get_server_keys().private(),
 | 
					            maybe_password_file,
 | 
				
			||||||
            request.login_start_request,
 | 
					            request.login_start_request,
 | 
				
			||||||
 | 
					            &request.username,
 | 
				
			||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
        let login_attempt_id = generate_random_id(&mut rng);
 | 
					        let secret_key = self.get_orion_secret_key()?;
 | 
				
			||||||
 | 
					        let server_data = login::ServerData {
 | 
				
			||||||
        {
 | 
					            username: request.username,
 | 
				
			||||||
            // Insert the current login attempt in the DB.
 | 
					            server_login: start_response.state,
 | 
				
			||||||
            let query = Query::insert()
 | 
					        };
 | 
				
			||||||
                .into_table(LoginAttempts::Table)
 | 
					        let encrypted_state = orion::aead::seal(&secret_key, &bincode::serialize(&server_data)?)?;
 | 
				
			||||||
                .columns(vec![
 | 
					 | 
				
			||||||
                    LoginAttempts::RandomId,
 | 
					 | 
				
			||||||
                    LoginAttempts::UserId,
 | 
					 | 
				
			||||||
                    LoginAttempts::ServerLoginData,
 | 
					 | 
				
			||||||
                    LoginAttempts::Timestamp,
 | 
					 | 
				
			||||||
                ])
 | 
					 | 
				
			||||||
                .values_panic(vec![
 | 
					 | 
				
			||||||
                    login_attempt_id.as_str().into(),
 | 
					 | 
				
			||||||
                    request.username.as_str().into(),
 | 
					 | 
				
			||||||
                    start_response.state.serialize().into(),
 | 
					 | 
				
			||||||
                    chrono::Utc::now().naive_utc().into(),
 | 
					 | 
				
			||||||
                ])
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {});
 | 
					 | 
				
			||||||
            sqlx::query(&query).execute(&self.sql_pool).await?;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(login::ServerLoginStartResponse {
 | 
					        Ok(login::ServerLoginStartResponse {
 | 
				
			||||||
            login_key: login_attempt_id,
 | 
					            server_data: base64::encode(&encrypted_state),
 | 
				
			||||||
            credential_response: start_response.message,
 | 
					            credential_response: start_response.message,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn login_finish(&self, request: login::ClientLoginFinishRequest) -> Result<String> {
 | 
					    async fn login_finish(&self, request: login::ClientLoginFinishRequest) -> Result<String> {
 | 
				
			||||||
        // Fetch the previous data from this login attempt.
 | 
					        let secret_key = self.get_orion_secret_key()?;
 | 
				
			||||||
        let row = {
 | 
					        let login::ServerData {
 | 
				
			||||||
            let query = Query::select()
 | 
					            username,
 | 
				
			||||||
                .column(LoginAttempts::UserId)
 | 
					            server_login,
 | 
				
			||||||
                .column(LoginAttempts::ServerLoginData)
 | 
					        } = bincode::deserialize(&orion::aead::open(
 | 
				
			||||||
                .from(LoginAttempts::Table)
 | 
					            &secret_key,
 | 
				
			||||||
                .and_where(Expr::col(LoginAttempts::RandomId).eq(request.login_key.as_str()))
 | 
					            &base64::decode(&request.server_data)?,
 | 
				
			||||||
                .and_where(
 | 
					        )?)?;
 | 
				
			||||||
                    Expr::col(LoginAttempts::Timestamp)
 | 
					 | 
				
			||||||
                        .gt(chrono::Utc::now().naive_utc() - chrono::Duration::minutes(5)),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {});
 | 
					 | 
				
			||||||
            sqlx::query(&query).fetch_one(&self.sql_pool).await?
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        let username = row.get::<String, _>(&*LoginAttempts::UserId.to_string());
 | 
					 | 
				
			||||||
        let login_data = opaque::server::login::ServerLogin::deserialize(
 | 
					 | 
				
			||||||
            &row.get::<Vec<u8>, _>(&*LoginAttempts::ServerLoginData.to_string()),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .map_err(|_| {
 | 
					 | 
				
			||||||
            DomainError::InternalError(format!(
 | 
					 | 
				
			||||||
                "Corrupted login data for user `{}` [id `{}`]",
 | 
					 | 
				
			||||||
                username, request.login_key
 | 
					 | 
				
			||||||
            ))
 | 
					 | 
				
			||||||
        })?;
 | 
					 | 
				
			||||||
        // Finish the login: this makes sure the client data is correct, and gives a session key we
 | 
					        // Finish the login: this makes sure the client data is correct, and gives a session key we
 | 
				
			||||||
        // don't need.
 | 
					        // don't need.
 | 
				
			||||||
        let _session_key =
 | 
					        let _session_key =
 | 
				
			||||||
            opaque::server::login::finish_login(login_data, request.credential_finalization)?
 | 
					            opaque::server::login::finish_login(server_login, request.credential_finalization)?
 | 
				
			||||||
                .session_key;
 | 
					                .session_key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // Login was successful, we can delete the login attempt from the table.
 | 
					 | 
				
			||||||
            let delete_query = Query::delete()
 | 
					 | 
				
			||||||
                .from_table(LoginAttempts::Table)
 | 
					 | 
				
			||||||
                .and_where(Expr::col(LoginAttempts::RandomId).eq(request.login_key))
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {});
 | 
					 | 
				
			||||||
            sqlx::query(&delete_query).execute(&self.sql_pool).await?;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Ok(username)
 | 
					        Ok(username)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -189,36 +161,19 @@ impl OpaqueHandler for SqlOpaqueHandler {
 | 
				
			|||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        request: registration::ClientRegistrationStartRequest,
 | 
					        request: registration::ClientRegistrationStartRequest,
 | 
				
			||||||
    ) -> Result<registration::ServerRegistrationStartResponse> {
 | 
					    ) -> Result<registration::ServerRegistrationStartResponse> {
 | 
				
			||||||
        let mut rng = rand::rngs::OsRng;
 | 
					 | 
				
			||||||
        // Generate the server-side key and derive the data to send back.
 | 
					        // Generate the server-side key and derive the data to send back.
 | 
				
			||||||
        let start_response = opaque::server::registration::start_registration(
 | 
					        let start_response = opaque::server::registration::start_registration(
 | 
				
			||||||
            &mut rng,
 | 
					            self.config.get_server_setup(),
 | 
				
			||||||
            request.registration_start_request,
 | 
					            request.registration_start_request,
 | 
				
			||||||
            self.config.get_server_keys().public(),
 | 
					            &request.username,
 | 
				
			||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
        // Unique ID to identify the registration attempt.
 | 
					        let secret_key = self.get_orion_secret_key()?;
 | 
				
			||||||
        let registration_attempt_id = generate_random_id(&mut rng);
 | 
					        let server_data = registration::ServerData {
 | 
				
			||||||
        {
 | 
					            username: request.username,
 | 
				
			||||||
            // Write the registration attempt to the DB for the later turn.
 | 
					        };
 | 
				
			||||||
            let query = Query::insert()
 | 
					        let encrypted_state = orion::aead::seal(&secret_key, &bincode::serialize(&server_data)?)?;
 | 
				
			||||||
                .into_table(RegistrationAttempts::Table)
 | 
					 | 
				
			||||||
                .columns(vec![
 | 
					 | 
				
			||||||
                    RegistrationAttempts::RandomId,
 | 
					 | 
				
			||||||
                    RegistrationAttempts::UserId,
 | 
					 | 
				
			||||||
                    RegistrationAttempts::ServerRegistrationData,
 | 
					 | 
				
			||||||
                    RegistrationAttempts::Timestamp,
 | 
					 | 
				
			||||||
                ])
 | 
					 | 
				
			||||||
                .values_panic(vec![
 | 
					 | 
				
			||||||
                    registration_attempt_id.as_str().into(),
 | 
					 | 
				
			||||||
                    request.username.as_str().into(),
 | 
					 | 
				
			||||||
                    start_response.state.serialize().into(),
 | 
					 | 
				
			||||||
                    chrono::Utc::now().naive_utc().into(),
 | 
					 | 
				
			||||||
                ])
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {});
 | 
					 | 
				
			||||||
            sqlx::query(&query).execute(&self.sql_pool).await?;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Ok(registration::ServerRegistrationStartResponse {
 | 
					        Ok(registration::ServerRegistrationStartResponse {
 | 
				
			||||||
            registration_key: registration_attempt_id,
 | 
					            server_data: base64::encode(encrypted_state),
 | 
				
			||||||
            registration_response: start_response.message,
 | 
					            registration_response: start_response.message,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -227,37 +182,14 @@ impl OpaqueHandler for SqlOpaqueHandler {
 | 
				
			|||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        request: registration::ClientRegistrationFinishRequest,
 | 
					        request: registration::ClientRegistrationFinishRequest,
 | 
				
			||||||
    ) -> Result<()> {
 | 
					    ) -> Result<()> {
 | 
				
			||||||
        // Fetch the previous state.
 | 
					        let secret_key = self.get_orion_secret_key()?;
 | 
				
			||||||
        let row = {
 | 
					        let registration::ServerData { username } = bincode::deserialize(&orion::aead::open(
 | 
				
			||||||
            let query = Query::select()
 | 
					            &secret_key,
 | 
				
			||||||
                .column(RegistrationAttempts::UserId)
 | 
					            &base64::decode(&request.server_data)?,
 | 
				
			||||||
                .column(RegistrationAttempts::ServerRegistrationData)
 | 
					        )?)?;
 | 
				
			||||||
                .from(RegistrationAttempts::Table)
 | 
					 | 
				
			||||||
                .and_where(
 | 
					 | 
				
			||||||
                    Expr::col(RegistrationAttempts::RandomId).eq(request.registration_key.as_str()),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                .and_where(
 | 
					 | 
				
			||||||
                    Expr::col(RegistrationAttempts::Timestamp)
 | 
					 | 
				
			||||||
                        .gt(chrono::Utc::now().naive_utc() - chrono::Duration::minutes(5)),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {});
 | 
					 | 
				
			||||||
            sqlx::query(&query).fetch_one(&self.sql_pool).await?
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        let username = row.get::<String, _>(&*RegistrationAttempts::UserId.to_string());
 | 
					 | 
				
			||||||
        let registration_data = opaque::server::registration::ServerRegistration::deserialize(
 | 
					 | 
				
			||||||
            &row.get::<Vec<u8>, _>(&*RegistrationAttempts::ServerRegistrationData.to_string()),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .map_err(|_| {
 | 
					 | 
				
			||||||
            DomainError::InternalError(format!(
 | 
					 | 
				
			||||||
                "Corrupted registration data for user `{}` [id `{}`]",
 | 
					 | 
				
			||||||
                username, request.registration_key
 | 
					 | 
				
			||||||
            ))
 | 
					 | 
				
			||||||
        })?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let password_file = opaque::server::registration::get_password_file(
 | 
					        let password_file =
 | 
				
			||||||
            registration_data,
 | 
					            opaque::server::registration::get_password_file(request.registration_upload);
 | 
				
			||||||
            request.registration_upload,
 | 
					 | 
				
			||||||
        )?;
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Set the user password to the new password.
 | 
					            // Set the user password to the new password.
 | 
				
			||||||
            let update_query = Query::update()
 | 
					            let update_query = Query::update()
 | 
				
			||||||
@ -270,14 +202,6 @@ impl OpaqueHandler for SqlOpaqueHandler {
 | 
				
			|||||||
                .to_string(DbQueryBuilder {});
 | 
					                .to_string(DbQueryBuilder {});
 | 
				
			||||||
            sqlx::query(&update_query).execute(&self.sql_pool).await?;
 | 
					            sqlx::query(&update_query).execute(&self.sql_pool).await?;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // Delete the registration attempt.
 | 
					 | 
				
			||||||
            let delete_query = Query::delete()
 | 
					 | 
				
			||||||
                .from_table(RegistrationAttempts::Table)
 | 
					 | 
				
			||||||
                .and_where(Expr::col(RegistrationAttempts::RandomId).eq(request.registration_key))
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {});
 | 
					 | 
				
			||||||
            sqlx::query(&delete_query).execute(&self.sql_pool).await?;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -341,7 +265,7 @@ mod tests {
 | 
				
			|||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
        opaque_handler
 | 
					        opaque_handler
 | 
				
			||||||
            .login_finish(ClientLoginFinishRequest {
 | 
					            .login_finish(ClientLoginFinishRequest {
 | 
				
			||||||
                login_key: start_response.login_key,
 | 
					                server_data: start_response.server_data,
 | 
				
			||||||
                credential_finalization: login_finish.message,
 | 
					                credential_finalization: login_finish.message,
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .await?;
 | 
					            .await?;
 | 
				
			||||||
@ -370,7 +294,7 @@ mod tests {
 | 
				
			|||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
        opaque_handler
 | 
					        opaque_handler
 | 
				
			||||||
            .registration_finish(ClientRegistrationFinishRequest {
 | 
					            .registration_finish(ClientRegistrationFinishRequest {
 | 
				
			||||||
                registration_key: start_response.registration_key,
 | 
					                server_data: start_response.server_data,
 | 
				
			||||||
                registration_upload: registration_finish.message,
 | 
					                registration_upload: registration_finish.message,
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .await
 | 
					            .await
 | 
				
			||||||
 | 
				
			|||||||
@ -34,27 +34,6 @@ pub enum Memberships {
 | 
				
			|||||||
    GroupId,
 | 
					    GroupId,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Contains the temporary data that needs to be kept between the first and second message when
 | 
					 | 
				
			||||||
/// logging in with the OPAQUE protocol.
 | 
					 | 
				
			||||||
#[derive(Iden)]
 | 
					 | 
				
			||||||
pub enum LoginAttempts {
 | 
					 | 
				
			||||||
    Table,
 | 
					 | 
				
			||||||
    RandomId,
 | 
					 | 
				
			||||||
    UserId,
 | 
					 | 
				
			||||||
    ServerLoginData,
 | 
					 | 
				
			||||||
    Timestamp,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Same for registration.
 | 
					 | 
				
			||||||
#[derive(Iden)]
 | 
					 | 
				
			||||||
pub enum RegistrationAttempts {
 | 
					 | 
				
			||||||
    Table,
 | 
					 | 
				
			||||||
    RandomId,
 | 
					 | 
				
			||||||
    UserId,
 | 
					 | 
				
			||||||
    ServerRegistrationData,
 | 
					 | 
				
			||||||
    Timestamp,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn init_table(pool: &Pool) -> sqlx::Result<()> {
 | 
					pub async fn init_table(pool: &Pool) -> sqlx::Result<()> {
 | 
				
			||||||
    // SQLite needs this pragma to be turned on. Other DB might not understand this, so ignore the
 | 
					    // SQLite needs this pragma to be turned on. Other DB might not understand this, so ignore the
 | 
				
			||||||
    // error.
 | 
					    // error.
 | 
				
			||||||
@ -135,80 +114,6 @@ pub async fn init_table(pool: &Pool) -> sqlx::Result<()> {
 | 
				
			|||||||
    .execute(pool)
 | 
					    .execute(pool)
 | 
				
			||||||
    .await?;
 | 
					    .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sqlx::query(
 | 
					 | 
				
			||||||
        &Table::create()
 | 
					 | 
				
			||||||
            .table(LoginAttempts::Table)
 | 
					 | 
				
			||||||
            .if_not_exists()
 | 
					 | 
				
			||||||
            .col(
 | 
					 | 
				
			||||||
                ColumnDef::new(LoginAttempts::RandomId)
 | 
					 | 
				
			||||||
                    .string_len(32)
 | 
					 | 
				
			||||||
                    .primary_key(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .col(
 | 
					 | 
				
			||||||
                ColumnDef::new(LoginAttempts::UserId)
 | 
					 | 
				
			||||||
                    .string_len(255)
 | 
					 | 
				
			||||||
                    .not_null(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .col(
 | 
					 | 
				
			||||||
                ColumnDef::new(LoginAttempts::ServerLoginData)
 | 
					 | 
				
			||||||
                    .binary()
 | 
					 | 
				
			||||||
                    .not_null(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .col(
 | 
					 | 
				
			||||||
                ColumnDef::new(LoginAttempts::Timestamp)
 | 
					 | 
				
			||||||
                    .date_time()
 | 
					 | 
				
			||||||
                    .not_null(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .foreign_key(
 | 
					 | 
				
			||||||
                ForeignKey::create()
 | 
					 | 
				
			||||||
                    .name("LoginAttemptsUserIdForeignKey")
 | 
					 | 
				
			||||||
                    .table(LoginAttempts::Table, Users::Table)
 | 
					 | 
				
			||||||
                    .col(LoginAttempts::UserId, Users::UserId)
 | 
					 | 
				
			||||||
                    .on_delete(ForeignKeyAction::Cascade)
 | 
					 | 
				
			||||||
                    .on_update(ForeignKeyAction::Cascade),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .to_string(DbQueryBuilder {}),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    .execute(pool)
 | 
					 | 
				
			||||||
    .await?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sqlx::query(
 | 
					 | 
				
			||||||
        &Table::create()
 | 
					 | 
				
			||||||
            .table(RegistrationAttempts::Table)
 | 
					 | 
				
			||||||
            .if_not_exists()
 | 
					 | 
				
			||||||
            .col(
 | 
					 | 
				
			||||||
                ColumnDef::new(RegistrationAttempts::RandomId)
 | 
					 | 
				
			||||||
                    .string_len(32)
 | 
					 | 
				
			||||||
                    .primary_key(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .col(
 | 
					 | 
				
			||||||
                ColumnDef::new(RegistrationAttempts::UserId)
 | 
					 | 
				
			||||||
                    .string_len(255)
 | 
					 | 
				
			||||||
                    .not_null(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .col(
 | 
					 | 
				
			||||||
                ColumnDef::new(RegistrationAttempts::ServerRegistrationData)
 | 
					 | 
				
			||||||
                    .binary()
 | 
					 | 
				
			||||||
                    .not_null(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .col(
 | 
					 | 
				
			||||||
                ColumnDef::new(RegistrationAttempts::Timestamp)
 | 
					 | 
				
			||||||
                    .date_time()
 | 
					 | 
				
			||||||
                    .not_null(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .foreign_key(
 | 
					 | 
				
			||||||
                ForeignKey::create()
 | 
					 | 
				
			||||||
                    .name("RegistrationAttemptsUserIdForeignKey")
 | 
					 | 
				
			||||||
                    .table(RegistrationAttempts::Table, Users::Table)
 | 
					 | 
				
			||||||
                    .col(RegistrationAttempts::UserId, Users::UserId)
 | 
					 | 
				
			||||||
                    .on_delete(ForeignKeyAction::Cascade)
 | 
					 | 
				
			||||||
                    .on_update(ForeignKeyAction::Cascade),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .to_string(DbQueryBuilder {}),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    .execute(pool)
 | 
					 | 
				
			||||||
    .await?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@ use figment::{
 | 
				
			|||||||
    providers::{Env, Format, Serialized, Toml},
 | 
					    providers::{Env, Format, Serialized, Toml},
 | 
				
			||||||
    Figment,
 | 
					    Figment,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use lldap_model::{opaque, opaque::KeyPair};
 | 
					use lldap_model::opaque::{server::ServerSetup, KeyPair};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::infra::cli::CLIOpts;
 | 
					use crate::infra::cli::CLIOpts;
 | 
				
			||||||
@ -27,18 +27,18 @@ pub struct Configuration {
 | 
				
			|||||||
    pub key_file: String,
 | 
					    pub key_file: String,
 | 
				
			||||||
    #[serde(skip)]
 | 
					    #[serde(skip)]
 | 
				
			||||||
    #[builder(field(private), setter(strip_option))]
 | 
					    #[builder(field(private), setter(strip_option))]
 | 
				
			||||||
    server_keys: Option<KeyPair>,
 | 
					    server_setup: Option<ServerSetup>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ConfigurationBuilder {
 | 
					impl ConfigurationBuilder {
 | 
				
			||||||
    #[cfg(test)]
 | 
					    #[cfg(test)]
 | 
				
			||||||
    pub fn build(self) -> Result<Configuration> {
 | 
					    pub fn build(self) -> Result<Configuration> {
 | 
				
			||||||
        let server_keys = get_server_keys(self.key_file.as_deref().unwrap_or("server_key"))?;
 | 
					        let server_setup = get_server_setup(self.key_file.as_deref().unwrap_or("server_key"))?;
 | 
				
			||||||
        Ok(self.server_keys(server_keys).private_build()?)
 | 
					        Ok(self.server_setup(server_setup).private_build()?)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn validate(&self) -> Result<(), String> {
 | 
					    fn validate(&self) -> Result<(), String> {
 | 
				
			||||||
        if self.server_keys.is_none() {
 | 
					        if self.server_setup.is_none() {
 | 
				
			||||||
            Err("Don't use `private_build`, use `build` instead".to_string())
 | 
					            Err("Don't use `private_build`, use `build` instead".to_string())
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Ok(())
 | 
					            Ok(())
 | 
				
			||||||
@ -47,8 +47,12 @@ impl ConfigurationBuilder {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Configuration {
 | 
					impl Configuration {
 | 
				
			||||||
 | 
					    pub fn get_server_setup(&self) -> &ServerSetup {
 | 
				
			||||||
 | 
					        self.server_setup.as_ref().unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn get_server_keys(&self) -> &KeyPair {
 | 
					    pub fn get_server_keys(&self) -> &KeyPair {
 | 
				
			||||||
        self.server_keys.as_ref().unwrap()
 | 
					        self.get_server_setup().keypair()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn merge_with_cli(mut self: Configuration, cli_opts: CLIOpts) -> Configuration {
 | 
					    fn merge_with_cli(mut self: Configuration, cli_opts: CLIOpts) -> Configuration {
 | 
				
			||||||
@ -80,30 +84,29 @@ impl Configuration {
 | 
				
			|||||||
            database_url: String::from("sqlite://users.db?mode=rwc"),
 | 
					            database_url: String::from("sqlite://users.db?mode=rwc"),
 | 
				
			||||||
            verbose: false,
 | 
					            verbose: false,
 | 
				
			||||||
            key_file: String::from("server_key"),
 | 
					            key_file: String::from("server_key"),
 | 
				
			||||||
            server_keys: None,
 | 
					            server_setup: None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn get_server_keys(file_path: &str) -> Result<KeyPair> {
 | 
					fn get_server_setup(file_path: &str) -> Result<ServerSetup> {
 | 
				
			||||||
    use opaque_ke::ciphersuite::CipherSuite;
 | 
					 | 
				
			||||||
    use std::path::Path;
 | 
					    use std::path::Path;
 | 
				
			||||||
    let path = Path::new(file_path);
 | 
					    let path = Path::new(file_path);
 | 
				
			||||||
    if path.exists() {
 | 
					    if path.exists() {
 | 
				
			||||||
        let bytes = std::fs::read(file_path)
 | 
					        let bytes = std::fs::read(file_path)
 | 
				
			||||||
            .map_err(|e| anyhow!("Could not read key file `{}`: {}", file_path, e))?;
 | 
					            .map_err(|e| anyhow!("Could not read key file `{}`: {}", file_path, e))?;
 | 
				
			||||||
        Ok(KeyPair::from_private_key_slice(&bytes)?)
 | 
					        Ok(ServerSetup::deserialize(&bytes)?)
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        let mut rng = rand::rngs::OsRng;
 | 
					        let mut rng = rand::rngs::OsRng;
 | 
				
			||||||
        let keypair = opaque::DefaultSuite::generate_random_keypair(&mut rng);
 | 
					        let server_setup = ServerSetup::new(&mut rng);
 | 
				
			||||||
        std::fs::write(path, keypair.private().as_slice()).map_err(|e| {
 | 
					        std::fs::write(path, server_setup.serialize()).map_err(|e| {
 | 
				
			||||||
            anyhow!(
 | 
					            anyhow!(
 | 
				
			||||||
                "Could not write the generated server keys to file `{}`: {}",
 | 
					                "Could not write the generated server setup to file `{}`: {}",
 | 
				
			||||||
                file_path,
 | 
					                file_path,
 | 
				
			||||||
                e
 | 
					                e
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        })?;
 | 
					        })?;
 | 
				
			||||||
        Ok(keypair)
 | 
					        Ok(server_setup)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -116,6 +119,6 @@ pub fn init(cli_opts: CLIOpts) -> Result<Configuration> {
 | 
				
			|||||||
        .extract()?;
 | 
					        .extract()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut 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)?);
 | 
					    config.server_setup = Some(get_server_setup(&config.key_file)?);
 | 
				
			||||||
    Ok(config)
 | 
					    Ok(config)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    domain::sql_tables::{DbQueryBuilder, LoginAttempts, Pool, RegistrationAttempts},
 | 
					    domain::sql_tables::{DbQueryBuilder, Pool},
 | 
				
			||||||
    infra::jwt_sql_tables::{JwtRefreshStorage, JwtStorage},
 | 
					    infra::jwt_sql_tables::{JwtRefreshStorage, JwtStorage},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use actix::prelude::*;
 | 
					use actix::prelude::*;
 | 
				
			||||||
@ -70,34 +70,6 @@ impl Scheduler {
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            log::error!("DB error while cleaning up JWT storage: {}", e);
 | 
					            log::error!("DB error while cleaning up JWT storage: {}", e);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        if let Err(e) = sqlx::query(
 | 
					 | 
				
			||||||
            &Query::delete()
 | 
					 | 
				
			||||||
                .from_table(LoginAttempts::Table)
 | 
					 | 
				
			||||||
                .and_where(
 | 
					 | 
				
			||||||
                    Expr::col(LoginAttempts::Timestamp)
 | 
					 | 
				
			||||||
                        .lt(Local::now().naive_utc() - chrono::Duration::minutes(5)),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {}),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .execute(&sql_pool)
 | 
					 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            log::error!("DB error while cleaning up login attempts: {}", e);
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        if let Err(e) = sqlx::query(
 | 
					 | 
				
			||||||
            &Query::delete()
 | 
					 | 
				
			||||||
                .from_table(RegistrationAttempts::Table)
 | 
					 | 
				
			||||||
                .and_where(
 | 
					 | 
				
			||||||
                    Expr::col(RegistrationAttempts::Timestamp)
 | 
					 | 
				
			||||||
                        .lt(Local::now().naive_utc() - chrono::Duration::minutes(5)),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                .to_string(DbQueryBuilder {}),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .execute(&sql_pool)
 | 
					 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            log::error!("DB error while cleaning up registration attempts: {}", e);
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        log::info!("DB cleaned!");
 | 
					        log::info!("DB cleaned!");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -32,8 +32,11 @@ pub(crate) fn error_to_http_response(error: DomainError) -> HttpResponse {
 | 
				
			|||||||
        DomainError::AuthenticationError(_) | DomainError::AuthenticationProtocolError(_) => {
 | 
					        DomainError::AuthenticationError(_) | DomainError::AuthenticationProtocolError(_) => {
 | 
				
			||||||
            HttpResponse::Unauthorized()
 | 
					            HttpResponse::Unauthorized()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        DomainError::DatabaseError(_) | DomainError::InternalError(_) => {
 | 
					        DomainError::DatabaseError(_)
 | 
				
			||||||
            HttpResponse::InternalServerError()
 | 
					        | DomainError::InternalError(_)
 | 
				
			||||||
 | 
					        | DomainError::UnknownCryptoError(_) => HttpResponse::InternalServerError(),
 | 
				
			||||||
 | 
					        DomainError::Base64DecodeError(_) | DomainError::BinarySerializationError(_) => {
 | 
				
			||||||
 | 
					            HttpResponse::BadRequest()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    .body(error.to_string())
 | 
					    .body(error.to_string())
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user