Advance Red Bear runtime services and tools

This commit is contained in:
2026-04-20 18:37:35 +01:00
parent 2b3b592dab
commit f3e6b09811
24 changed files with 1362 additions and 357 deletions
@@ -8,6 +8,8 @@ name = "redbear-authd"
path = "src/main.rs"
[dependencies]
redbear-login-protocol = { path = "../../redbear-login-protocol/source" }
rust-argon2 = "3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# Pure-Rust SHA-256/SHA-512 crypt verifier for /etc/shadow entries.
@@ -10,7 +10,9 @@ use std::{
time::{Duration, Instant},
};
use serde::{Deserialize, Serialize};
use argon2::{self, verify_encoded};
use redbear_login_protocol::{AuthRequest, AuthResponse};
use serde::Serialize;
use sha_crypt::{PasswordVerifier, ShaCrypt};
#[derive(Debug, PartialEq, Eq)]
@@ -49,51 +51,6 @@ struct RuntimeState {
failures: Arc<Mutex<HashMap<String, FailureState>>>,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
enum AuthRequest {
Authenticate {
request_id: u64,
username: String,
password: String,
vt: u32,
},
StartSession {
request_id: u64,
username: String,
session: String,
vt: u32,
},
PowerAction {
request_id: u64,
action: String,
},
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
enum AuthResponse {
AuthenticateResult {
request_id: u64,
ok: bool,
message: String,
},
SessionResult {
request_id: u64,
ok: bool,
exit_code: Option<i32>,
message: String,
},
PowerResult {
request_id: u64,
ok: bool,
message: String,
},
Error {
message: String,
},
}
#[derive(Debug, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
enum SessiondUpdate {
@@ -229,6 +186,9 @@ fn verify_shadow_password(password: &str, shadow_hash: &str) -> Result<bool, Ver
.verify_password(password.as_bytes(), shadow_hash)
.is_ok());
}
if shadow_hash.starts_with("$argon2") {
return Ok(verify_encoded(shadow_hash, password.as_bytes()).unwrap_or(false));
}
Err(VerifyError::UnsupportedHashFormat)
}
@@ -589,6 +549,15 @@ mod tests {
assert_eq!(verify_shadow_password("wrong", hash), Ok(false));
}
#[test]
fn verify_shadow_password_accepts_argon2_hashes() {
let config = argon2::Config::default();
let hash = argon2::hash_encoded(b"password", b"testsalt", &config)
.expect("argon2 hash should encode");
assert_eq!(verify_shadow_password("password", &hash), Ok(true));
assert_eq!(verify_shadow_password("wrong", &hash), Ok(false));
}
#[test]
fn verify_shadow_password_rejects_unknown_hash_prefix() {
assert_eq!(verify_shadow_password("password", "$1$legacy$hash"), Err(VerifyError::UnsupportedHashFormat));