Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions server/src/internal_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,17 +453,22 @@ pub(crate) async fn send_json<T: serde::Serialize + ?Sized>(
#[cfg(test)]
mod tests {
use super::*;

fn keyring(byte: u8) -> String {
let secret = data_encoding::BASE64.encode(&[byte; 32]);
format!(r#"{{"active":"{secret}"}}"#)
}

fn nonce() -> String {
data_encoding::BASE64URL_NOPAD.encode(&shared::internal_auth::new_nonce())
}

#[test]
fn config_requires_distinct_directional_keyrings_and_valid_active_ids() {
let ce = keyring(1);
let ee = keyring(2);
let config = Config::from_values(&ce, "active", &ee, "active").unwrap();
let nonce = [3; 32];
let nonce = shared::internal_auth::new_nonce();
let ce_signature = shared::internal_auth::sign_request(
&config.ce_to_ee[0],
Direction::CeToEe,
Expand Down Expand Up @@ -498,14 +503,15 @@ mod tests {
async fn nonce_is_consumed_once_and_persists_in_sqlite() {
let pool = sqlx::SqlitePool::connect("sqlite::memory:").await.unwrap();
init_nonce_schema(&pool).await.unwrap();
let nonce = nonce();

assert!(
consume_nonce(&pool, Direction::EeToCe, "k1", "nonce", 100)
consume_nonce(&pool, Direction::EeToCe, "k1", &nonce, 100)
.await
.is_ok()
);
assert!(matches!(
consume_nonce(&pool, Direction::EeToCe, "k1", "nonce", 101).await,
consume_nonce(&pool, Direction::EeToCe, "k1", &nonce, 101).await,
Err(Error::Replay)
));
}
Expand All @@ -514,15 +520,16 @@ mod tests {
async fn expired_nonce_is_pruned_before_insert() {
let pool = sqlx::SqlitePool::connect("sqlite::memory:").await.unwrap();
init_nonce_schema(&pool).await.unwrap();
consume_nonce(&pool, Direction::EeToCe, "k1", "nonce", 100)
let nonce = nonce();
consume_nonce(&pool, Direction::EeToCe, "k1", &nonce, 100)
.await
.unwrap();
assert!(
consume_nonce(
&pool,
Direction::EeToCe,
"k1",
"nonce",
&nonce,
100 + NONCE_TTL_SECS + 1,
)
.await
Expand Down
31 changes: 17 additions & 14 deletions shared/src/internal_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use std::fmt;

use base64::Engine;
use hmac::{Hmac, Mac};
use rand::RngCore;
use rand::{
distributions::{Distribution, Standard},
rngs::OsRng,
};
use sha2::Sha256;
use zeroize::Zeroizing;

Expand Down Expand Up @@ -214,9 +217,8 @@ fn validate_nonce(encoded: &str) -> Result<(), AuthError> {
}

pub fn new_nonce() -> [u8; 32] {
let mut nonce = [0u8; 32];
rand::rngs::OsRng.fill_bytes(&mut nonce);
nonce
let mut rng = OsRng;
Standard.sample(&mut rng)
}

pub fn parse_keyring(json: &str) -> Result<Vec<InternalKey>, AuthError> {
Expand Down Expand Up @@ -362,11 +364,12 @@ mod tests {
#[test]
fn request_signature_binds_body_path_identity_and_direction() {
let key = key("k1", 7);
let nonce = new_nonce();
let signed = sign_request(
&key,
Direction::CeToEe,
100,
&[9; 32],
&nonce,
"POST",
"/api/ee/acl?x=1",
br#"{"a":1}"#,
Expand Down Expand Up @@ -426,14 +429,8 @@ mod tests {
#[test]
fn response_signature_binds_request_nonce_status_and_body() {
let key = key("response", 11);
let response = sign_response(
&key,
Direction::EeToCe,
"CQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQk",
200,
b"ok",
)
.unwrap();
let request_nonce = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(new_nonce());
let response = sign_response(&key, Direction::EeToCe, &request_nonce, 200, b"ok").unwrap();

assert!(
verify_response(
Expand Down Expand Up @@ -461,11 +458,12 @@ mod tests {
#[test]
fn request_rejects_stale_timestamp_and_malformed_nonce() {
let key = key("k1", 7);
let nonce = new_nonce();
let mut signed = sign_request(
&key,
Direction::CeToEe,
100,
&[9; 32],
&nonce,
"GET",
"/api/ee/audit",
b"",
Expand Down Expand Up @@ -522,4 +520,9 @@ mod tests {
Err(AuthError::InvalidKeyring)
));
}

#[test]
fn new_nonce_returns_fresh_values() {
assert_ne!(new_nonce(), new_nonce());
}
}
Loading