Skip to content

Instantly share code, notes, and snippets.

@Dowwie
Last active January 18, 2017 20:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Dowwie/50761d4d8bac12d94509885b66729111 to your computer and use it in GitHub Desktop.
Save Dowwie/50761d4d8bac12d94509885b66729111 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)
# 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"
def testRust():
lib = ctypes.cdll.LoadLibrary(rustLib)
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)
#![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;
static PART_DELIMETER: &'static str = ":";
static SUBPART_DELIMETER: &'static str = ",";
struct Permission {
domain: String,
actions: HashSet<String>,
targets: HashSet<String>
}
impl Permission {
fn new(wildcard_perm: &str) -> Permission {
let mut perm = Permission {
domain: String::from(""),
actions: HashSet::new(),
targets: HashSet::new()};
perm.init_parts(wildcard_perm);
perm
}
fn init_parts(&mut self, wildcard_perm: &str) {
let old_parts: Vec<String> = wildcard_perm.split(':').map(|s| s.trim().to_string()).collect();
let mut new_parts: Vec<String> = vec!["*".to_string(),"*".to_string(),"*".to_string()];
new_parts[..old_parts.len()].clone_from_slice(&old_parts);
let mut iter = new_parts.into_iter();
self.domain = iter.next().unwrap();
self.actions = iter.next().unwrap().split(',').map(|s| s.trim().to_string()).collect();
self.targets = iter.next().unwrap().split(',').map(|s| s.trim().to_string()).collect();
}
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: Vec<&str> = 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())
.collect(); // iterator of &str
_is_permitted_from_str(required_permission, &assigned_permissions)
}
#[no_mangle]
pub extern fn _is_permitted_from_str(required_perm: &str, assigned_perms: &Vec<&str>) -> bool{
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