-
-
Save mbrubeck/100d4c99ec45bb6e34f9a4a66ada9212 to your computer and use it in GitHub Desktop.
Experimenting with refactoring permission authorization with a Rust implementation (thus far, a Rust integration is slower)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# works for python 2.7 | |
import ctypes | |
import timeit | |
rustLib = "./libauthz.so" | |
assigned_perms = ["domain1:action3:target1", "domain1:action1,action2", "domain1:action4:target2"] | |
required_perm = "domain1:action4:target3" | |
lib = ctypes.cdll.LoadLibrary(rustLib) | |
def testRust(): | |
perm_array = (ctypes.c_char_p * len(assigned_perms))(*assigned_perms) | |
result = lib.is_permitted_from_str(ctypes.c_char_p(required_perm), perm_array, len(assigned_perms)) | |
if __name__=="__main__": | |
rusty_test = timeit.repeat("testRust()", "from __main__ import testRust", number=100000, repeat=1) | |
print 'rusty_test: ', min(rusty_test) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bench: libauthz.so | |
python2 main.py | |
libauthz.so: rusty_authz.rs Makefile | |
rustc -C opt-level=3 -C lto rusty_authz.rs --crate-type cdylib -o libauthz.so | |
.PHONY: bench |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(libc)] | |
extern crate libc; | |
use std::slice; | |
use std::ffi::CStr; | |
use std::str; | |
use libc::{size_t, c_char}; | |
use std::collections::HashSet; | |
#[derive(Debug)] | |
struct Permission<'a> { | |
domain: &'a str, | |
actions: HashSet<&'a str>, | |
targets: HashSet<&'a str> | |
} | |
impl<'a> Permission<'a> { | |
fn new(wildcard_perm: &str) -> Permission { | |
let mut perm = Permission { | |
domain: "", | |
actions: HashSet::new(), | |
targets: HashSet::new()}; | |
perm.init_parts(wildcard_perm); | |
perm | |
} | |
fn split_string_by_comma(str: &str) -> HashSet<&str> { | |
str.split(',').map(str::trim).collect() | |
} | |
fn init_parts(&mut self, wildcard_perm: &'a str) { | |
let mut iter = wildcard_perm.split(':').map(str::trim); | |
self.domain = match iter.next() { | |
Some(s) => s, | |
None => "*" | |
}; | |
if let Some(s) = iter.next() { | |
self.actions = Permission::split_string_by_comma(s); | |
} | |
if let Some(s) = iter.next() { | |
self.targets = Permission::split_string_by_comma(s); | |
} | |
} | |
fn implies_from_perm(&self, permission: &Permission) -> bool { | |
if self.domain != permission.domain || self.domain == "*" { | |
return false; | |
} | |
if !&self.actions.is_superset(&permission.actions) || self.actions.contains("*"){ | |
return false; | |
} | |
self.targets.is_superset(&permission.targets) || self.targets.contains("*") | |
} | |
fn implies_from_str(&self, wildcard_permission: &str) -> bool { | |
let permission = Permission::new(wildcard_permission); | |
self.implies_from_perm(&permission) | |
} | |
} | |
#[no_mangle] | |
pub extern fn is_permitted_from_str(required_perm: *const c_char, assigned_perms: *const *const c_char, assigned_perms_len: size_t) -> bool{ | |
let perms = unsafe {slice::from_raw_parts(assigned_perms, assigned_perms_len as usize)}; | |
let required_permission = unsafe {CStr::from_ptr(required_perm).to_str().unwrap()}; | |
let assigned_permissions = perms.iter() | |
.map(|&p| unsafe { CStr::from_ptr(p) }) // iterator of &CStr | |
.map(|cs| cs.to_bytes()) // iterator of &[u8] | |
.map(|bs| str::from_utf8(bs).unwrap()); // iterator of &str | |
_is_permitted_from_str(required_permission, assigned_permissions) | |
} | |
#[inline] | |
fn _is_permitted_from_str<'a, I>(required_perm: &str, assigned_perms: I) -> bool | |
where I: IntoIterator<Item=&'a str> | |
{ | |
let required_permission = Permission::new(&required_perm); | |
// see: http://hermanradtke.com/2015/06/22/effectively-using-iterators-in-rust.html | |
for assigned in assigned_perms { | |
let assigned_permission = Permission::new(&assigned); | |
if assigned_permission.implies_from_perm(&required_permission){ | |
return true; | |
} | |
} | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment