parent
339975b030
commit
bc665120ee
2 changed files with 209 additions and 0 deletions
|
@ -18,6 +18,21 @@ impl<'a> Document<'a> {
|
|||
if self.id.is_some() {
|
||||
// Should we run permissions checks?
|
||||
if opt.check_perms(stm.into())? {
|
||||
// Check that record authentication matches session
|
||||
if opt.auth.is_record() {
|
||||
let ns = opt.ns()?;
|
||||
if opt.auth.level().ns() != Some(ns) {
|
||||
return Err(Error::NsNotAllowed {
|
||||
ns: ns.into(),
|
||||
});
|
||||
}
|
||||
let db = opt.db()?;
|
||||
if opt.auth.level().db() != Some(db) {
|
||||
return Err(Error::DbNotAllowed {
|
||||
db: db.into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
// Get the table
|
||||
let tb = self.tb(ctx, opt).await?;
|
||||
// Get the permission clause
|
||||
|
|
|
@ -1472,6 +1472,200 @@ async fn session_reauthentication_expired() {
|
|||
server.finish().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn session_use_change_database() {
|
||||
// Setup database server
|
||||
let (addr, mut server) = common::start_server_with_defaults().await.unwrap();
|
||||
// Connect to WebSocket
|
||||
let mut socket = Socket::connect(&addr, SERVER, FORMAT).await.unwrap();
|
||||
// Authenticate the connection as a root level system user
|
||||
let _ = socket.send_message_signin(USER, PASS, None, None, None).await.unwrap();
|
||||
// Check that we have root access
|
||||
socket.send_message_query("INFO FOR ROOT").await.unwrap();
|
||||
// Specify a namespace and database
|
||||
socket.send_message_use(Some(NS), Some("original")).await.unwrap();
|
||||
// Define a scope on the original database
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
DEFINE USER user ON DATABASE PASSWORD "secret" ROLES VIEWER
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Create resource that requires an authenticated record user to query
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
DEFINE TABLE user SCHEMALESS
|
||||
PERMISSIONS FOR select, create, update, delete NONE
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
CREATE user:1 CONTENT { name: "original", pass: crypto::argon2::generate("original") }
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Change to a different database
|
||||
socket.send_message_use(Some(NS), Some("different")).await.unwrap();
|
||||
// Create the same user table with a user record with the same identifier
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
DEFINE TABLE user SCHEMALESS
|
||||
PERMISSIONS FOR select, create, update, delete NONE
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
CREATE user:1 CONTENT { name: "different", pass: crypto::argon2::generate("different") }
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Sign in to original database as user
|
||||
let res = socket
|
||||
.send_request(
|
||||
"signin",
|
||||
json!(
|
||||
[{
|
||||
"ns": NS,
|
||||
"db": "original",
|
||||
"user": "user",
|
||||
"pass": "secret",
|
||||
}]
|
||||
),
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_ok(), "result: {:?}", res);
|
||||
let res = res.unwrap();
|
||||
assert!(res.is_object(), "result: {:?}", res);
|
||||
let res = res.as_object().unwrap();
|
||||
// Verify response contains no error
|
||||
assert!(res.keys().all(|k| ["id", "result"].contains(&k.as_str())), "result: {:?}", res);
|
||||
// Verify that the authenticated session corresponds with the original user
|
||||
let res = socket.send_message_query("SELECT VALUE name FROM user:1").await.unwrap();
|
||||
assert_eq!(res[0]["result"], json!(["original"]), "result: {:?}", res);
|
||||
// Swtich to the different database without signing in again
|
||||
socket.send_message_use(Some(NS), Some("different")).await.unwrap();
|
||||
// Verify that the authenticated session is unable to query data
|
||||
let res = socket.send_message_query("SELECT VALUE name FROM user:1").await.unwrap();
|
||||
// The query succeeds but the results does not contain the value with permissions
|
||||
assert_eq!(res[0]["status"], "OK", "result: {:?}", res);
|
||||
assert_eq!(res[0]["result"], json!([]), "result: {:?}", res);
|
||||
// Test passed
|
||||
server.finish().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn session_use_change_database_scope() {
|
||||
// Setup database server
|
||||
let (addr, mut server) = common::start_server_with_defaults().await.unwrap();
|
||||
// Connect to WebSocket
|
||||
let mut socket = Socket::connect(&addr, SERVER, FORMAT).await.unwrap();
|
||||
// Authenticate the connection as a root level system user
|
||||
let _ = socket.send_message_signin(USER, PASS, None, None, None).await.unwrap();
|
||||
// Check that we have root access
|
||||
socket.send_message_query("INFO FOR ROOT").await.unwrap();
|
||||
// Specify a namespace and database
|
||||
socket.send_message_use(Some(NS), Some("original")).await.unwrap();
|
||||
// Define a user record access method on the original database
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
DEFINE ACCESS user ON DATABASE TYPE RECORD
|
||||
SIGNIN ( SELECT * FROM user WHERE name = $name AND crypto::argon2::compare(pass, $pass) )
|
||||
DURATION FOR SESSION 24h, FOR TOKEN 24h
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Create resource that requires an authenticated record user to query
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
DEFINE TABLE user SCHEMALESS
|
||||
PERMISSIONS FOR select, create, update, delete WHERE id = $auth
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
CREATE user:1 CONTENT { name: "original", pass: crypto::argon2::generate("original") }
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Change to a different database
|
||||
socket.send_message_use(Some(NS), Some("different")).await.unwrap();
|
||||
// Create the same user table with a user record with the same identifier
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
DEFINE TABLE user SCHEMALESS
|
||||
PERMISSIONS FOR select, create, update, delete WHERE id = $auth
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
socket
|
||||
.send_message_query(
|
||||
r#"
|
||||
CREATE user:1 CONTENT { name: "different", pass: crypto::argon2::generate("different") }
|
||||
;"#,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Sign in to original database as user
|
||||
let res = socket
|
||||
.send_request(
|
||||
"signin",
|
||||
json!(
|
||||
[{
|
||||
"ns": NS,
|
||||
"db": "original",
|
||||
"ac": "user",
|
||||
"name": "original",
|
||||
"pass": "original",
|
||||
}]
|
||||
),
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_ok(), "result: {:?}", res);
|
||||
let res = res.unwrap();
|
||||
assert!(res.is_object(), "result: {:?}", res);
|
||||
let res = res.as_object().unwrap();
|
||||
// Verify response contains no error
|
||||
assert!(res.keys().all(|k| ["id", "result"].contains(&k.as_str())), "result: {:?}", res);
|
||||
// Verify that the authenticated session corresponds with the original user
|
||||
let res = socket.send_message_query("SELECT VALUE name FROM $auth").await.unwrap();
|
||||
assert_eq!(res[0]["result"], json!(["original"]), "result: {:?}", res);
|
||||
// Swtich to the different database without signing in again
|
||||
socket.send_message_use(Some(NS), Some("different")).await.unwrap();
|
||||
// Verify that the authenticated session is unable to query data
|
||||
let res = socket.send_message_query("SELECT VALUE name FROM $auth").await.unwrap();
|
||||
// The following statement would be true when the bug was present:
|
||||
// assert_eq!(res[0]["result"], json!(["different"]), "result: {:?}", res);
|
||||
assert_eq!(res[0]["status"], "ERR", "result: {:?}", res);
|
||||
assert_eq!(
|
||||
res[0]["result"], "You don't have permission to change to the different database",
|
||||
"result: {:?}",
|
||||
res
|
||||
);
|
||||
// Test passed
|
||||
server.finish().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn run_functions() {
|
||||
// Setup database server
|
||||
|
|
Loading…
Reference in a new issue