pub mod common;
use common::{
TestDbExt, materialize_role_test_path, role_test_request_body,
server_auth_route_catalog, server_main_route_catalog,
};
use ave_http::auth::database::DatabaseError;
use reqwest::{Client, StatusCode};
use serde_json::json;
use std::collections::BTreeSet;
use test_log::test;
#[test(tokio::test)]
async fn test_api_keys_revoked_when_role_added() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user_transactional(
"testuser",
"TestPass123!",
None,
None,
Some(false),
None,
)
.unwrap();
let (api_key, _) = db
.create_api_key(user.id, Some("key1"), None, None, false)
.unwrap();
assert!(
db.authenticate_api_key_request(&api_key, None, "/peer-id")
.is_ok()
);
let role = db.create_role_transactional("editor", None, None).unwrap();
db.assign_role_to_user_transactional(user.id, role.id, None, None)
.unwrap();
let result = db.authenticate_api_key_request(&api_key, None, "/peer-id");
assert!(matches!(result, Err(DatabaseError::PermissionDenied(_))));
}
#[test(tokio::test)]
async fn test_api_keys_revoked_when_role_removed() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user("testuser", "TestPass123!", None, None, Some(false))
.unwrap();
let role = db.create_role("editor", None).unwrap();
db.assign_role_to_user(user.id, role.id, None).unwrap();
let (api_key, _) = db
.create_api_key(user.id, Some("key1"), None, None, false)
.unwrap();
assert!(
db.authenticate_api_key_request(&api_key, None, "/peer-id")
.is_ok()
);
db.remove_role_from_user(user.id, role.id).unwrap();
let result = db.authenticate_api_key_request(&api_key, None, "/peer-id");
assert!(matches!(result, Err(DatabaseError::PermissionDenied(_))));
}
#[test(tokio::test)]
async fn test_permissions_change_when_role_added() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user("testuser", "TestPass123!", None, None, Some(false))
.unwrap();
let role = db.create_role("editor", None).unwrap();
db.set_role_permission(role.id, "node_subject", "get", true)
.unwrap();
let perms_before = db.get_user_effective_permissions(user.id).unwrap();
assert!(!perms_before.iter().any(|p| p.resource == "node_subject"
&& p.action == "get"
&& p.allowed));
db.assign_role_to_user(user.id, role.id, None).unwrap();
let perms_after = db.get_user_effective_permissions(user.id).unwrap();
assert!(perms_after.iter().any(|p| p.resource == "node_subject"
&& p.action == "get"
&& p.allowed));
}
#[test(tokio::test)]
async fn test_permissions_change_when_role_removed() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user("testuser", "TestPass123!", None, None, Some(false))
.unwrap();
let role = db.create_role("editor", None).unwrap();
db.set_role_permission(role.id, "node_request", "post", true)
.unwrap();
db.assign_role_to_user(user.id, role.id, None).unwrap();
let perms_before = db.get_user_effective_permissions(user.id).unwrap();
assert!(perms_before.iter().any(|p| p.resource == "node_request"
&& p.action == "post"
&& p.allowed));
db.remove_role_from_user(user.id, role.id).unwrap();
let perms_after = db.get_user_effective_permissions(user.id).unwrap();
assert!(!perms_after.iter().any(|p| p.resource == "node_request"
&& p.action == "post"
&& p.allowed));
}
#[test(tokio::test)]
async fn test_multiple_role_changes() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user("testuser", "TestPass123!", None, None, Some(false))
.unwrap();
let (api_key1, _) = db
.create_api_key(user.id, Some("key1"), None, None, false)
.unwrap();
let role1 = db.create_role("role1", None).unwrap();
db.assign_role_to_user(user.id, role1.id, None).unwrap();
assert!(matches!(
db.authenticate_api_key_request(&api_key1, None, "/peer-id"),
Err(DatabaseError::PermissionDenied(_))
));
let (api_key2, _) = db
.create_api_key(user.id, Some("key2"), None, None, false)
.unwrap();
let role2 = db.create_role("role2", None).unwrap();
db.assign_role_to_user(user.id, role2.id, None).unwrap();
assert!(matches!(
db.authenticate_api_key_request(&api_key2, None, "/peer-id"),
Err(DatabaseError::PermissionDenied(_))
));
assert!(matches!(
db.authenticate_api_key_request(&api_key1, None, "/peer-id"),
Err(DatabaseError::PermissionDenied(_))
));
}
#[test(tokio::test)]
async fn test_user_with_multiple_roles_permission_merge() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user("testuser", "TestPass123!", None, None, Some(false))
.unwrap();
let role1 = db.create_role("reader", None).unwrap();
let role2 = db.create_role("writer", None).unwrap();
db.set_role_permission(role1.id, "node_subject", "get", true)
.unwrap();
db.set_role_permission(role2.id, "node_subject", "post", true)
.unwrap();
db.assign_role_to_user(user.id, role1.id, None).unwrap();
db.assign_role_to_user(user.id, role2.id, None).unwrap();
let perms = db.get_user_effective_permissions(user.id).unwrap();
assert!(perms.iter().any(|p| p.resource == "node_subject"
&& p.action == "get"
&& p.allowed));
assert!(perms.iter().any(|p| p.resource == "node_subject"
&& p.action == "post"
&& p.allowed));
}
#[test(tokio::test)]
async fn test_user_override_persists_through_role_changes() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user("testuser", "TestPass123!", None, None, Some(false))
.unwrap();
db.set_user_permission(user.id, "admin_users", "delete", false, None)
.unwrap();
let role = db.create_role("user_admin", None).unwrap();
db.set_role_permission(role.id, "admin_users", "delete", true)
.unwrap();
db.assign_role_to_user(user.id, role.id, None).unwrap();
let perms = db.get_user_effective_permissions(user.id).unwrap();
let perm = perms
.iter()
.find(|p| p.resource == "admin_users" && p.action == "delete")
.unwrap();
assert!(!perm.allowed);
}
#[test(tokio::test)]
async fn test_role_permission_modification_affects_all_users() {
let (db, _dirs) = common::create_test_db();
let user1 = db
.create_user("user1", "TestPass123!", None, None, Some(false))
.unwrap();
let user2 = db
.create_user("user2", "TestPass123!", None, None, Some(false))
.unwrap();
let role = db.create_role("editor", None).unwrap();
db.assign_role_to_user(user1.id, role.id, None).unwrap();
db.assign_role_to_user(user2.id, role.id, None).unwrap();
db.set_role_permission(role.id, "node_subject", "post", true)
.unwrap();
let perms1 = db.get_user_effective_permissions(user1.id).unwrap();
let perms2 = db.get_user_effective_permissions(user2.id).unwrap();
assert!(perms1.iter().any(|p| p.resource == "node_subject"
&& p.action == "post"
&& p.allowed));
assert!(perms2.iter().any(|p| p.resource == "node_subject"
&& p.action == "post"
&& p.allowed));
db.set_role_permission(role.id, "node_subject", "post", false)
.unwrap();
let perms1 = db.get_user_effective_permissions(user1.id).unwrap();
let perms2 = db.get_user_effective_permissions(user2.id).unwrap();
assert!(!perms1.iter().any(|p| p.resource == "node_subject"
&& p.action == "post"
&& p.allowed));
assert!(!perms2.iter().any(|p| p.resource == "node_subject"
&& p.action == "post"
&& p.allowed));
}
#[test(tokio::test)]
async fn test_deny_permission_overrides_multiple_allows() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user("testuser", "TestPass123!", None, None, Some(false))
.unwrap();
let role1 = db.create_role("role1", None).unwrap();
let role2 = db.create_role("role2", None).unwrap();
db.set_role_permission(role1.id, "node_subject", "delete", true)
.unwrap();
db.set_role_permission(role2.id, "node_subject", "delete", true)
.unwrap();
db.assign_role_to_user(user.id, role1.id, None).unwrap();
db.assign_role_to_user(user.id, role2.id, None).unwrap();
db.set_user_permission(user.id, "node_subject", "delete", false, None)
.unwrap();
let perms = db.get_user_effective_permissions(user.id).unwrap();
let perm = perms
.iter()
.find(|p| p.resource == "node_subject" && p.action == "delete")
.unwrap();
assert!(!perm.allowed);
}
#[test(tokio::test)]
async fn test_deleted_roles_removed_from_users() {
let (db, _dirs) = common::create_test_db();
let user = db
.create_user("testuser", "TestPass123!", None, None, Some(false))
.unwrap();
let role = db.create_role("temp_role", None).unwrap();
db.assign_role_to_user(user.id, role.id, None).unwrap();
let roles_before = db.get_user_roles(user.id).unwrap();
assert!(roles_before.contains(&"temp_role".to_string()));
db.delete_role(role.id).unwrap();
let roles_after = db.get_user_roles(user.id).unwrap();
assert!(!roles_after.contains(&"temp_role".to_string()));
}
fn has_access(status: StatusCode) -> bool {
!matches!(status, StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN)
}
fn node_routes() -> BTreeSet<(String, String)> {
server_main_route_catalog()
}
fn user_routes() -> BTreeSet<(String, String)> {
server_auth_route_catalog()
.into_iter()
.filter(|(_, path)| {
*path == "/me"
|| *path == "/me/permissions"
|| *path == "/me/permissions/detailed"
})
.collect()
}
fn user_api_key_routes() -> BTreeSet<(String, String)> {
server_auth_route_catalog()
.into_iter()
.filter(|(_, path)| {
*path == "/me/api-keys" || *path == "/me/api-keys/{name}"
})
.collect()
}
fn admin_users_routes() -> BTreeSet<(String, String)> {
server_auth_route_catalog()
.into_iter()
.filter(|(_, path)| path.starts_with("/admin/users"))
.collect()
}
fn admin_roles_routes() -> BTreeSet<(String, String)> {
server_auth_route_catalog()
.into_iter()
.filter(|(_, path)| path.starts_with("/admin/roles"))
.collect()
}
fn admin_apikey_routes() -> BTreeSet<(String, String)> {
server_auth_route_catalog()
.into_iter()
.filter(|(_, path)| {
path.starts_with("/admin/api-keys")
|| path.starts_with("/admin/usage-plans")
})
.collect()
}
fn admin_system_routes() -> BTreeSet<(String, String)> {
server_auth_route_catalog()
.into_iter()
.filter(|(_, path)| {
matches!(
path.as_str(),
"/admin/resources"
| "/admin/actions"
| "/admin/audit-logs"
| "/admin/audit-logs/stats"
| "/admin/rate-limits/stats"
| "/admin/config"
| "/admin/config/{key}"
)
})
.collect()
}
async fn execute_role_endpoint(
client: &Client,
base_url: &str,
api_key: &str,
method: &str,
path: &str,
) -> StatusCode {
let url =
format!("{}{}", base_url, materialize_role_test_path(method, path));
let body = role_test_request_body(method, path);
let request = match method {
"get" => client.get(&url),
"post" => client.post(&url).json(&body.unwrap_or(json!({}))),
"put" => client.put(&url).json(&body.unwrap_or(json!({}))),
"patch" => client.patch(&url).json(&body.unwrap_or(json!({}))),
"delete" => {
let request = client.delete(&url);
if let Some(body) = body {
request.json(&body)
} else {
request
}
}
_ => panic!("Unsupported method: {method}"),
};
request
.header("X-API-Key", api_key)
.send()
.await
.unwrap()
.status()
}
async fn test_node_endpoints(
client: &Client,
base_url: &str,
api_key: &str,
default_access: bool,
overrides: &[(&str, &str, bool)],
) {
for (method, path) in node_routes() {
let status =
execute_role_endpoint(client, base_url, api_key, &method, &path)
.await;
let expected_access = overrides
.iter()
.find(|(m, p, _)| m.eq_ignore_ascii_case(&method) && *p == path)
.map(|(_, _, allow)| *allow)
.unwrap_or(default_access);
let access = has_access(status);
assert_eq!(
access, expected_access,
"{} {} - Expected access: {}, Got status: {} (access: {})",
method, path, expected_access, status, access
);
}
}
async fn test_user_endpoints(
client: &Client,
base_url: &str,
api_key: &str,
should_have_access: bool,
is_management_key: bool,
) {
for (method, path) in user_routes() {
let status =
execute_role_endpoint(client, base_url, api_key, &method, &path)
.await;
let access = has_access(status);
assert_eq!(
access, should_have_access,
"{} {} - Expected access: {}, Got status: {} (access: {})",
method, path, should_have_access, status, access
);
}
for (method, path) in user_api_key_routes() {
let status =
execute_role_endpoint(client, base_url, api_key, &method, &path)
.await;
let access = has_access(status);
let expected_access = should_have_access && is_management_key;
assert_eq!(
access, expected_access,
"{} {} (is_management: {}) - Expected access: {}, Got status: {} (access: {})",
method, path, is_management_key, expected_access, status, access
);
}
}
async fn test_admin_users_endpoints(
client: &Client,
base_url: &str,
api_key: &str,
should_have_access: bool,
) {
for (method, path) in admin_users_routes() {
let status =
execute_role_endpoint(client, base_url, api_key, &method, &path)
.await;
let access = has_access(status);
assert_eq!(
access, should_have_access,
"{} {} - Expected access: {}, Got status: {} (access: {})",
method, path, should_have_access, status, access
);
}
}
async fn test_admin_roles_endpoints(
client: &Client,
base_url: &str,
api_key: &str,
should_have_access: bool,
is_superadmin: bool,
) {
for (method, path) in admin_roles_routes() {
let status =
execute_role_endpoint(client, base_url, api_key, &method, &path)
.await;
let access = has_access(status);
let expected_access = match (method.as_str(), path.as_str()) {
("post", "/admin/roles/{role_id}/permissions")
| ("delete", "/admin/roles/{role_id}/permissions") => {
should_have_access && is_superadmin
}
_ => should_have_access,
};
assert_eq!(
access, expected_access,
"{} {} - Expected access: {}, Got status: {} (access: {})",
method, path, expected_access, status, access
);
}
}
async fn test_admin_apikeys_endpoints(
client: &Client,
base_url: &str,
api_key: &str,
should_have_access: bool,
is_superadmin: bool,
) {
for (method, path) in admin_apikey_routes() {
let status =
execute_role_endpoint(client, base_url, api_key, &method, &path)
.await;
let access = has_access(status);
let expected_access = match (method.as_str(), path.as_str()) {
("post", "/admin/api-keys/user/{user_id}") => {
should_have_access && is_superadmin
}
_ => should_have_access,
};
assert_eq!(
access, expected_access,
"{} {} - Expected access: {}, Got status: {} (access: {})",
method, path, expected_access, status, access
);
}
}
async fn test_admin_system_endpoints(
client: &Client,
base_url: &str,
api_key: &str,
should_have_access: bool,
) {
for (method, path) in admin_system_routes() {
let status =
execute_role_endpoint(client, base_url, api_key, &method, &path)
.await;
let access = has_access(status);
assert_eq!(
access, should_have_access,
"{} {} - Expected access: {}, Got status: {} (access: {})",
method, path, should_have_access, status, access
);
}
}
#[test(tokio::test)]
async fn test_superadmin_all_endpoints_access() {
let Some((server, _dirs)) =
common::TestServer::build(true, false, None).await
else {
return;
};
let client = Client::new();
let base_url = server.url("");
let (status, login_response) = common::make_request(
&client,
&server.url("/login"),
"POST",
None,
Some(json!({"username": "admin", "password": "AdminPass123!"})),
)
.await;
assert!(status.is_success(), "Login failed with status: {}", status);
let mgmt_key = login_response["api_key"]
.as_str()
.expect("No api_key in login response")
.to_string();
let (status, service_key_response) = common::make_request(
&client,
&server.url("/me/api-keys"),
"POST",
Some(&mgmt_key),
Some(json!({"name": "service_test"})),
)
.await;
assert!(
status.is_success(),
"Service key creation failed with status: {}",
status
);
let service_key = service_key_response["api_key"]
.as_str()
.expect("No api_key in service key response")
.to_string();
let superadmin_mgmt_overrides: &[(&str, &str, bool)] = &[];
let superadmin_service_overrides: &[(&str, &str, bool)] =
&[("delete", "/maintenance/subjects/{subject_id}", false)];
test_node_endpoints(
&client,
&base_url,
&mgmt_key,
true,
superadmin_mgmt_overrides,
)
.await;
test_user_endpoints(&client, &base_url, &mgmt_key, true, true).await;
test_admin_users_endpoints(&client, &base_url, &mgmt_key, true).await;
test_admin_roles_endpoints(&client, &base_url, &mgmt_key, true, true).await;
test_admin_apikeys_endpoints(&client, &base_url, &mgmt_key, true, true)
.await;
test_admin_system_endpoints(&client, &base_url, &mgmt_key, true).await;
test_node_endpoints(
&client,
&base_url,
&service_key,
true,
superadmin_service_overrides,
)
.await;
test_user_endpoints(&client, &base_url, &service_key, true, false).await;
test_admin_users_endpoints(&client, &base_url, &service_key, false).await;
test_admin_roles_endpoints(&client, &base_url, &service_key, false, true)
.await;
test_admin_apikeys_endpoints(&client, &base_url, &service_key, false, true)
.await;
test_admin_system_endpoints(&client, &base_url, &service_key, false).await;
}
#[test(tokio::test)]
async fn test_admin_role_endpoints_access() {
let Some((server, _dirs)) =
common::TestServer::build(true, false, None).await
else {
return;
};
let client = Client::new();
let base_url = server.url("");
let login_response: serde_json::Value = client
.post(&server.url("/login"))
.json(&json!({"username": "admin", "password": "AdminPass123!"}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let admin_api_key = login_response["api_key"].as_str().unwrap();
let roles_response: serde_json::Value = client
.get(&server.url("/admin/roles"))
.header("X-API-Key", admin_api_key)
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let admin_role_id = roles_response
.as_array()
.unwrap()
.iter()
.find(|r| r["name"] == "admin")
.unwrap()["id"]
.as_i64()
.unwrap();
let _create_user_response: serde_json::Value = client
.post(&server.url("/admin/users"))
.header("X-API-Key", admin_api_key)
.json(&json!({
"username": "test_admin_user",
"password": "TestPass123!",
"is_superadmin": false,
"role_ids": [admin_role_id],
"must_change_password": false
}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_login_response: serde_json::Value = client
.post(&server.url("/login"))
.json(
&json!({"username": "test_admin_user", "password": "TestPass123!"}),
)
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_mgmt_key = test_login_response["api_key"].as_str().unwrap();
let service_key_response: serde_json::Value = client
.post(&server.url("/me/api-keys"))
.header("X-API-Key", test_mgmt_key)
.json(&json!({
"name": "service_key",
"is_management": false
}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
eprintln!(
"ADMIN TEST - Service key response: {:?}",
service_key_response
);
let test_service_key = service_key_response["api_key"].as_str().unwrap();
test_user_endpoints(&client, &base_url, test_mgmt_key, true, true).await;
test_admin_users_endpoints(&client, &base_url, test_mgmt_key, true).await;
test_admin_roles_endpoints(&client, &base_url, test_mgmt_key, true, false)
.await;
test_admin_apikeys_endpoints(
&client,
&base_url,
test_mgmt_key,
true,
false,
)
.await;
test_admin_system_endpoints(&client, &base_url, test_mgmt_key, true).await;
test_node_endpoints(&client, &base_url, test_mgmt_key, false, &[]).await;
test_user_endpoints(&client, &base_url, test_service_key, true, false)
.await;
test_admin_users_endpoints(&client, &base_url, test_service_key, false)
.await;
test_admin_roles_endpoints(
&client,
&base_url,
test_service_key,
false,
false,
)
.await;
test_admin_apikeys_endpoints(
&client,
&base_url,
test_service_key,
false,
false,
)
.await;
test_admin_system_endpoints(&client, &base_url, test_service_key, false)
.await;
test_node_endpoints(&client, &base_url, test_service_key, false, &[]).await; }
#[test(tokio::test)]
async fn test_sender_role_endpoints_access() {
let Some((server, _dirs)) =
common::TestServer::build(true, false, None).await
else {
return;
};
let client = Client::new();
let base_url = server.url("");
let login_response: serde_json::Value = client
.post(&server.url("/login"))
.json(&json!({"username": "admin", "password": "AdminPass123!"}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let admin_api_key = login_response["api_key"].as_str().unwrap();
let roles_response: serde_json::Value = client
.get(&server.url("/admin/roles"))
.header("X-API-Key", admin_api_key)
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let sender_role_id = roles_response
.as_array()
.unwrap()
.iter()
.find(|r| r["name"] == "sender")
.unwrap()["id"]
.as_i64()
.unwrap();
let _create_user_response: serde_json::Value = client
.post(&server.url("/admin/users"))
.header("X-API-Key", admin_api_key)
.json(&json!({
"username": "test_sender_user",
"password": "TestPass123!",
"is_superadmin": false,
"role_ids": [sender_role_id],
"must_change_password": false
}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_login_response: serde_json::Value = client
.post(&server.url("/login"))
.json(&json!({"username": "test_sender_user", "password": "TestPass123!"}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_mgmt_key = test_login_response["api_key"].as_str().unwrap();
let service_key_response: serde_json::Value = client
.post(&server.url("/me/api-keys"))
.header("X-API-Key", test_mgmt_key)
.json(&json!({
"name": "service_key",
"is_management": false
}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_service_key = service_key_response["api_key"].as_str().unwrap();
let sender_node_access = [
("post", "/request", true),
("get", "/request", true),
("get", "/request/{request_id}", true),
("get", "/requests-in-manager", true),
("get", "/requests-in-manager/{subject_id}", true),
("get", "/state/{subject_id}", true),
("get", "/events/{subject_id}", true),
("get", "/events/{subject_id}/{sn}", true),
("get", "/events-first-last/{subject_id}", true),
("get", "/aborts/{subject_id}", true),
("get", "/subjects", true),
("get", "/subjects/{governance_id}", true),
("get", "/approval", true),
("get", "/approval/{subject_id}", true),
("get", "/auth", true),
("get", "/auth/{subject_id}", true),
("get", "/pending-transfers", true),
("get", "/public-key", true),
("get", "/peer-id", true),
("get", "/network-state", true),
];
test_user_endpoints(&client, &base_url, test_mgmt_key, true, true).await;
test_node_endpoints(
&client,
&base_url,
test_mgmt_key,
false,
&sender_node_access,
)
.await; test_admin_users_endpoints(&client, &base_url, test_mgmt_key, false).await; test_admin_roles_endpoints(&client, &base_url, test_mgmt_key, false, false)
.await; test_admin_apikeys_endpoints(
&client,
&base_url,
test_mgmt_key,
false,
false,
)
.await; test_admin_system_endpoints(&client, &base_url, test_mgmt_key, false).await;
test_user_endpoints(&client, &base_url, test_service_key, true, false)
.await;
test_node_endpoints(
&client,
&base_url,
test_service_key,
false,
&sender_node_access,
)
.await; test_admin_users_endpoints(&client, &base_url, test_service_key, false)
.await; test_admin_roles_endpoints(
&client,
&base_url,
test_service_key,
false,
false,
)
.await; test_admin_apikeys_endpoints(
&client,
&base_url,
test_service_key,
false,
false,
)
.await; test_admin_system_endpoints(&client, &base_url, test_service_key, false)
.await; }
#[test(tokio::test)]
async fn test_manager_role_endpoints_access() {
let Some((server, _dirs)) =
common::TestServer::build(true, false, None).await
else {
return;
};
let client = Client::new();
let base_url = server.url("");
let login_response: serde_json::Value = client
.post(&server.url("/login"))
.json(&json!({"username": "admin", "password": "AdminPass123!"}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let admin_api_key = login_response["api_key"].as_str().unwrap();
let roles_response: serde_json::Value = client
.get(&server.url("/admin/roles"))
.header("X-API-Key", admin_api_key)
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let manager_role_id = roles_response
.as_array()
.unwrap()
.iter()
.find(|r| r["name"] == "manager")
.unwrap()["id"]
.as_i64()
.unwrap();
let _create_user_response: serde_json::Value = client
.post(&server.url("/admin/users"))
.header("X-API-Key", admin_api_key)
.json(&json!({
"username": "test_manager_user",
"password": "TestPass123!",
"is_superadmin": false,
"role_ids": [manager_role_id],
"must_change_password": false
}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_login_response: serde_json::Value = client
.post(&server.url("/login"))
.json(&json!({"username": "test_manager_user", "password": "TestPass123!"}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_mgmt_key = test_login_response["api_key"].as_str().unwrap();
let service_key_response: serde_json::Value = client
.post(&server.url("/me/api-keys"))
.header("X-API-Key", test_mgmt_key)
.json(&json!({
"name": "service_key",
"is_management": false
}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_service_key = service_key_response["api_key"].as_str().unwrap();
let manager_overrides: &[(&str, &str, bool)] = &[
("get", "/sink-events/{subject_id}", false),
("delete", "/maintenance/subjects/{subject_id}", false),
];
test_user_endpoints(&client, &base_url, test_mgmt_key, true, true).await;
test_node_endpoints(
&client,
&base_url,
test_mgmt_key,
true,
manager_overrides,
)
.await;
test_admin_users_endpoints(&client, &base_url, test_mgmt_key, false).await; test_admin_roles_endpoints(&client, &base_url, test_mgmt_key, false, false)
.await; test_admin_apikeys_endpoints(
&client,
&base_url,
test_mgmt_key,
false,
false,
)
.await; test_admin_system_endpoints(&client, &base_url, test_mgmt_key, false).await;
test_user_endpoints(&client, &base_url, test_service_key, true, false)
.await;
test_node_endpoints(
&client,
&base_url,
test_service_key,
true,
manager_overrides,
)
.await;
test_admin_users_endpoints(&client, &base_url, test_service_key, false)
.await; test_admin_roles_endpoints(
&client,
&base_url,
test_service_key,
false,
false,
)
.await; test_admin_apikeys_endpoints(
&client,
&base_url,
test_service_key,
false,
false,
)
.await; test_admin_system_endpoints(&client, &base_url, test_service_key, false)
.await; }
#[test(tokio::test)]
async fn test_data_role_endpoints_access() {
let Some((server, _dirs)) =
common::TestServer::build(true, false, None).await
else {
return;
};
let client = Client::new();
let base_url = server.url("");
let login_response: serde_json::Value = client
.post(&server.url("/login"))
.json(&json!({"username": "admin", "password": "AdminPass123!"}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let admin_api_key = login_response["api_key"].as_str().unwrap();
let roles_response: serde_json::Value = client
.get(&server.url("/admin/roles"))
.header("X-API-Key", admin_api_key)
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let data_role_id = roles_response
.as_array()
.unwrap()
.iter()
.find(|r| r["name"] == "data")
.unwrap()["id"]
.as_i64()
.unwrap();
let _create_user_response: serde_json::Value = client
.post(&server.url("/admin/users"))
.header("X-API-Key", admin_api_key)
.json(&json!({
"username": "test_data_user",
"password": "TestPass123!",
"is_superadmin": false,
"role_ids": [data_role_id],
"must_change_password": false
}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_login_response: serde_json::Value = client
.post(&server.url("/login"))
.json(
&json!({"username": "test_data_user", "password": "TestPass123!"}),
)
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_mgmt_key = test_login_response["api_key"].as_str().unwrap();
let service_key_response: serde_json::Value = client
.post(&server.url("/me/api-keys"))
.header("X-API-Key", test_mgmt_key)
.json(&json!({
"name": "service_key",
"is_management": false
}))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let test_service_key = service_key_response["api_key"].as_str().unwrap();
let data_read_access = [
("get", "/public-key", true),
("get", "/peer-id", true),
("get", "/network-state", true),
("get", "/state/{subject_id}", true),
("get", "/events/{subject_id}", true),
("get", "/events/{subject_id}/{sn}", true),
("get", "/events-first-last/{subject_id}", true),
("get", "/aborts/{subject_id}", true),
("get", "/subjects", true),
("get", "/subjects/{governance_id}", true),
("get", "/approval", true),
("get", "/approval/{subject_id}", true),
("get", "/auth", true),
("get", "/auth/{subject_id}", true),
("get", "/pending-transfers", true),
("get", "/request", true),
("get", "/request/{request_id}", true),
("get", "/requests-in-manager", true),
("get", "/requests-in-manager/{subject_id}", true),
];
test_user_endpoints(&client, &base_url, test_mgmt_key, true, true).await;
test_node_endpoints(
&client,
&base_url,
test_mgmt_key,
false,
&data_read_access,
)
.await; test_admin_users_endpoints(&client, &base_url, test_mgmt_key, false).await; test_admin_roles_endpoints(&client, &base_url, test_mgmt_key, false, false)
.await; test_admin_apikeys_endpoints(
&client,
&base_url,
test_mgmt_key,
false,
false,
)
.await; test_admin_system_endpoints(&client, &base_url, test_mgmt_key, false).await;
test_user_endpoints(&client, &base_url, test_service_key, true, false)
.await;
test_node_endpoints(
&client,
&base_url,
test_service_key,
false,
&data_read_access,
)
.await; test_admin_users_endpoints(&client, &base_url, test_service_key, false)
.await; test_admin_roles_endpoints(
&client,
&base_url,
test_service_key,
false,
false,
)
.await; test_admin_apikeys_endpoints(
&client,
&base_url,
test_service_key,
false,
false,
)
.await; test_admin_system_endpoints(&client, &base_url, test_service_key, false)
.await; }
#[test]
fn role_tests_cover_all_protected_http_route_catalogs() {
let mut covered = node_routes();
covered.extend(user_routes());
covered.extend(user_api_key_routes());
covered.extend(admin_users_routes());
covered.extend(admin_roles_routes());
covered.extend(admin_apikey_routes());
covered.extend(admin_system_routes());
let mut catalog = server_main_route_catalog();
catalog.extend(server_auth_route_catalog());
let missing: Vec<_> = catalog.difference(&covered).cloned().collect();
let stale: Vec<_> = covered.difference(&catalog).cloned().collect();
assert!(
missing.is_empty() && stale.is_empty(),
"Role test route matrix is out of sync with protected HTTP route catalogs. Missing: {missing:?}. Stale: {stale:?}"
);
}