veyron/security/acl: Implement a LabelACL and a corresponding
Authorizer.

Motivation and design discussed in:
https://docs.google.com/a/google.com/document/d/1DZUu2sGKrf-b4p9JFdIbN0ULhz9Loa8reuPNKsdMKD0/edit#

Change-Id: I181a9ad8a0311e1376cb73cac560b302eeb8bded
diff --git a/security/acl/acl.go b/security/acl/acl.go
new file mode 100644
index 0000000..3971530
--- /dev/null
+++ b/security/acl/acl.go
@@ -0,0 +1,44 @@
+package acl
+
+import (
+	"encoding/json"
+	"io"
+
+	"veyron.io/veyron/veyron2/security"
+)
+
+// Includes returns true iff the ACL grants access to a principal
+// that presents blessings.
+func (acl ACL) Includes(blessings ...string) bool {
+	blessings = pruneBlacklisted(acl.NotIn, blessings)
+	for _, pattern := range acl.In {
+		if pattern.MatchedBy(blessings...) {
+			return true
+		}
+	}
+	return false
+}
+
+// WriteTo writes the JSON-encoded representation of a TaggedACLMap to w.
+func (m TaggedACLMap) WriteTo(w io.Writer) error {
+	return json.NewEncoder(w).Encode(m)
+}
+
+// ReadTaggedACLMap reads the JSON-encoded representation of a TaggedACLMap from r.
+func ReadTaggedACLMap(r io.Reader) (m TaggedACLMap, err error) {
+	err = json.NewDecoder(r).Decode(&m)
+	return
+}
+
+func pruneBlacklisted(blacklist, blessings []string) []string {
+	if len(blacklist) == 0 {
+		return blessings
+	}
+	var filtered []string
+	for _, b := range blessings {
+		if !security.BlessingPattern(b).MatchedBy(blacklist...) {
+			filtered = append(filtered, b)
+		}
+	}
+	return filtered
+}
diff --git a/security/acl/acl.vdl b/security/acl/acl.vdl
new file mode 100644
index 0000000..51bc01c
--- /dev/null
+++ b/security/acl/acl.vdl
@@ -0,0 +1,38 @@
+// Package acl defines types and methods to represent Access Control Lists and enforce authorization policies based on them.
+package acl
+
+import "veyron.io/veyron/veyron2/security"
+
+// ACL represents an Access Control List - a set of blessings that should be
+// granted access.
+type ACL struct {
+  // In denotes the set of blessings (represented as BlessingPatterns) that
+  // should be granted access, unless blacklisted by an entry in NotIn.
+  //
+  // For example:
+  //   In: {"alice/family/..."}
+  // grants access to a principal that presents at least one of "alice",
+  // "alice/family", "alice/family/friend" etc. as a blessing.
+  In []security.BlessingPattern
+
+  // NotIn denotes the set of blessings (and their delegates) that
+  // have been explicitly blacklisted from the In set.
+  //
+  // For example:
+  //   In: {"alice/friend/..."}, NotIn: {"alice/friend/bob"}
+  // grants access to principals that present "alice", "alice/friend",
+  // "alice/friend/carol" etc. but NOT to a principal that presents
+  // "alice/friend/bob" or "alice/friend/bob/spouse" etc.
+  NotIn []string
+
+  // TODO(ashankar,ataly): At some point, introduce group identifiers here?
+}
+
+// TaggedACLMap maps string tags to access control lists specifying the
+// blessings required to invoke methods with that tag.
+//
+// These tags are meant to add a layer of interposition between set of users
+// (blessings, specifically) and the set of methods, much like "Roles" do in
+// Role Based Access Control (RBAC).
+// (http://en.wikipedia.org/wiki/Role-based_access_control)
+type TaggedACLMap map[string]ACL
diff --git a/security/acl/acl.vdl.go b/security/acl/acl.vdl.go
new file mode 100644
index 0000000..4a658de
--- /dev/null
+++ b/security/acl/acl.vdl.go
@@ -0,0 +1,40 @@
+// This file was auto-generated by the veyron vdl tool.
+// Source: acl.vdl
+
+// Package acl defines types and methods to represent Access Control Lists and enforce authorization policies based on them.
+package acl
+
+import (
+	"veyron.io/veyron/veyron2/security"
+)
+
+// ACL represents an Access Control List - a set of blessings that should be
+// granted access.
+type ACL struct {
+	// In denotes the set of blessings (represented as BlessingPatterns) that
+	// should be granted access, unless blacklisted by an entry in NotIn.
+	//
+	// For example:
+	//   In: {"alice/family/..."}
+	// grants access to a principal that presents at least one of "alice",
+	// "alice/family", "alice/family/friend" etc. as a blessing.
+	In []security.BlessingPattern
+	// NotIn denotes the set of blessings (and their delegates) that
+	// have been explicitly blacklisted from the In set.
+	//
+	// For example:
+	//   In: {"alice/friend/..."}, NotIn: {"alice/friend/bob"}
+	// grants access to principals that present "alice", "alice/friend",
+	// "alice/friend/carol" etc. but NOT to a principal that presents
+	// "alice/friend/bob" or "alice/friend/bob/spouse" etc.
+	NotIn []string
+}
+
+// TaggedACLMap maps string tags to access control lists specifying the
+// blessings required to invoke methods with that tag.
+//
+// These tags are meant to add a layer of interposition between set of users
+// (blessings, specifically) and the set of methods, much like "Roles" do in
+// Role Based Access Control (RBAC).
+// (http://en.wikipedia.org/wiki/Role-based_access_control)
+type TaggedACLMap map[string]ACL
diff --git a/security/acl/acl_test.go b/security/acl/acl_test.go
new file mode 100644
index 0000000..4187b18
--- /dev/null
+++ b/security/acl/acl_test.go
@@ -0,0 +1,86 @@
+package acl
+
+import (
+	"bytes"
+	"reflect"
+	"testing"
+
+	"veyron.io/veyron/veyron2/security"
+)
+
+func TestInclude(t *testing.T) {
+	acl := ACL{
+		In:    []security.BlessingPattern{"alice", "alice/friend/...", "bob/family/..."},
+		NotIn: []string{"alice/friend/carol", "bob/family/mallory"},
+	}
+	type V []string // shorthand
+	tests := []struct {
+		Blessings []string
+		Want      bool
+	}{
+		{nil, false}, // No blessings presented, cannot access
+		{V{}, false},
+		{V{"alice"}, true},
+		{V{"bob"}, true},
+		{V{"carol"}, false},
+		{V{"alice/colleague"}, false},
+		{V{"alice", "carol/friend"}, true}, // Presenting one blessing that grants access is sufficient
+		{V{"alice/friend/bob"}, true},
+		{V{"alice/friend/carol"}, false},        // alice/friend/carol is blacklisted
+		{V{"alice/friend/carol/family"}, false}, // alice/friend/carol is blacklisted, thus her delegates must be too.
+		{V{"alice/friend/bob", "alice/friend/carol"}, true},
+		{V{"bob/family/eve", "bob/family/mallory"}, true},
+		{V{"bob/family/mallory", "alice/friend/carol"}, false},
+	}
+	for _, test := range tests {
+		if got, want := acl.Includes(test.Blessings...), test.Want; got != want {
+			t.Errorf("Includes(%v): Got %v, want %v", test.Blessings, got, want)
+		}
+	}
+}
+
+func TestOpenACL(t *testing.T) {
+	acl := ACL{In: []security.BlessingPattern{security.AllPrincipals}}
+	if !acl.Includes() {
+		t.Errorf("OpenACL should allow principals that present no blessings")
+	}
+	if !acl.Includes("frank") {
+		t.Errorf("OpenACL should allow principals that present any blessings")
+	}
+}
+
+func TestTaggedACLMapSerialization(t *testing.T) {
+	obj := TaggedACLMap{
+		"R": ACL{
+			In:    []security.BlessingPattern{"foo/...", "bar/..."},
+			NotIn: []string{"bar/baz"},
+		},
+		"W": ACL{
+			In:    []security.BlessingPattern{"foo/...", "bar"},
+			NotIn: []string{"foo/bar", "foo/baz/boz"},
+		},
+	}
+	txt := `
+{
+	"R": {
+		"In":["foo/...","bar/..."],
+		"NotIn":["bar/baz"]
+	},
+	"W": {
+		"In":["foo/...","bar"],
+		"NotIn":["foo/bar","foo/baz/boz"]
+	}
+}
+`
+	if got, err := ReadTaggedACLMap(bytes.NewBufferString(txt)); err != nil || !reflect.DeepEqual(got, obj) {
+		t.Errorf("Got error %v, TaggedACLMap: %v, want %v", err, got, obj)
+	}
+	// And round-trip (don't compare with 'txt' because indentation/spacing might differ).
+	var buf bytes.Buffer
+	if err := obj.WriteTo(&buf); err != nil {
+		t.Fatal(err)
+	}
+	if got, err := ReadTaggedACLMap(&buf); err != nil || !reflect.DeepEqual(got, obj) {
+		t.Errorf("Got error %v, TaggedACLMap: %v, want %v", err, got, obj)
+	}
+}
diff --git a/security/acl/authorizer.go b/security/acl/authorizer.go
new file mode 100644
index 0000000..f4d60c9
--- /dev/null
+++ b/security/acl/authorizer.go
@@ -0,0 +1,150 @@
+package acl
+
+import (
+	"fmt"
+	"os"
+	"reflect"
+
+	"veyron.io/veyron/veyron2/security"
+)
+
+// TaggedACLAuthorizer implements an authorization policy where access is
+// granted if the remote end presents blessings included in the Access Control
+// Lists (ACLs) associated with the set of relevant tags.
+//
+// The set of relevant tags is the subset of tags associated with the
+// method (security.Context.MethodTags) that have the same type as tagType.
+// Currently, tagType.Kind must be reflect.String, i.e., only tags that are
+// named string types are supported.
+//
+// If multiple tags of tagType are associated with the method, then access is
+// granted if the peer presents blessings that match the ACLs of each one of
+// those tags. If no tags of tagType are associated with the method, then
+// access is denied.
+//
+// If the TaggedACLMap provided is nil, then a nil authorizer is returned.
+//
+// Sample usage:
+//
+// (1) Attach tags to methods in the VDL (eg. myservice.vdl)
+//   package myservice
+//
+//   type MyTag string
+//   const (
+//     ReadAccess  = MyTag("R")
+//     WriteAccess = MyTag("W")
+//   )
+//
+//   type MyService interface {
+//     Get() ([]string, error)       {ReadAccess}
+//     GetIndex(int) (string, error) {ReadAccess}
+//
+//     Set([]string) error           {WriteAccess}
+//     SetIndex(int, string) error   {WriteAccess}
+//
+//     GetAndSet([]string) ([]string, error) {ReadAccess, WriteAccess}
+//   }
+//
+// (2) Setup the ipc.Dispatcher to use the TaggedACLAuthorizer
+//   import (
+//     "reflect"
+//     "veyron.io/veyron/veyron/security/acl"
+//
+//     "veyron.io/veyron/veyron2/ipc"
+//     "veyron.io/veyron/veyron2/security"
+//   )
+//
+//   type dispatcher struct{}
+//   func (d dispatcher) Lookup(suffix, method) (ipc.Invoker, security.Authorizer, error) {
+//      acl := acl.TaggedACLMap{
+//        "R": acl.ACL{In: []security.BlessingPattern{"alice/friends/...", "alice/family/..."} },
+//        "W": acl.ACL{In: []security.BlessingPattern{"alice/family/...", "alice/colleagues/..." } },
+//      }
+//      typ := reflect.TypeOf(ReadAccess)  // equivalently, reflect.TypeOf(WriteAccess)
+//      return newInvoker(), acl.TaggedACLAuthorizer(acl, typ), nil
+//   }
+//
+// With the above dispatcher, the server will grant access to a peer with the blessing
+// "alice/friend/bob" access only to the "Get" and "GetIndex" methods. A peer presenting
+// the blessing "alice/colleague/carol" will get access only to the "Set" and "SetIndex"
+// methods. A peer presenting "alice/family/mom" will get access to all methods, even
+// GetAndSet - which requires that the blessing appear in the ACLs for both the
+// ReadAccess and WriteAccess tags.
+func TaggedACLAuthorizer(acls TaggedACLMap, tagType reflect.Type) (security.Authorizer, error) {
+	if tagType.Kind() != reflect.String {
+		return nil, fmt.Errorf("tag type(%v) must be backed by a string not %v", tagType, tagType.Kind())
+	}
+	return &authorizer{acls, tagType}, nil
+}
+
+// TaggedACLAuthorizerFromFile applies the same authorization policy as
+// TaggedACLAuthorizer, with the TaggedACLMap to be used sourced from a file named
+// filename.
+//
+// Changes to the file are monitored and affect subsequent calls to Authorize.
+// Currently, this is achieved by re-reading the file on every call to
+// Authorize.
+// TODO(ashankar,ataly): Use inotify or a similar mechanism to watch for
+// changes.
+func TaggedACLAuthorizerFromFile(filename string, tagType reflect.Type) (security.Authorizer, error) {
+	if tagType.Kind() != reflect.String {
+		return nil, fmt.Errorf("tag type(%v) must be backed by a string not %v", tagType, tagType.Kind())
+	}
+	return &fileAuthorizer{filename, tagType}, nil
+}
+
+type authorizer struct {
+	acls    TaggedACLMap
+	tagType reflect.Type
+}
+
+func (a *authorizer) Authorize(ctx security.Context) error {
+	// "Self-RPCs" are always authorized.
+	if l, r := ctx.LocalBlessings(), ctx.RemoteBlessings(); l != nil && r != nil && reflect.DeepEqual(l.PublicKey(), r.PublicKey()) {
+		return nil
+	}
+	var blessings []string
+	if ctx.RemoteBlessings() != nil {
+		blessings = ctx.RemoteBlessings().ForContext(ctx)
+	}
+	grant := false
+	for _, tag := range ctx.MethodTags() {
+		if v := reflect.ValueOf(tag); v.Type() == a.tagType {
+			if acl, exists := a.acls[v.String()]; !exists || !acl.Includes(blessings...) {
+				return errACLMatch(blessings)
+			}
+			grant = true
+		}
+	}
+	if grant {
+		return nil
+	}
+	return errACLMatch(blessings)
+}
+
+type fileAuthorizer struct {
+	filename string
+	tagType  reflect.Type
+}
+
+func (a *fileAuthorizer) Authorize(ctx security.Context) error {
+	acl, err := loadTaggedACLMapFromFile(a.filename)
+	if err != nil {
+		// TODO(ashankar): Information leak?
+		return fmt.Errorf("failed to read ACL from file: %v", err)
+	}
+	return (&authorizer{acl, a.tagType}).Authorize(ctx)
+}
+
+func loadTaggedACLMapFromFile(filename string) (TaggedACLMap, error) {
+	file, err := os.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+	return ReadTaggedACLMap(file)
+}
+
+func errACLMatch(blessings []string) error {
+	return fmt.Errorf("%v does not match ACL", blessings)
+}
diff --git a/security/acl/authorizer_test.go b/security/acl/authorizer_test.go
new file mode 100644
index 0000000..2832194
--- /dev/null
+++ b/security/acl/authorizer_test.go
@@ -0,0 +1,213 @@
+package acl
+
+import (
+	"io/ioutil"
+	"reflect"
+	"testing"
+	"time"
+
+	vsecurity "veyron.io/veyron/veyron/security"
+	"veyron.io/veyron/veyron/security/acl/test"
+	"veyron.io/veyron/veyron2/naming"
+	"veyron.io/veyron/veyron2/security"
+)
+
+// TestTaggedACLAuthorizer is both a test and a demonstration of the use of the
+// TaggedACLAuthorizer and interaction with interface specification in VDL.
+func TestTaggedACLAuthorizer(t *testing.T) {
+	type P []security.BlessingPattern
+	type S []string
+	// TaggedACLMap to test against.
+	acl := TaggedACLMap{
+		"R": {
+			In: P{"..."},
+		},
+		"W": {
+			In:    P{"ali/family/...", "bob/...", "che"},
+			NotIn: S{"bob/acquaintances"},
+		},
+		"X": {
+			In: P{"ali/family/boss", "superman"},
+		},
+	}
+	type testcase struct {
+		Method string
+		Client security.Blessings
+	}
+	var (
+		authorizer, _ = TaggedACLAuthorizer(acl, reflect.TypeOf(test.Read))
+		// Two principals: The "server" and the "client"
+		pserver, _ = vsecurity.NewPrincipal()
+		pclient, _ = vsecurity.NewPrincipal()
+		server, _  = pserver.BlessSelf("server")
+
+		// B generates the provided blessings for the client and ensures
+		// that the server will recognize them.
+		B = func(names ...string) security.Blessings {
+			var ret security.Blessings
+			for _, name := range names {
+				b, err := pclient.BlessSelf(name)
+				if err != nil {
+					t.Fatalf("%q: %v", name, err)
+				}
+				if err := pserver.AddToRoots(b); err != nil {
+					t.Fatalf("%q: %v", name, err)
+				}
+				if ret, err = security.UnionOfBlessings(ret, b); err != nil {
+					t.Fatal(err)
+				}
+			}
+			return ret
+		}
+
+		run = func(test testcase) error {
+			ctx := &context{
+				localP: pserver,
+				local:  server,
+				remote: test.Client,
+				method: test.Method,
+			}
+			return authorizer.Authorize(ctx)
+		}
+	)
+
+	// Test cases where access should be granted to methods with tags on
+	// them.
+	for _, test := range []testcase{
+		{"Get", nil},
+		{"Get", B("ali")},
+		{"Get", B("bob/friend", "che/enemy")},
+
+		{"Put", B("ali")},
+		{"Put", B("ali/family/mom")},
+		{"Put", B("bob/friends")},
+		{"Put", B("bob/acquantainces/carol", "che")}, // Access granted because of "che"
+
+		{"Resolve", B("ali")},
+		{"Resolve", B("ali/family/boss")},
+
+		{"AllTags", B("ali/family/boss")},
+	} {
+		if err := run(test); err != nil {
+			t.Errorf("Access denied to method %q to %v: %v", test.Method, test.Client, err)
+		}
+	}
+	// Test cases where access should be denied.
+	for _, test := range []testcase{
+		// Nobody is denied access to "Get"
+		{"Put", B("bob/acquaintances/dave", "che/friend", "dave")},
+		{"Resolve", B("ali/family/friend")},
+		// Since there are no tags on the NoTags method, it has an
+		// empty ACL.  No client will have access.
+		{"NoTags", B("ali", "ali/family/boss", "bob")},
+		// On a method with multiple tags on it, all must be satisfied.
+		{"AllTags", B("superman")},          // Only in the X ACL, not in R or W
+		{"AllTags", B("superman", "clark")}, // In X and in R, but not W
+	} {
+		if err := run(test); err == nil {
+			t.Errorf("Access to %q granted to %v", test.Method, test.Client)
+		}
+	}
+}
+
+func TestTaggedACLAuthorizerSelfRPCs(t *testing.T) {
+	var (
+		// Client and server are the same principal, though have
+		// different blessings.
+		p, _      = vsecurity.NewPrincipal()
+		client, _ = p.BlessSelf("client")
+		server, _ = p.BlessSelf("server")
+		// Authorizer with a TaggedACLMap that grants read access to
+		// anyone, write/execute access to noone.
+		typ           test.MyTag
+		authorizer, _ = TaggedACLAuthorizer(TaggedACLMap{"R": {In: []security.BlessingPattern{"nobody"}}}, reflect.TypeOf(typ))
+	)
+	for _, test := range []string{"Put", "Get", "Resolve", "NoTags", "AllTags"} {
+		if err := authorizer.Authorize(&context{localP: p, local: server, remote: client, method: test}); err != nil {
+			t.Errorf("Got error %v for method %q", err, test)
+		}
+	}
+}
+
+func TestTaggedACLAuthorizerWithNilACL(t *testing.T) {
+	var (
+		authorizer, _ = TaggedACLAuthorizer(nil, reflect.TypeOf(test.Read))
+		pserver, _    = vsecurity.NewPrincipal()
+		pclient, _    = vsecurity.NewPrincipal()
+		server, _     = pserver.BlessSelf("server")
+		client, _     = pclient.BlessSelf("client")
+	)
+	for _, test := range []string{"Put", "Get", "Resolve", "NoTags", "AllTags"} {
+		if err := authorizer.Authorize(&context{localP: pserver, local: server, remote: client, method: test}); err == nil {
+			t.Errorf("nil TaggedACLMap authorized method %q", test)
+		}
+	}
+}
+
+func TestTaggedACLAuthorizerFromFile(t *testing.T) {
+	file, err := ioutil.TempFile("", "TestTaggedACLAuthorizerFromFile")
+	if err != nil {
+		t.Fatal(err)
+	}
+	filename := file.Name()
+	file.Close()
+
+	var (
+		authorizer, _  = TaggedACLAuthorizerFromFile(filename, reflect.TypeOf(test.Read))
+		pserver, _     = vsecurity.NewPrincipal()
+		pclient, _     = vsecurity.NewPrincipal()
+		server, _      = pserver.BlessSelf("alice")
+		alicefriend, _ = pserver.Bless(pclient.PublicKey(), server, "friend/bob", security.UnconstrainedUse())
+		ctx            = &context{localP: pserver, local: server, remote: alicefriend, method: "Get"}
+	)
+	// Make pserver recognize itself as an authority on "alice/..." blessings.
+	if err := pserver.AddToRoots(server); err != nil {
+		t.Fatal(err)
+	}
+	// "alice/friend/bob" should not have access to test.Read methods like Get.
+	if err := authorizer.Authorize(ctx); err == nil {
+		t.Fatalf("Expected authorization error as %v is not on the ACL for Read operations", ctx.remote)
+	}
+	// Rewrite the file giving access
+	if err := ioutil.WriteFile(filename, []byte(`{"R": { "In":["alice/friend/..."] }}`), 0600); err != nil {
+		t.Fatal(err)
+	}
+	// Now should have access
+	if err := authorizer.Authorize(ctx); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestTagTypeMustBeString(t *testing.T) {
+	type I int
+	if auth, err := TaggedACLAuthorizer(TaggedACLMap{}, reflect.TypeOf(I(0))); err == nil || auth != nil {
+		t.Errorf("Got (%v, %v), wanted error since tag type is not a string", auth, err)
+	}
+	if auth, err := TaggedACLAuthorizerFromFile("does_not_matter", reflect.TypeOf(I(0))); err == nil || auth != nil {
+		t.Errorf("Got (%v, %v), wanted error since tag type is not a string", auth, err)
+	}
+}
+
+// context implements security.Context.
+type context struct {
+	localP        security.Principal
+	local, remote security.Blessings
+	method        string
+}
+
+func (*context) Timestamp() (t time.Time)                  { return t }
+func (c *context) Method() string                          { return c.method }
+func (*context) Name() string                              { return "" }
+func (*context) Suffix() string                            { return "" }
+func (*context) Label() (l security.Label)                 { return l }
+func (*context) Discharges() map[string]security.Discharge { return nil }
+func (c *context) LocalPrincipal() security.Principal      { return c.localP }
+func (c *context) LocalBlessings() security.Blessings      { return c.local }
+func (c *context) RemoteBlessings() security.Blessings     { return c.remote }
+func (*context) LocalEndpoint() naming.Endpoint            { return nil }
+func (*context) RemoteEndpoint() naming.Endpoint           { return nil }
+func (c *context) MethodTags() []interface{} {
+	server := &test.ServerStubMyObject{}
+	tags, _ := server.GetMethodTags(nil, c.method)
+	return tags
+}
diff --git a/security/acl/test/vdl.vdl b/security/acl/test/vdl.vdl
new file mode 100644
index 0000000..fd3a73f
--- /dev/null
+++ b/security/acl/test/vdl.vdl
@@ -0,0 +1,23 @@
+// Package test provides a VDL specification for a service used in the unittest of the acl package.
+package test
+
+// Any package can define tags (of arbitrary types) to be attached to methods.
+// This type can be used to index into a TaggedACLMap.
+type MyTag string
+
+const (
+	// For this example/unittest, there are three possible values of MyTag,
+        // each represented by a single-character string.
+	Read    = MyTag("R")
+	Write   = MyTag("W")
+	Execute = MyTag("X")
+)
+
+// MyObject demonstrates how tags are attached to methods.
+type MyObject interface {
+  Get() error     {Read}
+  Put() error     {Write}
+  Resolve() error {Execute}
+  NoTags() error  // No tags attached to this.
+  AllTags() error {Read, Write, Execute}
+}
diff --git a/security/acl/test/vdl.vdl.go b/security/acl/test/vdl.vdl.go
new file mode 100644
index 0000000..37b3dac
--- /dev/null
+++ b/security/acl/test/vdl.vdl.go
@@ -0,0 +1,301 @@
+// This file was auto-generated by the veyron vdl tool.
+// Source: vdl.vdl
+
+// Package test provides a VDL specification for a service used in the unittest of the acl package.
+package test
+
+import (
+	// The non-user imports are prefixed with "_gen_" to prevent collisions.
+	_gen_veyron2 "veyron.io/veyron/veyron2"
+	_gen_context "veyron.io/veyron/veyron2/context"
+	_gen_ipc "veyron.io/veyron/veyron2/ipc"
+	_gen_naming "veyron.io/veyron/veyron2/naming"
+	_gen_vdlutil "veyron.io/veyron/veyron2/vdl/vdlutil"
+	_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
+)
+
+// Any package can define tags (of arbitrary types) to be attached to methods.
+// This type can be used to index into a TaggedACLMap.
+type MyTag string
+
+// For this example/unittest, there are three possible values of MyTag,
+// each represented by a single-character string.
+const Read = MyTag("R")
+
+const Write = MyTag("W")
+
+const Execute = MyTag("X")
+
+// TODO(toddw): Remove this line once the new signature support is done.
+// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
+// bootstrap types are used on interfaces.
+const _ = _gen_wiretype.TypeIDInvalid
+
+// MyObject demonstrates how tags are attached to methods.
+// MyObject is the interface the client binds and uses.
+// MyObject_ExcludingUniversal is the interface without internal framework-added methods
+// to enable embedding without method collisions.  Not to be used directly by clients.
+type MyObject_ExcludingUniversal interface {
+	Get(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error)
+	Put(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error)
+	Resolve(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error)
+	NoTags(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error) // No tags attached to this.
+	AllTags(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error)
+}
+type MyObject interface {
+	_gen_ipc.UniversalServiceMethods
+	MyObject_ExcludingUniversal
+}
+
+// MyObjectService is the interface the server implements.
+type MyObjectService interface {
+	Get(context _gen_ipc.ServerContext) (err error)
+	Put(context _gen_ipc.ServerContext) (err error)
+	Resolve(context _gen_ipc.ServerContext) (err error)
+	NoTags(context _gen_ipc.ServerContext) (err error) // No tags attached to this.
+	AllTags(context _gen_ipc.ServerContext) (err error)
+}
+
+// BindMyObject returns the client stub implementing the MyObject
+// interface.
+//
+// If no _gen_ipc.Client is specified, the default _gen_ipc.Client in the
+// global Runtime is used.
+func BindMyObject(name string, opts ..._gen_ipc.BindOpt) (MyObject, error) {
+	var client _gen_ipc.Client
+	switch len(opts) {
+	case 0:
+		// Do nothing.
+	case 1:
+		if clientOpt, ok := opts[0].(_gen_ipc.Client); opts[0] == nil || ok {
+			client = clientOpt
+		} else {
+			return nil, _gen_vdlutil.ErrUnrecognizedOption
+		}
+	default:
+		return nil, _gen_vdlutil.ErrTooManyOptionsToBind
+	}
+	stub := &clientStubMyObject{defaultClient: client, name: name}
+
+	return stub, nil
+}
+
+// NewServerMyObject creates a new server stub.
+//
+// It takes a regular server implementing the MyObjectService
+// interface, and returns a new server stub.
+func NewServerMyObject(server MyObjectService) interface{} {
+	return &ServerStubMyObject{
+		service: server,
+	}
+}
+
+// clientStubMyObject implements MyObject.
+type clientStubMyObject struct {
+	defaultClient _gen_ipc.Client
+	name          string
+}
+
+func (__gen_c *clientStubMyObject) client(ctx _gen_context.T) _gen_ipc.Client {
+	if __gen_c.defaultClient != nil {
+		return __gen_c.defaultClient
+	}
+	return _gen_veyron2.RuntimeFromContext(ctx).Client()
+}
+
+func (__gen_c *clientStubMyObject) Get(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error) {
+	var call _gen_ipc.Call
+	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Get", nil, opts...); err != nil {
+		return
+	}
+	if ierr := call.Finish(&err); ierr != nil {
+		err = ierr
+	}
+	return
+}
+
+func (__gen_c *clientStubMyObject) Put(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error) {
+	var call _gen_ipc.Call
+	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Put", nil, opts...); err != nil {
+		return
+	}
+	if ierr := call.Finish(&err); ierr != nil {
+		err = ierr
+	}
+	return
+}
+
+func (__gen_c *clientStubMyObject) Resolve(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error) {
+	var call _gen_ipc.Call
+	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Resolve", nil, opts...); err != nil {
+		return
+	}
+	if ierr := call.Finish(&err); ierr != nil {
+		err = ierr
+	}
+	return
+}
+
+func (__gen_c *clientStubMyObject) NoTags(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error) {
+	var call _gen_ipc.Call
+	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "NoTags", nil, opts...); err != nil {
+		return
+	}
+	if ierr := call.Finish(&err); ierr != nil {
+		err = ierr
+	}
+	return
+}
+
+func (__gen_c *clientStubMyObject) AllTags(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (err error) {
+	var call _gen_ipc.Call
+	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "AllTags", nil, opts...); err != nil {
+		return
+	}
+	if ierr := call.Finish(&err); ierr != nil {
+		err = ierr
+	}
+	return
+}
+
+func (__gen_c *clientStubMyObject) UnresolveStep(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply []string, err error) {
+	var call _gen_ipc.Call
+	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "UnresolveStep", nil, opts...); err != nil {
+		return
+	}
+	if ierr := call.Finish(&reply, &err); ierr != nil {
+		err = ierr
+	}
+	return
+}
+
+func (__gen_c *clientStubMyObject) Signature(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply _gen_ipc.ServiceSignature, err error) {
+	var call _gen_ipc.Call
+	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Signature", nil, opts...); err != nil {
+		return
+	}
+	if ierr := call.Finish(&reply, &err); ierr != nil {
+		err = ierr
+	}
+	return
+}
+
+func (__gen_c *clientStubMyObject) GetMethodTags(ctx _gen_context.T, method string, opts ..._gen_ipc.CallOpt) (reply []interface{}, err error) {
+	var call _gen_ipc.Call
+	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "GetMethodTags", []interface{}{method}, opts...); err != nil {
+		return
+	}
+	if ierr := call.Finish(&reply, &err); ierr != nil {
+		err = ierr
+	}
+	return
+}
+
+// ServerStubMyObject wraps a server that implements
+// MyObjectService and provides an object that satisfies
+// the requirements of veyron2/ipc.ReflectInvoker.
+type ServerStubMyObject struct {
+	service MyObjectService
+}
+
+func (__gen_s *ServerStubMyObject) GetMethodTags(call _gen_ipc.ServerCall, method string) ([]interface{}, error) {
+	// TODO(bprosnitz) GetMethodTags() will be replaces with Signature().
+	// Note: This exhibits some weird behavior like returning a nil error if the method isn't found.
+	// This will change when it is replaced with Signature().
+	switch method {
+	case "Get":
+		return []interface{}{MyTag("R")}, nil
+	case "Put":
+		return []interface{}{MyTag("W")}, nil
+	case "Resolve":
+		return []interface{}{MyTag("X")}, nil
+	case "NoTags":
+		return []interface{}{}, nil
+	case "AllTags":
+		return []interface{}{MyTag("R"), MyTag("W"), MyTag("X")}, nil
+	default:
+		return nil, nil
+	}
+}
+
+func (__gen_s *ServerStubMyObject) Signature(call _gen_ipc.ServerCall) (_gen_ipc.ServiceSignature, error) {
+	result := _gen_ipc.ServiceSignature{Methods: make(map[string]_gen_ipc.MethodSignature)}
+	result.Methods["AllTags"] = _gen_ipc.MethodSignature{
+		InArgs: []_gen_ipc.MethodArgument{},
+		OutArgs: []_gen_ipc.MethodArgument{
+			{Name: "", Type: 65},
+		},
+	}
+	result.Methods["Get"] = _gen_ipc.MethodSignature{
+		InArgs: []_gen_ipc.MethodArgument{},
+		OutArgs: []_gen_ipc.MethodArgument{
+			{Name: "", Type: 65},
+		},
+	}
+	result.Methods["NoTags"] = _gen_ipc.MethodSignature{
+		InArgs: []_gen_ipc.MethodArgument{},
+		OutArgs: []_gen_ipc.MethodArgument{
+			{Name: "", Type: 65},
+		},
+	}
+	result.Methods["Put"] = _gen_ipc.MethodSignature{
+		InArgs: []_gen_ipc.MethodArgument{},
+		OutArgs: []_gen_ipc.MethodArgument{
+			{Name: "", Type: 65},
+		},
+	}
+	result.Methods["Resolve"] = _gen_ipc.MethodSignature{
+		InArgs: []_gen_ipc.MethodArgument{},
+		OutArgs: []_gen_ipc.MethodArgument{
+			{Name: "", Type: 65},
+		},
+	}
+
+	result.TypeDefs = []_gen_vdlutil.Any{
+		_gen_wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}}
+
+	return result, nil
+}
+
+func (__gen_s *ServerStubMyObject) UnresolveStep(call _gen_ipc.ServerCall) (reply []string, err error) {
+	if unresolver, ok := __gen_s.service.(_gen_ipc.Unresolver); ok {
+		return unresolver.UnresolveStep(call)
+	}
+	if call.Server() == nil {
+		return
+	}
+	var published []string
+	if published, err = call.Server().Published(); err != nil || published == nil {
+		return
+	}
+	reply = make([]string, len(published))
+	for i, p := range published {
+		reply[i] = _gen_naming.Join(p, call.Name())
+	}
+	return
+}
+
+func (__gen_s *ServerStubMyObject) Get(call _gen_ipc.ServerCall) (err error) {
+	err = __gen_s.service.Get(call)
+	return
+}
+
+func (__gen_s *ServerStubMyObject) Put(call _gen_ipc.ServerCall) (err error) {
+	err = __gen_s.service.Put(call)
+	return
+}
+
+func (__gen_s *ServerStubMyObject) Resolve(call _gen_ipc.ServerCall) (err error) {
+	err = __gen_s.service.Resolve(call)
+	return
+}
+
+func (__gen_s *ServerStubMyObject) NoTags(call _gen_ipc.ServerCall) (err error) {
+	err = __gen_s.service.NoTags(call)
+	return
+}
+
+func (__gen_s *ServerStubMyObject) AllTags(call _gen_ipc.ServerCall) (err error) {
+	err = __gen_s.service.AllTags(call)
+	return
+}