We don't use remote roles for now

This commit is contained in:
Gregor Reitzenstein 2021-01-27 14:40:33 +00:00
parent 4aaa281303
commit 9c87c192fa
5 changed files with 62 additions and 51 deletions

View File

@ -1,18 +1,17 @@
[anotherrole]
[testrole] [testrole]
name = "Testrole"
permissions = [ permissions = [
"lab.test.*" "lab.test.*"
] ]
[somerole] [somerole]
name = "Somerole" parents = ["testparent/lmdb"]
parents = ["testparent%lmdb"]
permissions = [ permissions = [
"lab.some.admin" "lab.some.admin"
] ]
[testparent] [testparent]
name = "Testparent"
permissions = [ permissions = [
"lab.some.write", "lab.some.write",
"lab.some.read", "lab.some.read",

2
schema

@ -1 +1 @@
Subproject commit 83cd61e299230f33474e2efa950667d1acfbe085 Subproject commit 4adb05341763b96a43440a6a96e0d9959ba71e89

View File

@ -42,7 +42,8 @@ impl machines::Server for Machines {
let res = results.get(); let res = results.get();
let mut machines = res.init_machines(v.len() as u32); let mut machines = res.init_machines(v.len() as u32);
for (i, (_name, machine)) in v.into_iter().enumerate() { for (i, (name, machine)) in v.into_iter().enumerate() {
debug!(self.session.log, "Adding machine {}: {:?}", name, machine);
let machine = Arc::new(Machine::new(self.session.clone(), machine, self.db.clone())); let machine = Arc::new(Machine::new(self.session.clone(), machine, self.db.clone()));
let mut builder = machines.reborrow().get(i as u32); let mut builder = machines.reborrow().get(i as u32);
Machine::fill(machine, &mut builder); Machine::fill(machine, &mut builder);

View File

@ -50,6 +50,10 @@ impl AccessControl {
pub fn dump_roles(&self) -> Result<Vec<(RoleIdentifier, Role)>> { pub fn dump_roles(&self) -> Result<Vec<(RoleIdentifier, Role)>> {
self.internal.dump_roles() self.internal.dump_roles()
} }
pub fn get_role(&self, role_id: &RoleIdentifier) -> Result<Option<Role>> {
self.internal.get_role(role_id)
}
} }
impl fmt::Debug for AccessControl { impl fmt::Debug for AccessControl {
@ -162,37 +166,24 @@ type SourceID = String;
fn split_once(s: &str, split: char) -> Option<(&str, &str)> { fn split_once(s: &str, split: char) -> Option<(&str, &str)> {
s s
.find(split) .find(split)
.map(|idx| s.split_at(idx)) .map(|idx| (&s[..idx], &s[(idx+1)..]))
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(try_from = "String")] #[serde(try_from = "String")]
#[serde(into = "String")]
/// Universal (relative) id of a role /// Universal (relative) id of a role
pub enum RoleIdentifier { pub struct RoleIdentifier {
/// The role comes from this instance
Local {
/// Locally unique name for the role. No other role at this instance no matter the source /// Locally unique name for the role. No other role at this instance no matter the source
/// may have the same name /// may have the same name
name: String, name: String,
/// Role Source, i.e. the database the role comes from /// Role Source, i.e. the database the role comes from
source: SourceID, source: SourceID,
},
/// The role comes from a federated instance
Remote {
/// Name of the role. This role is unique in that instance so the tuple (name, location)
/// refers to a unique role
name: String,
/// The federated instance this role comes from
location: String,
}
} }
impl fmt::Display for RoleIdentifier { impl fmt::Display for RoleIdentifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { write!(f, "{}/{}", self.name, self.source)
RoleIdentifier::Local {name, source} => write!(f, "{}/{}@local", name, source),
RoleIdentifier::Remote {name, location} => write!(f, "{}@{}", name, location),
}
} }
} }
@ -200,10 +191,8 @@ impl std::str::FromStr for RoleIdentifier {
type Err = RoleFromStrError; type Err = RoleFromStrError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
if let Some((name, location)) = split_once(s, '@') { if let Some((name, source)) = split_once(s, '/') {
Ok(RoleIdentifier::Remote { name: name.to_string(), location: location.to_string() }) Ok(RoleIdentifier { name: name.to_string(), source: source.to_string() })
} else if let Some((name, source)) = split_once(s, '%') {
Ok(RoleIdentifier::Local { name: name.to_string(), source: source.to_string() })
} else { } else {
Err(RoleFromStrError::Invalid) Err(RoleFromStrError::Invalid)
} }
@ -214,21 +203,18 @@ impl TryFrom<String> for RoleIdentifier {
type Error = RoleFromStrError; type Error = RoleFromStrError;
fn try_from(s: String) -> std::result::Result<Self, Self::Error> { fn try_from(s: String) -> std::result::Result<Self, Self::Error> {
if let Some((name, location)) = split_once(&s, '@') { <RoleIdentifier as std::str::FromStr>::from_str(&s)
let location = &location[1..];
Ok(RoleIdentifier::Remote { name: name.to_string(), location: location.to_string() })
} else if let Some((name, source)) = split_once(&s, '%') {
let source = &source[1..];
Ok(RoleIdentifier::Local { name: name.to_string(), source: source.to_string() })
} else {
Err(RoleFromStrError::Invalid)
} }
} }
impl Into<String> for RoleIdentifier {
fn into(self) -> String {
format!("{}", self)
}
} }
impl RoleIdentifier { impl RoleIdentifier {
pub fn local_from_str(source: String, name: String) -> Self { pub fn local_from_str(source: String, name: String) -> Self {
RoleIdentifier::Local { name, source } RoleIdentifier { name, source }
} }
} }
@ -505,7 +491,7 @@ impl TryFrom<String> for PermRule {
} }
} }
#[cfg(test_DISABLED)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -532,23 +518,46 @@ mod tests {
assert!(rule.match_perm(&perm)); assert!(rule.match_perm(&perm));
} }
#[test]
fn format_and_read_compatible() {
use std::convert::TryInto;
let testdata = vec![
("testrole", "testsource"),
("", "norole"),
("nosource", "")
].into_iter().map(|(n,s)| (n.to_string(), s.to_string()));
for (name, source) in testdata {
let role = RoleIdentifier { name, source };
let fmt_string = format!("{}", &role);
println!("{:?} is formatted: {}", &role, &fmt_string);
let parsed: RoleIdentifier = fmt_string.try_into().unwrap();
println!("Which parses into {:?}", &parsed);
assert_eq!(role, parsed);
}
}
#[test] #[test]
fn load_examples_roles_test() { fn load_examples_roles_test() {
let mut roles = Role::load_file("examples/roles.toml") let mut roles = Role::load_file("examples/roles.toml")
.expect("Couldn't load the example role defs. Does `examples/roles.toml` exist?"); .expect("Couldn't load the example role defs. Does `examples/roles.toml` exist?");
let expected = vec![ let expected = vec![
(RoleIdentifier::Local { name: "testrole".to_string(), source: "lmdb".to_string() }, (RoleIdentifier { name: "testrole".to_string(), source: "lmdb".to_string() },
Role { Role {
name: "Testrole".to_string(),
parents: vec![], parents: vec![],
permissions: vec![ permissions: vec![
PermRule::Subtree(PermissionBuf::from_string("lab.test".to_string())) PermRule::Subtree(PermissionBuf::from_string("lab.test".to_string()))
], ],
}), }),
(RoleIdentifier::Local { name: "somerole".to_string(), source: "lmdb".to_string() }, (RoleIdentifier { name: "somerole".to_string(), source: "lmdb".to_string() },
Role { Role {
name: "Somerole".to_string(),
parents: vec![ parents: vec![
RoleIdentifier::local_from_str("lmdb".to_string(), "testparent".to_string()), RoleIdentifier::local_from_str("lmdb".to_string(), "testparent".to_string()),
], ],
@ -556,9 +565,8 @@ mod tests {
PermRule::Base(PermissionBuf::from_string("lab.some.admin".to_string())) PermRule::Base(PermissionBuf::from_string("lab.some.admin".to_string()))
], ],
}), }),
(RoleIdentifier::Local { name: "testparent".to_string(), source: "lmdb".to_string() }, (RoleIdentifier { name: "testparent".to_string(), source: "lmdb".to_string() },
Role { Role {
name: "Testparent".to_string(),
parents: vec![], parents: vec![],
permissions: vec![ permissions: vec![
PermRule::Base(PermissionBuf::from_string("lab.some.write".to_string())), PermRule::Base(PermissionBuf::from_string("lab.some.write".to_string())),

View File

@ -77,6 +77,7 @@ impl Internal {
pub fn _get_role<'txn, T: Transaction>(&self, txn: &'txn T, role_id: &RoleIdentifier) -> Result<Option<Role>> { pub fn _get_role<'txn, T: Transaction>(&self, txn: &'txn T, role_id: &RoleIdentifier) -> Result<Option<Role>> {
let string = format!("{}", role_id); let string = format!("{}", role_id);
debug!(self.log, "Reading role '{}'", &string);
match txn.get(self.roledb, &string.as_bytes()) { match txn.get(self.roledb, &string.as_bytes()) {
Ok(bytes) => { Ok(bytes) => {
Ok(Some(flexbuffers::from_slice(bytes)?)) Ok(Some(flexbuffers::from_slice(bytes)?))
@ -108,8 +109,10 @@ impl Internal {
Ok( (k,v) ) => { Ok( (k,v) ) => {
let role_id_str = unsafe { std::str::from_utf8_unchecked(k) }; let role_id_str = unsafe { std::str::from_utf8_unchecked(k) };
let role_id = role_id_str.parse::<RoleIdentifier>().unwrap(); let role_id = role_id_str.parse::<RoleIdentifier>().unwrap();
let role = flexbuffers::from_slice(v)?; match flexbuffers::from_slice(v) {
vec.push((role_id, role)); Ok(role) => vec.push((role_id, role)),
Err(e) => error!(self.log, "Bad format for roleid {}: {}", role_id, e),
}
}, },
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
} }