"veyron/security/flag": Methods for processing Auth flags
This CL adds methods for parsing "--acl", "--acl_file" flags
and constructing an Authorizer from them.
Change-Id: I36fba5954bddf99b8348cbf5c26507952ed0eeeb
diff --git a/security/flag/flag.go b/security/flag/flag.go
new file mode 100644
index 0000000..fa032b8
--- /dev/null
+++ b/security/flag/flag.go
@@ -0,0 +1,37 @@
+// Package flag defines a method for parsing ACL flags and constructing
+// a security.Authorizer based on them.
+package flag
+
+import (
+ "bytes"
+ "errors"
+ "flag"
+
+ "veyron2/security"
+)
+
+var (
+ acl = flag.String("acl", "", "acl is an optional JSON-encoded security.ACL that is used to construct a security.Authorizer. Example: \"{\"veyron/alice\":\"RW\"}\" is a JSON-encoded ACL that allows all principals matching \"veyron/alice\" to access all methods with ReadLabel or WriteLabel. If this flag is provided then the \"--acl_file\" must be absent.")
+ aclFile = flag.String("acl_file", "", "acl_file is an optional path to a file containing a JSON-encoded security.ACL that is used to construct a security.Authorizer. If this flag is provided then the \"--acl_file\" flag must be absent.")
+)
+
+// NewAuthorizerOrDie constructs an Authorizer based on the provided "--acl" or
+// "--acl_file" flags. If both flags are provided the function panics, and if
+// neither flag is provided a nil Authorizer is returned (Note that services with
+// nil Authorizers are provided with default authorization by the framework.)
+func NewAuthorizerOrDie() security.Authorizer {
+ if len(*acl) == 0 && len(*aclFile) == 0 {
+ return nil
+ }
+ if len(*acl) != 0 && len(*aclFile) != 0 {
+ panic(errors.New("only one of the flags \"--acl\" or \"--acl_file\" must be provided"))
+ }
+ if len(*aclFile) != 0 {
+ return security.NewFileACLAuthorizer(*aclFile)
+ }
+ a, err := security.LoadACL(bytes.NewBufferString(*acl))
+ if err != nil {
+ return nil
+ }
+ return security.NewACLAuthorizer(a)
+}
diff --git a/security/flag/flag_test.go b/security/flag/flag_test.go
new file mode 100644
index 0000000..56640e0
--- /dev/null
+++ b/security/flag/flag_test.go
@@ -0,0 +1,74 @@
+package flag
+
+import (
+ "flag"
+ "os"
+ "reflect"
+ "testing"
+
+ "veyron/lib/testutil"
+
+ "veyron2/security"
+)
+
+func TestNewAuthorizerOrDie(t *testing.T) {
+ type flagValue map[string]string
+ testNewAuthorizerOrDie := func(flags flagValue, wantAuth security.Authorizer, wantPanic bool) {
+ defer func() {
+ if gotPanic := (recover() != nil); wantPanic != gotPanic {
+ t.Errorf("AuthorizerFromFlags() with flags %v, got panic: %v, want panic: %v ", flags, gotPanic, wantPanic)
+ }
+ }()
+ if got := NewAuthorizerOrDie(); !reflect.DeepEqual(got, wantAuth) {
+ t.Errorf("AuthorizerFromFlags() with flags %v: got Authorizer: %v, want: %v", flags, got, wantAuth)
+ }
+ }
+ clearACLFlags := func() {
+ flag.Set("acl", "")
+ flag.Set("acl_file", "")
+ }
+ var (
+ acl1 = security.ACL{}
+ acl2 = security.ACL{"veyron/alice": security.LabelSet(security.ReadLabel | security.WriteLabel), "veyron/bob": security.LabelSet(security.ReadLabel)}
+ )
+ acl2File := testutil.SaveACLToFile(acl2)
+ defer os.Remove(acl2File)
+
+ testdata := []struct {
+ flags flagValue
+ wantAuth security.Authorizer
+ wantPanic bool
+ }{
+ {
+ flags: flagValue{},
+ wantAuth: nil,
+ },
+ {
+ flags: flagValue{"acl": "{}"},
+ wantAuth: security.NewACLAuthorizer(acl1),
+ },
+ {
+ flags: flagValue{"acl": "{\"veyron/alice\":\"RW\", \"veyron/bob\": \"R\"}"},
+ wantAuth: security.NewACLAuthorizer(acl2),
+ },
+ {
+ flags: flagValue{"acl": "{\"veyron/bob\":\"R\", \"veyron/alice\": \"WR\"}"},
+ wantAuth: security.NewACLAuthorizer(acl2),
+ },
+ {
+ flags: flagValue{"acl_file": acl2File},
+ wantAuth: security.NewFileACLAuthorizer(acl2File),
+ },
+ {
+ flags: flagValue{"acl_file": acl2File, "acl": "{\"veyron/alice\":\"RW\", \"veyron/bob\": \"R\"}"},
+ wantPanic: true,
+ },
+ }
+ for _, d := range testdata {
+ clearACLFlags()
+ for f, v := range d.flags {
+ flag.Set(f, v)
+ }
+ testNewAuthorizerOrDie(d.flags, d.wantAuth, d.wantPanic)
+ }
+}