veyron2/security, veyron2/services/security/access: Update security.ACL to support the Access API.

- Move access.ACL to security.ACL and update services that use ACLs.
- Replace PublicID.Match(PrincipalPattern) with
  Matches(PublicID, PrincipalPattern).

Change-Id: I59b6399a30089c48d97755e96e428e692c6551e0
diff --git a/examples/bank/pbankd/main.go b/examples/bank/pbankd/main.go
index d8a6dbc..e4fa5ef 100644
--- a/examples/bank/pbankd/main.go
+++ b/examples/bank/pbankd/main.go
@@ -442,7 +442,10 @@
 	// 	bankAccountServer := bank.NewServerBankAccount(pbankd)
 
 	// 	// Setup bank and account authorizers.
-	// 	bankAuth := vsecurity.NewACLAuthorizer(security.ACL{security.AllPrincipals: security.LabelSet(security.ReadLabel | security.WriteLabel)})
+	//  bankAuth := vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+	// 		map[security.PrincipalPattern]security.LabelSet{
+	// 			security.AllPrincipals: security.LabelSet(security.ReadLabel | security.WriteLabel),
+	// 		}))
 	// 	bankAccountAuth := AccountAuthorizer(runtime.Identity().PublicID().Names()[0] + SUFFIX_REGEXP)
 
 	// 	dispatcher := newBankDispatcher(bankServer, bankAccountServer, bankAuth, bankAccountAuth)
diff --git a/examples/boxes/android/src/boxesp2p/main.go b/examples/boxes/android/src/boxesp2p/main.go
index 0cc51e6..392710b 100644
--- a/examples/boxes/android/src/boxesp2p/main.go
+++ b/examples/boxes/android/src/boxesp2p/main.go
@@ -256,7 +256,10 @@
 }
 
 func (gs *goState) registerAsPeer() {
-	auth := vsecurity.NewACLAuthorizer(security.ACL{security.AllPrincipals: security.LabelSet(security.AdminLabel)})
+	auth := vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+		map[security.PrincipalPattern]security.LabelSet{
+			security.AllPrincipals: security.LabelSet(security.AdminLabel),
+		}))
 	gs.disp.drawAuth = auth
 	gs.disp.drawServer = ipc.ReflectInvoker(boxes.NewServerDrawInterface(gs))
 	endPt, err := gs.ipc.Listen("tcp", gs.myIPAddr+drawServicePort)
diff --git a/lib/testutil/security/util_test.go b/lib/testutil/security/util_test.go
index 3aac88d..3f2a38e 100644
--- a/lib/testutil/security/util_test.go
+++ b/lib/testutil/security/util_test.go
@@ -49,9 +49,14 @@
 		t.Fatalf("rt.New failed: %v", err)
 	}
 	defer r.Cleanup()
-	acl := security.ACL{
+	acl := security.ACL{}
+	acl.In.Principals = map[security.PrincipalPattern]security.LabelSet{
+		"veyron/*":     security.LabelSet(security.ReadLabel),
 		"veyron/alice": security.LabelSet(security.ReadLabel | security.WriteLabel),
-		"veyron/bob":   security.LabelSet(security.ReadLabel),
+		"veyron/bob":   security.LabelSet(security.AdminLabel),
+	}
+	acl.NotIn.Principals = map[security.PrincipalPattern]security.LabelSet{
+		"veyron/che": security.LabelSet(security.ReadLabel),
 	}
 
 	filePath := SaveACLToFile(acl)
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index bff3c70..4efe411 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -192,7 +192,7 @@
 	for _, o := range opts {
 		switch v := o.(type) {
 		case veyron2.RemoteID:
-			if !authID.Match(security.PrincipalPattern(v)) {
+			if !security.Matches(authID, security.PrincipalPattern(v)) {
 				return nil, fmt.Errorf("server %q does not match the provided pattern %q", authID, v)
 			}
 		case ipc.Granter:
diff --git a/runtimes/google/ipc/discharges.go b/runtimes/google/ipc/discharges.go
index 8e390f5..4f2a665 100644
--- a/runtimes/google/ipc/discharges.go
+++ b/runtimes/google/ipc/discharges.go
@@ -25,7 +25,7 @@
 
 	var caveats []security.ThirdPartyCaveat
 	for _, cav := range blessing.ThirdPartyCaveats() {
-		if server.Match(cav.Service) {
+		if security.Matches(server, cav.Service) {
 			caveats = append(caveats, cav.Caveat.(security.ThirdPartyCaveat))
 		}
 	}
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 5b87cbb..a495340 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -163,10 +163,11 @@
 		authorizer = nil
 	case "aclAuth":
 		// Only authorize clients matching patterns "client" or "server/*".
-		authorizer = vsecurity.NewACLAuthorizer(security.ACL{
-			"server/*": security.LabelSet(security.AdminLabel),
-			"client":   security.LabelSet(security.AdminLabel),
-		})
+		authorizer = vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+			map[security.PrincipalPattern]security.LabelSet{
+				"server/*": security.LabelSet(security.AdminLabel),
+				"client":   security.LabelSet(security.AdminLabel),
+			}))
 	default:
 		authorizer = testServerAuthorizer{}
 	}
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 6ed86f0..84c66df 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -19,7 +19,6 @@
 	"veyron2/ipc/stream"
 	"veyron2/naming"
 	"veyron2/security"
-	"veyron2/security/wire"
 	"veyron2/verror"
 	"veyron2/vlog"
 	"veyron2/vom"
@@ -380,13 +379,13 @@
 
 func defaultACL(id security.PublicID) security.ACL {
 	if id == nil {
-		return nil
+		return security.ACL{}
 	}
-	acl := make(security.ACL)
+	in := map[security.PrincipalPattern]security.LabelSet{}
 	for _, n := range id.Names() {
-		acl[security.PrincipalPattern(n+wire.ChainSeparator+security.AllPrincipals)] = security.AllLabels
+		in[security.PrincipalPattern(n+security.ChainSeparator+security.AllPrincipals)] = security.AllLabels
 	}
-	return acl
+	return security.NewWhitelistACL(in)
 }
 
 func (fs *flowServer) serve() error {
diff --git a/runtimes/google/rt/ipc_test.go b/runtimes/google/rt/ipc_test.go
index 804e4fc..a8360a1 100644
--- a/runtimes/google/rt/ipc_test.go
+++ b/runtimes/google/rt/ipc_test.go
@@ -161,7 +161,11 @@
 			continue
 		}
 		defer stopServer(server)
-		if err := server.Serve("", ipc.SoloDispatcher(&testService{}, vsecurity.NewACLAuthorizer(security.ACL{security.AllPrincipals: security.AllLabels}))); err != nil {
+		if err := server.Serve("", ipc.SoloDispatcher(&testService{},
+			vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+				map[security.PrincipalPattern]security.LabelSet{
+					security.AllPrincipals: security.AllLabels,
+				})))); err != nil {
 			t.Errorf("error serving service: ", err)
 			continue
 		}
diff --git a/runtimes/google/security/identity_chain.go b/runtimes/google/security/identity_chain.go
index 7351b41..a16447d 100644
--- a/runtimes/google/security/identity_chain.go
+++ b/runtimes/google/security/identity_chain.go
@@ -49,15 +49,6 @@
 	return nil
 }
 
-// Match determines if the PublicID's chained name can be extended to match the
-// provided PrincipalPattern. An extension of a chained name is any name obtained
-// by joining additional strings to the name using wire.ChainSeparator. Ex: extensions
-// of the name "foo/bar" are the names "foo/bar", "foo/bar/baz", "foo/bar/baz/car", and
-// so on.
-func (id *chainPublicID) Match(pattern security.PrincipalPattern) bool {
-	return matchPrincipalPattern(id.Names(), pattern)
-}
-
 func (id *chainPublicID) PublicKey() *ecdsa.PublicKey { return id.publicKey }
 
 func (id *chainPublicID) String() string {
diff --git a/runtimes/google/security/identity_set.go b/runtimes/google/security/identity_set.go
index 1c00e00..912536e 100644
--- a/runtimes/google/security/identity_set.go
+++ b/runtimes/google/security/identity_set.go
@@ -52,15 +52,6 @@
 	return names
 }
 
-func (s *setPublicID) Match(pattern security.PrincipalPattern) bool {
-	for _, id := range *s {
-		if id.Match(pattern) {
-			return true
-		}
-	}
-	return false
-}
-
 func (s *setPublicID) PublicKey() *ecdsa.PublicKey {
 	return (*s)[0].PublicKey()
 }
diff --git a/runtimes/google/security/identity_test.go b/runtimes/google/security/identity_test.go
index 890325c..0ea92dc 100644
--- a/runtimes/google/security/identity_test.go
+++ b/runtimes/google/security/identity_test.go
@@ -137,7 +137,7 @@
 	}
 	for _, d := range testdata {
 		for _, m := range d.matchData {
-			if got := d.id.Match(m.pattern); got != m.want {
+			if got := security.Matches(d.id, m.pattern); got != m.want {
 				t.Errorf("%q.Match(%s), Got %t, want %t", d.id, m.pattern, got, m.want)
 			}
 		}
diff --git a/runtimes/google/security/jni/publicid.go b/runtimes/google/security/jni/publicid.go
index 4b0dae7..07f855c 100644
--- a/runtimes/google/security/jni/publicid.go
+++ b/runtimes/google/security/jni/publicid.go
@@ -51,13 +51,6 @@
 	return util.CallStringArrayMethodOrCatch(env, id.jPublicID, "names", nil)
 }
 
-func (id *publicID) Match(pattern security.PrincipalPattern) bool {
-	envPtr, freeFunc := util.GetEnv(id.jVM)
-	env := (*C.JNIEnv)(envPtr)
-	defer freeFunc()
-	return util.CallBooleanMethodOrCatch(env, id.jPublicID, "match", []util.Sign{util.StringSign})
-}
-
 func (id *publicID) PublicKey() *ecdsa.PublicKey {
 	envPtr, freeFunc := util.GetEnv(id.jVM)
 	env := (*C.JNIEnv)(envPtr)
diff --git a/runtimes/google/security/publicid_store.go b/runtimes/google/security/publicid_store.go
index 4ce543c..7758762 100644
--- a/runtimes/google/security/publicid_store.go
+++ b/runtimes/google/security/publicid_store.go
@@ -119,7 +119,7 @@
 	var matchingIDs []security.PublicID
 	for id, peerPatterns := range s.state.Store {
 		for _, peerPattern := range peerPatterns {
-			if peer.Match(peerPattern) {
+			if security.Matches(peer, peerPattern) {
 				matchingIDs = append(matchingIDs, id)
 				break
 			}
@@ -140,7 +140,7 @@
 	defer s.mu.RUnlock()
 	var matchingIDs []security.PublicID
 	for id, _ := range s.state.Store {
-		if id.Match(s.state.DefaultPattern) {
+		if security.Matches(id, s.state.DefaultPattern) {
 			matchingIDs = append(matchingIDs, id)
 		}
 	}
diff --git a/runtimes/google/security/util.go b/runtimes/google/security/util.go
index 6c9f1aa..b4fb38d 100644
--- a/runtimes/google/security/util.go
+++ b/runtimes/google/security/util.go
@@ -4,12 +4,10 @@
 	"bytes"
 	"errors"
 	"fmt"
-	"strings"
 
 	"veyron/runtimes/google/security/keys"
 	"veyron2/naming"
 	"veyron2/security"
-	"veyron2/security/wire"
 )
 
 var errDeriveMismatch = errors.New("public key does not match that of deriving identity")
@@ -29,49 +27,6 @@
 	}
 }
 
-// matchesPattern checks if the provided name conforms to the provided pattern.
-// This function assumes pattern to be one of the following forms:
-// - Pattern is a chained name of the form p_0/.../p_k; in this case the check
-//   succeeds iff the provided name is of the form n_0/.../n_m such that m <= k
-//   and for all i from 0 to m, p_i = n_i.
-// - Pattern is a chained name of the form p_0/.../p_k/*; in this case the check
-//   succeeds iff the provided name is of the form n_0/.../n_m such that for all i
-//   from 0 to min(m, k), p_i = n_i.
-func matchesPattern(name, pattern string) bool {
-	patternParts := strings.Split(pattern, wire.ChainSeparator)
-	patternLen := len(patternParts)
-	nameParts := strings.Split(name, wire.ChainSeparator)
-	nameLen := len(nameParts)
-
-	if patternParts[patternLen-1] != security.AllPrincipals && nameLen > patternLen {
-		return false
-	}
-
-	min := nameLen
-	if patternParts[patternLen-1] == security.AllPrincipals && nameLen > patternLen-1 {
-		min = patternLen - 1
-	}
-
-	for i := 0; i < min; i++ {
-		if patternParts[i] != nameParts[i] {
-			return false
-		}
-	}
-	return true
-}
-
-func matchPrincipalPattern(names []string, pattern security.PrincipalPattern) bool {
-	if pattern == security.AllPrincipals {
-		return true
-	}
-	for _, n := range names {
-		if matchesPattern(n, string(pattern)) {
-			return true
-		}
-	}
-	return false
-}
-
 // ContextArgs holds the arguments for creating a new security.Context for an IPC.
 type ContextArgs struct {
 	// LocalID, RemoteID are the identities at the local and remote ends of a request
diff --git a/security/acl_authorizer.go b/security/acl_authorizer.go
index 82b35d9..9d88e13 100644
--- a/security/acl_authorizer.go
+++ b/security/acl_authorizer.go
@@ -18,7 +18,6 @@
 	errACL          = errors.New("no matching ACL entry found")
 	errInvalidLabel = errors.New("label is invalid")
 	errNilID        = errors.New("identity being matched is nil")
-	errNilACL       = errors.New("ACL is nil")
 	nullACL         security.ACL
 )
 
@@ -82,13 +81,8 @@
 	if id == nil {
 		return errNilID
 	}
-	if acl == nil {
-		return errNilACL
-	}
-	for key, labels := range acl {
-		if labels.HasLabel(label) && id.Match(key) {
-			return nil
-		}
+	if acl.Matches(id, label) {
+		return nil
 	}
 	return errACL
 }
@@ -96,7 +90,7 @@
 func loadACLFromFile(filePath string) (security.ACL, error) {
 	f, err := os.Open(filePath)
 	if err != nil {
-		return nil, err
+		return nullACL, err
 	}
 	defer f.Close()
 	return security.LoadACL(f)
diff --git a/security/acl_authorizer_test.go b/security/acl_authorizer_test.go
index 6c54ca4..8e58b33 100644
--- a/security/acl_authorizer_test.go
+++ b/security/acl_authorizer_test.go
@@ -162,14 +162,19 @@
 	var (
 		veyronPrivateID = security.FakePrivateID("veyron")
 		alicePrivateID  = security.FakePrivateID("alice")
+		bobPrivateID    = security.FakePrivateID("bob")
+		chePrivateID    = security.FakePrivateID("che")
 		veyron          = veyronPrivateID.PublicID()
 		alice           = alicePrivateID.PublicID()
-		bob             = security.FakePrivateID("bob").PublicID()
+		bob             = bobPrivateID.PublicID()
+		che             = chePrivateID.PublicID()
 
 		// Blessed principals
 		veyronAlice       = bless(alice, veyronPrivateID, "alice")
 		veyronBob         = bless(bob, veyronPrivateID, "bob")
+		veyronChe         = bless(che, veyronPrivateID, "che")
 		veyronAliceFriend = bless(bob, derive(veyronAlice, alicePrivateID), "friend")
+		veyronCheFriend   = bless(che, derive(veyronChe, chePrivateID), "friend")
 	)
 	// Convenience function for combining Labels into a LabelSet.
 	LS := func(labels ...security.Label) security.LabelSet {
@@ -181,11 +186,17 @@
 	}
 
 	// ACL for testing
-	acl := security.ACL{
+	acl := security.ACL{}
+	acl.In.Principals = map[security.PrincipalPattern]security.LabelSet{
 		"*": LS(R),
 		"fake/veyron/alice/*": LS(W, R),
 		"fake/veyron/alice":   LS(A, D, M),
 		"fake/veyron/bob":     LS(D, M),
+		"fake/veyron/che/*":   LS(W, R),
+		"fake/veyron/che":     LS(W, R),
+	}
+	acl.NotIn.Principals = map[security.PrincipalPattern]security.LabelSet{
+		"fake/veyron/che/friend": LS(W),
 	}
 
 	// Authorizations for the above ACL.
@@ -193,6 +204,7 @@
 		// alice and bob have only what "*" has.
 		alice: LS(R),
 		bob:   LS(R),
+		che:   LS(R),
 		// veyron and veyronAlice have R, W, A, D, M from the "veyron/alice" and
 		// "veyron/alice/*" ACL entries.
 		veyron:      LS(R, W, A, D, M),
@@ -201,6 +213,11 @@
 		veyronBob: LS(R, D, M),
 		// veyronAliceFriend has W, R from the "veyron/alice/*" ACL entry.
 		veyronAliceFriend: LS(W, R),
+		// veyronChe has W, R from the "veyron/che" entry.
+		veyronChe: LS(W, R),
+		// veyronCheFriend has W, R from the "veyron/che/*" entry, but loses W
+		// from the blacklist entry "veyron/che/friend".
+		veyronCheFriend: LS(R),
 		// nil PublicIDs are not authorized.
 		nil: LS(),
 	}
@@ -219,7 +236,7 @@
 
 	// Modify the ACL stored in the file and verify that the authorizations appropriately
 	// change for the fileACLAuthorizer.
-	acl["fake/veyron/bob"] = LS(R, W, A, D, M)
+	acl.In.Principals["fake/veyron/bob"] = LS(R, W, A, D, M)
 	updateACLInFile(fileName, acl)
 
 	authorizations[veyronBob] = LS(R, W, A, D, M)
@@ -243,7 +260,7 @@
 }
 
 func TestNilACLAuthorizer(t *testing.T) {
-	authorizer := NewACLAuthorizer(nil)
+	authorizer := NewACLAuthorizer(nullACL)
 	testNothingPermitted(t, authorizer)
 	testSelfRPCs(t, authorizer)
 }
diff --git a/security/caveat/caveat.go b/security/caveat/caveat.go
index a0e0f11..d3da712 100644
--- a/security/caveat/caveat.go
+++ b/security/caveat/caveat.go
@@ -52,7 +52,7 @@
 // identified by the PrincipalPatterns on the caveat.
 func (c PeerIdentity) Validate(ctx security.Context) error {
 	for _, p := range c {
-		if ctx.LocalID() != nil && ctx.LocalID().Match(p) {
+		if ctx.LocalID() != nil && security.Matches(ctx.LocalID(), p) {
 			return nil
 		}
 	}
diff --git a/security/flag/flag_test.go b/security/flag/flag_test.go
index 03ae915..0f7ff63 100644
--- a/security/flag/flag_test.go
+++ b/security/flag/flag_test.go
@@ -30,7 +30,10 @@
 	}
 	var (
 		acl1 = security.ACL{}
-		acl2 = security.ACL{"veyron/alice": security.LabelSet(security.ReadLabel | security.WriteLabel), "veyron/bob": security.LabelSet(security.ReadLabel)}
+		acl2 = security.NewWhitelistACL(map[security.PrincipalPattern]security.LabelSet{
+			"veyron/alice": security.LabelSet(security.ReadLabel | security.WriteLabel),
+			"veyron/bob":   security.LabelSet(security.ReadLabel),
+		})
 	)
 	acl2File := tsecurity.SaveACLToFile(acl2)
 	defer os.Remove(acl2File)
@@ -49,11 +52,11 @@
 			wantAuth: vsecurity.NewACLAuthorizer(acl1),
 		},
 		{
-			flags:    flagValue{"acl": "{\"veyron/alice\":\"RW\", \"veyron/bob\": \"R\"}"},
+			flags:    flagValue{"acl": "{\"In\":{\"Principals\":{\"veyron/alice\":\"RW\", \"veyron/bob\": \"R\"}}}"},
 			wantAuth: vsecurity.NewACLAuthorizer(acl2),
 		},
 		{
-			flags:    flagValue{"acl": "{\"veyron/bob\":\"R\", \"veyron/alice\": \"WR\"}"},
+			flags:    flagValue{"acl": "{\"In\":{\"Principals\":{\"veyron/bob\":\"R\", \"veyron/alice\": \"WR\"}}}"},
 			wantAuth: vsecurity.NewACLAuthorizer(acl2),
 		},
 		{
@@ -61,7 +64,7 @@
 			wantAuth: vsecurity.NewFileACLAuthorizer(acl2File),
 		},
 		{
-			flags:     flagValue{"acl_file": acl2File, "acl": "{\"veyron/alice\":\"RW\", \"veyron/bob\": \"R\"}"},
+			flags:     flagValue{"acl_file": acl2File, "acl": "{\"In\":{\"Principals\":{\"veyron/alice\":\"RW\", \"veyron/bob\": \"R\"}}}"},
 			wantPanic: true,
 		},
 	}
diff --git a/services/identity/identityd/main.go b/services/identity/identityd/main.go
index 0a1d716..b3d8191 100644
--- a/services/identity/identityd/main.go
+++ b/services/identity/identityd/main.go
@@ -134,7 +134,9 @@
 	if err != nil {
 		return nil, nil, fmt.Errorf("server.Listen(%q, %q) failed: %v", "tcp", *address, err)
 	}
-	allowEveryoneACL := security.ACL{security.AllPrincipals: security.AllLabels}
+	allowEveryoneACL := security.NewWhitelistACL(map[security.PrincipalPattern]security.LabelSet{
+		security.AllPrincipals: security.AllLabels,
+	})
 	objectname := fmt.Sprintf("identity/%s/google", r.Identity().PublicID().Names()[0])
 	if err := server.Serve(objectname, ipc.SoloDispatcher(blesser.NewGoogleOAuthBlesserServer(params), vsecurity.NewACLAuthorizer(allowEveryoneACL))); err != nil {
 		return nil, nil, fmt.Errorf("failed to start Veyron service: %v", err)
diff --git a/services/mounttable/lib/testdata/test.acl b/services/mounttable/lib/testdata/test.acl
index 1a3c98c..b65c35b 100644
--- a/services/mounttable/lib/testdata/test.acl
+++ b/services/mounttable/lib/testdata/test.acl
@@ -1,5 +1,5 @@
 {
-"/": {"fake/root": "RW", "*": "R"},
-"/stuff": {"fake/root": "RW", "fake/bob": "R"},
-"/a": {"fake/root": "RW", "fake/alice": "R"}
+"/": {"In": {"Principals": {"fake/root": "RW", "*": "R"}}},
+"/stuff": {"In": {"Principals": {"fake/root": "RW", "fake/bob": "R"}}},
+"/a": {"In": {"Principals": {"fake/root": "RW", "fake/alice": "R"}}}
 }
\ No newline at end of file
diff --git a/services/security/dischargerd/main.go b/services/security/dischargerd/main.go
index 2b5524e..6afb52b 100644
--- a/services/security/dischargerd/main.go
+++ b/services/security/dischargerd/main.go
@@ -30,7 +30,10 @@
 
 func authorizer(file string) security.Authorizer {
 	if file == "" {
-		return vsecurity.NewACLAuthorizer(security.ACL{security.AllPrincipals: security.AllLabels})
+		return vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+			map[security.PrincipalPattern]security.LabelSet{
+				security.AllPrincipals: security.AllLabels,
+			}))
 	}
 	return vsecurity.NewFileACLAuthorizer(file)
 }
diff --git a/services/wsprd/identity/identity.go b/services/wsprd/identity/identity.go
index 51b8ec6..989be61 100644
--- a/services/wsprd/identity/identity.go
+++ b/services/wsprd/identity/identity.go
@@ -137,7 +137,7 @@
 	defer i.mu.Unlock()
 	result := []string{}
 	for name, id := range i.state.Accounts {
-		if id.PublicID().Match(trustedRoot) {
+		if security.Matches(id.PublicID(), trustedRoot) {
 			result = append(result, name)
 		}
 	}
diff --git a/services/wsprd/ipc/server/server.go b/services/wsprd/ipc/server/server.go
index 6f9e601..5349086 100644
--- a/services/wsprd/ipc/server/server.go
+++ b/services/wsprd/ipc/server/server.go
@@ -176,9 +176,11 @@
 	}
 
 	if s.dispatcher == nil {
-		s.dispatcher = newDispatcher(invoker, vsecurity.NewACLAuthorizer(
-			security.ACL{security.AllPrincipals: security.AllLabels},
-		))
+		s.dispatcher = newDispatcher(invoker,
+			vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
+				map[security.PrincipalPattern]security.LabelSet{
+					security.AllPrincipals: security.AllLabels,
+				})))
 	}
 
 	if s.endpoint == "" {