use axum::body::Body;
use axum::http::{Request, StatusCode};
use laterite_admin::{router, AdminConfig};
use laterite_auth::{password, store, AuthConfig, AuthService, NewOperator, RequestContext};
use laterite_core::Db;
use tower::ServiceExt;
const SESSION_COOKIE: &str = "laterite_session";
async fn test_db() -> (Db, laterite_core::testing::TestGuard) {
laterite_core::testing::connect_test(&laterite_admin::builtin_migrations()).await
}
async fn login(svc: &AuthService, username: &str, password: &str) -> String {
svc.authenticate(username, password, &RequestContext::default())
.await
.expect("authenticate")
.token
}
fn get(path: &str, token: Option<&str>) -> Request<Body> {
let mut builder = Request::builder().method("GET").uri(path);
if let Some(token) = token {
builder = builder.header("cookie", format!("{SESSION_COOKIE}={token}"));
}
builder.body(Body::empty()).unwrap()
}
#[tokio::test]
async fn resource_routes_enforce_their_permission() {
let (pool, _guard) = test_db().await;
let svc = AuthService::new(pool.clone(), AuthConfig::default());
svc.create_superuser(NewOperator {
username: "root",
email: "root@acme.test",
first_name: "Root",
last_name: None,
password: "rootpw12345",
timezone: None,
})
.await
.unwrap();
let hash = password::hash_password("mgrpw12345").unwrap();
let mgr_id = store::create_user(&pool, "mgr", "mgr@acme.test", "Mgr", None, &hash, false)
.await
.unwrap();
let role_id = store::create_role(
&pool,
"user_mgr",
"User Manager",
&["backend.manage_users".to_string()],
)
.await
.unwrap();
store::assign_role(&pool, mgr_id, role_id).await.unwrap();
let hash = password::hash_password("plainpw12345").unwrap();
store::create_user(
&pool,
"plain",
"plain@acme.test",
"Plain",
None,
&hash,
false,
)
.await
.unwrap();
let root = login(&svc, "root", "rootpw12345").await;
let mgr = login(&svc, "mgr", "mgrpw12345").await;
let plain = login(&svc, "plain", "plainpw12345").await;
let app = || {
router(
AuthService::new(pool.clone(), AuthConfig::default()),
pool.clone(),
Vec::new(),
Vec::new(),
Vec::new(),
AdminConfig::default(),
)
};
let status = app()
.oneshot(get("/admin/users", Some(&root)))
.await
.unwrap()
.status();
assert_eq!(status, StatusCode::OK);
let status = app()
.oneshot(get("/admin/users", Some(&mgr)))
.await
.unwrap()
.status();
assert_eq!(status, StatusCode::OK);
let status = app()
.oneshot(get("/admin/users", Some(&plain)))
.await
.unwrap()
.status();
assert_eq!(status, StatusCode::FORBIDDEN);
let status = app()
.oneshot(get("/admin/roles", Some(&mgr)))
.await
.unwrap()
.status();
assert_eq!(status, StatusCode::FORBIDDEN);
let status = app()
.oneshot(get("/admin/users", None))
.await
.unwrap()
.status();
assert_eq!(status, StatusCode::SEE_OTHER);
}