Allow defining a maximum session duration on DEFINE USER
(#4116)
This commit is contained in:
parent
876f281be5
commit
d2821461b7
8 changed files with 127 additions and 59 deletions
|
@ -235,8 +235,7 @@ pub async fn db_user(
|
|||
session.tk = Some(val.into());
|
||||
session.ns = Some(ns.to_owned());
|
||||
session.db = Some(db.to_owned());
|
||||
// TODO(gguillemas): Enforce expiration once session lifetime can be customized.
|
||||
session.exp = None;
|
||||
session.exp = expiration(u.session)?;
|
||||
session.au = Arc::new((&u, Level::Database(ns.to_owned(), db.to_owned())).into());
|
||||
// Check the authentication token
|
||||
match enc {
|
||||
|
@ -279,8 +278,7 @@ pub async fn ns_user(
|
|||
// Set the authentication on the session
|
||||
session.tk = Some(val.into());
|
||||
session.ns = Some(ns.to_owned());
|
||||
// TODO(gguillemas): Enforce expiration once session lifetime can be customized.
|
||||
session.exp = None;
|
||||
session.exp = expiration(u.session)?;
|
||||
session.au = Arc::new((&u, Level::Namespace(ns.to_owned())).into());
|
||||
// Check the authentication token
|
||||
match enc {
|
||||
|
@ -321,8 +319,7 @@ pub async fn root_user(
|
|||
let enc = encode(&HEADER, &val, &key);
|
||||
// Set the authentication on the session
|
||||
session.tk = Some(val.into());
|
||||
// TODO(gguillemas): Enforce expiration once session lifetime can be customized.
|
||||
session.exp = None;
|
||||
session.exp = expiration(u.session)?;
|
||||
session.au = Arc::new((&u, Level::Root).into());
|
||||
// Check the authentication token
|
||||
match enc {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::dbs::Session;
|
||||
use crate::err::Error;
|
||||
use crate::iam::issue::expiration;
|
||||
#[cfg(feature = "jwks")]
|
||||
use crate::iam::jwks;
|
||||
use crate::iam::{token::Claims, Actor, Auth, Level, Role};
|
||||
|
@ -98,8 +99,7 @@ pub async fn basic(
|
|||
(Some(ns), Some(db)) => match verify_db_creds(kvs, ns, db, user, pass).await {
|
||||
Ok(u) => {
|
||||
debug!("Authenticated as database user '{}'", user);
|
||||
// TODO(gguillemas): Enforce expiration once session lifetime can be customized.
|
||||
session.exp = None;
|
||||
session.exp = expiration(u.session)?;
|
||||
session.au = Arc::new((&u, Level::Database(ns.to_owned(), db.to_owned())).into());
|
||||
Ok(())
|
||||
}
|
||||
|
@ -109,8 +109,7 @@ pub async fn basic(
|
|||
(Some(ns), None) => match verify_ns_creds(kvs, ns, user, pass).await {
|
||||
Ok(u) => {
|
||||
debug!("Authenticated as namespace user '{}'", user);
|
||||
// TODO(gguillemas): Enforce expiration once session lifetime can be customized.
|
||||
session.exp = None;
|
||||
session.exp = expiration(u.session)?;
|
||||
session.au = Arc::new((&u, Level::Namespace(ns.to_owned())).into());
|
||||
Ok(())
|
||||
}
|
||||
|
@ -120,8 +119,7 @@ pub async fn basic(
|
|||
(None, None) => match verify_root_creds(kvs, user, pass).await {
|
||||
Ok(u) => {
|
||||
debug!("Authenticated as root user '{}'", user);
|
||||
// TODO(gguillemas): Enforce expiration once session lifetime can be customized.
|
||||
session.exp = None;
|
||||
session.exp = expiration(u.session)?;
|
||||
session.au = Arc::new((&u, Level::Root).into());
|
||||
Ok(())
|
||||
}
|
||||
|
@ -494,7 +492,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn test_basic_root() {
|
||||
//
|
||||
// Test without roles defined
|
||||
// Test without roles or expiration defined
|
||||
//
|
||||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
|
@ -520,14 +518,18 @@ mod tests {
|
|||
}
|
||||
|
||||
//
|
||||
// Test with roles defined
|
||||
// Test with roles and expiration defined
|
||||
//
|
||||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner().with_ns("test").with_db("test");
|
||||
ds.execute("DEFINE USER user ON ROOT PASSWORD 'pass' ROLES EDITOR, OWNER", &sess, None)
|
||||
.await
|
||||
.unwrap();
|
||||
ds.execute(
|
||||
"DEFINE USER user ON ROOT PASSWORD 'pass' ROLES EDITOR, OWNER SESSION 1d",
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut sess = Session {
|
||||
..Default::default()
|
||||
|
@ -544,7 +546,15 @@ mod tests {
|
|||
assert!(!sess.au.has_role(&Role::Viewer), "Auth user expected to not have Viewer role");
|
||||
assert!(sess.au.has_role(&Role::Editor), "Auth user expected to have Editor role");
|
||||
assert!(sess.au.has_role(&Role::Owner), "Auth user expected to have Owner role");
|
||||
assert_eq!(sess.exp, None, "Default system user expiration is expected to be None");
|
||||
// Expiration has been set explicitly
|
||||
let exp = sess.exp.unwrap();
|
||||
// Expiration should match the current time plus session duration with some margin
|
||||
let min_exp = (Utc::now() + Duration::days(1) - Duration::seconds(10)).timestamp();
|
||||
let max_exp = (Utc::now() + Duration::days(1) + Duration::seconds(10)).timestamp();
|
||||
assert!(
|
||||
exp > min_exp && exp < max_exp,
|
||||
"Session expiration is expected to match the defined duration"
|
||||
);
|
||||
}
|
||||
|
||||
// Test invalid password
|
||||
|
@ -565,7 +575,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn test_basic_ns() {
|
||||
//
|
||||
// Test without roles defined
|
||||
// Test without roles or expiration defined
|
||||
//
|
||||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
|
@ -592,14 +602,18 @@ mod tests {
|
|||
}
|
||||
|
||||
//
|
||||
// Test with roles defined
|
||||
// Test with roles and expiration defined
|
||||
//
|
||||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner().with_ns("test").with_db("test");
|
||||
ds.execute("DEFINE USER user ON NS PASSWORD 'pass' ROLES EDITOR, OWNER", &sess, None)
|
||||
.await
|
||||
.unwrap();
|
||||
ds.execute(
|
||||
"DEFINE USER user ON NS PASSWORD 'pass' ROLES EDITOR, OWNER SESSION 1d",
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut sess = Session {
|
||||
ns: Some("test".to_string()),
|
||||
|
@ -617,7 +631,15 @@ mod tests {
|
|||
assert!(!sess.au.has_role(&Role::Viewer), "Auth user expected to not have Viewer role");
|
||||
assert!(sess.au.has_role(&Role::Editor), "Auth user expected to have Editor role");
|
||||
assert!(sess.au.has_role(&Role::Owner), "Auth user expected to have Owner role");
|
||||
assert_eq!(sess.exp, None, "Default system user expiration is expected to be None");
|
||||
// Expiration has been set explicitly
|
||||
let exp = sess.exp.unwrap();
|
||||
// Expiration should match the current time plus session duration with some margin
|
||||
let min_exp = (Utc::now() + Duration::days(1) - Duration::seconds(10)).timestamp();
|
||||
let max_exp = (Utc::now() + Duration::days(1) + Duration::seconds(10)).timestamp();
|
||||
assert!(
|
||||
exp > min_exp && exp < max_exp,
|
||||
"Session expiration is expected to match the defined duration"
|
||||
);
|
||||
}
|
||||
|
||||
// Test invalid password
|
||||
|
@ -638,7 +660,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn test_basic_db() {
|
||||
//
|
||||
// Test without roles defined
|
||||
// Test without roles or expiration defined
|
||||
//
|
||||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
|
@ -666,14 +688,18 @@ mod tests {
|
|||
}
|
||||
|
||||
//
|
||||
// Test with roles defined
|
||||
// Test with roles and expiration defined
|
||||
//
|
||||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner().with_ns("test").with_db("test");
|
||||
ds.execute("DEFINE USER user ON DB PASSWORD 'pass' ROLES EDITOR, OWNER", &sess, None)
|
||||
.await
|
||||
.unwrap();
|
||||
ds.execute(
|
||||
"DEFINE USER user ON DB PASSWORD 'pass' ROLES EDITOR, OWNER SESSION 1d",
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut sess = Session {
|
||||
ns: Some("test".to_string()),
|
||||
|
@ -692,7 +718,15 @@ mod tests {
|
|||
assert!(!sess.au.has_role(&Role::Viewer), "Auth user expected to not have Viewer role");
|
||||
assert!(sess.au.has_role(&Role::Editor), "Auth user expected to have Editor role");
|
||||
assert!(sess.au.has_role(&Role::Owner), "Auth user expected to have Owner role");
|
||||
assert_eq!(sess.exp, None, "Default system user expiration is expected to be None");
|
||||
// Expiration has been set explicitly
|
||||
let exp = sess.exp.unwrap();
|
||||
// Expiration should match the current time plus session duration with some margin
|
||||
let min_exp = (Utc::now() + Duration::days(1) - Duration::seconds(10)).timestamp();
|
||||
let max_exp = (Utc::now() + Duration::days(1) + Duration::seconds(10)).timestamp();
|
||||
assert!(
|
||||
exp > min_exp && exp < max_exp,
|
||||
"Session expiration is expected to match the defined duration"
|
||||
);
|
||||
}
|
||||
|
||||
// Test invalid password
|
||||
|
|
|
@ -59,6 +59,9 @@ const LQ_CHANNEL_SIZE: usize = 100;
|
|||
// The batch size used for non-paged operations (i.e. if there are more results, they are ignored)
|
||||
const NON_PAGED_BATCH_SIZE: u32 = 100_000;
|
||||
|
||||
// The role assigned to the initial user created when starting the server with credentials for the first time
|
||||
const INITIAL_USER_ROLE: &str = "owner";
|
||||
|
||||
/// The underlying datastore instance which stores the dataset.
|
||||
#[allow(dead_code)]
|
||||
#[non_exhaustive]
|
||||
|
@ -482,8 +485,9 @@ impl Datastore {
|
|||
Ok(v) if v.is_empty() => {
|
||||
// Display information in the logs
|
||||
info!("Credentials were provided, and no root users were found. The root user '{}' will be created", username);
|
||||
// Create and save a new root users
|
||||
let stm = DefineUserStatement::from((Base::Root, username, password));
|
||||
// Create and save a new root user
|
||||
let stm =
|
||||
DefineUserStatement::from((Base::Root, username, password, INITIAL_USER_ROLE));
|
||||
let ctx = Context::default().set_transaction(txn.clone());
|
||||
let opt = Options::new().with_auth(Arc::new(Auth::for_root(Role::Owner)));
|
||||
let _ = stm.compute(&ctx, &opt, None).await?;
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::doc::CursorDoc;
|
|||
use crate::err::Error;
|
||||
use crate::iam::{Action, ResourceKind};
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::{escape::quote_str, fmt::Fmt, Base, Ident, Object, Strand, Value};
|
||||
use crate::sql::{escape::quote_str, fmt::Fmt, Base, Duration, Ident, Object, Strand, Value};
|
||||
use argon2::{
|
||||
password_hash::{PasswordHasher, SaltString},
|
||||
Argon2,
|
||||
|
@ -15,7 +15,7 @@ use revision::revisioned;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[revisioned(revision = 2)]
|
||||
#[revisioned(revision = 3)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[non_exhaustive]
|
||||
|
@ -25,13 +25,15 @@ pub struct DefineUserStatement {
|
|||
pub hash: String,
|
||||
pub code: String,
|
||||
pub roles: Vec<Ident>,
|
||||
#[revision(start = 3)]
|
||||
pub session: Option<Duration>,
|
||||
pub comment: Option<Strand>,
|
||||
#[revision(start = 2)]
|
||||
pub if_not_exists: bool,
|
||||
}
|
||||
|
||||
impl From<(Base, &str, &str)> for DefineUserStatement {
|
||||
fn from((base, user, pass): (Base, &str, &str)) -> Self {
|
||||
impl From<(Base, &str, &str, &str)> for DefineUserStatement {
|
||||
fn from((base, user, pass, role): (Base, &str, &str, &str)) -> Self {
|
||||
DefineUserStatement {
|
||||
base,
|
||||
name: user.into(),
|
||||
|
@ -44,7 +46,8 @@ impl From<(Base, &str, &str)> for DefineUserStatement {
|
|||
.take(128)
|
||||
.map(char::from)
|
||||
.collect::<String>(),
|
||||
roles: vec!["owner".into()],
|
||||
roles: vec![role.into()],
|
||||
session: None,
|
||||
comment: None,
|
||||
if_not_exists: false,
|
||||
}
|
||||
|
@ -52,11 +55,17 @@ impl From<(Base, &str, &str)> for DefineUserStatement {
|
|||
}
|
||||
|
||||
impl DefineUserStatement {
|
||||
pub(crate) fn from_parsed_values(name: Ident, base: Base, roles: Vec<Ident>) -> Self {
|
||||
pub(crate) fn from_parsed_values(
|
||||
name: Ident,
|
||||
base: Base,
|
||||
roles: Vec<Ident>,
|
||||
session: Option<Duration>,
|
||||
) -> Self {
|
||||
DefineUserStatement {
|
||||
name,
|
||||
base,
|
||||
roles, // New users get the viewer role by default
|
||||
roles, // New users get the viewer role by default
|
||||
session, // Sessions for system users do not expire by default
|
||||
code: rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(128)
|
||||
|
@ -77,6 +86,10 @@ impl DefineUserStatement {
|
|||
self.hash = passhash;
|
||||
}
|
||||
|
||||
pub(crate) fn set_session(&mut self, session: Option<Duration>) {
|
||||
self.session = session;
|
||||
}
|
||||
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
|
@ -191,8 +204,11 @@ impl Display for DefineUserStatement {
|
|||
quote_str(&self.hash),
|
||||
Fmt::comma_separated(
|
||||
&self.roles.iter().map(|r| r.to_string().to_uppercase()).collect::<Vec<String>>()
|
||||
)
|
||||
),
|
||||
)?;
|
||||
if let Some(ref v) = self.session {
|
||||
write!(f, " SESSION {v}")?
|
||||
}
|
||||
if let Some(ref v) = self.comment {
|
||||
write!(f, " COMMENT {v}")?
|
||||
}
|
||||
|
@ -207,6 +223,7 @@ impl InfoStructure for DefineUserStatement {
|
|||
base,
|
||||
hash,
|
||||
roles,
|
||||
session,
|
||||
comment,
|
||||
..
|
||||
} = self;
|
||||
|
@ -223,6 +240,10 @@ impl InfoStructure for DefineUserStatement {
|
|||
Value::Array(roles.into_iter().map(|r| r.structure()).collect()),
|
||||
);
|
||||
|
||||
if let Some(session) = session {
|
||||
acc.insert("session".to_string(), session.into());
|
||||
}
|
||||
|
||||
if let Some(comment) = comment {
|
||||
acc.insert("comment".to_string(), comment.into());
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::err::Error;
|
|||
use crate::sql::statements::DefineUserStatement;
|
||||
use crate::sql::value::serde::ser;
|
||||
use crate::sql::Base;
|
||||
use crate::sql::Duration;
|
||||
use crate::sql::Ident;
|
||||
use crate::sql::Strand;
|
||||
use ser::Serializer as _;
|
||||
|
@ -44,6 +45,7 @@ pub struct SerializeDefineUserStatement {
|
|||
hash: String,
|
||||
code: String,
|
||||
roles: Vec<Ident>,
|
||||
session: Option<Duration>,
|
||||
comment: Option<Strand>,
|
||||
if_not_exists: bool,
|
||||
}
|
||||
|
@ -72,6 +74,10 @@ impl serde::ser::SerializeStruct for SerializeDefineUserStatement {
|
|||
"roles" => {
|
||||
self.roles = value.serialize(ser::ident::vec::Serializer.wrap())?;
|
||||
}
|
||||
"session" => {
|
||||
self.session =
|
||||
value.serialize(ser::duration::opt::Serializer.wrap())?.map(Into::into);
|
||||
}
|
||||
"comment" => {
|
||||
self.comment = value.serialize(ser::strand::opt::Serializer.wrap())?;
|
||||
}
|
||||
|
@ -94,6 +100,7 @@ impl serde::ser::SerializeStruct for SerializeDefineUserStatement {
|
|||
hash: self.hash,
|
||||
code: self.code,
|
||||
roles: self.roles,
|
||||
session: self.session,
|
||||
comment: self.comment,
|
||||
if_not_exists: self.if_not_exists,
|
||||
})
|
||||
|
|
|
@ -182,6 +182,7 @@ impl Parser<'_> {
|
|||
name,
|
||||
base,
|
||||
vec!["Viewer".into()], // New users get the viewer role by default
|
||||
None, // Sessions for system users do not expire by default
|
||||
);
|
||||
|
||||
if if_not_exists {
|
||||
|
@ -209,6 +210,10 @@ impl Parser<'_> {
|
|||
res.roles.push(self.next_token_value()?);
|
||||
}
|
||||
}
|
||||
t!("SESSION") => {
|
||||
self.pop_peek();
|
||||
res.set_session(Some(self.next_token_value()?));
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1782,13 +1782,13 @@ async fn permissions_checks_define_access_db() {
|
|||
async fn permissions_checks_define_user_root() {
|
||||
let scenario = HashMap::from([
|
||||
("prepare", ""),
|
||||
("test", "DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER"),
|
||||
("test", "DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER SESSION 1d"),
|
||||
("check", "INFO FOR ROOT"),
|
||||
]);
|
||||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ namespaces: { }, users: { user: \"DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ namespaces: { }, users: { user: \"DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER SESSION 1d\" } }"],
|
||||
vec!["{ namespaces: { }, users: { } }"]
|
||||
];
|
||||
|
||||
|
@ -1824,13 +1824,13 @@ async fn permissions_checks_define_user_root() {
|
|||
async fn permissions_checks_define_user_ns() {
|
||||
let scenario = HashMap::from([
|
||||
("prepare", ""),
|
||||
("test", "DEFINE USER user ON NS PASSHASH 'secret' ROLES VIEWER"),
|
||||
("test", "DEFINE USER user ON NS PASSHASH 'secret' ROLES VIEWER SESSION 1d"),
|
||||
("check", "INFO FOR NS"),
|
||||
]);
|
||||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ accesses: { }, databases: { }, users: { user: \"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ accesses: { }, databases: { }, users: { user: \"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER SESSION 1d\" } }"],
|
||||
vec!["{ accesses: { }, databases: { }, users: { } }"]
|
||||
];
|
||||
|
||||
|
@ -1866,13 +1866,13 @@ async fn permissions_checks_define_user_ns() {
|
|||
async fn permissions_checks_define_user_db() {
|
||||
let scenario = HashMap::from([
|
||||
("prepare", ""),
|
||||
("test", "DEFINE USER user ON DB PASSHASH 'secret' ROLES VIEWER"),
|
||||
("test", "DEFINE USER user ON DB PASSHASH 'secret' ROLES VIEWER SESSION 1d"),
|
||||
("check", "INFO FOR DB"),
|
||||
]);
|
||||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["{ accesses: { }, analyzers: { }, functions: { }, models: { }, params: { }, tables: { }, users: { user: \"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER\" } }"],
|
||||
vec!["{ accesses: { }, analyzers: { }, functions: { }, models: { }, params: { }, tables: { }, users: { user: \"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER SESSION 1d\" } }"],
|
||||
vec!["{ accesses: { }, analyzers: { }, functions: { }, models: { }, params: { }, tables: { }, users: { } }"]
|
||||
];
|
||||
|
||||
|
@ -2601,8 +2601,8 @@ async fn redefining_existing_table_with_if_not_exists_should_error() -> Result<(
|
|||
#[tokio::test]
|
||||
async fn redefining_existing_user_should_not_error() -> Result<(), Error> {
|
||||
let sql = "
|
||||
DEFINE USER example ON ROOT PASSWORD \"example\" ROLES OWNER;
|
||||
DEFINE USER example ON ROOT PASSWORD \"example\" ROLES OWNER;
|
||||
DEFINE USER example ON ROOT PASSWORD \"example\" ROLES OWNER SESSION 1d;
|
||||
DEFINE USER example ON ROOT PASSWORD \"example\" ROLES OWNER SESSION 1d;
|
||||
";
|
||||
let dbs = new_ds().await?;
|
||||
let ses = Session::owner().with_ns("test").with_db("test");
|
||||
|
@ -2621,8 +2621,8 @@ async fn redefining_existing_user_should_not_error() -> Result<(), Error> {
|
|||
#[tokio::test]
|
||||
async fn redefining_existing_user_with_if_not_exists_should_error() -> Result<(), Error> {
|
||||
let sql = "
|
||||
DEFINE USER IF NOT EXISTS example ON ROOT PASSWORD \"example\" ROLES OWNER;
|
||||
DEFINE USER IF NOT EXISTS example ON ROOT PASSWORD \"example\" ROLES OWNER;
|
||||
DEFINE USER IF NOT EXISTS example ON ROOT PASSWORD \"example\" ROLES OWNER SESSION 1d;
|
||||
DEFINE USER IF NOT EXISTS example ON ROOT PASSWORD \"example\" ROLES OWNER SESSION 1d;
|
||||
";
|
||||
let dbs = new_ds().await?;
|
||||
let ses = Session::owner().with_ns("test").with_db("test");
|
||||
|
|
|
@ -363,15 +363,15 @@ async fn permissions_checks_info_table() {
|
|||
#[tokio::test]
|
||||
async fn permissions_checks_info_user_root() {
|
||||
let scenario = HashMap::from([
|
||||
("prepare", "DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER"),
|
||||
("prepare", "DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER SESSION 1d"),
|
||||
("test", "INFO FOR USER user ON ROOT"),
|
||||
("check", "INFO FOR USER user ON ROOT"),
|
||||
]);
|
||||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["\"DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER\""],
|
||||
vec!["\"DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER\""],
|
||||
vec!["\"DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER SESSION 1d\""],
|
||||
vec!["\"DEFINE USER user ON ROOT PASSHASH 'secret' ROLES VIEWER SESSION 1d\""],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -405,15 +405,15 @@ async fn permissions_checks_info_user_root() {
|
|||
#[tokio::test]
|
||||
async fn permissions_checks_info_user_ns() {
|
||||
let scenario = HashMap::from([
|
||||
("prepare", "DEFINE USER user ON NS PASSHASH 'secret' ROLES VIEWER"),
|
||||
("prepare", "DEFINE USER user ON NS PASSHASH 'secret' ROLES VIEWER SESSION 1d"),
|
||||
("test", "INFO FOR USER user ON NS"),
|
||||
("check", "INFO FOR USER user ON NS"),
|
||||
]);
|
||||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["\"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER\""],
|
||||
vec!["\"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER\""],
|
||||
vec!["\"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER SESSION 1d\""],
|
||||
vec!["\"DEFINE USER user ON NAMESPACE PASSHASH 'secret' ROLES VIEWER SESSION 1d\""],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
@ -447,15 +447,15 @@ async fn permissions_checks_info_user_ns() {
|
|||
#[tokio::test]
|
||||
async fn permissions_checks_info_user_db() {
|
||||
let scenario = HashMap::from([
|
||||
("prepare", "DEFINE USER user ON DB PASSHASH 'secret' ROLES VIEWER"),
|
||||
("prepare", "DEFINE USER user ON DB PASSHASH 'secret' ROLES VIEWER SESSION 1d"),
|
||||
("test", "INFO FOR USER user ON DB"),
|
||||
("check", "INFO FOR USER user ON DB"),
|
||||
]);
|
||||
|
||||
// Define the expected results for the check statement when the test statement succeeded and when it failed
|
||||
let check_results = [
|
||||
vec!["\"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER\""],
|
||||
vec!["\"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER\""],
|
||||
vec!["\"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER SESSION 1d\""],
|
||||
vec!["\"DEFINE USER user ON DATABASE PASSHASH 'secret' ROLES VIEWER SESSION 1d\""],
|
||||
];
|
||||
|
||||
let test_cases = [
|
||||
|
|
Loading…
Reference in a new issue