Created
January 21, 2017 18:38
-
-
Save Dowwie/4ee4e2b059769bc03c7ce14bc7ca4905 to your computer and use it in GitHub Desktop.
experimenting with refactoring yosai permission authorization checks using Go
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
package main | |
import ( | |
"C" | |
"fmt" | |
"strings" | |
"gopkg.in/fatih/set.v0" | |
) | |
type Permission struct { | |
domain string | |
actions *set.Set | |
targets *set.Set | |
} | |
func perm_parts(wildcard_perm string) func() (string, bool) { | |
perms := strings.Split(wildcard_perm, ":") | |
i := -1 | |
return func() (string, bool) { | |
i++ | |
if i >= len(perms) { | |
return "", false | |
} | |
return perms[i], true | |
} | |
} | |
func (p *Permission) init_parts(wildcard_perm string) { | |
next_part := perm_parts(wildcard_perm) | |
d_part, _ := next_part() | |
p.domain = strings.TrimSpace(d_part) | |
action_part := "" | |
a_part, a_check := next_part() | |
if !a_check { | |
action_part = "*" | |
} else { | |
action_part = a_part | |
} | |
p.actions = set.New() | |
for _, sub_part := range strings.Split(action_part, ",") { | |
p.actions.Add(strings.TrimSpace(sub_part)) | |
} | |
target_part := "" | |
t_part, t_check := next_part() | |
if !t_check { | |
target_part = "*" | |
} else { | |
target_part = t_part | |
} | |
p.targets = set.New() | |
for _, t_sub_part := range strings.Split(target_part, ",") { | |
p.targets.Add(strings.TrimSpace(t_sub_part)) | |
} | |
} | |
func new_permission(wildcard_perm string) *Permission { | |
p := new(Permission) | |
p.init_parts(wildcard_perm) | |
return p | |
} | |
func (self *Permission) implies_from_perm(permission *Permission) bool { | |
if self.domain != "*" { | |
if self.domain != permission.domain { return false } | |
} | |
if !self.actions.Has("*"){ | |
if !self.actions.IsSubset(permission.actions) { return false } | |
} | |
if !self.targets.Has("*"){ | |
if !self.targets.IsSubset(permission.targets) { return false } | |
} | |
return true | |
} | |
//export is_permitted_from_str | |
func is_permitted_from_str(required_perm string, assigned_perms []string) bool { | |
required_permission := new_permission(required_perm) | |
for _, assigned := range assigned_perms { | |
assigned_permission := new_permission(assigned) | |
if assigned_permission.implies_from_perm(required_permission){ | |
return true | |
} | |
} | |
return false | |
} | |
func main() { | |
p1 := new_permission("domain:action1, action2, action3:*") | |
p2 := new_permission("domain:action1") | |
p3 := new_permission("domain:action4") | |
p4 := new_permission("domain") | |
fmt.Println("p1 implies p2: ", p1.implies_from_perm(p2)) | |
fmt.Println("p1 implies p3: ", p1.implies_from_perm(p3)) | |
fmt.Println("p4 implies p3: ", p4.implies_from_perm(p3)) | |
fmt.Println("p4 implies p2: ", p4.implies_from_perm(p2)) | |
fmt.Println("p4 implies p1: ", p4.implies_from_perm(p1)) | |
fmt.Println("p1 implies p4: ", p1.implies_from_perm(p4)) | |
result := is_permitted_from_str("domain:action1:target1", []string{"domain:action2:target2", "domain:action1"}) | |
fmt.Println("result is: ", result) | |
result2 := is_permitted_from_str("domain:action3:target4", []string{"domain:action2:target2", "domain:action1"}) | |
fmt.Println("result is: ", result2) | |
} |
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
package authz | |
import "testing" | |
var authzTests = []struct { | |
required_perm string | |
assigned_perms []string | |
expected_result bool | |
}{ | |
{"domain1:action4:target4", | |
[]string {"domain1:action1","domain1:action2","domain1:action4"}, | |
true}, | |
{"domain1:action5:target4", | |
[]string {"domain1:action1","domain1:action2","domain1:action4"}, | |
false}, | |
} | |
func TestImplies(t *testing.T) { | |
for _, tt := range authzTests { | |
result := is_permitted_from_str(tt.required_perm, tt.assigned_perms) | |
if result != tt.expected_result { | |
t.Errorf("is_permitted_from_str failed") | |
} | |
} | |
} | |
func benchmarkAuthz(required string, assigned []string, b *testing.B) { | |
for n := 0; n < b.N; n++ { | |
is_permitted_from_str(required, assigned) | |
} | |
} | |
func BenchmarkAuthz1(b *testing.B) { | |
benchmarkAuthz("domain1:action4:target4", | |
[]string {"domain1:action1","domain1:action2","domain1:action4"}, | |
b) | |
} | |
var result bool | |
func BenchmarkAuthzComplete(b *testing.B) { | |
var r bool | |
for n := 0; n < b.N; n++ { | |
// always record the result of Authz to prevent | |
// the compiler eliminating the function call. | |
r = is_permitted_from_str("domain1:action4:target4", | |
[]string {"domain1:action1","domain1:action2","domain1:action4"}) | |
} | |
// always store the result to a package level variable | |
// so the compiler cannot eliminate the Benchmark itself. | |
result = r | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment