Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul core Tracker: extract authentication #1192

Prev Previous commit
refactor: [#1191] remove tracker dependency for authentication tests
josecelano committed Jan 21, 2025
commit 6584fe434067c3a8c5eb12d5aa108df817291ccb
407 changes: 190 additions & 217 deletions src/core/authentication/mod.rs
Original file line number Diff line number Diff line change
@@ -306,297 +306,270 @@ impl Facade {
#[cfg(test)]
mod tests {

mod the_tracker {
mod the_tracker_configured_as_private {

use std::str::FromStr;
use std::time::Duration;

use torrust_tracker_configuration::v2_0_0::core::PrivateMode;
use torrust_tracker_test_helpers::configuration;

use crate::app_test::initialize_tracker_dependencies;
use crate::core::services::initialize_tracker;
use crate::core::Tracker;
use crate::core::authentication;
use crate::core::services::initialize_database;

fn private_tracker() -> Tracker {
fn instantiate_authentication() -> authentication::Facade {
let config = configuration::ephemeral_private();

let (database, _in_memory_whitelist, whitelist_authorization, authentication) =
initialize_tracker_dependencies(&config);

initialize_tracker(&config, &database, &whitelist_authorization, &authentication)
let database = initialize_database(&config);
authentication::Facade::new(&config.core, &database.clone())
}

fn private_tracker_without_checking_keys_expiration() -> Tracker {
fn instantiate_authentication_with_checking_keys_expiration_disabled() -> authentication::Facade {
let mut config = configuration::ephemeral_private();

config.core.private_mode = Some(PrivateMode {
check_keys_expiration: false,
});

let (database, _in_memory_whitelist, whitelist_authorization, authentication) =
initialize_tracker_dependencies(&config);
let database = initialize_database(&config);
authentication::Facade::new(&config.core, &database.clone())
}

#[tokio::test]
async fn it_should_fail_authenticating_a_peer_when_it_uses_an_unregistered_key() {
let authentication = instantiate_authentication();

let unregistered_key = authentication::Key::from_str("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap();

initialize_tracker(&config, &database, &whitelist_authorization, &authentication)
let result = authentication.authenticate(&unregistered_key).await;

assert!(result.is_err());
}

mod configured_as_private {
#[tokio::test]
async fn it_should_fail_verifying_an_unregistered_authentication_key() {
let authentication = instantiate_authentication();

mod handling_authentication {
use std::str::FromStr;
use std::time::Duration;
let unregistered_key = authentication::Key::from_str("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap();

use crate::core::authentication::tests::the_tracker::private_tracker;
use crate::core::authentication::{self};
assert!(authentication.verify_auth_key(&unregistered_key).await.is_err());
}

#[tokio::test]
async fn it_should_fail_authenticating_a_peer_when_it_uses_an_unregistered_key() {
let tracker = private_tracker();
#[tokio::test]
async fn it_should_remove_an_authentication_key() {
let authentication = instantiate_authentication();

let unregistered_key = authentication::Key::from_str("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap();
let expiring_key = authentication
.generate_auth_key(Some(Duration::from_secs(100)))
.await
.unwrap();

let result = tracker.authentication.authenticate(&unregistered_key).await;
let result = authentication.remove_auth_key(&expiring_key.key()).await;

assert!(result.is_err());
}
assert!(result.is_ok());
assert!(authentication.verify_auth_key(&expiring_key.key()).await.is_err());
}

#[tokio::test]
async fn it_should_fail_verifying_an_unregistered_authentication_key() {
let tracker = private_tracker();
#[tokio::test]
async fn it_should_load_authentication_keys_from_the_database() {
let authentication = instantiate_authentication();

let unregistered_key = authentication::Key::from_str("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap();
let expiring_key = authentication
.generate_auth_key(Some(Duration::from_secs(100)))
.await
.unwrap();

assert!(tracker.authentication.verify_auth_key(&unregistered_key).await.is_err());
}
// Remove the newly generated key in memory
authentication.remove_in_memory_auth_key(&expiring_key.key()).await;

let result = authentication.load_keys_from_database().await;

assert!(result.is_ok());
assert!(authentication.verify_auth_key(&expiring_key.key()).await.is_ok());
}

mod with_expiring_and {

mod randomly_generated_keys {
use std::time::Duration;

use torrust_tracker_clock::clock::Time;

use crate::core::authentication::tests::the_tracker_configured_as_private::{
instantiate_authentication, instantiate_authentication_with_checking_keys_expiration_disabled,
};
use crate::core::authentication::Key;
use crate::CurrentClock;

#[tokio::test]
async fn it_should_remove_an_authentication_key() {
let tracker = private_tracker();
async fn it_should_generate_the_key() {
let authentication = instantiate_authentication();

let expiring_key = tracker
.authentication
let peer_key = authentication
.generate_auth_key(Some(Duration::from_secs(100)))
.await
.unwrap();

let result = tracker.authentication.remove_auth_key(&expiring_key.key()).await;

assert!(result.is_ok());
assert!(tracker.authentication.verify_auth_key(&expiring_key.key()).await.is_err());
assert_eq!(
peer_key.valid_until,
Some(CurrentClock::now_add(&Duration::from_secs(100)).unwrap())
);
}

#[tokio::test]
async fn it_should_load_authentication_keys_from_the_database() {
let tracker = private_tracker();
async fn it_should_authenticate_a_peer_with_the_key() {
let authentication = instantiate_authentication();

let expiring_key = tracker
.authentication
let peer_key = authentication
.generate_auth_key(Some(Duration::from_secs(100)))
.await
.unwrap();

// Remove the newly generated key in memory
tracker.authentication.remove_in_memory_auth_key(&expiring_key.key()).await;

let result = tracker.authentication.load_keys_from_database().await;
let result = authentication.authenticate(&peer_key.key()).await;

assert!(result.is_ok());
assert!(tracker.authentication.verify_auth_key(&expiring_key.key()).await.is_ok());
}

mod with_expiring_and {
#[tokio::test]
async fn it_should_accept_an_expired_key_when_checking_expiration_is_disabled_in_configuration() {
let authentication = instantiate_authentication_with_checking_keys_expiration_disabled();

mod randomly_generated_keys {
use std::time::Duration;
let past_timestamp = Duration::ZERO;

use torrust_tracker_clock::clock::Time;
let peer_key = authentication
.add_auth_key(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap(), Some(past_timestamp))
.await
.unwrap();

use crate::core::authentication::tests::the_tracker::{
private_tracker, private_tracker_without_checking_keys_expiration,
};
use crate::core::authentication::Key;
use crate::CurrentClock;
assert!(authentication.authenticate(&peer_key.key()).await.is_ok());
}
}

#[tokio::test]
async fn it_should_generate_the_key() {
let tracker = private_tracker();
mod pre_generated_keys {
use std::time::Duration;

let peer_key = tracker
.authentication
.generate_auth_key(Some(Duration::from_secs(100)))
.await
.unwrap();
use torrust_tracker_clock::clock::Time;

assert_eq!(
peer_key.valid_until,
Some(CurrentClock::now_add(&Duration::from_secs(100)).unwrap())
);
}
use crate::core::authentication::tests::the_tracker_configured_as_private::{
instantiate_authentication, instantiate_authentication_with_checking_keys_expiration_disabled,
};
use crate::core::authentication::{AddKeyRequest, Key};
use crate::CurrentClock;

#[tokio::test]
async fn it_should_authenticate_a_peer_with_the_key() {
let tracker = private_tracker();
#[tokio::test]
async fn it_should_add_a_pre_generated_key() {
let authentication = instantiate_authentication();

let peer_key = authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: Some(100),
})
.await
.unwrap();

let peer_key = tracker
.authentication
.generate_auth_key(Some(Duration::from_secs(100)))
.await
.unwrap();
assert_eq!(
peer_key.valid_until,
Some(CurrentClock::now_add(&Duration::from_secs(100)).unwrap())
);
}

let result = tracker.authentication.authenticate(&peer_key.key()).await;
#[tokio::test]
async fn it_should_authenticate_a_peer_with_the_key() {
let authentication = instantiate_authentication();

let peer_key = authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: Some(100),
})
.await
.unwrap();

assert!(result.is_ok());
}
let result = authentication.authenticate(&peer_key.key()).await;

#[tokio::test]
async fn it_should_accept_an_expired_key_when_checking_expiration_is_disabled_in_configuration() {
let tracker = private_tracker_without_checking_keys_expiration();
assert!(result.is_ok());
}

let past_timestamp = Duration::ZERO;
#[tokio::test]
async fn it_should_accept_an_expired_key_when_checking_expiration_is_disabled_in_configuration() {
let authentication = instantiate_authentication_with_checking_keys_expiration_disabled();

let peer_key = authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: Some(0),
})
.await
.unwrap();

let peer_key = tracker
.authentication
.add_auth_key(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap(), Some(past_timestamp))
.await
.unwrap();
assert!(authentication.authenticate(&peer_key.key()).await.is_ok());
}
}
}

assert!(tracker.authentication.authenticate(&peer_key.key()).await.is_ok());
}
}
mod with_permanent_and {

mod pre_generated_keys {
use std::time::Duration;

use torrust_tracker_clock::clock::Time;

use crate::core::authentication::tests::the_tracker::{
private_tracker, private_tracker_without_checking_keys_expiration,
};
use crate::core::authentication::{AddKeyRequest, Key};
use crate::CurrentClock;

#[tokio::test]
async fn it_should_add_a_pre_generated_key() {
let tracker = private_tracker();

let peer_key = tracker
.authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: Some(100),
})
.await
.unwrap();

assert_eq!(
peer_key.valid_until,
Some(CurrentClock::now_add(&Duration::from_secs(100)).unwrap())
);
}

#[tokio::test]
async fn it_should_authenticate_a_peer_with_the_key() {
let tracker = private_tracker();

let peer_key = tracker
.authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: Some(100),
})
.await
.unwrap();

let result = tracker.authentication.authenticate(&peer_key.key()).await;

assert!(result.is_ok());
}

#[tokio::test]
async fn it_should_accept_an_expired_key_when_checking_expiration_is_disabled_in_configuration() {
let tracker = private_tracker_without_checking_keys_expiration();

let peer_key = tracker
.authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: Some(0),
})
.await
.unwrap();

assert!(tracker.authentication.authenticate(&peer_key.key()).await.is_ok());
}
}
}
mod randomly_generated_keys {
use crate::core::authentication::tests::the_tracker_configured_as_private::instantiate_authentication;

mod with_permanent_and {
#[tokio::test]
async fn it_should_generate_the_key() {
let authentication = instantiate_authentication();

mod randomly_generated_keys {
use crate::core::authentication::tests::the_tracker::private_tracker;
let peer_key = authentication.generate_permanent_auth_key().await.unwrap();

#[tokio::test]
async fn it_should_generate_the_key() {
let tracker = private_tracker();
assert_eq!(peer_key.valid_until, None);
}

let peer_key = tracker.authentication.generate_permanent_auth_key().await.unwrap();
#[tokio::test]
async fn it_should_authenticate_a_peer_with_the_key() {
let authentication = instantiate_authentication();

assert_eq!(peer_key.valid_until, None);
}
let peer_key = authentication.generate_permanent_auth_key().await.unwrap();

#[tokio::test]
async fn it_should_authenticate_a_peer_with_the_key() {
let tracker = private_tracker();
let result = authentication.authenticate(&peer_key.key()).await;

let peer_key = tracker.authentication.generate_permanent_auth_key().await.unwrap();
assert!(result.is_ok());
}
}

let result = tracker.authentication.authenticate(&peer_key.key()).await;
mod pre_generated_keys {
use crate::core::authentication::tests::the_tracker_configured_as_private::instantiate_authentication;
use crate::core::authentication::{AddKeyRequest, Key};

assert!(result.is_ok());
}
}
#[tokio::test]
async fn it_should_add_a_pre_generated_key() {
let authentication = instantiate_authentication();

let peer_key = authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: None,
})
.await
.unwrap();

mod pre_generated_keys {
use crate::core::authentication::tests::the_tracker::private_tracker;
use crate::core::authentication::{AddKeyRequest, Key};

#[tokio::test]
async fn it_should_add_a_pre_generated_key() {
let tracker = private_tracker();

let peer_key = tracker
.authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: None,
})
.await
.unwrap();

assert_eq!(peer_key.valid_until, None);
}

#[tokio::test]
async fn it_should_authenticate_a_peer_with_the_key() {
let tracker = private_tracker();

let peer_key = tracker
.authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: None,
})
.await
.unwrap();

let result = tracker.authentication.authenticate(&peer_key.key()).await;

assert!(result.is_ok());
}
}
assert_eq!(peer_key.valid_until, None);
}
}

mod handling_an_announce_request {}
#[tokio::test]
async fn it_should_authenticate_a_peer_with_the_key() {
let authentication = instantiate_authentication();

let peer_key = authentication
.add_peer_key(AddKeyRequest {
opt_key: Some(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap().to_string()),
opt_seconds_valid: None,
})
.await
.unwrap();

let result = authentication.authenticate(&peer_key.key()).await;

mod handling_an_scrape_request {}
assert!(result.is_ok());
}
}
}
}
}