blob: 19252f1c2209632e2e9bc4ffbd79e9ecff98392f [file] [log] [blame]
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001package ipc
2
3import (
4 "errors"
5 "fmt"
6 "io"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -07007 "net"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07008 "reflect"
9 "strings"
Bogdan Caprita27953142014-05-12 11:41:42 -070010 "sync"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070011 "testing"
12 "time"
13
Jiri Simsa519c5072014-09-17 21:37:57 -070014 "veyron.io/veyron/veyron2/ipc"
15 "veyron.io/veyron/veyron2/ipc/stream"
16 "veyron.io/veyron/veyron2/naming"
Asim Shankarcc044212014-10-15 23:25:26 -070017 "veyron.io/veyron/veyron2/options"
Jiri Simsa519c5072014-09-17 21:37:57 -070018 "veyron.io/veyron/veyron2/security"
19 "veyron.io/veyron/veyron2/vdl/vdlutil"
20 "veyron.io/veyron/veyron2/verror"
21 "veyron.io/veyron/veyron2/vlog"
22 "veyron.io/veyron/veyron2/vom"
Cosmos Nicolaouf889c732014-10-16 20:46:54 -070023
24 "veyron.io/veyron/veyron/lib/netstate"
25 "veyron.io/veyron/veyron/lib/testutil"
26 imanager "veyron.io/veyron/veyron/runtimes/google/ipc/stream/manager"
27 "veyron.io/veyron/veyron/runtimes/google/ipc/stream/sectest"
28 "veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"
29 "veyron.io/veyron/veyron/runtimes/google/ipc/version"
30 "veyron.io/veyron/veyron/runtimes/google/lib/publisher"
31 inaming "veyron.io/veyron/veyron/runtimes/google/naming"
32 tnaming "veyron.io/veyron/veyron/runtimes/google/testing/mocks/naming"
33 vsecurity "veyron.io/veyron/veyron/security"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070034)
35
36var (
Cosmos Nicolaouf889c732014-10-16 20:46:54 -070037 errMethod = verror.Abortedf("server returned an error")
38 clock = new(fakeClock)
39 listenSpec = ipc.ListenSpec{Protocol: "tcp", Address: "127.0.0.1:0"}
Jiri Simsa5293dcb2014-05-10 09:56:38 -070040)
41
Andres Erbsenb7f95f32014-07-07 12:07:56 -070042type fakeClock struct {
43 sync.Mutex
44 time int
45}
46
47func (c *fakeClock) Now() int {
48 c.Lock()
49 defer c.Unlock()
50 return c.time
51}
52
53func (c *fakeClock) Advance(steps uint) {
54 c.Lock()
55 c.time += int(steps)
56 c.Unlock()
57}
58
59type fakeTimeCaveat int
60
61func (c fakeTimeCaveat) Validate(security.Context) error {
62 now := clock.Now()
63 if now > int(c) {
64 return fmt.Errorf("fakeTimeCaveat expired: now=%d > then=%d", now, c)
65 }
66 return nil
67}
Jiri Simsa5293dcb2014-05-10 09:56:38 -070068
69type userType string
70
71type testServer struct{}
72
73func (*testServer) Closure(call ipc.ServerCall) {
74}
75
76func (*testServer) Error(call ipc.ServerCall) error {
77 return errMethod
78}
79
80func (*testServer) Echo(call ipc.ServerCall, arg string) string {
81 return fmt.Sprintf("method:%q,suffix:%q,arg:%q", call.Method(), call.Suffix(), arg)
82}
83
84func (*testServer) EchoUser(call ipc.ServerCall, arg string, u userType) (string, userType) {
85 return fmt.Sprintf("method:%q,suffix:%q,arg:%q", call.Method(), call.Suffix(), arg), u
86}
87
Asim Shankar8f05c222014-10-06 22:08:19 -070088func (*testServer) EchoBlessings(call ipc.ServerCall) (server, client string) {
89 return fmt.Sprintf("%v", call.LocalBlessings().ForContext(call)), fmt.Sprintf("%v", call.RemoteBlessings().ForContext(call))
Jiri Simsa5293dcb2014-05-10 09:56:38 -070090}
91
Asim Shankar8f05c222014-10-06 22:08:19 -070092func (*testServer) EchoGrantedBlessings(call ipc.ServerCall, arg string) (result, blessing string) {
93 return arg, fmt.Sprintf("%v", call.Blessings())
Asim Shankarb54d7642014-06-05 13:08:04 -070094}
95
Jiri Simsa5293dcb2014-05-10 09:56:38 -070096func (*testServer) EchoAndError(call ipc.ServerCall, arg string) (string, error) {
97 result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", call.Method(), call.Suffix(), arg)
98 if arg == "error" {
99 return result, errMethod
100 }
101 return result, nil
102}
103
104func (*testServer) Stream(call ipc.ServerCall, arg string) (string, error) {
105 result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", call.Method(), call.Suffix(), arg)
106 var u userType
107 var err error
108 for err = call.Recv(&u); err == nil; err = call.Recv(&u) {
109 result += " " + string(u)
110 if err := call.Send(u); err != nil {
111 return "", err
112 }
113 }
114 if err == io.EOF {
115 err = nil
116 }
117 return result, err
118}
119
120func (*testServer) Unauthorized(ipc.ServerCall) (string, error) {
121 return "UnauthorizedResult", fmt.Errorf("Unauthorized should never be called")
122}
123
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700124type dischargeServer struct{}
125
Tilak Sharmad6ade0e2014-08-20 16:28:32 -0700126func (*dischargeServer) Discharge(ctx ipc.ServerCall, cav vdlutil.Any, _ security.DischargeImpetus) (vdlutil.Any, error) {
127 c, ok := cav.(security.ThirdPartyCaveat)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700128 if !ok {
Tilak Sharmad6ade0e2014-08-20 16:28:32 -0700129 return nil, fmt.Errorf("discharger: unknown caveat(%T)", cav)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700130 }
Ankur0af4d3b2014-09-29 17:05:21 -0700131 if err := c.Dischargeable(ctx); err != nil {
132 return nil, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", c, err)
133 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700134 // Add a fakeTimeCaveat to be able to control discharge expiration via 'clock'.
135 return ctx.LocalPrincipal().MintDischarge(c, newCaveat(fakeTimeCaveat(clock.Now())))
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700136}
137
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700138type testServerAuthorizer struct{}
139
140func (testServerAuthorizer) Authorize(c security.Context) error {
141 if c.Method() != "Unauthorized" {
142 return nil
143 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700144 return fmt.Errorf("testServerAuthorizer denied access")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700145}
146
147type testServerDisp struct{ server interface{} }
148
Cosmos Nicolaou1ee5e1a2014-11-02 10:20:30 -0800149func (t testServerDisp) Lookup(suffix, method string) (interface{}, security.Authorizer, error) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700150 // If suffix is "nilAuth" we use default authorization, if it is "aclAuth" we
151 // use an ACL based authorizer, and otherwise we use the custom testServerAuthorizer.
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700152 var authorizer security.Authorizer
153 switch suffix {
154 case "discharger":
155 return ipc.ReflectInvoker(&dischargeServer{}), testServerAuthorizer{}, nil
156 case "nilAuth":
157 authorizer = nil
158 case "aclAuth":
Asim Shankar9f6db082014-08-27 16:44:03 -0700159 // Only authorize clients matching patterns "client" or "server/...".
160 authorizer = vsecurity.NewACLAuthorizer(security.ACL{In: map[security.BlessingPattern]security.LabelSet{
161 "server/...": security.LabelSet(security.AdminLabel),
162 "client": security.LabelSet(security.AdminLabel),
163 }})
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700164 default:
165 authorizer = testServerAuthorizer{}
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700166 }
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700167 return ipc.ReflectInvoker(t.server), authorizer, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700168}
169
Asim Shankar8f05c222014-10-06 22:08:19 -0700170func startServer(t *testing.T, principal security.Principal, sm stream.Manager, ns naming.Namespace, ts interface{}) (naming.Endpoint, ipc.Server) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700171 vlog.VI(1).Info("InternalNewServer")
Asim Shankar8f05c222014-10-06 22:08:19 -0700172 server, err := InternalNewServer(testContext(), sm, ns, vc.LocalPrincipal{principal})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700173 if err != nil {
174 t.Errorf("InternalNewServer failed: %v", err)
175 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700176 vlog.VI(1).Info("server.Listen")
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -0700177 ep, err := server.Listen(listenSpec)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700178 if err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700179 t.Errorf("server.Listen failed: %v", err)
180 }
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700181 vlog.VI(1).Info("server.Serve")
182 disp := testServerDisp{ts}
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800183 if err := server.ServeDispatcher("mountpoint/server", disp); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700184 t.Errorf("server.Publish failed: %v", err)
185 }
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800186 if err := server.AddName("mountpoint/discharger"); err != nil {
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700187 t.Errorf("server.Publish for discharger failed: %v", err)
188 }
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700189 return ep, server
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700190}
191
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700192func verifyMount(t *testing.T, ns naming.Namespace, name string) {
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700193 if _, err := ns.Resolve(testContext(), name); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700194 t.Errorf("%s not found in mounttable", name)
195 }
196}
197
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700198func verifyMountMissing(t *testing.T, ns naming.Namespace, name string) {
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700199 if servers, err := ns.Resolve(testContext(), name); err == nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700200 t.Errorf("%s not supposed to be found in mounttable; got %d servers instead", name, len(servers))
201 }
202}
203
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700204func stopServer(t *testing.T, server ipc.Server, ns naming.Namespace) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700205 vlog.VI(1).Info("server.Stop")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700206 n1 := "mountpoint/server"
207 n2 := "should_appear_in_mt/server"
208 verifyMount(t, ns, n1)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700209
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700210 // publish a second name
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800211 if err := server.AddName(n2); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700212 t.Errorf("server.Serve failed: %v", err)
213 }
214 verifyMount(t, ns, n2)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700215
216 if err := server.Stop(); err != nil {
217 t.Errorf("server.Stop failed: %v", err)
218 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700219
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700220 verifyMountMissing(t, ns, n1)
221 verifyMountMissing(t, ns, n2)
222
223 // Check that we can no longer serve after Stop.
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800224 err := server.AddName("name doesn't matter")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700225 if err == nil || err.Error() != "ipc: server is stopped" {
226 t.Errorf("either no error, or a wrong error was returned: %v", err)
227 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700228 vlog.VI(1).Info("server.Stop DONE")
229}
230
Bogdan Caprita27953142014-05-12 11:41:42 -0700231type bundle struct {
232 client ipc.Client
233 server ipc.Server
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700234 ep naming.Endpoint
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700235 ns naming.Namespace
Bogdan Caprita27953142014-05-12 11:41:42 -0700236 sm stream.Manager
237}
238
239func (b bundle) cleanup(t *testing.T) {
Ankura3c97652014-07-17 20:01:21 -0700240 if b.server != nil {
241 stopServer(t, b.server, b.ns)
242 }
243 if b.client != nil {
244 b.client.Close()
245 }
Bogdan Caprita27953142014-05-12 11:41:42 -0700246}
247
Asim Shankar8f05c222014-10-06 22:08:19 -0700248func createBundle(t *testing.T, client, server security.Principal, ts interface{}) (b bundle) {
Bogdan Caprita27953142014-05-12 11:41:42 -0700249 b.sm = imanager.InternalNew(naming.FixedRoutingID(0x555555555))
Matt Rosencrantz9fe60822014-09-12 10:09:53 -0700250 b.ns = tnaming.NewSimpleNamespace()
Asim Shankar8f05c222014-10-06 22:08:19 -0700251 if server != nil {
252 b.ep, b.server = startServer(t, server, b.sm, b.ns, ts)
Ankura3c97652014-07-17 20:01:21 -0700253 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700254 if client != nil {
Ankura3c97652014-07-17 20:01:21 -0700255 var err error
Asim Shankar8f05c222014-10-06 22:08:19 -0700256 if b.client, err = InternalNewClient(b.sm, b.ns, vc.LocalPrincipal{client}); err != nil {
Ankura3c97652014-07-17 20:01:21 -0700257 t.Fatalf("InternalNewClient failed: %v", err)
258 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700259 }
Bogdan Caprita27953142014-05-12 11:41:42 -0700260 return
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700261}
262
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700263func matchesErrorPattern(err error, pattern string) bool {
264 if (len(pattern) == 0) != (err == nil) {
265 return false
266 }
267 return err == nil || strings.Index(err.Error(), pattern) >= 0
268}
269
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800270func TestMultipleCallsToServeAndName(t *testing.T) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700271 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
Matt Rosencrantz9fe60822014-09-12 10:09:53 -0700272 ns := tnaming.NewSimpleNamespace()
Asim Shankar8f05c222014-10-06 22:08:19 -0700273 server, err := InternalNewServer(testContext(), sm, ns, vc.LocalPrincipal{sectest.NewPrincipal()})
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700274 if err != nil {
275 t.Errorf("InternalNewServer failed: %v", err)
276 }
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -0700277 _, err = server.Listen(listenSpec)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700278 if err != nil {
279 t.Errorf("server.Listen failed: %v", err)
280 }
281
282 disp := &testServerDisp{&testServer{}}
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800283 if err := server.ServeDispatcher("mountpoint/server", disp); err != nil {
284 t.Errorf("server.ServeDispatcher failed: %v", err)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700285 }
286
287 n1 := "mountpoint/server"
288 n2 := "should_appear_in_mt/server"
289 n3 := "should_appear_in_mt/server"
290 n4 := "should_not_appear_in_mt/server"
291
292 verifyMount(t, ns, n1)
293
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800294 if server.ServeDispatcher(n2, disp) == nil {
295 t.Errorf("server.ServeDispatcher should have failed")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700296 }
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800297
298 if err := server.Serve(n2, &testServer{}, nil); err == nil {
299 t.Errorf("server.Serve should have failed")
300 }
301
302 if err := server.AddName(n3); err != nil {
303 t.Errorf("server.AddName failed: %v", err)
304 }
305
306 if err := server.AddName(n3); err != nil {
307 t.Errorf("server.AddName failed: %v", err)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700308 }
309 verifyMount(t, ns, n2)
310 verifyMount(t, ns, n3)
311
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800312 if err := server.RemoveName(n1); err != nil {
313 t.Errorf("server.RemoveName failed: %v", err)
314 }
315 verifyMountMissing(t, ns, n1)
316
317 if err := server.RemoveName("some randome name"); err == nil {
318 t.Errorf("server.RemoveName should have failed")
319 }
320
321 if err := server.ServeDispatcher(n4, &testServerDisp{&testServer{}}); err == nil {
322 t.Errorf("server.ServeDispatcher should have failed")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700323 }
324 verifyMountMissing(t, ns, n4)
325
326 if err := server.Stop(); err != nil {
327 t.Errorf("server.Stop failed: %v", err)
328 }
329
330 verifyMountMissing(t, ns, n1)
331 verifyMountMissing(t, ns, n2)
332 verifyMountMissing(t, ns, n3)
333}
334
Asim Shankar8f05c222014-10-06 22:08:19 -0700335func TestRemoteIDCallOpt(t *testing.T) {
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700336 const (
Asim Shankar8f05c222014-10-06 22:08:19 -0700337 vcErr = "VC handshake failed"
338 nameErr = "does not match the provided pattern"
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700339 )
Asim Shankar5c576c42014-10-01 12:19:12 -0700340
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700341 var (
Asim Shankar8f05c222014-10-06 22:08:19 -0700342 pprovider, pclient, pserver = sectest.NewPrincipal("root"), sectest.NewPrincipal(), sectest.NewPrincipal()
343 bserver = bless(pprovider, pserver, "server")
344 bexpiredserver = bless(pprovider, pserver, "server", mkCaveat(security.ExpiryCaveat(time.Now().Add(-1*time.Second))))
345
346 mgr = imanager.InternalNew(naming.FixedRoutingID(0x1111111))
347 ns = tnaming.NewSimpleNamespace()
348 tests = []struct {
349 server security.Blessings // blessings presented by the server to the client.
350 pattern security.BlessingPattern // pattern on the server identity expected by the client.
351 err string
352 }{
353 // Client accepts talking to the server only if the server's identity matches the provided pattern
354 {bserver, security.AllPrincipals, ""},
355 {bserver, "root/server", ""},
356 {bserver, "root/otherserver", nameErr},
357 {bserver, "otherroot/server", nameErr},
358
359 // Client does not talk to a server that presents an expired identity.
360 {bexpiredserver, security.AllPrincipals, vcErr},
361 }
362 _, server = startServer(t, pserver, mgr, ns, &testServer{})
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700363 )
Asim Shankar8f05c222014-10-06 22:08:19 -0700364 defer stopServer(t, server, ns)
365 // Make the client and server principals trust root certificates from pprovider
366 pclient.AddToRoots(pprovider.BlessingStore().Default())
367 pserver.AddToRoots(pprovider.BlessingStore().Default())
368 // Create a blessing that the client is willing to share with server.
369 pclient.BlessingStore().Set(bless(pprovider, pclient, "client"), "root/server")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700370 for _, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -0700371 name := fmt.Sprintf("(%q@%q)", test.pattern, test.server)
372 pserver.BlessingStore().SetDefault(test.server)
373 // Recreate client in each test (so as to not re-use VCs to the server).
374 client, err := InternalNewClient(mgr, ns, vc.LocalPrincipal{pclient})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700375 if err != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700376 t.Errorf("%s: failed ot create client: %v", name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700377 continue
378 }
Ryan Brown2726b402014-11-04 17:13:27 -0800379 if call, err := client.StartCall(testContext(), fmt.Sprintf("[%s]mountpoint/server/suffix", test.pattern), "Method", nil); !matchesErrorPattern(err, test.err) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700380 t.Errorf(`%s: client.StartCall: got error "%v", want to match "%v"`, name, err, test.err)
Asim Shankar2d731a92014-09-29 17:46:38 -0700381 } else if call != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700382 blessings, proof := call.RemoteBlessings()
383 if proof == nil {
384 t.Errorf("%s: Returned nil for remote blessings", name)
385 }
386 if !test.pattern.MatchedBy(blessings...) {
387 t.Errorf("%s: %q.MatchedBy(%v) failed", name, test.pattern, blessings)
Asim Shankar2d731a92014-09-29 17:46:38 -0700388 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700389 }
390 client.Close()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700391 }
392}
393
394func TestRPC(t *testing.T) {
Tilak Sharma0c766112014-05-20 17:47:27 -0700395 testRPC(t, true)
396}
397
398// TestCloseSendOnFinish tests that Finish informs the server that no more
399// inputs will be sent by the client if CloseSend has not already done so.
400func TestRPCCloseSendOnFinish(t *testing.T) {
401 testRPC(t, false)
402}
403
404func testRPC(t *testing.T, shouldCloseSend bool) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700405 type v []interface{}
406 type testcase struct {
407 name string
408 method string
409 args v
410 streamArgs v
411 startErr error
412 results v
413 finishErr error
414 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700415 var (
416 tests = []testcase{
417 {"mountpoint/server/suffix", "Closure", nil, nil, nil, nil, nil},
418 {"mountpoint/server/suffix", "Error", nil, nil, nil, v{errMethod}, nil},
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700419
Asim Shankar8f05c222014-10-06 22:08:19 -0700420 {"mountpoint/server/suffix", "Echo", v{"foo"}, nil, nil, v{`method:"Echo",suffix:"suffix",arg:"foo"`}, nil},
421 {"mountpoint/server/suffix/abc", "Echo", v{"bar"}, nil, nil, v{`method:"Echo",suffix:"suffix/abc",arg:"bar"`}, nil},
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700422
Asim Shankar8f05c222014-10-06 22:08:19 -0700423 {"mountpoint/server/suffix", "EchoUser", v{"foo", userType("bar")}, nil, nil, v{`method:"EchoUser",suffix:"suffix",arg:"foo"`, userType("bar")}, nil},
424 {"mountpoint/server/suffix/abc", "EchoUser", v{"baz", userType("bla")}, nil, nil, v{`method:"EchoUser",suffix:"suffix/abc",arg:"baz"`, userType("bla")}, nil},
425 {"mountpoint/server/suffix", "Stream", v{"foo"}, v{userType("bar"), userType("baz")}, nil, v{`method:"Stream",suffix:"suffix",arg:"foo" bar baz`, nil}, nil},
426 {"mountpoint/server/suffix/abc", "Stream", v{"123"}, v{userType("456"), userType("789")}, nil, v{`method:"Stream",suffix:"suffix/abc",arg:"123" 456 789`, nil}, nil},
427 {"mountpoint/server/suffix", "EchoBlessings", nil, nil, nil, v{"[server]", "[client]"}, nil},
428 {"mountpoint/server/suffix", "EchoAndError", v{"bugs bunny"}, nil, nil, v{`method:"EchoAndError",suffix:"suffix",arg:"bugs bunny"`, nil}, nil},
429 {"mountpoint/server/suffix", "EchoAndError", v{"error"}, nil, nil, v{`method:"EchoAndError",suffix:"suffix",arg:"error"`, errMethod}, nil},
430 }
431 name = func(t testcase) string {
432 return fmt.Sprintf("%s.%s(%v)", t.name, t.method, t.args)
433 }
434
435 pserver = sectest.NewPrincipal("server")
436 pclient = sectest.NewPrincipal("client")
437
438 b = createBundle(t, pclient, pserver, &testServer{})
439 )
Bogdan Caprita27953142014-05-12 11:41:42 -0700440 defer b.cleanup(t)
Asim Shankar8f05c222014-10-06 22:08:19 -0700441 // The server needs to recognize the client's root certificate.
442 pserver.AddToRoots(pclient.BlessingStore().Default())
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700443 for _, test := range tests {
444 vlog.VI(1).Infof("%s client.StartCall", name(test))
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700445 call, err := b.client.StartCall(testContext(), test.name, test.method, test.args)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700446 if err != test.startErr {
447 t.Errorf(`%s client.StartCall got error "%v", want "%v"`, name(test), err, test.startErr)
448 continue
449 }
450 for _, sarg := range test.streamArgs {
451 vlog.VI(1).Infof("%s client.Send(%v)", name(test), sarg)
452 if err := call.Send(sarg); err != nil {
453 t.Errorf(`%s call.Send(%v) got unexpected error "%v"`, name(test), sarg, err)
454 }
455 var u userType
456 if err := call.Recv(&u); err != nil {
457 t.Errorf(`%s call.Recv(%v) got unexpected error "%v"`, name(test), sarg, err)
458 }
459 if !reflect.DeepEqual(u, sarg) {
460 t.Errorf("%s call.Recv got value %v, want %v", name(test), u, sarg)
461 }
462 }
Tilak Sharma0c766112014-05-20 17:47:27 -0700463 if shouldCloseSend {
464 vlog.VI(1).Infof("%s call.CloseSend", name(test))
Asim Shankar062d4222014-08-18 11:14:42 -0700465 // When the method does not involve streaming
466 // arguments, the server gets all the arguments in
467 // StartCall and then sends a response without
468 // (unnecessarily) waiting for a CloseSend message from
469 // the client. If the server responds before the
470 // CloseSend call is made at the client, the CloseSend
471 // call will fail. Thus, only check for errors on
472 // CloseSend if there are streaming arguments to begin
473 // with (i.e., only if the server is expected to wait
474 // for the CloseSend notification).
475 if err := call.CloseSend(); err != nil && len(test.streamArgs) > 0 {
Tilak Sharma0c766112014-05-20 17:47:27 -0700476 t.Errorf(`%s call.CloseSend got unexpected error "%v"`, name(test), err)
477 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700478 }
479 vlog.VI(1).Infof("%s client.Finish", name(test))
480 results := makeResultPtrs(test.results)
481 err = call.Finish(results...)
482 if err != test.finishErr {
483 t.Errorf(`%s call.Finish got error "%v", want "%v"`, name(test), err, test.finishErr)
484 }
485 checkResultPtrs(t, name(test), results, test.results)
486 }
487}
488
Ken Ashcraft2b8309a2014-09-09 10:44:43 -0700489func TestMultipleFinish(t *testing.T) {
490 type v []interface{}
Asim Shankar8f05c222014-10-06 22:08:19 -0700491 b := createBundle(t, sectest.NewPrincipal("client"), sectest.NewPrincipal("server"), &testServer{})
Ken Ashcraft2b8309a2014-09-09 10:44:43 -0700492 defer b.cleanup(t)
493 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "Echo", v{"foo"})
494 if err != nil {
495 t.Fatalf(`client.StartCall got error "%v"`, err)
496 }
497 var results string
498 err = call.Finish(&results)
499 if err != nil {
500 t.Fatalf(`call.Finish got error "%v"`, err)
501 }
502 // Calling Finish a second time should result in a useful error.
503 err = call.Finish(&results)
504 if got, want := err, verror.BadProtocolf("ipc: multiple calls to Finish not allowed"); got != want {
505 t.Fatalf(`call.Finish got error "%v", want "%v"`, got, want)
506 }
507}
508
Asim Shankar8f05c222014-10-06 22:08:19 -0700509// granter implements ipc.Granter, returning a fixed (security.Blessings, error) pair.
Asim Shankarb54d7642014-06-05 13:08:04 -0700510type granter struct {
511 ipc.CallOpt
Asim Shankar8f05c222014-10-06 22:08:19 -0700512 b security.Blessings
Asim Shankarb54d7642014-06-05 13:08:04 -0700513 err error
514}
515
Asim Shankar8f05c222014-10-06 22:08:19 -0700516func (g granter) Grant(id security.Blessings) (security.Blessings, error) { return g.b, g.err }
Asim Shankarb54d7642014-06-05 13:08:04 -0700517
Asim Shankar8f05c222014-10-06 22:08:19 -0700518func TestGranter(t *testing.T) {
519 var (
520 pclient = sectest.NewPrincipal("client")
521 pserver = sectest.NewPrincipal("server")
522 b = createBundle(t, pclient, pserver, &testServer{})
523 )
Asim Shankarb54d7642014-06-05 13:08:04 -0700524 defer b.cleanup(t)
525
526 tests := []struct {
Asim Shankar8f05c222014-10-06 22:08:19 -0700527 granter ipc.Granter
Asim Shankarb54d7642014-06-05 13:08:04 -0700528 blessing, starterr, finisherr string
529 }{
530 {blessing: "<nil>"},
Asim Shankarb18a44f2014-10-21 20:25:07 -0700531 {granter: granter{b: bless(pclient, pserver, "blessed")}, blessing: "client/blessed"},
Asim Shankarb54d7642014-06-05 13:08:04 -0700532 {granter: granter{err: errors.New("hell no")}, starterr: "hell no"},
Asim Shankar8f05c222014-10-06 22:08:19 -0700533 {granter: granter{b: pclient.BlessingStore().Default()}, finisherr: "blessing granted not bound to this server"},
Asim Shankarb54d7642014-06-05 13:08:04 -0700534 }
535 for _, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -0700536 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "EchoGrantedBlessings", []interface{}{"argument"}, test.granter)
Asim Shankarb54d7642014-06-05 13:08:04 -0700537 if !matchesErrorPattern(err, test.starterr) {
538 t.Errorf("%+v: StartCall returned error %v", test, err)
539 }
540 if err != nil {
541 continue
542 }
543 var result, blessing string
544 if err = call.Finish(&result, &blessing); !matchesErrorPattern(err, test.finisherr) {
545 t.Errorf("%+v: Finish returned error %v", test, err)
546 }
547 if err != nil {
548 continue
549 }
550 if result != "argument" || blessing != test.blessing {
551 t.Errorf("%+v: Got (%q, %q)", test, result, blessing)
552 }
553 }
554}
555
Asim Shankar8f05c222014-10-06 22:08:19 -0700556func mkThirdPartyCaveat(discharger security.PublicKey, location string, c security.Caveat) security.Caveat {
557 tpc, err := security.NewPublicKeyCaveat(discharger, location, security.ThirdPartyRequirements{}, c)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700558 if err != nil {
559 panic(err)
560 }
Asim Shankar50ff6362014-09-15 18:09:46 -0700561 return newCaveat(tpc)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700562}
563
Asim Shankara94e5072014-08-19 18:18:36 -0700564type dischargeImpetusTester struct {
565 LastDischargeImpetus security.DischargeImpetus
566}
567
568// Implements ipc.Dispatcher
Cosmos Nicolaou1ee5e1a2014-11-02 10:20:30 -0800569func (s *dischargeImpetusTester) Lookup(_, _ string) (interface{}, security.Authorizer, error) {
Asim Shankar8f05c222014-10-06 22:08:19 -0700570 return ipc.ReflectInvoker(s), testServerAuthorizer{}, nil
Asim Shankara94e5072014-08-19 18:18:36 -0700571}
572
573// Implements the discharge service: Always fails to issue a discharge, but records the impetus
574func (s *dischargeImpetusTester) Discharge(ctx ipc.ServerCall, cav vdlutil.Any, impetus security.DischargeImpetus) (vdlutil.Any, error) {
575 s.LastDischargeImpetus = impetus
576 return nil, fmt.Errorf("discharges not issued")
577}
578
Asim Shankar1fecbcc2014-09-15 00:39:13 -0700579func names2patterns(names []string) []security.BlessingPattern {
580 ret := make([]security.BlessingPattern, len(names))
581 for idx, n := range names {
582 ret[idx] = security.BlessingPattern(n)
583 }
584 return ret
585}
586
Asim Shankara94e5072014-08-19 18:18:36 -0700587func TestDischargeImpetus(t *testing.T) {
588 var (
Asim Shankar8f05c222014-10-06 22:08:19 -0700589 pserver = sectest.NewPrincipal("server")
590 pdischarger = pserver // In general, the discharger can be a separate principal. In this test, it happens to be the server.
591 sm = imanager.InternalNew(naming.FixedRoutingID(0x555555555))
592 ns = tnaming.NewSimpleNamespace()
Asim Shankara94e5072014-08-19 18:18:36 -0700593
Asim Shankar8f05c222014-10-06 22:08:19 -0700594 mkClient = func(req security.ThirdPartyRequirements) vc.LocalPrincipal {
595 pclient := sectest.NewPrincipal()
596 tpc, err := security.NewPublicKeyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", req, security.UnconstrainedUse())
Asim Shankara94e5072014-08-19 18:18:36 -0700597 if err != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700598 t.Fatalf("Failed to create ThirdPartyCaveat(%+v): %v", req, err)
Asim Shankara94e5072014-08-19 18:18:36 -0700599 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700600 cav, err := security.NewCaveat(tpc)
601 if err != nil {
602 t.Fatal(err)
603 }
604 b, err := pclient.BlessSelf("client", cav)
605 if err != nil {
606 t.Fatalf("BlessSelf failed: %v", err)
607 }
608 pclient.AddToRoots(pserver.BlessingStore().Default()) // make the client recognize the server.
609 pclient.BlessingStore().Set(b, "server")
610 return vc.LocalPrincipal{pclient}
Asim Shankara94e5072014-08-19 18:18:36 -0700611 }
612 )
Asim Shankar8f05c222014-10-06 22:08:19 -0700613 server, err := InternalNewServer(testContext(), sm, ns, vc.LocalPrincipal{pserver})
Asim Shankara94e5072014-08-19 18:18:36 -0700614 if err != nil {
615 t.Fatal(err)
616 }
617 defer server.Stop()
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -0700618 if _, err := server.Listen(listenSpec); err != nil {
Asim Shankara94e5072014-08-19 18:18:36 -0700619 t.Fatal(err)
620 }
621
622 var tester dischargeImpetusTester
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800623 if err := server.ServeDispatcher("mountpoint", &tester); err != nil {
Asim Shankara94e5072014-08-19 18:18:36 -0700624 t.Fatal(err)
625 }
626
627 tests := []struct {
628 Requirements security.ThirdPartyRequirements
629 Impetus security.DischargeImpetus
630 }{
631 { // No requirements, no impetus
632 Requirements: security.ThirdPartyRequirements{},
633 Impetus: security.DischargeImpetus{},
634 },
635 { // Require everything
636 Requirements: security.ThirdPartyRequirements{ReportServer: true, ReportMethod: true, ReportArguments: true},
Asim Shankar8f05c222014-10-06 22:08:19 -0700637 Impetus: security.DischargeImpetus{Server: []security.BlessingPattern{"server"}, Method: "Method", Arguments: []vdlutil.Any{vdlutil.Any("argument")}},
Asim Shankara94e5072014-08-19 18:18:36 -0700638 },
639 { // Require only the method name
640 Requirements: security.ThirdPartyRequirements{ReportMethod: true},
641 Impetus: security.DischargeImpetus{Method: "Method"},
642 },
643 }
644
645 for _, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -0700646 client, err := InternalNewClient(sm, ns, mkClient(test.Requirements))
Asim Shankara94e5072014-08-19 18:18:36 -0700647 if err != nil {
648 t.Fatalf("InternalNewClient(%+v) failed: %v", test.Requirements, err)
649 }
650 defer client.Close()
651 // StartCall should fetch the discharge, do not worry about finishing the RPC - do not care about that for this test.
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700652 if _, err := client.StartCall(testContext(), "mountpoint/object", "Method", []interface{}{"argument"}); err != nil {
Asim Shankara94e5072014-08-19 18:18:36 -0700653 t.Errorf("StartCall(%+v) failed: %v", test.Requirements, err)
654 continue
655 }
656 if got, want := tester.LastDischargeImpetus, test.Impetus; !reflect.DeepEqual(got, want) {
657 t.Errorf("Got [%v] want [%v] for test %+v", got, want, test.Requirements)
658 }
659 }
660}
661
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700662func TestRPCAuthorization(t *testing.T) {
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700663 var (
Asim Shankar8f05c222014-10-06 22:08:19 -0700664 // Principals
665 pclient = sectest.NewPrincipal("client")
666 pserver = sectest.NewPrincipal("server")
667 pdischarger = pserver
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700668
Asim Shankar8f05c222014-10-06 22:08:19 -0700669 now = time.Now()
670
671 // Caveats on blessings to the client: First-party caveats
672 cavOnlyEcho = mkCaveat(security.MethodCaveat("Echo"))
673 cavExpired = mkCaveat(security.ExpiryCaveat(now.Add(-1 * time.Second)))
674 // Caveats on blessings to the client: Third-party caveats
675 cavTPValid = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", mkCaveat(security.ExpiryCaveat(now.Add(24*time.Hour))))
676 cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", mkCaveat(security.ExpiryCaveat(now.Add(-1*time.Second))))
677
678 // Client blessings that will be tested.
679 bServerClientOnlyEcho = bless(pserver, pclient, "onlyecho", cavOnlyEcho)
680 bServerClientExpired = bless(pserver, pclient, "expired", cavExpired)
681 bServerClientTPValid = bless(pserver, pclient, "dischargeable_third_party_caveat", cavTPValid)
682 bServerClientTPExpired = bless(pserver, pclient, "expired_third_party_caveat", cavTPExpired)
683 bClient = pclient.BlessingStore().Default()
684 bRandom, _ = pclient.BlessSelf("random")
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700685 )
Asim Shankar8f05c222014-10-06 22:08:19 -0700686 // The server should recognize the client principal as an authority on "client/..." and "random/..." blessings.
687 pserver.AddToRoots(bClient)
688 pserver.AddToRoots(bRandom)
689 // And the client needs to recognize the server's blessing to decide which of its own blessings to share.
690 pclient.AddToRoots(pserver.BlessingStore().Default())
Asim Shankarae8d4c52014-10-08 13:03:31 -0700691 // sectest.NewPrincipal sets up a principal that shares blessings with all servers, undo that.
692 pclient.BlessingStore().Set(nil, security.AllPrincipals)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700693
694 type v []interface{}
Asim Shankar8f05c222014-10-06 22:08:19 -0700695 tests := []struct {
696 blessings security.Blessings // Blessings used by the client
697 name string // object name on which the method is invoked
698 method string
699 args v
700 results v
701 authorized bool // Whether or not the RPC should be authorized by the server.
702 }{
703 // There are three different authorization policies (security.Authorizer implementations)
704 // used by the server, depending on the suffix (see testServerDisp.Lookup):
705 // - nilAuth suffix: the default authorization policy (only delegates of or delegators of the server can call RPCs)
706 // - aclAuth suffix: the ACL only allows "server/..." or "client"
707 // - other suffixes: testServerAuthorizer allows any principal to call any method except "Unauthorized"
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700708
Asim Shankar8f05c222014-10-06 22:08:19 -0700709 // Expired blessings should fail nilAuth and aclAuth (which care about names), but should succeed on
710 // other suffixes (which allow all blessings), unless calling the Unauthorized method.
711 {bServerClientExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
712 {bServerClientExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
713 {bServerClientExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
714 {bServerClientExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
715
716 // Same for blessings that should fail to obtain a discharge for the third party caveat.
717 {bServerClientTPExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
718 {bServerClientTPExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
719 {bServerClientTPExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
720 {bServerClientTPExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
721
722 // The "server/client" blessing (with MethodCaveat("Echo")) should satisfy all authorization policies
723 // when "Echo" is called.
724 {bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
725 {bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
726 {bServerClientOnlyEcho, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
727
728 // The "server/client" blessing (with MethodCaveat("Echo")) should satisfy no authorization policy
729 // when any other method is invoked, except for the testServerAuthorizer policy (which will
730 // not recognize the blessing "server/onlyecho", but it would authorize anyone anyway).
731 {bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Closure", nil, nil, false},
732 {bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Closure", nil, nil, false},
733 {bServerClientOnlyEcho, "mountpoint/server/suffix", "Closure", nil, nil, true},
734
735 // The "client" blessing doesn't satisfy the default authorization policy, but does satisfy
736 // the ACL and the testServerAuthorizer policy.
737 {bClient, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
738 {bClient, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
739 {bClient, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
740 {bClient, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
741
742 // The "random" blessing does not satisfy either the default policy or the ACL, but does
743 // satisfy testServerAuthorizer.
744 {bRandom, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
745 {bRandom, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
746 {bRandom, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
747 {bRandom, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
748
749 // The "server/dischargeable_third_party_caveat" blessing satisfies all policies.
750 // (the discharges should be fetched).
751 {bServerClientTPValid, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
752 {bServerClientTPValid, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
753 {bServerClientTPValid, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
754 {bServerClientTPValid, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
755 }
756 b := createBundle(t, nil, pserver, &testServer{}) // we only create the server, a separate client will be created for each test.
Bogdan Caprita27953142014-05-12 11:41:42 -0700757 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700758 for _, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -0700759 name := fmt.Sprintf("%q.%s(%v) by %v", test.name, test.method, test.args, test.blessings)
760 client, err := InternalNewClient(b.sm, b.ns, vc.LocalPrincipal{pclient})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700761 if err != nil {
762 t.Fatalf("InternalNewClient failed: %v", err)
763 }
764 defer client.Close()
Asim Shankar8f05c222014-10-06 22:08:19 -0700765 pclient.BlessingStore().Set(test.blessings, "server")
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700766 call, err := client.StartCall(testContext(), test.name, test.method, test.args)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700767 if err != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700768 t.Errorf(`%s client.StartCall got unexpected error: "%v"`, name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700769 continue
770 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700771 results := makeResultPtrs(test.results)
772 err = call.Finish(results...)
Asim Shankar8f05c222014-10-06 22:08:19 -0700773 if err != nil && test.authorized {
774 t.Errorf(`%s call.Finish got error: "%v", wanted the RPC to succeed`, name, err)
775 } else if err == nil && !test.authorized {
776 t.Errorf("%s call.Finish succeeded, expected authorization failure", name)
777 } else if !test.authorized && !verror.Is(err, verror.NoAccess) {
778 t.Errorf("%s. call.Finish returned error %v(%v), wanted %v", name, verror.Convert(err).ErrorID(), err, verror.NoAccess)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700779 }
780 }
781}
782
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700783func TestDischargePurgeFromCache(t *testing.T) {
784 var (
Asim Shankar8f05c222014-10-06 22:08:19 -0700785 pserver = sectest.NewPrincipal("server")
786 pdischarger = pserver // In general, the discharger can be a separate principal. In this test, it happens to be the server.
787 pclient = sectest.NewPrincipal("client")
788 // Client is blessed with a third-party caveat. The discharger service issues discharges with a fakeTimeCaveat.
789 // This blessing is presented to "server".
790 bclient = bless(pserver, pclient, "client", mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", security.UnconstrainedUse()))
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700791 )
Asim Shankar8f05c222014-10-06 22:08:19 -0700792 // Setup the client to recognize the server's blessing and present bclient to it.
793 pclient.AddToRoots(pserver.BlessingStore().Default())
794 pclient.BlessingStore().Set(bclient, "server")
795
796 b := createBundle(t, pclient, pserver, &testServer{})
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700797 defer b.cleanup(t)
798
799 call := func() error {
Asim Shankar8f05c222014-10-06 22:08:19 -0700800 call, err := b.client.StartCall(testContext(), "mountpoint/server/aclAuth", "Echo", []interface{}{"batman"})
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700801 if err != nil {
802 return fmt.Errorf("client.StartCall failed: %v", err)
803 }
804 var got string
805 if err := call.Finish(&got); err != nil {
806 return fmt.Errorf("client.Finish failed: %v", err)
807 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700808 if want := `method:"Echo",suffix:"aclAuth",arg:"batman"`; got != want {
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700809 return fmt.Errorf("Got [%v] want [%v]", got, want)
810 }
811 return nil
812 }
813
814 // First call should succeed
815 if err := call(); err != nil {
816 t.Fatal(err)
817 }
818 // Advance virtual clock, which will invalidate the discharge
819 clock.Advance(1)
Asim Shankar8f05c222014-10-06 22:08:19 -0700820 if err, want := call(), "not authorized"; !matchesErrorPattern(err, want) {
821 t.Errorf("Got error [%v] wanted to match pattern %q", err, want)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700822 }
823 // But retrying will succeed since the discharge should be purged from cache and refreshed
824 if err := call(); err != nil {
825 t.Fatal(err)
826 }
827}
828
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700829type cancelTestServer struct {
830 started chan struct{}
831 cancelled chan struct{}
Matt Rosencrantzbae08212014-10-03 08:04:17 -0700832 t *testing.T
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700833}
834
Matt Rosencrantzbae08212014-10-03 08:04:17 -0700835func newCancelTestServer(t *testing.T) *cancelTestServer {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700836 return &cancelTestServer{
837 started: make(chan struct{}),
838 cancelled: make(chan struct{}),
Matt Rosencrantzbae08212014-10-03 08:04:17 -0700839 t: t,
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700840 }
841}
842
843func (s *cancelTestServer) CancelStreamReader(call ipc.ServerCall) error {
844 close(s.started)
Matt Rosencrantzbae08212014-10-03 08:04:17 -0700845 var b []byte
846 if err := call.Recv(&b); err != io.EOF {
847 s.t.Errorf("Got error %v, want io.EOF", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700848 }
Matt Rosencrantzbae08212014-10-03 08:04:17 -0700849 <-call.Done()
850 close(s.cancelled)
851 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700852}
853
854// CancelStreamIgnorer doesn't read from it's input stream so all it's
Matt Rosencrantz137b8d22014-08-18 09:56:15 -0700855// buffers fill. The intention is to show that call.Done() is closed
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700856// even when the stream is stalled.
857func (s *cancelTestServer) CancelStreamIgnorer(call ipc.ServerCall) error {
858 close(s.started)
Matt Rosencrantzbae08212014-10-03 08:04:17 -0700859 <-call.Done()
860 close(s.cancelled)
861 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700862}
863
Matt Rosencrantzf5afcaf2014-06-02 11:31:22 -0700864func waitForCancel(t *testing.T, ts *cancelTestServer, call ipc.Call) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700865 <-ts.started
866 call.Cancel()
867 <-ts.cancelled
868}
869
870// TestCancel tests cancellation while the server is reading from a stream.
871func TestCancel(t *testing.T) {
Matt Rosencrantzbae08212014-10-03 08:04:17 -0700872 ts := newCancelTestServer(t)
Asim Shankar8f05c222014-10-06 22:08:19 -0700873 b := createBundle(t, sectest.NewPrincipal("client"), sectest.NewPrincipal("server"), ts)
Bogdan Caprita27953142014-05-12 11:41:42 -0700874 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700875
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700876 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "CancelStreamReader", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700877 if err != nil {
878 t.Fatalf("Start call failed: %v", err)
879 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700880 waitForCancel(t, ts, call)
881}
882
883// TestCancelWithFullBuffers tests that even if the writer has filled the buffers and
884// the server is not reading that the cancel message gets through.
885func TestCancelWithFullBuffers(t *testing.T) {
Matt Rosencrantzbae08212014-10-03 08:04:17 -0700886 ts := newCancelTestServer(t)
Asim Shankar8f05c222014-10-06 22:08:19 -0700887 b := createBundle(t, sectest.NewPrincipal("client"), sectest.NewPrincipal("server"), ts)
Bogdan Caprita27953142014-05-12 11:41:42 -0700888 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700889
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700890 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "CancelStreamIgnorer", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700891 if err != nil {
892 t.Fatalf("Start call failed: %v", err)
893 }
894 // Fill up all the write buffers to ensure that cancelling works even when the stream
895 // is blocked.
896 call.Send(make([]byte, vc.MaxSharedBytes))
897 call.Send(make([]byte, vc.DefaultBytesBufferedPerFlow))
898
899 waitForCancel(t, ts, call)
900}
901
902type streamRecvInGoroutineServer struct{ c chan error }
903
904func (s *streamRecvInGoroutineServer) RecvInGoroutine(call ipc.ServerCall) error {
905 // Spawn a goroutine to read streaming data from the client.
906 go func() {
907 var i interface{}
908 for {
909 err := call.Recv(&i)
910 if err != nil {
911 s.c <- err
912 return
913 }
914 }
915 }()
916 // Imagine the server did some processing here and now that it is done,
917 // it does not care to see what else the client has to say.
918 return nil
919}
920
921func TestStreamReadTerminatedByServer(t *testing.T) {
922 s := &streamRecvInGoroutineServer{c: make(chan error, 1)}
Asim Shankar8f05c222014-10-06 22:08:19 -0700923 b := createBundle(t, sectest.NewPrincipal("client"), sectest.NewPrincipal("server"), s)
Bogdan Caprita27953142014-05-12 11:41:42 -0700924 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700925
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700926 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "RecvInGoroutine", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700927 if err != nil {
928 t.Fatalf("StartCall failed: %v", err)
929 }
930
931 c := make(chan error, 1)
932 go func() {
933 for i := 0; true; i++ {
934 if err := call.Send(i); err != nil {
935 c <- err
936 return
937 }
938 }
939 }()
940
941 // The goroutine at the server executing "Recv" should have terminated
942 // with EOF.
943 if err := <-s.c; err != io.EOF {
944 t.Errorf("Got %v at server, want io.EOF", err)
945 }
946 // The client Send should have failed since the RPC has been
947 // terminated.
948 if err := <-c; err == nil {
949 t.Errorf("Client Send should fail as the server should have closed the flow")
950 }
951}
952
953// TestConnectWithIncompatibleServers tests that clients ignore incompatible endpoints.
954func TestConnectWithIncompatibleServers(t *testing.T) {
Asim Shankar8f05c222014-10-06 22:08:19 -0700955 b := createBundle(t, sectest.NewPrincipal("client"), sectest.NewPrincipal("server"), &testServer{})
Bogdan Caprita27953142014-05-12 11:41:42 -0700956 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700957
958 // Publish some incompatible endpoints.
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700959 publisher := publisher.New(testContext(), b.ns, publishPeriod)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700960 defer publisher.WaitForStop()
961 defer publisher.Stop()
962 publisher.AddName("incompatible")
David Why Use Two When One Will Do Presotto3da1c792014-10-03 11:15:53 -0700963 publisher.AddServer("/@2@tcp@localhost:10000@@1000000@2000000@@", false)
964 publisher.AddServer("/@2@tcp@localhost:10001@@2000000@3000000@@", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700965
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700966 _, err := b.client.StartCall(testContext(), "incompatible/suffix", "Echo", []interface{}{"foo"})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700967 if !strings.Contains(err.Error(), version.NoCompatibleVersionErr.Error()) {
968 t.Errorf("Expected error %v, found: %v", version.NoCompatibleVersionErr, err)
969 }
970
971 // Now add a server with a compatible endpoint and try again.
David Why Use Two When One Will Do Presotto3da1c792014-10-03 11:15:53 -0700972 publisher.AddServer("/"+b.ep.String(), false)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700973 publisher.AddName("incompatible")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700974
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700975 call, err := b.client.StartCall(testContext(), "incompatible/suffix", "Echo", []interface{}{"foo"})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700976 if err != nil {
Asim Shankar3a8a7e22014-05-12 18:01:44 -0700977 t.Fatal(err)
978 }
979 var result string
980 if err = call.Finish(&result); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700981 t.Errorf("Unexpected error finishing call %v", err)
982 }
Asim Shankar3a8a7e22014-05-12 18:01:44 -0700983 expected := `method:"Echo",suffix:"suffix",arg:"foo"`
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700984 if result != expected {
985 t.Errorf("Wrong result returned. Got %s, wanted %s", result, expected)
986 }
987}
988
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -0700989func TestPreferredAddress(t *testing.T) {
990 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
991 defer sm.Shutdown()
Matt Rosencrantz9fe60822014-09-12 10:09:53 -0700992 ns := tnaming.NewSimpleNamespace()
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -0700993 pa := func(string, []ipc.Address) ([]ipc.Address, error) {
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -0700994 a := &net.IPAddr{}
995 a.IP = net.ParseIP("1.1.1.1")
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -0700996 return []ipc.Address{&netstate.AddrIfc{Addr: a}}, nil
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -0700997 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700998 server, err := InternalNewServer(testContext(), sm, ns, vc.LocalPrincipal{sectest.NewPrincipal("server")})
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -0700999 if err != nil {
1000 t.Errorf("InternalNewServer failed: %v", err)
1001 }
1002 defer server.Stop()
Cosmos Nicolaouf889c732014-10-16 20:46:54 -07001003 spec := listenSpec
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -07001004 spec.Address = ":0"
1005 spec.AddressChooser = pa
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -07001006 ep, err := server.Listen(spec)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001007 iep := ep.(*inaming.Endpoint)
1008 host, _, err := net.SplitHostPort(iep.Address)
1009 if err != nil {
1010 t.Errorf("unexpected error: %s", err)
1011 }
1012 if got, want := host, "1.1.1.1"; got != want {
1013 t.Errorf("got %q, want %q", got, want)
1014 }
1015 // Won't override the specified address.
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -07001016 ep, err = server.Listen(listenSpec)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001017 iep = ep.(*inaming.Endpoint)
1018 host, _, err = net.SplitHostPort(iep.Address)
1019 if err != nil {
1020 t.Errorf("unexpected error: %s", err)
1021 }
1022 if got, want := host, "127.0.0.1"; got != want {
1023 t.Errorf("got %q, want %q", got, want)
1024 }
1025}
1026
1027func TestPreferredAddressErrors(t *testing.T) {
1028 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
1029 defer sm.Shutdown()
Matt Rosencrantz9fe60822014-09-12 10:09:53 -07001030 ns := tnaming.NewSimpleNamespace()
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -07001031 paerr := func(_ string, a []ipc.Address) ([]ipc.Address, error) {
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001032 return nil, fmt.Errorf("oops")
1033 }
Asim Shankar8f05c222014-10-06 22:08:19 -07001034 server, err := InternalNewServer(testContext(), sm, ns, vc.LocalPrincipal{sectest.NewPrincipal("server")})
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001035 if err != nil {
1036 t.Errorf("InternalNewServer failed: %v", err)
1037 }
1038 defer server.Stop()
Cosmos Nicolaouf889c732014-10-16 20:46:54 -07001039 spec := listenSpec
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -07001040 spec.Address = ":0"
1041 spec.AddressChooser = paerr
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -07001042 ep, err := server.Listen(spec)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001043 iep := ep.(*inaming.Endpoint)
1044 host, _, err := net.SplitHostPort(iep.Address)
1045 if err != nil {
1046 t.Errorf("unexpected error: %s", err)
1047 }
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -07001048 ip := net.ParseIP(host)
1049 if ip == nil {
1050 t.Fatalf("failed to parse IP address: %q", host)
1051 }
1052 if !ip.IsUnspecified() {
1053 t.Errorf("IP: %q is not unspecified", ip)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001054 }
1055}
1056
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001057func TestSecurityNone(t *testing.T) {
1058 sm := imanager.InternalNew(naming.FixedRoutingID(0x66666666))
1059 defer sm.Shutdown()
1060 ns := tnaming.NewSimpleNamespace()
1061 server, err := InternalNewServer(testContext(), sm, ns, options.VCSecurityNone)
1062 if err != nil {
1063 t.Fatalf("InternalNewServer failed: %v", err)
1064 }
1065 if _, err = server.Listen(listenSpec); err != nil {
1066 t.Fatalf("server.Listen failed: %v", err)
1067 }
1068 disp := &testServerDisp{&testServer{}}
Cosmos Nicolaou92dba582014-11-05 17:24:10 -08001069 if err := server.ServeDispatcher("mp/server", disp); err != nil {
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001070 t.Fatalf("server.Serve failed: %v", err)
1071 }
1072 client, err := InternalNewClient(sm, ns, options.VCSecurityNone)
1073 if err != nil {
1074 t.Fatalf("InternalNewClient failed: %v", err)
1075 }
1076 // When using VCSecurityNone, all authorization checks should be skipped, so
1077 // unauthorized methods shoudl be callable.
1078 call, err := client.StartCall(testContext(), "mp/server", "Unauthorized", nil)
1079 if err != nil {
1080 t.Fatalf("client.StartCall failed: %v", err)
1081 }
1082 var got string
1083 var ierr error
1084 if err := call.Finish(&got, &ierr); err != nil {
1085 t.Errorf("call.Finish failed: %v", err)
1086 }
1087 if want := "UnauthorizedResult"; got != want {
1088 t.Errorf("got (%v), want (%v)", got, want)
1089 }
1090}
1091
Matt Rosencrantz321a51d2014-10-30 10:37:56 -07001092func TestCallWithNilContext(t *testing.T) {
1093 sm := imanager.InternalNew(naming.FixedRoutingID(0x66666666))
1094 defer sm.Shutdown()
1095 ns := tnaming.NewSimpleNamespace()
1096 client, err := InternalNewClient(sm, ns, options.VCSecurityNone)
1097 if err != nil {
1098 t.Fatalf("InternalNewClient failed: %v", err)
1099 }
1100 call, err := client.StartCall(nil, "foo", "bar", []interface{}{})
1101 if call != nil {
1102 t.Errorf("Expected nil interface got: %#v", call)
1103 }
1104 if !verror.Is(err, verror.BadArg) {
1105 t.Errorf("Expected a BadArg error, got: %s", err.Error())
1106 }
1107}
1108
Ryan Brown2726b402014-11-04 17:13:27 -08001109func TestSplitObjectName(t *testing.T) {
1110 cases := []struct {
1111 input, mt, server, name string
1112 }{
1113 {"[foo/bar]", "", "foo/bar", ""},
1114 {"[x/y/...]/", "x/y/...", "", "/"},
1115 {"[foo/...]//", "", "foo/...", "//"},
1116 {"[foo]//abc@@/foo", "", "foo", "//abc@@/foo"},
1117 {"[foo]a", "", "foo", "a"},
1118 {"[foo]/a", "foo", "", "/a"},
1119 {"[foo]/a/[bar]", "foo", "bar", "/a"},
1120 {"a/b", "", "", "a/b"},
1121 {"[foo]a/b", "", "foo", "a/b"},
1122 {"/a/b", "", "", "/a/b"},
1123 {"[foo]/a/b", "foo", "", "/a/b"},
1124 {"/a/[bar]b", "", "bar", "/a/b"},
1125 {"[foo]/a/[bar]b", "foo", "bar", "/a/b"},
1126 {"/a/b[foo]", "", "", "/a/b[foo]"},
1127 {"/a/b/[foo]c", "", "", "/a/b/[foo]c"},
1128 {"/[01:02::]:444", "", "", "/[01:02::]:444"},
1129 {"[foo]/[01:02::]:444", "foo", "", "/[01:02::]:444"},
1130 {"/[01:02::]:444/foo", "", "", "/[01:02::]:444/foo"},
1131 {"[a]/[01:02::]:444/foo", "a", "", "/[01:02::]:444/foo"},
1132 {"/[01:02::]:444/[b]foo", "", "b", "/[01:02::]:444/foo"},
1133 {"[c]/[01:02::]:444/[d]foo", "c", "d", "/[01:02::]:444/foo"},
1134 }
1135 for _, c := range cases {
1136 mt, server, name := splitObjectName(c.input)
1137 if string(mt) != c.mt {
1138 t.Errorf("%q: unexpected mt pattern: %q not %q", c.input, mt, c.mt)
1139 }
1140 if string(server) != c.server {
1141 t.Errorf("%q: unexpected server pattern: %q not %q", c.input, server, c.server)
1142 }
1143 if name != c.name {
1144 t.Errorf("%q: unexpected name: %q not %q", c.input, name, c.name)
1145 }
1146 }
1147}
1148
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001149func init() {
Asim Shankarc920db32014-10-16 19:18:21 -07001150 testutil.Init()
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001151 vom.Register(fakeTimeCaveat(0))
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001152}