kanidm/kanidm_client/tests/proto_v1_test.rs
Firstyear 8cfa8f3f95
12 totp (#201)
Implements #12, TOTP. This adds support for TOTP to the api and server, with server side token generation, authentication and the correct URI for encoding into QR codes for client token addition. Some extra measures have been taken such as in the stepped auth to always notify on the success or failure of the TOTP first (regardless of order) to prevent PW bruteforce attacks.
2020-04-10 15:50:45 +10:00

826 lines
27 KiB
Rust

#![deny(warnings)]
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc;
use std::thread;
use std::time::SystemTime;
use kanidm::config::{Configuration, IntegrationTestConfig};
use kanidm::core::create_server_core;
use kanidm::credential::totp::TOTP;
use kanidm_client::{KanidmClient, KanidmClientBuilder};
use kanidm_proto::v1::{Entry, Filter, Modify, ModifyList};
use actix::prelude::*;
use log::debug;
static PORT_ALLOC: AtomicUsize = AtomicUsize::new(8080);
static ADMIN_TEST_PASSWORD: &str = "integration test admin password";
static ADMIN_TEST_PASSWORD_CHANGE: &str = "integration test admin new🎉";
static UNIX_TEST_PASSWORD: &str = "unix test user password";
// Test external behaviorus of the service.
fn run_test(test_fn: fn(KanidmClient) -> ()) {
// ::std::env::set_var("RUST_LOG", "actix_web=debug,kanidm=debug");
let _ = env_logger::builder().is_test(true).try_init();
let (tx, rx) = mpsc::channel();
let port = PORT_ALLOC.fetch_add(1, Ordering::SeqCst);
let int_config = Box::new(IntegrationTestConfig {
admin_password: ADMIN_TEST_PASSWORD.to_string(),
});
let mut config = Configuration::new();
config.address = format!("127.0.0.1:{}", port);
config.secure_cookies = false;
config.integration_test_config = Some(int_config);
// Setup the config ...
thread::spawn(move || {
// Spawn a thread for the test runner, this should have a unique
// port....
System::run(move || {
create_server_core(config);
// This appears to be bind random ...
// let srv = srv.bind("127.0.0.1:0").unwrap();
let _ = tx.send(System::current());
})
.expect("unable to start system");
});
let sys = rx.recv().unwrap();
System::set_current(sys.clone());
// Do we need any fixtures?
// Yes probably, but they'll need to be futures as well ...
// later we could accept fixture as it's own future for re-use
// Setup the client, and the address we selected.
let addr = format!("http://127.0.0.1:{}", port);
let rsclient = KanidmClientBuilder::new()
.address(addr)
.build()
.expect("Failed to build client");
test_fn(rsclient);
// We DO NOT need teardown, as sqlite is in mem
// let the tables hit the floor
sys.stop();
}
#[test]
fn test_server_create() {
run_test(|rsclient: KanidmClient| {
let e: Entry = serde_json::from_str(
r#"{
"attrs": {
"class": ["account"],
"name": ["testperson"],
"displayname": ["testperson"]
}
}"#,
)
.unwrap();
// Not logged in - should fail!
let res = rsclient.create(vec![e.clone()]);
assert!(res.is_err());
let a_res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(a_res.is_ok());
let res = rsclient.create(vec![e]);
assert!(res.is_ok());
});
}
#[test]
fn test_server_modify() {
run_test(|rsclient: KanidmClient| {
// Build a self mod.
let f = Filter::SelfUUID;
let m = ModifyList::new_list(vec![
Modify::Purged("displayname".to_string()),
Modify::Present("displayname".to_string(), "test".to_string()),
]);
// Not logged in - should fail!
let res = rsclient.modify(f.clone(), m.clone());
assert!(res.is_err());
let a_res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(a_res.is_ok());
let res = rsclient.modify(f, m);
println!("{:?}", res);
assert!(res.is_ok());
});
}
#[test]
fn test_server_whoami_anonymous() {
run_test(|rsclient: KanidmClient| {
// First show we are un-authenticated.
let pre_res = rsclient.whoami();
// This means it was okay whoami, but no uat attached.
assert!(pre_res.unwrap().is_none());
// Now login as anonymous
let res = rsclient.auth_anonymous();
assert!(res.is_ok());
// Now do a whoami.
let (_e, uat) = match rsclient.whoami().unwrap() {
Some((e, uat)) => (e, uat),
None => panic!(),
};
debug!("{}", uat);
assert!(uat.name == "anonymous");
});
}
#[test]
fn test_server_whoami_admin_simple_password() {
run_test(|rsclient: KanidmClient| {
// First show we are un-authenticated.
let pre_res = rsclient.whoami();
// This means it was okay whoami, but no uat attached.
assert!(pre_res.unwrap().is_none());
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Now do a whoami.
let (_e, uat) = match rsclient.whoami().unwrap() {
Some((e, uat)) => (e, uat),
None => panic!(),
};
debug!("{}", uat);
assert!(uat.name == "admin");
});
}
#[test]
fn test_server_search() {
run_test(|rsclient: KanidmClient| {
// First show we are un-authenticated.
let pre_res = rsclient.whoami();
// This means it was okay whoami, but no uat attached.
assert!(pre_res.unwrap().is_none());
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
let rset = rsclient
.search(Filter::Eq("name".to_string(), "admin".to_string()))
.unwrap();
println!("{:?}", rset);
let e = rset.first().unwrap();
// Check it's admin.
println!("{:?}", e);
let name = e.attrs.get("name").unwrap();
assert!(name == &vec!["admin".to_string()]);
});
}
#[test]
fn test_server_admin_change_simple_password() {
run_test(|mut rsclient: KanidmClient| {
// First show we are un-authenticated.
let pre_res = rsclient.whoami();
// This means it was okay whoami, but no uat attached.
assert!(pre_res.unwrap().is_none());
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Now change the password.
rsclient
.idm_account_set_password(ADMIN_TEST_PASSWORD_CHANGE.to_string())
.unwrap();
// Now "reset" the client.
let _ = rsclient.logout();
// Old password fails
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_err());
// New password works!
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD_CHANGE);
assert!(res.is_ok());
});
}
// Add a test for reseting another accounts pws via the rest api
#[test]
fn test_server_admin_reset_simple_password() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Create a diff account
let e: Entry = serde_json::from_str(
r#"{
"attrs": {
"class": ["account"],
"name": ["testperson"],
"displayname": ["testperson"]
}
}"#,
)
.unwrap();
// Not logged in - should fail!
let res = rsclient.create(vec![e]);
assert!(res.is_ok());
// By default, admin's can't actually administer accounts, so mod them into
// the account admin group.
let f = Filter::Eq("name".to_string(), "idm_admins".to_string());
let m = ModifyList::new_list(vec![Modify::Present(
"member".to_string(),
"system_admins".to_string(),
)]);
let res = rsclient.modify(f, m);
assert!(res.is_ok());
// Now set it's password - should be rejected based on low quality
let res = rsclient.idm_account_primary_credential_set_password("testperson", "password");
assert!(res.is_err());
// Set the password to ensure it's good
let res = rsclient.idm_account_primary_credential_set_password(
"testperson",
"tai4eCohtae9aegheo3Uw0oobahVighaig6heeli",
);
assert!(res.is_ok());
// Check it stuck.
let tclient = rsclient.new_session().expect("failed to build new session");
assert!(tclient
.auth_simple_password("testperson", "tai4eCohtae9aegheo3Uw0oobahVighaig6heeli")
.is_ok());
// Generate a pw instead
let res = rsclient.idm_account_primary_credential_set_generated("testperson");
assert!(res.is_ok());
let gpw = res.unwrap();
let tclient = rsclient.new_session().expect("failed to build new session");
assert!(tclient
.auth_simple_password("testperson", gpw.as_str())
.is_ok());
});
}
// test the rest group endpoint.
#[test]
fn test_server_rest_group_read() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// List the groups
let g_list = rsclient.idm_group_list().unwrap();
assert!(!g_list.is_empty());
let g = rsclient.idm_group_get("idm_admins").unwrap();
assert!(g.is_some());
println!("{:?}", g);
});
}
#[test]
fn test_server_rest_group_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// List the groups
let g_list = rsclient.idm_group_list().unwrap();
assert!(!g_list.is_empty());
// Create a new group
rsclient.idm_group_create("demo_group").unwrap();
// List again, ensure one more.
let g_list_2 = rsclient.idm_group_list().unwrap();
assert!(g_list_2.len() > g_list.len());
// Test modifications to the group
// Add a member.
rsclient
.idm_group_add_members("demo_group", vec!["admin"])
.unwrap();
let members = rsclient.idm_group_get_members("demo_group").unwrap();
assert!(members == Some(vec!["admin".to_string()]));
// Set the list of members
rsclient
.idm_group_set_members("demo_group", vec!["admin", "demo_group"])
.unwrap();
let members = rsclient.idm_group_get_members("demo_group").unwrap();
assert!(members == Some(vec!["admin".to_string(), "demo_group".to_string()]));
// Remove a member from the group
/*
rsclient
.idm_group_remove_member("demo_group", "demo_group")
.unwrap();
let members = rsclient.idm_group_get_members("demo_group").unwrap();
assert!(members == vec!["admin".to_string()]);
*/
// purge members
rsclient.idm_group_purge_members("demo_group").unwrap();
let members = rsclient.idm_group_get_members("demo_group").unwrap();
assert!(members == None);
// Delete the group
rsclient.idm_group_delete("demo_group").unwrap();
let g_list_3 = rsclient.idm_group_list().unwrap();
assert!(g_list_3.len() == g_list.len());
// Check we can get an exact group
let g = rsclient.idm_group_get("idm_admins").unwrap();
assert!(g.is_some());
println!("{:?}", g);
// They should have members
let members = rsclient.idm_group_get_members("idm_admins").unwrap();
println!("{:?}", members);
assert!(members == Some(vec!["idm_admin".to_string()]));
});
}
#[test]
fn test_server_rest_account_read() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// List the accounts
let a_list = rsclient.idm_account_list().unwrap();
assert!(!a_list.is_empty());
let a = rsclient.idm_account_get("admin").unwrap();
assert!(a.is_some());
println!("{:?}", a);
});
}
#[test]
fn test_server_rest_schema_read() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// List the schema
let s_list = rsclient.idm_schema_list().unwrap();
assert!(!s_list.is_empty());
let a_list = rsclient.idm_schema_attributetype_list().unwrap();
assert!(!a_list.is_empty());
let c_list = rsclient.idm_schema_classtype_list().unwrap();
assert!(!c_list.is_empty());
// Get an attr/class
let a = rsclient.idm_schema_attributetype_get("name").unwrap();
assert!(a.is_some());
println!("{:?}", a);
let c = rsclient.idm_schema_classtype_get("account").unwrap();
assert!(c.is_some());
println!("{:?}", c);
});
}
// Test resetting a radius cred, and then checking/viewing it.
#[test]
fn test_server_radius_credential_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Should have no radius secret
let n_sec = rsclient.idm_account_radius_credential_get("admin").unwrap();
assert!(n_sec.is_none());
// Set one
let sec1 = rsclient
.idm_account_radius_credential_regenerate("admin")
.unwrap();
// Should be able to get it.
let r_sec = rsclient.idm_account_radius_credential_get("admin").unwrap();
assert!(sec1 == r_sec.unwrap());
// test getting the token - we can do this as self or the radius server
let r_tok = rsclient.idm_account_radius_token_get("admin").unwrap();
assert!(sec1 == r_tok.secret);
assert!(r_tok.name == "admin");
// Reset it
let sec2 = rsclient
.idm_account_radius_credential_regenerate("admin")
.unwrap();
// Should be different
println!("s1 {} != s2 {}", sec1, sec2);
assert!(sec1 != sec2);
// Delete it
let res = rsclient.idm_account_radius_credential_delete("admin");
assert!(res.is_ok());
// No secret
let n_sec = rsclient.idm_account_radius_credential_get("admin").unwrap();
assert!(n_sec.is_none());
});
}
#[test]
fn test_server_rest_account_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// To enable the admin to actually make some of these changes, we have
// to make them a people admin. NOT recommended in production!
rsclient
.idm_group_add_members("idm_account_write_priv", vec!["admin"])
.unwrap();
// Create a new account
rsclient
.idm_account_create("demo_account", "Deeeeemo")
.unwrap();
// View the account
rsclient.idm_account_get("demo_account").unwrap();
// change the name?
rsclient
.idm_account_set_displayname("demo_account", "Demo Account")
.unwrap();
// Delete the account
rsclient.idm_account_delete("demo_account").unwrap();
});
}
#[test]
fn test_server_rest_sshkey_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Get the keys, should be empty vec.
let sk1 = rsclient.idm_account_get_ssh_pubkeys("admin").unwrap();
assert!(sk1.is_empty());
// idm_account_get_ssh_pubkeys
// idm_account_post_ssh_pubkey
// idm_account_get_ssh_pubkey
// idm_account_delete_ssh_pubkey
// Post an invalid key (should error)
let r1 = rsclient.idm_account_post_ssh_pubkey("admin", "inv", "invalid key");
assert!(r1.is_err());
// Post a valid key
let r2 = rsclient
.idm_account_post_ssh_pubkey("admin", "k1", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAeGW1P6Pc2rPq0XqbRaDKBcXZUPRklo0L1EyR30CwoP william@amethyst");
println!("{:?}", r2);
assert!(r2.is_ok());
// Get, should have the key
let sk2 = rsclient.idm_account_get_ssh_pubkeys("admin").unwrap();
assert!(sk2.len() == 1);
// Post a valid key
let r3 = rsclient
.idm_account_post_ssh_pubkey("admin", "k2", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBx4TpJYQjd0YI5lQIHqblIsCIK5NKVFURYS/eM3o6/Z william@amethyst");
assert!(r3.is_ok());
// Get, should have both keys.
let sk3 = rsclient.idm_account_get_ssh_pubkeys("admin").unwrap();
assert!(sk3.len() == 2);
// Delete a key (by tag)
let r4 = rsclient.idm_account_delete_ssh_pubkey("admin", "k1");
assert!(r4.is_ok());
// Get, should have remaining key.
let sk4 = rsclient.idm_account_get_ssh_pubkeys("admin").unwrap();
assert!(sk4.len() == 1);
// get by tag
let skn = rsclient.idm_account_get_ssh_pubkey("admin", "k2");
assert!(skn.is_ok());
assert!(skn.unwrap() == Some("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBx4TpJYQjd0YI5lQIHqblIsCIK5NKVFURYS/eM3o6/Z william@amethyst".to_string()));
});
}
#[test]
fn test_server_rest_domain_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
let mut dlist = rsclient.idm_domain_list().unwrap();
assert!(dlist.len() == 1);
let dlocal = rsclient.idm_domain_get("domain_local").unwrap();
// There should be one, and it's the domain_local
assert!(dlist.pop().unwrap().attrs == dlocal.attrs);
// Change the ssid
rsclient
.idm_domain_set_ssid("domain_local", "new_ssid")
.unwrap();
// check get and get the ssid and domain info
let nssid = rsclient.idm_domain_get_ssid("domain_local").unwrap();
assert!(nssid == "new_ssid");
});
}
#[test]
fn test_server_rest_posix_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Not recommended in production!
rsclient
.idm_group_add_members("idm_admins", vec!["admin"])
.unwrap();
// Create a new account
rsclient
.idm_account_create("posix_account", "Posix Demo Account")
.unwrap();
// Extend the account with posix attrs.
rsclient
.idm_account_unix_extend("posix_account", None, None)
.unwrap();
// Create a group
// Extend the group with posix attrs
rsclient.idm_group_create("posix_group").unwrap();
rsclient
.idm_group_add_members("posix_group", vec!["posix_account"])
.unwrap();
rsclient.idm_group_unix_extend("posix_group", None).unwrap();
// Open a new connection as anonymous
let res = rsclient.auth_anonymous();
assert!(res.is_ok());
// Get the account by name
let r = rsclient
.idm_account_unix_token_get("posix_account")
.unwrap();
// Get the account by gidnumber
let r1 = rsclient
.idm_account_unix_token_get(r.gidnumber.to_string().as_str())
.unwrap();
// get the account by spn
let r2 = rsclient.idm_account_unix_token_get(r.spn.as_str()).unwrap();
// get the account by uuid
let r3 = rsclient
.idm_account_unix_token_get(r.uuid.as_str())
.unwrap();
println!("{:?}", r);
assert!(r.name == "posix_account");
assert!(r1.name == "posix_account");
assert!(r2.name == "posix_account");
assert!(r3.name == "posix_account");
// get the group by nam
let r = rsclient.idm_group_unix_token_get("posix_group").unwrap();
// Get the group by gidnumber
let r1 = rsclient
.idm_group_unix_token_get(r.gidnumber.to_string().as_str())
.unwrap();
// get the group spn
let r2 = rsclient.idm_group_unix_token_get(r.spn.as_str()).unwrap();
// get the group by uuid
let r3 = rsclient.idm_group_unix_token_get(r.uuid.as_str()).unwrap();
println!("{:?}", r);
assert!(r.name == "posix_group");
assert!(r1.name == "posix_group");
assert!(r2.name == "posix_group");
assert!(r3.name == "posix_group");
});
}
#[test]
fn test_server_rest_posix_auth_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Get an anon connection
let anon_rsclient = rsclient.new_session().unwrap();
assert!(anon_rsclient.auth_anonymous().is_ok());
// Not recommended in production!
rsclient
.idm_group_add_members("idm_admins", vec!["admin"])
.unwrap();
// Setup a unix user
rsclient
.idm_account_create("posix_account", "Posix Demo Account")
.unwrap();
// Extend the account with posix attrs.
rsclient
.idm_account_unix_extend("posix_account", None, None)
.unwrap();
// add their password (unix self)
rsclient
.idm_account_unix_cred_put("posix_account", UNIX_TEST_PASSWORD)
.unwrap();
// attempt to verify (good, anon-conn)
let r1 = anon_rsclient.idm_account_unix_cred_verify("posix_account", UNIX_TEST_PASSWORD);
match r1 {
Ok(Some(_tok)) => {}
_ => assert!(false),
};
// attempt to verify (bad, anon-conn)
let r2 = anon_rsclient.idm_account_unix_cred_verify("posix_account", "ntaotnhuohtsuoehtsu");
match r2 {
Ok(None) => {}
_ => assert!(false),
};
// lock? (admin-conn)
// attempt to verify (good pw, should fail, anon-conn)
// status? (self-conn)
// clear password? (unix self)
rsclient
.idm_account_unix_cred_delete("posix_account")
.unwrap();
// attempt to verify (good pw, should fail, anon-conn)
let r3 = anon_rsclient.idm_account_unix_cred_verify("posix_account", UNIX_TEST_PASSWORD);
match r3 {
Ok(None) => {}
_ => assert!(false),
};
});
}
#[test]
fn test_server_rest_recycle_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Not recommended in production!
rsclient
.idm_group_add_members("idm_admins", vec!["admin"])
.unwrap();
// Setup a unix user
rsclient
.idm_account_create("recycle_account", "Recycle Demo Account")
.unwrap();
// delete them
rsclient.idm_account_delete("recycle_account").unwrap();
// not there
let acc = rsclient.idm_account_get("recycle_account").unwrap();
assert!(acc.is_none());
// list the recycle bin
let r_list = rsclient.recycle_bin_list().unwrap();
assert!(r_list.len() == 1);
// get the user in recycle bin
let r_user = rsclient.recycle_bin_get("recycle_account").unwrap();
assert!(r_user.is_some());
// revive
rsclient.recycle_bin_revive("recycle_account").unwrap();
// they are there!
let acc = rsclient.idm_account_get("recycle_account").unwrap();
assert!(acc.is_some());
});
}
#[test]
fn test_server_rest_account_import_password() {
run_test(|mut rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// To enable the admin to actually make some of these changes, we have
// to make them a password import admin. NOT recommended in production!
rsclient
.idm_group_add_members("idm_people_account_password_import_priv", vec!["admin"])
.unwrap();
rsclient
.idm_group_add_members("idm_people_extend_priv", vec!["admin"])
.unwrap();
// Create a new account
rsclient
.idm_account_create("demo_account", "Deeeeemo")
.unwrap();
// Make them a person, so we can import the password
rsclient.idm_account_person_extend("demo_account").unwrap();
// Attempt to import a bad password
let r = rsclient.idm_account_primary_credential_import_password("demo_account", "password");
assert!(r.is_err());
// Import a good password
// eicieY7ahchaoCh0eeTa
// pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=
rsclient
.idm_account_primary_credential_import_password(
"demo_account",
"pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=",
)
.unwrap();
// Now show we can auth with it
// "reset" the client.
let _ = rsclient.logout();
let res = rsclient.auth_simple_password("demo_account", "eicieY7ahchaoCh0eeTa");
assert!(res.is_ok());
});
}
#[test]
fn test_server_rest_totp_auth_lifecycle() {
run_test(|rsclient: KanidmClient| {
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
assert!(res.is_ok());
// Not recommended in production!
rsclient
.idm_group_add_members("idm_admins", vec!["admin"])
.unwrap();
// Create a new account
rsclient
.idm_account_create("demo_account", "Deeeeemo")
.unwrap();
// Enroll a totp to the account
assert!(rsclient
.idm_account_primary_credential_set_password("demo_account", "sohdi3iuHo6mai7noh0a")
.is_ok());
let (sessionid, tok) = rsclient
.idm_account_primary_credential_generate_totp("demo_account", "demo")
.unwrap();
let r_tok: TOTP = tok.into();
let totp = r_tok
.do_totp_duration_from_epoch(
&SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap(),
)
.expect("Failed to do totp?");
rsclient
.idm_account_primary_credential_verify_totp("demo_account", totp, sessionid)
.unwrap(); // the result
// Check a bad auth
// Get a new connection
let rsclient_bad = rsclient.new_session().unwrap();
assert!(rsclient_bad
.auth_password_totp("demo_account", "sohdi3iuHo6mai7noh0a", 0)
.is_err());
// Check a good auth
let rsclient_good = rsclient.new_session().unwrap();
let totp = r_tok
.do_totp_duration_from_epoch(
&SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap(),
)
.expect("Failed to do totp?");
assert!(rsclient_good
.auth_password_totp("demo_account", "sohdi3iuHo6mai7noh0a", totp)
.is_ok());
});
}
// Test the self version of the radius path.
// Test hitting all auth-required endpoints and assert they give unauthorized.