Last active
January 18, 2017 20:31
-
-
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)
This file contains 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" | |
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) |
This file contains 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; | |
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