blob: 572f007070ab9c25989ed533373da6bacf0ffca9 [file] [log] [blame]
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001package ipc
2
3import (
Asim Shankarf4864f42014-11-25 18:53:05 -08004 "encoding/hex"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07005 "errors"
6 "fmt"
7 "io"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -07008 "net"
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -08009 "os"
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -080010 "path/filepath"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070011 "reflect"
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -080012 "runtime"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070013 "strings"
Bogdan Caprita27953142014-05-12 11:41:42 -070014 "sync"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070015 "testing"
16 "time"
17
Jiri Simsa764efb72014-12-25 20:57:03 -080018 "v.io/core/veyron2/context"
19 "v.io/core/veyron2/ipc"
20 "v.io/core/veyron2/ipc/stream"
21 "v.io/core/veyron2/naming"
22 "v.io/core/veyron2/options"
23 "v.io/core/veyron2/security"
24 "v.io/core/veyron2/services/security/access"
25 "v.io/core/veyron2/uniqueid"
26 "v.io/core/veyron2/vdl/vdlutil"
27 verror "v.io/core/veyron2/verror2"
28 "v.io/core/veyron2/vlog"
Cosmos Nicolaouf889c732014-10-16 20:46:54 -070029
Jiri Simsa764efb72014-12-25 20:57:03 -080030 "v.io/core/veyron/lib/netstate"
31 "v.io/core/veyron/lib/stats"
32 "v.io/core/veyron/lib/testutil"
33 tsecurity "v.io/core/veyron/lib/testutil/security"
34 _ "v.io/core/veyron/runtimes/google/ipc/protocols/tcp"
35 imanager "v.io/core/veyron/runtimes/google/ipc/stream/manager"
36 "v.io/core/veyron/runtimes/google/ipc/stream/vc"
37 "v.io/core/veyron/runtimes/google/lib/publisher"
38 inaming "v.io/core/veyron/runtimes/google/naming"
39 tnaming "v.io/core/veyron/runtimes/google/testing/mocks/naming"
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -080040 truntime "v.io/core/veyron/runtimes/google/testing/mocks/runtime"
Jiri Simsa764efb72014-12-25 20:57:03 -080041 ivtrace "v.io/core/veyron/runtimes/google/vtrace"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070042)
43
44var (
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080045 errMethod = verror.Make(verror.Aborted, nil)
46 clock = new(fakeClock)
47 listenAddrs = ipc.ListenAddrs{{"tcp", "127.0.0.1:0"}}
48 listenWSAddrs = ipc.ListenAddrs{{"ws", "127.0.0.1:0"}, {"tcp", "127.0.0.1:0"}}
49 listenSpec = ipc.ListenSpec{Addrs: listenAddrs}
50 listenWSSpec = ipc.ListenSpec{Addrs: listenWSAddrs}
Jiri Simsa5293dcb2014-05-10 09:56:38 -070051)
52
Andres Erbsenb7f95f32014-07-07 12:07:56 -070053type fakeClock struct {
54 sync.Mutex
55 time int
56}
57
58func (c *fakeClock) Now() int {
59 c.Lock()
60 defer c.Unlock()
61 return c.time
62}
63
64func (c *fakeClock) Advance(steps uint) {
65 c.Lock()
66 c.time += int(steps)
67 c.Unlock()
68}
69
70type fakeTimeCaveat int
71
72func (c fakeTimeCaveat) Validate(security.Context) error {
73 now := clock.Now()
74 if now > int(c) {
75 return fmt.Errorf("fakeTimeCaveat expired: now=%d > then=%d", now, c)
76 }
77 return nil
78}
Jiri Simsa5293dcb2014-05-10 09:56:38 -070079
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -080080// We need a special way to create contexts for tests. We
81// can't create a real runtime in the runtime implementation
82// so we use a fake one that panics if used. The runtime
83// implementation should not ever use the Runtime from a context.
84func testContext() *context.T {
Matt Rosencrantz89445a42015-01-05 13:32:37 -080085 ctx, _ := context.WithTimeout(testContextWithoutDeadline(), 20*time.Second)
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -080086 return ctx
87}
88
89func testContextWithoutDeadline() *context.T {
90 ctx := context.NewUninitializedContext(&truntime.PanicRuntime{})
91 ctx, _ = ivtrace.WithNewRootSpan(ctx, nil, false)
92 return ctx
93}
94
Jiri Simsa5293dcb2014-05-10 09:56:38 -070095type userType string
96
97type testServer struct{}
98
Todd Wang1fe7cdd2014-11-12 12:51:49 -080099func (*testServer) Closure(ctx ipc.ServerContext) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700100}
101
Todd Wang1fe7cdd2014-11-12 12:51:49 -0800102func (*testServer) Error(ctx ipc.ServerContext) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700103 return errMethod
104}
105
Todd Wang1fe7cdd2014-11-12 12:51:49 -0800106func (*testServer) Echo(ctx ipc.ServerContext, arg string) string {
107 return fmt.Sprintf("method:%q,suffix:%q,arg:%q", ctx.Method(), ctx.Suffix(), arg)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700108}
109
Todd Wang1fe7cdd2014-11-12 12:51:49 -0800110func (*testServer) EchoUser(ctx ipc.ServerContext, arg string, u userType) (string, userType) {
111 return fmt.Sprintf("method:%q,suffix:%q,arg:%q", ctx.Method(), ctx.Suffix(), arg), u
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700112}
113
Todd Wang1fe7cdd2014-11-12 12:51:49 -0800114func (*testServer) EchoBlessings(ctx ipc.ServerContext) (server, client string) {
115 return fmt.Sprintf("%v", ctx.LocalBlessings().ForContext(ctx)), fmt.Sprintf("%v", ctx.RemoteBlessings().ForContext(ctx))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700116}
117
Todd Wang1fe7cdd2014-11-12 12:51:49 -0800118func (*testServer) EchoGrantedBlessings(ctx ipc.ServerContext, arg string) (result, blessing string) {
119 return arg, fmt.Sprintf("%v", ctx.Blessings())
Asim Shankarb54d7642014-06-05 13:08:04 -0700120}
121
Todd Wang1fe7cdd2014-11-12 12:51:49 -0800122func (*testServer) EchoAndError(ctx ipc.ServerContext, arg string) (string, error) {
123 result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", ctx.Method(), ctx.Suffix(), arg)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700124 if arg == "error" {
125 return result, errMethod
126 }
127 return result, nil
128}
129
130func (*testServer) Stream(call ipc.ServerCall, arg string) (string, error) {
131 result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", call.Method(), call.Suffix(), arg)
132 var u userType
133 var err error
134 for err = call.Recv(&u); err == nil; err = call.Recv(&u) {
135 result += " " + string(u)
136 if err := call.Send(u); err != nil {
137 return "", err
138 }
139 }
140 if err == io.EOF {
141 err = nil
142 }
143 return result, err
144}
145
146func (*testServer) Unauthorized(ipc.ServerCall) (string, error) {
147 return "UnauthorizedResult", fmt.Errorf("Unauthorized should never be called")
148}
149
150type testServerAuthorizer struct{}
151
152func (testServerAuthorizer) Authorize(c security.Context) error {
153 if c.Method() != "Unauthorized" {
154 return nil
155 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700156 return fmt.Errorf("testServerAuthorizer denied access")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700157}
158
159type testServerDisp struct{ server interface{} }
160
Robin Thellenda02fe8f2014-11-19 09:58:29 -0800161func (t testServerDisp) Lookup(suffix string) (interface{}, security.Authorizer, error) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700162 // If suffix is "nilAuth" we use default authorization, if it is "aclAuth" we
163 // use an ACL based authorizer, and otherwise we use the custom testServerAuthorizer.
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700164 var authorizer security.Authorizer
165 switch suffix {
166 case "discharger":
Cosmos Nicolaou710daa22014-11-11 19:39:18 -0800167 return &dischargeServer{}, testServerAuthorizer{}, nil
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700168 case "nilAuth":
169 authorizer = nil
170 case "aclAuth":
Asim Shankar9f6db082014-08-27 16:44:03 -0700171 // Only authorize clients matching patterns "client" or "server/...".
Asim Shankar68885192014-11-26 12:48:35 -0800172 authorizer = &access.ACL{
173 In: []security.BlessingPattern{"client", "server/..."},
174 }
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700175 default:
176 authorizer = testServerAuthorizer{}
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700177 }
Cosmos Nicolaou710daa22014-11-11 19:39:18 -0800178 return t.server, authorizer, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700179}
180
Ankure49a86a2014-11-11 18:52:43 -0800181type dischargeServer struct{}
182
183func (*dischargeServer) Discharge(ctx ipc.ServerCall, cav vdlutil.Any, _ security.DischargeImpetus) (vdlutil.Any, error) {
184 c, ok := cav.(security.ThirdPartyCaveat)
185 if !ok {
186 return nil, fmt.Errorf("discharger: unknown caveat(%T)", cav)
187 }
188 if err := c.Dischargeable(ctx); err != nil {
189 return nil, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", c, err)
190 }
191 // Add a fakeTimeCaveat to be able to control discharge expiration via 'clock'.
192 return ctx.LocalPrincipal().MintDischarge(c, newCaveat(fakeTimeCaveat(clock.Now())))
193}
194
195func startServer(t *testing.T, principal security.Principal, sm stream.Manager, ns naming.Namespace, name string, disp ipc.Dispatcher, opts ...ipc.ServerOpt) (naming.Endpoint, ipc.Server) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800196 return startServerWS(t, principal, sm, ns, name, disp, noWebsocket, opts...)
197}
198
199func startServerWS(t *testing.T, principal security.Principal, sm stream.Manager, ns naming.Namespace, name string, disp ipc.Dispatcher, shouldUseWebsocket websocketMode, opts ...ipc.ServerOpt) (naming.Endpoint, ipc.Server) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700200 vlog.VI(1).Info("InternalNewServer")
Ankure49a86a2014-11-11 18:52:43 -0800201 opts = append(opts, vc.LocalPrincipal{principal})
202 server, err := InternalNewServer(testContext(), sm, ns, nil, opts...)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700203 if err != nil {
204 t.Errorf("InternalNewServer failed: %v", err)
205 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700206 vlog.VI(1).Info("server.Listen")
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800207 spec := listenSpec
208 if shouldUseWebsocket {
209 spec = listenWSSpec
210 }
211 ep, err := server.Listen(spec)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700212 if err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700213 t.Errorf("server.Listen failed: %v", err)
214 }
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700215 vlog.VI(1).Info("server.Serve")
Ankure49a86a2014-11-11 18:52:43 -0800216 if err := server.ServeDispatcher(name, disp); err != nil {
217 t.Errorf("server.ServeDispatcher failed: %v", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700218 }
Ankure49a86a2014-11-11 18:52:43 -0800219 if err := server.AddName(name); err != nil {
220 t.Errorf("server.AddName for discharger failed: %v", err)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700221 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800222 return ep[0], server
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700223}
224
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -0800225func loc(d int) string {
226 _, file, line, _ := runtime.Caller(d + 1)
227 return fmt.Sprintf("%s:%d", filepath.Base(file), line)
228}
229
230func verifyMount(t *testing.T, ns naming.Namespace, name string) []string {
231 addrs, err := ns.Resolve(testContext(), name)
232 if err != nil {
233 t.Errorf("%s: %s not found in mounttable", loc(1), name)
234 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700235 }
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -0800236 return addrs
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700237}
238
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700239func verifyMountMissing(t *testing.T, ns naming.Namespace, name string) {
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700240 if servers, err := ns.Resolve(testContext(), name); err == nil {
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -0800241 t.Errorf("%s: %s not supposed to be found in mounttable; got %d servers instead", loc(1), name, len(servers))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700242 }
243}
244
Ankure49a86a2014-11-11 18:52:43 -0800245func stopServer(t *testing.T, server ipc.Server, ns naming.Namespace, name string) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700246 vlog.VI(1).Info("server.Stop")
Ankure49a86a2014-11-11 18:52:43 -0800247 new_name := "should_appear_in_mt/server"
248 verifyMount(t, ns, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700249
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700250 // publish a second name
Ankure49a86a2014-11-11 18:52:43 -0800251 if err := server.AddName(new_name); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700252 t.Errorf("server.Serve failed: %v", err)
253 }
Ankure49a86a2014-11-11 18:52:43 -0800254 verifyMount(t, ns, new_name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700255
256 if err := server.Stop(); err != nil {
257 t.Errorf("server.Stop failed: %v", err)
258 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700259
Ankure49a86a2014-11-11 18:52:43 -0800260 verifyMountMissing(t, ns, name)
261 verifyMountMissing(t, ns, new_name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700262
263 // Check that we can no longer serve after Stop.
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800264 err := server.AddName("name doesn't matter")
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800265 if err == nil || !verror.Is(err, verror.BadState.ID) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700266 t.Errorf("either no error, or a wrong error was returned: %v", err)
267 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700268 vlog.VI(1).Info("server.Stop DONE")
269}
270
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800271func resolveWSEndpoint(ns naming.Namespace, name string) (string, error) {
272 // Find the ws endpoint and use that.
273 servers, err := ns.Resolve(testContext(), name)
274 if err != nil {
275 return "", err
276 }
277 for _, s := range servers {
278 if strings.Index(s, "@ws@") != -1 {
279 return s, nil
280 }
281 }
282 return "", fmt.Errorf("No ws endpoint found %v", servers)
283}
284
Bogdan Caprita27953142014-05-12 11:41:42 -0700285type bundle struct {
286 client ipc.Client
287 server ipc.Server
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700288 ep naming.Endpoint
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700289 ns naming.Namespace
Bogdan Caprita27953142014-05-12 11:41:42 -0700290 sm stream.Manager
Ankure49a86a2014-11-11 18:52:43 -0800291 name string
Bogdan Caprita27953142014-05-12 11:41:42 -0700292}
293
294func (b bundle) cleanup(t *testing.T) {
Ankura3c97652014-07-17 20:01:21 -0700295 if b.server != nil {
Ankure49a86a2014-11-11 18:52:43 -0800296 stopServer(t, b.server, b.ns, b.name)
Ankura3c97652014-07-17 20:01:21 -0700297 }
298 if b.client != nil {
299 b.client.Close()
300 }
Bogdan Caprita27953142014-05-12 11:41:42 -0700301}
302
Asim Shankar8f05c222014-10-06 22:08:19 -0700303func createBundle(t *testing.T, client, server security.Principal, ts interface{}) (b bundle) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800304 return createBundleWS(t, client, server, ts, noWebsocket)
305}
306
307func createBundleWS(t *testing.T, client, server security.Principal, ts interface{}, shouldUseWebsocket websocketMode) (b bundle) {
Bogdan Caprita27953142014-05-12 11:41:42 -0700308 b.sm = imanager.InternalNew(naming.FixedRoutingID(0x555555555))
Matt Rosencrantz9fe60822014-09-12 10:09:53 -0700309 b.ns = tnaming.NewSimpleNamespace()
Ankure49a86a2014-11-11 18:52:43 -0800310 b.name = "mountpoint/server"
Asim Shankar8f05c222014-10-06 22:08:19 -0700311 if server != nil {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800312 b.ep, b.server = startServerWS(t, server, b.sm, b.ns, b.name, testServerDisp{ts}, shouldUseWebsocket)
Ankura3c97652014-07-17 20:01:21 -0700313 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700314 if client != nil {
Ankura3c97652014-07-17 20:01:21 -0700315 var err error
Asim Shankar8f05c222014-10-06 22:08:19 -0700316 if b.client, err = InternalNewClient(b.sm, b.ns, vc.LocalPrincipal{client}); err != nil {
Ankura3c97652014-07-17 20:01:21 -0700317 t.Fatalf("InternalNewClient failed: %v", err)
318 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700319 }
Bogdan Caprita27953142014-05-12 11:41:42 -0700320 return
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700321}
322
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800323func matchesErrorPattern(err error, id verror.IDAction, pattern string) bool {
324 if len(pattern) > 0 && err != nil {
325 if strings.Index(err.Error(), pattern) < 0 {
326 fmt.Fprintf(os.Stderr, "got error msg: %q, expected: %q\n", err, pattern)
327 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700328 }
Cosmos Nicolaou1bce7d12015-01-05 17:42:06 -0800329 if err == nil && id.ID == "" {
330 return true
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800331 }
332 return verror.Is(err, id.ID)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700333}
334
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800335func TestMultipleCallsToServeAndName(t *testing.T) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700336 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
Matt Rosencrantz9fe60822014-09-12 10:09:53 -0700337 ns := tnaming.NewSimpleNamespace()
Ankure49a86a2014-11-11 18:52:43 -0800338 server, err := InternalNewServer(testContext(), sm, ns, nil, vc.LocalPrincipal{tsecurity.NewPrincipal()})
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700339 if err != nil {
340 t.Errorf("InternalNewServer failed: %v", err)
341 }
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -0700342 _, err = server.Listen(listenSpec)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700343 if err != nil {
344 t.Errorf("server.Listen failed: %v", err)
345 }
346
347 disp := &testServerDisp{&testServer{}}
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800348 if err := server.ServeDispatcher("mountpoint/server", disp); err != nil {
349 t.Errorf("server.ServeDispatcher failed: %v", err)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700350 }
351
352 n1 := "mountpoint/server"
353 n2 := "should_appear_in_mt/server"
354 n3 := "should_appear_in_mt/server"
355 n4 := "should_not_appear_in_mt/server"
356
357 verifyMount(t, ns, n1)
358
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800359 if server.ServeDispatcher(n2, disp) == nil {
360 t.Errorf("server.ServeDispatcher should have failed")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700361 }
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800362
363 if err := server.Serve(n2, &testServer{}, nil); err == nil {
364 t.Errorf("server.Serve should have failed")
365 }
366
367 if err := server.AddName(n3); err != nil {
368 t.Errorf("server.AddName failed: %v", err)
369 }
370
371 if err := server.AddName(n3); err != nil {
372 t.Errorf("server.AddName failed: %v", err)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700373 }
374 verifyMount(t, ns, n2)
375 verifyMount(t, ns, n3)
376
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800377 if err := server.RemoveName(n1); err != nil {
378 t.Errorf("server.RemoveName failed: %v", err)
379 }
380 verifyMountMissing(t, ns, n1)
381
382 if err := server.RemoveName("some randome name"); err == nil {
383 t.Errorf("server.RemoveName should have failed")
384 }
385
386 if err := server.ServeDispatcher(n4, &testServerDisp{&testServer{}}); err == nil {
387 t.Errorf("server.ServeDispatcher should have failed")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700388 }
389 verifyMountMissing(t, ns, n4)
390
391 if err := server.Stop(); err != nil {
392 t.Errorf("server.Stop failed: %v", err)
393 }
394
395 verifyMountMissing(t, ns, n1)
396 verifyMountMissing(t, ns, n2)
397 verifyMountMissing(t, ns, n3)
398}
399
Ankure49a86a2014-11-11 18:52:43 -0800400func TestRPCServerAuthorization(t *testing.T) {
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700401 const (
Asim Shankar8f05c222014-10-06 22:08:19 -0700402 vcErr = "VC handshake failed"
Todd Wang34ed4c62014-11-26 15:15:52 -0800403 nameErr = "do not match pattern"
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700404 )
405 var (
Ankure49a86a2014-11-11 18:52:43 -0800406 pprovider, pclient, pserver = tsecurity.NewPrincipal("root"), tsecurity.NewPrincipal(), tsecurity.NewPrincipal()
407 pdischarger = pprovider
408
409 now = time.Now()
410
411 serverName = "mountpoint/server"
412 dischargeServerName = "mountpoint/dischargeserver"
413
414 // Third-party caveats on blessings presented by server.
415 cavTPValid = mkThirdPartyCaveat(pdischarger.PublicKey(), dischargeServerName, mkCaveat(security.ExpiryCaveat(now.Add(24*time.Hour))))
416 cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), dischargeServerName, mkCaveat(security.ExpiryCaveat(now.Add(-1*time.Second))))
417
418 // Server blessings.
419 bServer = bless(pprovider, pserver, "server")
420 bServerExpired = bless(pprovider, pserver, "server", mkCaveat(security.ExpiryCaveat(time.Now().Add(-1*time.Second))))
421 bServerTPValid = bless(pprovider, pserver, "serverWithTPCaveats", cavTPValid)
422 bServerTPExpired = bless(pprovider, pserver, "serverWithTPCaveats", cavTPExpired)
Asim Shankar8f05c222014-10-06 22:08:19 -0700423
424 mgr = imanager.InternalNew(naming.FixedRoutingID(0x1111111))
425 ns = tnaming.NewSimpleNamespace()
426 tests = []struct {
427 server security.Blessings // blessings presented by the server to the client.
428 pattern security.BlessingPattern // pattern on the server identity expected by the client.
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800429 errID verror.IDAction
Asim Shankar8f05c222014-10-06 22:08:19 -0700430 err string
431 }{
Ankure49a86a2014-11-11 18:52:43 -0800432 // Client accepts talking to the server only if the server's blessings match the provided pattern
Cosmos Nicolaou1bce7d12015-01-05 17:42:06 -0800433 {bServer, security.AllPrincipals, verror.IDAction{}, ""},
434 {bServer, "root/server", verror.IDAction{}, ""},
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800435 {bServer, "root/otherserver", verror.NotTrusted, nameErr},
436 {bServer, "otherroot/server", verror.NotTrusted, nameErr},
Asim Shankar8f05c222014-10-06 22:08:19 -0700437
Ankure49a86a2014-11-11 18:52:43 -0800438 // and, if the server's blessing has third-party caveats then the server provides
439 // appropriate discharges.
Cosmos Nicolaou1bce7d12015-01-05 17:42:06 -0800440 {bServerTPValid, security.AllPrincipals, verror.IDAction{}, ""},
441 {bServerTPValid, "root/serverWithTPCaveats", verror.IDAction{}, ""},
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800442 {bServerTPValid, "root/otherserver", verror.NotTrusted, nameErr},
443 {bServerTPValid, "otherroot/server", verror.NotTrusted, nameErr},
Ankure49a86a2014-11-11 18:52:43 -0800444
445 // Client does not talk to a server that presents expired blessings.
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800446 {bServerExpired, security.AllPrincipals, verror.NotTrusted, vcErr},
Ankure49a86a2014-11-11 18:52:43 -0800447
448 // Client does not talk to a server that fails to provide discharges for
449 // third-party caveats on the blessings presented by it.
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800450 {bServerTPExpired, security.AllPrincipals, verror.NotTrusted, vcErr},
Asim Shankar8f05c222014-10-06 22:08:19 -0700451 }
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700452 )
Ankure49a86a2014-11-11 18:52:43 -0800453
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -0800454 _, server := startServer(t, pserver, mgr, ns, serverName, testServerDisp{&testServer{}})
Ankure49a86a2014-11-11 18:52:43 -0800455 defer stopServer(t, server, ns, serverName)
456
457 // Start the discharge server.
458 _, dischargeServer := startServer(t, pdischarger, mgr, ns, dischargeServerName, ipc.LeafDispatcher(&dischargeServer{}, &acceptAllAuthorizer{}))
459 defer stopServer(t, dischargeServer, ns, dischargeServerName)
460
Asim Shankar8f05c222014-10-06 22:08:19 -0700461 // Make the client and server principals trust root certificates from pprovider
462 pclient.AddToRoots(pprovider.BlessingStore().Default())
463 pserver.AddToRoots(pprovider.BlessingStore().Default())
Ankure49a86a2014-11-11 18:52:43 -0800464 // Set a blessing that the client is willing to share with servers with blessings
465 // from pprovider.
466 pclient.BlessingStore().Set(bless(pprovider, pclient, "client"), "root/...")
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800467 for i, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -0700468 name := fmt.Sprintf("(%q@%q)", test.pattern, test.server)
Ankure49a86a2014-11-11 18:52:43 -0800469 if err := pserver.BlessingStore().SetDefault(test.server); err != nil {
470 t.Fatalf("SetDefault failed on server's BlessingStore: %v", err)
471 }
472 if _, err := pserver.BlessingStore().Set(test.server, "root/..."); err != nil {
473 t.Fatalf("Set failed on server's BlessingStore: %v", err)
474 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700475 // Recreate client in each test (so as to not re-use VCs to the server).
476 client, err := InternalNewClient(mgr, ns, vc.LocalPrincipal{pclient})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700477 if err != nil {
Asim Shankara5b60b22014-11-06 15:37:07 -0800478 t.Errorf("%s: failed to create client: %v", name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700479 continue
480 }
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -0800481 ctx := testContextWithoutDeadline()
Matt Rosencrantz89445a42015-01-05 13:32:37 -0800482 dctx, cancel := context.WithTimeout(ctx, 10*time.Second)
Matt Rosencrantzcc922c12014-11-28 20:28:59 -0800483 call, err := client.StartCall(dctx, fmt.Sprintf("[%s]%s/suffix", test.pattern, serverName), "Method", nil)
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800484 if !matchesErrorPattern(err, test.errID, test.err) {
485 t.Errorf(`%d: %s: client.StartCall: got error "%v", want to match "%v"`, i, name, err, test.err)
Asim Shankar2d731a92014-09-29 17:46:38 -0700486 } else if call != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700487 blessings, proof := call.RemoteBlessings()
488 if proof == nil {
489 t.Errorf("%s: Returned nil for remote blessings", name)
490 }
491 if !test.pattern.MatchedBy(blessings...) {
492 t.Errorf("%s: %q.MatchedBy(%v) failed", name, test.pattern, blessings)
Asim Shankar2d731a92014-09-29 17:46:38 -0700493 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700494 }
Matt Rosencrantzcc922c12014-11-28 20:28:59 -0800495 cancel()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700496 client.Close()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700497 }
498}
499
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800500type websocketMode bool
501type closeSendMode bool
502
503const (
504 useWebsocket websocketMode = true
505 noWebsocket websocketMode = false
506
507 closeSend closeSendMode = true
508 noCloseSend closeSendMode = false
509)
510
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700511func TestRPC(t *testing.T) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800512 testRPC(t, closeSend, noWebsocket)
513}
514
515func TestRPCWithWebsocket(t *testing.T) {
516 testRPC(t, closeSend, useWebsocket)
Tilak Sharma0c766112014-05-20 17:47:27 -0700517}
518
519// TestCloseSendOnFinish tests that Finish informs the server that no more
520// inputs will be sent by the client if CloseSend has not already done so.
521func TestRPCCloseSendOnFinish(t *testing.T) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800522 testRPC(t, noCloseSend, noWebsocket)
Tilak Sharma0c766112014-05-20 17:47:27 -0700523}
524
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800525func TestRPCCloseSendOnFinishWithWebsocket(t *testing.T) {
526 testRPC(t, noCloseSend, useWebsocket)
527}
528
529func testRPC(t *testing.T, shouldCloseSend closeSendMode, shouldUseWebsocket websocketMode) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700530 type v []interface{}
531 type testcase struct {
532 name string
533 method string
534 args v
535 streamArgs v
536 startErr error
537 results v
538 finishErr error
539 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700540 var (
541 tests = []testcase{
542 {"mountpoint/server/suffix", "Closure", nil, nil, nil, nil, nil},
543 {"mountpoint/server/suffix", "Error", nil, nil, nil, v{errMethod}, nil},
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700544
Asim Shankar8f05c222014-10-06 22:08:19 -0700545 {"mountpoint/server/suffix", "Echo", v{"foo"}, nil, nil, v{`method:"Echo",suffix:"suffix",arg:"foo"`}, nil},
546 {"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 -0700547
Asim Shankar8f05c222014-10-06 22:08:19 -0700548 {"mountpoint/server/suffix", "EchoUser", v{"foo", userType("bar")}, nil, nil, v{`method:"EchoUser",suffix:"suffix",arg:"foo"`, userType("bar")}, nil},
549 {"mountpoint/server/suffix/abc", "EchoUser", v{"baz", userType("bla")}, nil, nil, v{`method:"EchoUser",suffix:"suffix/abc",arg:"baz"`, userType("bla")}, nil},
550 {"mountpoint/server/suffix", "Stream", v{"foo"}, v{userType("bar"), userType("baz")}, nil, v{`method:"Stream",suffix:"suffix",arg:"foo" bar baz`, nil}, nil},
551 {"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},
552 {"mountpoint/server/suffix", "EchoBlessings", nil, nil, nil, v{"[server]", "[client]"}, nil},
553 {"mountpoint/server/suffix", "EchoAndError", v{"bugs bunny"}, nil, nil, v{`method:"EchoAndError",suffix:"suffix",arg:"bugs bunny"`, nil}, nil},
554 {"mountpoint/server/suffix", "EchoAndError", v{"error"}, nil, nil, v{`method:"EchoAndError",suffix:"suffix",arg:"error"`, errMethod}, nil},
555 }
556 name = func(t testcase) string {
557 return fmt.Sprintf("%s.%s(%v)", t.name, t.method, t.args)
558 }
559
Ankure49a86a2014-11-11 18:52:43 -0800560 pserver = tsecurity.NewPrincipal("server")
561 pclient = tsecurity.NewPrincipal("client")
Asim Shankar8f05c222014-10-06 22:08:19 -0700562
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800563 b = createBundleWS(t, pclient, pserver, &testServer{}, shouldUseWebsocket)
Asim Shankar8f05c222014-10-06 22:08:19 -0700564 )
Bogdan Caprita27953142014-05-12 11:41:42 -0700565 defer b.cleanup(t)
Asim Shankar8f05c222014-10-06 22:08:19 -0700566 // The server needs to recognize the client's root certificate.
567 pserver.AddToRoots(pclient.BlessingStore().Default())
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700568 for _, test := range tests {
569 vlog.VI(1).Infof("%s client.StartCall", name(test))
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800570 vname := test.name
571 if shouldUseWebsocket {
572 var err error
573 vname, err = resolveWSEndpoint(b.ns, vname)
574 if err != nil && err != test.startErr {
575 t.Errorf(`%s ns.Resolve got error "%v", want "%v"`, name(test), err, test.startErr)
576 continue
577 }
578 }
579 call, err := b.client.StartCall(testContext(), vname, test.method, test.args)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700580 if err != test.startErr {
581 t.Errorf(`%s client.StartCall got error "%v", want "%v"`, name(test), err, test.startErr)
582 continue
583 }
584 for _, sarg := range test.streamArgs {
585 vlog.VI(1).Infof("%s client.Send(%v)", name(test), sarg)
586 if err := call.Send(sarg); err != nil {
587 t.Errorf(`%s call.Send(%v) got unexpected error "%v"`, name(test), sarg, err)
588 }
589 var u userType
590 if err := call.Recv(&u); err != nil {
591 t.Errorf(`%s call.Recv(%v) got unexpected error "%v"`, name(test), sarg, err)
592 }
593 if !reflect.DeepEqual(u, sarg) {
594 t.Errorf("%s call.Recv got value %v, want %v", name(test), u, sarg)
595 }
596 }
Tilak Sharma0c766112014-05-20 17:47:27 -0700597 if shouldCloseSend {
598 vlog.VI(1).Infof("%s call.CloseSend", name(test))
Asim Shankar062d4222014-08-18 11:14:42 -0700599 // When the method does not involve streaming
600 // arguments, the server gets all the arguments in
601 // StartCall and then sends a response without
602 // (unnecessarily) waiting for a CloseSend message from
603 // the client. If the server responds before the
604 // CloseSend call is made at the client, the CloseSend
605 // call will fail. Thus, only check for errors on
606 // CloseSend if there are streaming arguments to begin
607 // with (i.e., only if the server is expected to wait
608 // for the CloseSend notification).
609 if err := call.CloseSend(); err != nil && len(test.streamArgs) > 0 {
Tilak Sharma0c766112014-05-20 17:47:27 -0700610 t.Errorf(`%s call.CloseSend got unexpected error "%v"`, name(test), err)
611 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700612 }
613 vlog.VI(1).Infof("%s client.Finish", name(test))
614 results := makeResultPtrs(test.results)
615 err = call.Finish(results...)
616 if err != test.finishErr {
617 t.Errorf(`%s call.Finish got error "%v", want "%v"`, name(test), err, test.finishErr)
618 }
619 checkResultPtrs(t, name(test), results, test.results)
620 }
621}
622
Ken Ashcraft2b8309a2014-09-09 10:44:43 -0700623func TestMultipleFinish(t *testing.T) {
624 type v []interface{}
Ankure49a86a2014-11-11 18:52:43 -0800625 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), &testServer{})
Ken Ashcraft2b8309a2014-09-09 10:44:43 -0700626 defer b.cleanup(t)
627 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "Echo", v{"foo"})
628 if err != nil {
629 t.Fatalf(`client.StartCall got error "%v"`, err)
630 }
631 var results string
632 err = call.Finish(&results)
633 if err != nil {
634 t.Fatalf(`call.Finish got error "%v"`, err)
635 }
636 // Calling Finish a second time should result in a useful error.
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800637 if err = call.Finish(&results); !matchesErrorPattern(err, verror.BadState, "Finish has already been called") {
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800638 t.Fatalf(`got "%v", want "%v"`, err, verror.BadState)
Ken Ashcraft2b8309a2014-09-09 10:44:43 -0700639 }
640}
641
Asim Shankar8f05c222014-10-06 22:08:19 -0700642// granter implements ipc.Granter, returning a fixed (security.Blessings, error) pair.
Asim Shankarb54d7642014-06-05 13:08:04 -0700643type granter struct {
644 ipc.CallOpt
Asim Shankar8f05c222014-10-06 22:08:19 -0700645 b security.Blessings
Asim Shankarb54d7642014-06-05 13:08:04 -0700646 err error
647}
648
Asim Shankar8f05c222014-10-06 22:08:19 -0700649func (g granter) Grant(id security.Blessings) (security.Blessings, error) { return g.b, g.err }
Asim Shankarb54d7642014-06-05 13:08:04 -0700650
Asim Shankar8f05c222014-10-06 22:08:19 -0700651func TestGranter(t *testing.T) {
652 var (
Ankure49a86a2014-11-11 18:52:43 -0800653 pclient = tsecurity.NewPrincipal("client")
654 pserver = tsecurity.NewPrincipal("server")
Asim Shankar8f05c222014-10-06 22:08:19 -0700655 b = createBundle(t, pclient, pserver, &testServer{})
656 )
Asim Shankarb54d7642014-06-05 13:08:04 -0700657 defer b.cleanup(t)
658
659 tests := []struct {
Asim Shankar8f05c222014-10-06 22:08:19 -0700660 granter ipc.Granter
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800661 startErrID, finishErrID verror.IDAction
Asim Shankarb54d7642014-06-05 13:08:04 -0700662 blessing, starterr, finisherr string
663 }{
664 {blessing: "<nil>"},
Asim Shankarb18a44f2014-10-21 20:25:07 -0700665 {granter: granter{b: bless(pclient, pserver, "blessed")}, blessing: "client/blessed"},
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800666 {granter: granter{err: errors.New("hell no")}, startErrID: verror.NotTrusted, starterr: "hell no"},
667 {granter: granter{b: pclient.BlessingStore().Default()}, finishErrID: verror.NoAccess, finisherr: "blessing granted not bound to this server"},
Asim Shankarb54d7642014-06-05 13:08:04 -0700668 }
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800669 for i, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -0700670 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "EchoGrantedBlessings", []interface{}{"argument"}, test.granter)
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800671 if !matchesErrorPattern(err, test.startErrID, test.starterr) {
672 t.Errorf("%d: %+v: StartCall returned error %v", i, test, err)
Asim Shankarb54d7642014-06-05 13:08:04 -0700673 }
674 if err != nil {
675 continue
676 }
677 var result, blessing string
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800678 if err = call.Finish(&result, &blessing); !matchesErrorPattern(err, test.finishErrID, test.finisherr) {
Asim Shankarb54d7642014-06-05 13:08:04 -0700679 t.Errorf("%+v: Finish returned error %v", test, err)
680 }
681 if err != nil {
682 continue
683 }
684 if result != "argument" || blessing != test.blessing {
685 t.Errorf("%+v: Got (%q, %q)", test, result, blessing)
686 }
687 }
688}
689
Asim Shankar8f05c222014-10-06 22:08:19 -0700690func mkThirdPartyCaveat(discharger security.PublicKey, location string, c security.Caveat) security.Caveat {
691 tpc, err := security.NewPublicKeyCaveat(discharger, location, security.ThirdPartyRequirements{}, c)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700692 if err != nil {
693 panic(err)
694 }
Asim Shankar50ff6362014-09-15 18:09:46 -0700695 return newCaveat(tpc)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700696}
697
Asim Shankarf4864f42014-11-25 18:53:05 -0800698// dischargeTestServer implements the discharge service. Always fails to
699// issue a discharge, but records the impetus and traceid of the RPC call.
700type dischargeTestServer struct {
701 p security.Principal
702 impetus []security.DischargeImpetus
703 traceid []uniqueid.ID
Asim Shankara94e5072014-08-19 18:18:36 -0700704}
705
Asim Shankarf4864f42014-11-25 18:53:05 -0800706func (s *dischargeTestServer) Discharge(ctx ipc.ServerContext, cav vdlutil.Any, impetus security.DischargeImpetus) (vdlutil.Any, error) {
Asim Shankarc8cfcf12014-11-20 12:26:58 -0800707 s.impetus = append(s.impetus, impetus)
Matt Rosencrantz8f9fca12014-12-19 14:02:31 -0800708 s.traceid = append(s.traceid, ivtrace.FromContext(ctx.Context()).Trace().ID())
Asim Shankara94e5072014-08-19 18:18:36 -0700709 return nil, fmt.Errorf("discharges not issued")
710}
711
Asim Shankarf4864f42014-11-25 18:53:05 -0800712func (s *dischargeTestServer) Release() ([]security.DischargeImpetus, []uniqueid.ID) {
713 impetus, traceid := s.impetus, s.traceid
714 s.impetus, s.traceid = nil, nil
715 return impetus, traceid
Asim Shankarc8cfcf12014-11-20 12:26:58 -0800716}
717
Asim Shankarf4864f42014-11-25 18:53:05 -0800718func TestDischargeImpetusAndContextPropagation(t *testing.T) {
Asim Shankara94e5072014-08-19 18:18:36 -0700719 var (
Ankure49a86a2014-11-11 18:52:43 -0800720 pserver = tsecurity.NewPrincipal("server")
Asim Shankarf4864f42014-11-25 18:53:05 -0800721 pdischarger = tsecurity.NewPrincipal("discharger")
722 pclient = tsecurity.NewPrincipal("client")
Asim Shankar8f05c222014-10-06 22:08:19 -0700723 sm = imanager.InternalNew(naming.FixedRoutingID(0x555555555))
724 ns = tnaming.NewSimpleNamespace()
Asim Shankara94e5072014-08-19 18:18:36 -0700725
Asim Shankar8f05c222014-10-06 22:08:19 -0700726 mkClient = func(req security.ThirdPartyRequirements) vc.LocalPrincipal {
Asim Shankarf4864f42014-11-25 18:53:05 -0800727 // Setup the client so that it shares a blessing with a third-party caveat with the server.
728 tpc, err := security.NewPublicKeyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", req, security.UnconstrainedUse())
Asim Shankara94e5072014-08-19 18:18:36 -0700729 if err != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700730 t.Fatalf("Failed to create ThirdPartyCaveat(%+v): %v", req, err)
Asim Shankara94e5072014-08-19 18:18:36 -0700731 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700732 cav, err := security.NewCaveat(tpc)
733 if err != nil {
734 t.Fatal(err)
735 }
Asim Shankarf4864f42014-11-25 18:53:05 -0800736 b, err := pclient.BlessSelf("client_for_server", cav)
Asim Shankar8f05c222014-10-06 22:08:19 -0700737 if err != nil {
738 t.Fatalf("BlessSelf failed: %v", err)
739 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700740 pclient.BlessingStore().Set(b, "server")
741 return vc.LocalPrincipal{pclient}
Asim Shankara94e5072014-08-19 18:18:36 -0700742 }
743 )
Asim Shankarf4864f42014-11-25 18:53:05 -0800744 // Initialize the client principal.
745 // It trusts both the application server and the discharger.
746 pclient.AddToRoots(pserver.BlessingStore().Default())
747 pclient.AddToRoots(pdischarger.BlessingStore().Default())
748 // Share a blessing without any third-party caveats with the discharger.
749 // It could share the same blessing as generated by setupClientBlessing, but
750 // that will lead to possibly debugging confusion (since it will try to fetch
751 // a discharge to talk to the discharge service).
752 if b, err := pclient.BlessSelf("client_for_discharger"); err != nil {
753 t.Fatalf("BlessSelf failed: %v", err)
754 } else {
755 pclient.BlessingStore().Set(b, "discharger")
756 }
757
758 // Setup the discharge server.
759 var tester dischargeTestServer
760 dischargeServer, err := InternalNewServer(testContext(), sm, ns, nil, vc.LocalPrincipal{pdischarger})
Asim Shankara94e5072014-08-19 18:18:36 -0700761 if err != nil {
762 t.Fatal(err)
763 }
Asim Shankarf4864f42014-11-25 18:53:05 -0800764 defer dischargeServer.Stop()
765 if _, err := dischargeServer.Listen(listenSpec); err != nil {
766 t.Fatal(err)
767 }
768 if err := dischargeServer.Serve("mountpoint/discharger", &tester, &testServerAuthorizer{}); err != nil {
Asim Shankara94e5072014-08-19 18:18:36 -0700769 t.Fatal(err)
770 }
771
Asim Shankarf4864f42014-11-25 18:53:05 -0800772 // Setup the application server.
773 appServer, err := InternalNewServer(testContext(), sm, ns, nil, vc.LocalPrincipal{pserver})
774 if err != nil {
775 t.Fatal(err)
776 }
777 defer appServer.Stop()
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800778 eps, err := appServer.Listen(listenSpec)
Asim Shankarf4864f42014-11-25 18:53:05 -0800779 if err != nil {
780 t.Fatal(err)
781 }
782 // TODO(bjornick,cnicolaou,ashankar): This is a hack to workaround the
783 // fact that a single Listen on the "tcp" protocol followed by a call
784 // to Serve(<name>, ...) transparently creates two endpoints (one for
785 // tcp, one for websockets) and maps both to <name> via a mount.
786 // Because all endpoints to a name are tried in a parallel, this
787 // transparency makes this test hard to follow (many discharge fetch
788 // attempts are made - one for VIF authentication, one for VC
789 // authentication and one for the actual RPC - and having them be made
790 // to two different endpoints in parallel leads to a lot of
791 // non-determinism). The last plan of record known by the author of
792 // this comment was to stop this sly creation of two endpoints and
793 // require that they be done explicitly. When that happens, this hack
794 // can go away, but till then, this workaround allows the test to be
795 // more predictable by ensuring there is only one VIF/VC/Flow to the
796 // server.
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800797 object := naming.JoinAddressName(eps[0].String(), "object") // instead of "mountpoint/object"
Asim Shankarf4864f42014-11-25 18:53:05 -0800798 if err := appServer.Serve("mountpoint/object", &testServer{}, &testServerAuthorizer{}); err != nil {
799 t.Fatal(err)
800 }
Asim Shankara94e5072014-08-19 18:18:36 -0700801 tests := []struct {
802 Requirements security.ThirdPartyRequirements
803 Impetus security.DischargeImpetus
804 }{
805 { // No requirements, no impetus
806 Requirements: security.ThirdPartyRequirements{},
807 Impetus: security.DischargeImpetus{},
808 },
809 { // Require everything
810 Requirements: security.ThirdPartyRequirements{ReportServer: true, ReportMethod: true, ReportArguments: true},
Asim Shankar8f05c222014-10-06 22:08:19 -0700811 Impetus: security.DischargeImpetus{Server: []security.BlessingPattern{"server"}, Method: "Method", Arguments: []vdlutil.Any{vdlutil.Any("argument")}},
Asim Shankara94e5072014-08-19 18:18:36 -0700812 },
813 { // Require only the method name
814 Requirements: security.ThirdPartyRequirements{ReportMethod: true},
815 Impetus: security.DischargeImpetus{Method: "Method"},
816 },
817 }
818
Asim Shankarf4864f42014-11-25 18:53:05 -0800819 for testidx, test := range tests {
Ankure49a86a2014-11-11 18:52:43 -0800820 pclient := mkClient(test.Requirements)
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -0800821 client, err := InternalNewClient(sm, ns, pclient)
Asim Shankara94e5072014-08-19 18:18:36 -0700822 if err != nil {
823 t.Fatalf("InternalNewClient(%+v) failed: %v", test.Requirements, err)
824 }
825 defer client.Close()
Asim Shankarf4864f42014-11-25 18:53:05 -0800826 ctx := testContext()
Matt Rosencrantzcc922c12014-11-28 20:28:59 -0800827 tid := ivtrace.FromContext(ctx).Trace().ID()
Asim Shankara94e5072014-08-19 18:18:36 -0700828 // StartCall should fetch the discharge, do not worry about finishing the RPC - do not care about that for this test.
Asim Shankarf4864f42014-11-25 18:53:05 -0800829 if _, err := client.StartCall(ctx, object, "Method", []interface{}{"argument"}); err != nil {
Asim Shankara94e5072014-08-19 18:18:36 -0700830 t.Errorf("StartCall(%+v) failed: %v", test.Requirements, err)
831 continue
832 }
Asim Shankarf4864f42014-11-25 18:53:05 -0800833 impetus, traceid := tester.Release()
834 // There should have been 2 or 3 attempts to fetch a discharge
835 // (since the discharge service doesn't actually issue a valid
836 // discharge, there is no re-usable discharge between these attempts):
837 // (1) When creating a VIF with the server hosting the remote object.
838 // (This will happen only for the first test, where the stream.Manager
839 // authenticates at the VIF level for the very first time).
840 // (2) When creating a VC with the server hosting the remote object.
841 // (3) When making the RPC to the remote object.
842 num := 3
843 if testidx > 0 {
844 num = 2
845 }
846 if want := num; len(impetus) != want || len(traceid) != want {
847 t.Errorf("Test %+v: Got (%d, %d) (#impetus, #traceid), wanted %d each", test.Requirements, len(impetus), len(traceid), want)
848 continue
849 }
850 // VC creation does not have any "impetus", it is established without
851 // knowledge of the context of the RPC. So ignore that.
852 //
853 // TODO(ashankar): Should the impetus of the RPC that initiated the
854 // VIF/VC creation be propagated?
855 if got, want := impetus[len(impetus)-1], test.Impetus; !reflect.DeepEqual(got, want) {
856 t.Errorf("Test %+v: Got impetus %v, want %v", test.Requirements, got, want)
857 }
858 // But the context used for all of this should be the same
859 // (thereby allowing debug traces to link VIF/VC creation with
860 // the RPC that initiated them).
861 for idx, got := range traceid {
862 if !reflect.DeepEqual(got, tid) {
863 t.Errorf("Test %+v: %d - Got trace id %q, want %q", test.Requirements, idx, hex.EncodeToString(got[:]), hex.EncodeToString(tid[:]))
864 }
Asim Shankara94e5072014-08-19 18:18:36 -0700865 }
866 }
867}
868
Ankure49a86a2014-11-11 18:52:43 -0800869func TestRPCClientAuthorization(t *testing.T) {
870 type v []interface{}
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700871 var (
Asim Shankar8f05c222014-10-06 22:08:19 -0700872 // Principals
Ankure49a86a2014-11-11 18:52:43 -0800873 pclient, pserver = tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server")
874 pdischarger = pserver
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700875
Asim Shankar8f05c222014-10-06 22:08:19 -0700876 now = time.Now()
877
Ankure49a86a2014-11-11 18:52:43 -0800878 serverName = "mountpoint/server"
879 dischargeServerName = "mountpoint/dischargeserver"
880
Asim Shankar8f05c222014-10-06 22:08:19 -0700881 // Caveats on blessings to the client: First-party caveats
882 cavOnlyEcho = mkCaveat(security.MethodCaveat("Echo"))
883 cavExpired = mkCaveat(security.ExpiryCaveat(now.Add(-1 * time.Second)))
884 // Caveats on blessings to the client: Third-party caveats
885 cavTPValid = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", mkCaveat(security.ExpiryCaveat(now.Add(24*time.Hour))))
886 cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", mkCaveat(security.ExpiryCaveat(now.Add(-1*time.Second))))
887
888 // Client blessings that will be tested.
889 bServerClientOnlyEcho = bless(pserver, pclient, "onlyecho", cavOnlyEcho)
890 bServerClientExpired = bless(pserver, pclient, "expired", cavExpired)
891 bServerClientTPValid = bless(pserver, pclient, "dischargeable_third_party_caveat", cavTPValid)
892 bServerClientTPExpired = bless(pserver, pclient, "expired_third_party_caveat", cavTPExpired)
893 bClient = pclient.BlessingStore().Default()
894 bRandom, _ = pclient.BlessSelf("random")
Ankure49a86a2014-11-11 18:52:43 -0800895
896 mgr = imanager.InternalNew(naming.FixedRoutingID(0x1111111))
897 ns = tnaming.NewSimpleNamespace()
898 tests = []struct {
899 blessings security.Blessings // Blessings used by the client
900 name string // object name on which the method is invoked
901 method string
902 args v
903 results v
904 authorized bool // Whether or not the RPC should be authorized by the server.
905 }{
906 // There are three different authorization policies (security.Authorizer implementations)
907 // used by the server, depending on the suffix (see testServerDisp.Lookup):
908 // - nilAuth suffix: the default authorization policy (only delegates of or delegators of the server can call RPCs)
909 // - aclAuth suffix: the ACL only allows "server/..." or "client"
910 // - other suffixes: testServerAuthorizer allows any principal to call any method except "Unauthorized"
911
912 // Expired blessings should fail nilAuth and aclAuth (which care about names), but should succeed on
913 // other suffixes (which allow all blessings), unless calling the Unauthorized method.
914 {bServerClientExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
915 {bServerClientExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
916 {bServerClientExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
917 {bServerClientExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
918
919 // Same for blessings that should fail to obtain a discharge for the third party caveat.
920 {bServerClientTPExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
921 {bServerClientTPExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
922 {bServerClientTPExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
923 {bServerClientTPExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
924
925 // The "server/client" blessing (with MethodCaveat("Echo")) should satisfy all authorization policies
926 // when "Echo" is called.
927 {bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
928 {bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
929 {bServerClientOnlyEcho, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
930
931 // The "server/client" blessing (with MethodCaveat("Echo")) should satisfy no authorization policy
932 // when any other method is invoked, except for the testServerAuthorizer policy (which will
933 // not recognize the blessing "server/onlyecho", but it would authorize anyone anyway).
934 {bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Closure", nil, nil, false},
935 {bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Closure", nil, nil, false},
936 {bServerClientOnlyEcho, "mountpoint/server/suffix", "Closure", nil, nil, true},
937
938 // The "client" blessing doesn't satisfy the default authorization policy, but does satisfy
939 // the ACL and the testServerAuthorizer policy.
940 {bClient, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
941 {bClient, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
942 {bClient, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
943 {bClient, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
944
945 // The "random" blessing does not satisfy either the default policy or the ACL, but does
946 // satisfy testServerAuthorizer.
947 {bRandom, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
948 {bRandom, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
949 {bRandom, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
950 {bRandom, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
951
952 // The "server/dischargeable_third_party_caveat" blessing satisfies all policies.
953 // (the discharges should be fetched).
954 {bServerClientTPValid, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
955 {bServerClientTPValid, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
956 {bServerClientTPValid, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
957 {bServerClientTPValid, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
958 }
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700959 )
Ankure49a86a2014-11-11 18:52:43 -0800960 // Start the main server.
961 _, server := startServer(t, pserver, mgr, ns, serverName, testServerDisp{&testServer{}})
962 defer stopServer(t, server, ns, serverName)
963
964 // Start the discharge server.
965 _, dischargeServer := startServer(t, pdischarger, mgr, ns, dischargeServerName, ipc.LeafDispatcher(&dischargeServer{}, &acceptAllAuthorizer{}))
966 defer stopServer(t, dischargeServer, ns, dischargeServerName)
967
Asim Shankar8f05c222014-10-06 22:08:19 -0700968 // The server should recognize the client principal as an authority on "client/..." and "random/..." blessings.
969 pserver.AddToRoots(bClient)
970 pserver.AddToRoots(bRandom)
Ankure49a86a2014-11-11 18:52:43 -0800971 // And the client needs to recognize the server's and discharger's blessings to decide which of its
972 // own blessings to share.
Asim Shankar8f05c222014-10-06 22:08:19 -0700973 pclient.AddToRoots(pserver.BlessingStore().Default())
Ankure49a86a2014-11-11 18:52:43 -0800974 // tsecurity.NewPrincipal sets up a principal that shares blessings with all servers, undo that.
Asim Shankarae8d4c52014-10-08 13:03:31 -0700975 pclient.BlessingStore().Set(nil, security.AllPrincipals)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700976
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700977 for _, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -0700978 name := fmt.Sprintf("%q.%s(%v) by %v", test.name, test.method, test.args, test.blessings)
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -0800979 client, err := InternalNewClient(mgr, ns, vc.LocalPrincipal{pclient})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700980 if err != nil {
981 t.Fatalf("InternalNewClient failed: %v", err)
982 }
983 defer client.Close()
Ankure49a86a2014-11-11 18:52:43 -0800984
Asim Shankar8f05c222014-10-06 22:08:19 -0700985 pclient.BlessingStore().Set(test.blessings, "server")
Matt Rosencrantzbf85d542014-08-22 13:31:14 -0700986 call, err := client.StartCall(testContext(), test.name, test.method, test.args)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700987 if err != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700988 t.Errorf(`%s client.StartCall got unexpected error: "%v"`, name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700989 continue
990 }
Ankure49a86a2014-11-11 18:52:43 -0800991
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700992 results := makeResultPtrs(test.results)
993 err = call.Finish(results...)
Asim Shankar8f05c222014-10-06 22:08:19 -0700994 if err != nil && test.authorized {
995 t.Errorf(`%s call.Finish got error: "%v", wanted the RPC to succeed`, name, err)
996 } else if err == nil && !test.authorized {
997 t.Errorf("%s call.Finish succeeded, expected authorization failure", name)
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800998 } else if !test.authorized && !verror.Is(err, verror.NoAccess.ID) {
999 t.Errorf("%s. call.Finish returned error %v(%v), wanted %v", name, verror.Convert(verror.NoAccess, nil, err).ErrorID(), err, verror.NoAccess)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001000 }
1001 }
1002}
1003
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001004func TestDischargePurgeFromCache(t *testing.T) {
1005 var (
Ankure49a86a2014-11-11 18:52:43 -08001006 pserver = tsecurity.NewPrincipal("server")
Asim Shankar8f05c222014-10-06 22:08:19 -07001007 pdischarger = pserver // In general, the discharger can be a separate principal. In this test, it happens to be the server.
Ankure49a86a2014-11-11 18:52:43 -08001008 pclient = tsecurity.NewPrincipal("client")
Asim Shankar8f05c222014-10-06 22:08:19 -07001009 // Client is blessed with a third-party caveat. The discharger service issues discharges with a fakeTimeCaveat.
1010 // This blessing is presented to "server".
1011 bclient = bless(pserver, pclient, "client", mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", security.UnconstrainedUse()))
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001012 )
Asim Shankar8f05c222014-10-06 22:08:19 -07001013 // Setup the client to recognize the server's blessing and present bclient to it.
1014 pclient.AddToRoots(pserver.BlessingStore().Default())
1015 pclient.BlessingStore().Set(bclient, "server")
1016
Ankure49a86a2014-11-11 18:52:43 -08001017 b := createBundle(t, nil, pserver, &testServer{})
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001018 defer b.cleanup(t)
1019
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001020 var err error
1021 if b.client, err = InternalNewClient(b.sm, b.ns, vc.LocalPrincipal{pclient}); err != nil {
Ankure49a86a2014-11-11 18:52:43 -08001022 t.Fatalf("InternalNewClient failed: %v", err)
1023 }
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -08001024 call := func() verror.E {
Asim Shankar8f05c222014-10-06 22:08:19 -07001025 call, err := b.client.StartCall(testContext(), "mountpoint/server/aclAuth", "Echo", []interface{}{"batman"})
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001026 if err != nil {
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -08001027 return err.(verror.E) //fmt.Errorf("client.StartCall failed: %v", err)
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001028 }
1029 var got string
1030 if err := call.Finish(&got); err != nil {
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -08001031 return err.(verror.E) //fmt.Errorf("client.Finish failed: %v", err)
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001032 }
Asim Shankar8f05c222014-10-06 22:08:19 -07001033 if want := `method:"Echo",suffix:"aclAuth",arg:"batman"`; got != want {
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -08001034 return verror.Convert(verror.BadArg, nil, fmt.Errorf("Got [%v] want [%v]", got, want))
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001035 }
1036 return nil
1037 }
1038
1039 // First call should succeed
1040 if err := call(); err != nil {
1041 t.Fatal(err)
1042 }
1043 // Advance virtual clock, which will invalidate the discharge
1044 clock.Advance(1)
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -08001045 if err, want := call(), "not authorized"; !matchesErrorPattern(err, verror.NoAccess, want) {
Asim Shankar8f05c222014-10-06 22:08:19 -07001046 t.Errorf("Got error [%v] wanted to match pattern %q", err, want)
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001047 }
1048 // But retrying will succeed since the discharge should be purged from cache and refreshed
1049 if err := call(); err != nil {
1050 t.Fatal(err)
1051 }
1052}
1053
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001054type cancelTestServer struct {
1055 started chan struct{}
1056 cancelled chan struct{}
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001057 t *testing.T
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001058}
1059
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001060func newCancelTestServer(t *testing.T) *cancelTestServer {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001061 return &cancelTestServer{
1062 started: make(chan struct{}),
1063 cancelled: make(chan struct{}),
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001064 t: t,
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001065 }
1066}
1067
1068func (s *cancelTestServer) CancelStreamReader(call ipc.ServerCall) error {
1069 close(s.started)
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001070 var b []byte
1071 if err := call.Recv(&b); err != io.EOF {
1072 s.t.Errorf("Got error %v, want io.EOF", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001073 }
Matt Rosencrantz8f9fca12014-12-19 14:02:31 -08001074 <-call.Context().Done()
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001075 close(s.cancelled)
1076 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001077}
1078
1079// CancelStreamIgnorer doesn't read from it's input stream so all it's
Matt Rosencrantz137b8d22014-08-18 09:56:15 -07001080// buffers fill. The intention is to show that call.Done() is closed
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001081// even when the stream is stalled.
1082func (s *cancelTestServer) CancelStreamIgnorer(call ipc.ServerCall) error {
1083 close(s.started)
Matt Rosencrantz8f9fca12014-12-19 14:02:31 -08001084 <-call.Context().Done()
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001085 close(s.cancelled)
1086 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001087}
1088
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001089func waitForCancel(t *testing.T, ts *cancelTestServer, cancel context.CancelFunc) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001090 <-ts.started
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001091 cancel()
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001092 <-ts.cancelled
1093}
1094
1095// TestCancel tests cancellation while the server is reading from a stream.
1096func TestCancel(t *testing.T) {
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001097 ts := newCancelTestServer(t)
Ankure49a86a2014-11-11 18:52:43 -08001098 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), ts)
Bogdan Caprita27953142014-05-12 11:41:42 -07001099 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001100
Matt Rosencrantz89445a42015-01-05 13:32:37 -08001101 ctx, cancel := context.WithCancel(testContext())
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001102 _, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "CancelStreamReader", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001103 if err != nil {
1104 t.Fatalf("Start call failed: %v", err)
1105 }
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001106 waitForCancel(t, ts, cancel)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001107}
1108
1109// TestCancelWithFullBuffers tests that even if the writer has filled the buffers and
1110// the server is not reading that the cancel message gets through.
1111func TestCancelWithFullBuffers(t *testing.T) {
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001112 ts := newCancelTestServer(t)
Ankure49a86a2014-11-11 18:52:43 -08001113 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), ts)
Bogdan Caprita27953142014-05-12 11:41:42 -07001114 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001115
Matt Rosencrantz89445a42015-01-05 13:32:37 -08001116 ctx, cancel := context.WithCancel(testContext())
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001117 call, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "CancelStreamIgnorer", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001118 if err != nil {
1119 t.Fatalf("Start call failed: %v", err)
1120 }
1121 // Fill up all the write buffers to ensure that cancelling works even when the stream
1122 // is blocked.
1123 call.Send(make([]byte, vc.MaxSharedBytes))
1124 call.Send(make([]byte, vc.DefaultBytesBufferedPerFlow))
1125
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001126 waitForCancel(t, ts, cancel)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001127}
1128
1129type streamRecvInGoroutineServer struct{ c chan error }
1130
1131func (s *streamRecvInGoroutineServer) RecvInGoroutine(call ipc.ServerCall) error {
1132 // Spawn a goroutine to read streaming data from the client.
1133 go func() {
1134 var i interface{}
1135 for {
1136 err := call.Recv(&i)
1137 if err != nil {
1138 s.c <- err
1139 return
1140 }
1141 }
1142 }()
1143 // Imagine the server did some processing here and now that it is done,
1144 // it does not care to see what else the client has to say.
1145 return nil
1146}
1147
1148func TestStreamReadTerminatedByServer(t *testing.T) {
1149 s := &streamRecvInGoroutineServer{c: make(chan error, 1)}
Ankure49a86a2014-11-11 18:52:43 -08001150 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), s)
Bogdan Caprita27953142014-05-12 11:41:42 -07001151 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001152
Matt Rosencrantzbf85d542014-08-22 13:31:14 -07001153 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "RecvInGoroutine", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001154 if err != nil {
1155 t.Fatalf("StartCall failed: %v", err)
1156 }
1157
1158 c := make(chan error, 1)
1159 go func() {
1160 for i := 0; true; i++ {
1161 if err := call.Send(i); err != nil {
1162 c <- err
1163 return
1164 }
1165 }
1166 }()
1167
1168 // The goroutine at the server executing "Recv" should have terminated
1169 // with EOF.
1170 if err := <-s.c; err != io.EOF {
1171 t.Errorf("Got %v at server, want io.EOF", err)
1172 }
1173 // The client Send should have failed since the RPC has been
1174 // terminated.
1175 if err := <-c; err == nil {
1176 t.Errorf("Client Send should fail as the server should have closed the flow")
1177 }
1178}
1179
1180// TestConnectWithIncompatibleServers tests that clients ignore incompatible endpoints.
1181func TestConnectWithIncompatibleServers(t *testing.T) {
Ankure49a86a2014-11-11 18:52:43 -08001182 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), &testServer{})
Bogdan Caprita27953142014-05-12 11:41:42 -07001183 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001184
1185 // Publish some incompatible endpoints.
Matt Rosencrantzbf85d542014-08-22 13:31:14 -07001186 publisher := publisher.New(testContext(), b.ns, publishPeriod)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001187 defer publisher.WaitForStop()
1188 defer publisher.Stop()
1189 publisher.AddName("incompatible")
David Why Use Two When One Will Do Presotto3da1c792014-10-03 11:15:53 -07001190 publisher.AddServer("/@2@tcp@localhost:10000@@1000000@2000000@@", false)
1191 publisher.AddServer("/@2@tcp@localhost:10001@@2000000@3000000@@", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001192
Matt Rosencrantz89445a42015-01-05 13:32:37 -08001193 ctx, _ := context.WithTimeout(testContext(), 100*time.Millisecond)
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -08001194
1195 _, err := b.client.StartCall(ctx, "incompatible/suffix", "Echo", []interface{}{"foo"})
1196 if !verror.Is(err, verror.NoServers.ID) {
1197 t.Errorf("Expected error %s, found: %v", verror.NoServers, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001198 }
1199
1200 // 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 -07001201 publisher.AddServer("/"+b.ep.String(), false)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -07001202 publisher.AddName("incompatible")
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001203
Matt Rosencrantzbf85d542014-08-22 13:31:14 -07001204 call, err := b.client.StartCall(testContext(), "incompatible/suffix", "Echo", []interface{}{"foo"})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001205 if err != nil {
Asim Shankar3a8a7e22014-05-12 18:01:44 -07001206 t.Fatal(err)
1207 }
1208 var result string
1209 if err = call.Finish(&result); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001210 t.Errorf("Unexpected error finishing call %v", err)
1211 }
Asim Shankar3a8a7e22014-05-12 18:01:44 -07001212 expected := `method:"Echo",suffix:"suffix",arg:"foo"`
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001213 if result != expected {
1214 t.Errorf("Wrong result returned. Got %s, wanted %s", result, expected)
1215 }
1216}
1217
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001218func TestPreferredAddress(t *testing.T) {
1219 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
1220 defer sm.Shutdown()
Matt Rosencrantz9fe60822014-09-12 10:09:53 -07001221 ns := tnaming.NewSimpleNamespace()
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -07001222 pa := func(string, []ipc.Address) ([]ipc.Address, error) {
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001223 a := &net.IPAddr{}
1224 a.IP = net.ParseIP("1.1.1.1")
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -07001225 return []ipc.Address{&netstate.AddrIfc{Addr: a}}, nil
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001226 }
Ankure49a86a2014-11-11 18:52:43 -08001227 server, err := InternalNewServer(testContext(), sm, ns, nil, vc.LocalPrincipal{tsecurity.NewPrincipal("server")})
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001228 if err != nil {
1229 t.Errorf("InternalNewServer failed: %v", err)
1230 }
1231 defer server.Stop()
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001232
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -08001233 spec := ipc.ListenSpec{
1234 Addrs: ipc.ListenAddrs{{"tcp", ":0"}},
1235 AddressChooser: pa,
1236 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001237 eps, err := server.Listen(spec)
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -08001238 if err != nil {
1239 t.Errorf("unexpected error: %s", err)
1240 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001241 iep := eps[0].(*inaming.Endpoint)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001242 host, _, err := net.SplitHostPort(iep.Address)
1243 if err != nil {
1244 t.Errorf("unexpected error: %s", err)
1245 }
1246 if got, want := host, "1.1.1.1"; got != want {
1247 t.Errorf("got %q, want %q", got, want)
1248 }
1249 // Won't override the specified address.
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001250 eps, err = server.Listen(listenSpec)
1251 iep = eps[0].(*inaming.Endpoint)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001252 host, _, err = net.SplitHostPort(iep.Address)
1253 if err != nil {
1254 t.Errorf("unexpected error: %s", err)
1255 }
1256 if got, want := host, "127.0.0.1"; got != want {
1257 t.Errorf("got %q, want %q", got, want)
1258 }
1259}
1260
1261func TestPreferredAddressErrors(t *testing.T) {
1262 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
1263 defer sm.Shutdown()
Matt Rosencrantz9fe60822014-09-12 10:09:53 -07001264 ns := tnaming.NewSimpleNamespace()
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -07001265 paerr := func(_ string, a []ipc.Address) ([]ipc.Address, error) {
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001266 return nil, fmt.Errorf("oops")
1267 }
Ankure49a86a2014-11-11 18:52:43 -08001268 server, err := InternalNewServer(testContext(), sm, ns, nil, vc.LocalPrincipal{tsecurity.NewPrincipal("server")})
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001269 if err != nil {
1270 t.Errorf("InternalNewServer failed: %v", err)
1271 }
1272 defer server.Stop()
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -08001273 spec := ipc.ListenSpec{
1274 Addrs: ipc.ListenAddrs{{"tcp", ":0"}},
1275 AddressChooser: paerr,
1276 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001277 eps, err := server.Listen(spec)
1278 iep := eps[0].(*inaming.Endpoint)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001279 host, _, err := net.SplitHostPort(iep.Address)
1280 if err != nil {
1281 t.Errorf("unexpected error: %s", err)
1282 }
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -07001283 ip := net.ParseIP(host)
1284 if ip == nil {
1285 t.Fatalf("failed to parse IP address: %q", host)
1286 }
1287 if !ip.IsUnspecified() {
1288 t.Errorf("IP: %q is not unspecified", ip)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001289 }
1290}
1291
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001292func TestSecurityNone(t *testing.T) {
1293 sm := imanager.InternalNew(naming.FixedRoutingID(0x66666666))
1294 defer sm.Shutdown()
1295 ns := tnaming.NewSimpleNamespace()
Matt Rosencrantz3e76f282014-11-10 09:38:57 -08001296 server, err := InternalNewServer(testContext(), sm, ns, nil, options.VCSecurityNone)
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001297 if err != nil {
1298 t.Fatalf("InternalNewServer failed: %v", err)
1299 }
1300 if _, err = server.Listen(listenSpec); err != nil {
1301 t.Fatalf("server.Listen failed: %v", err)
1302 }
1303 disp := &testServerDisp{&testServer{}}
Cosmos Nicolaou92dba582014-11-05 17:24:10 -08001304 if err := server.ServeDispatcher("mp/server", disp); err != nil {
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001305 t.Fatalf("server.Serve failed: %v", err)
1306 }
1307 client, err := InternalNewClient(sm, ns, options.VCSecurityNone)
1308 if err != nil {
1309 t.Fatalf("InternalNewClient failed: %v", err)
1310 }
1311 // When using VCSecurityNone, all authorization checks should be skipped, so
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001312 // unauthorized methods should be callable.
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001313 call, err := client.StartCall(testContext(), "mp/server", "Unauthorized", nil)
1314 if err != nil {
1315 t.Fatalf("client.StartCall failed: %v", err)
1316 }
1317 var got string
1318 var ierr error
1319 if err := call.Finish(&got, &ierr); err != nil {
1320 t.Errorf("call.Finish failed: %v", err)
1321 }
1322 if want := "UnauthorizedResult"; got != want {
1323 t.Errorf("got (%v), want (%v)", got, want)
1324 }
1325}
1326
Matt Rosencrantz321a51d2014-10-30 10:37:56 -07001327func TestCallWithNilContext(t *testing.T) {
1328 sm := imanager.InternalNew(naming.FixedRoutingID(0x66666666))
1329 defer sm.Shutdown()
1330 ns := tnaming.NewSimpleNamespace()
1331 client, err := InternalNewClient(sm, ns, options.VCSecurityNone)
1332 if err != nil {
1333 t.Fatalf("InternalNewClient failed: %v", err)
1334 }
1335 call, err := client.StartCall(nil, "foo", "bar", []interface{}{})
1336 if call != nil {
1337 t.Errorf("Expected nil interface got: %#v", call)
1338 }
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -08001339 if !verror.Is(err, verror.BadArg.ID) {
1340 t.Errorf("Expected an BadArg error, got: %s", err.Error())
Matt Rosencrantz321a51d2014-10-30 10:37:56 -07001341 }
1342}
1343
Asim Shankara5b60b22014-11-06 15:37:07 -08001344func TestServerBlessingsOpt(t *testing.T) {
1345 var (
Ankure49a86a2014-11-11 18:52:43 -08001346 pserver = tsecurity.NewPrincipal("server")
1347 pclient = tsecurity.NewPrincipal("client")
Asim Shankara5b60b22014-11-06 15:37:07 -08001348 batman, _ = pserver.BlessSelf("batman")
1349 )
1350 // Make the client recognize all server blessings
1351 if err := pclient.AddToRoots(batman); err != nil {
1352 t.Fatal(err)
1353 }
1354 if err := pclient.AddToRoots(pserver.BlessingStore().Default()); err != nil {
1355 t.Fatal(err)
1356 }
1357 // Start a server that uses the ServerBlessings option to configure itself
1358 // to act as batman (as opposed to using the default blessing).
1359 ns := tnaming.NewSimpleNamespace()
1360 runServer := func(name string, opts ...ipc.ServerOpt) stream.Manager {
1361 opts = append(opts, vc.LocalPrincipal{pserver})
1362 rid, err := naming.NewRoutingID()
1363 if err != nil {
1364 t.Fatal(err)
1365 }
1366 sm := imanager.InternalNew(rid)
1367 server, err := InternalNewServer(
1368 testContext(),
1369 sm,
1370 ns,
Matt Rosencrantz3e76f282014-11-10 09:38:57 -08001371 nil,
Asim Shankara5b60b22014-11-06 15:37:07 -08001372 opts...)
1373 if err != nil {
1374 t.Fatal(err)
1375 }
1376 if _, err := server.Listen(listenSpec); err != nil {
1377 t.Fatal(err)
1378 }
1379 if err := server.Serve(name, &testServer{}, nil); err != nil {
1380 t.Fatal(err)
1381 }
1382 return sm
1383 }
1384
1385 defer runServer("mountpoint/batman", options.ServerBlessings{batman}).Shutdown()
1386 defer runServer("mountpoint/default").Shutdown()
1387
1388 // And finally, make and RPC and see that the client sees "batman"
1389 runClient := func(server string) ([]string, error) {
1390 smc := imanager.InternalNew(naming.FixedRoutingID(0xc))
1391 defer smc.Shutdown()
1392 client, err := InternalNewClient(
1393 smc,
1394 ns,
1395 vc.LocalPrincipal{pclient})
1396 if err != nil {
1397 return nil, err
1398 }
1399 defer client.Close()
1400 call, err := client.StartCall(testContext(), server, "Closure", nil)
1401 if err != nil {
1402 return nil, err
1403 }
1404 blessings, _ := call.RemoteBlessings()
1405 return blessings, nil
1406 }
1407
1408 // When talking to mountpoint/batman, should see "batman"
1409 // When talking to mountpoint/default, should see "server"
1410 if got, err := runClient("mountpoint/batman"); err != nil || len(got) != 1 || got[0] != "batman" {
1411 t.Errorf("Got (%v, %v) wanted 'batman'", got, err)
1412 }
1413 if got, err := runClient("mountpoint/default"); err != nil || len(got) != 1 || got[0] != "server" {
1414 t.Errorf("Got (%v, %v) wanted 'server'", got, err)
1415 }
1416}
1417
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001418type mockDischarger struct {
Matt Rosencrantze3464f12014-11-25 17:54:02 -08001419 mu sync.Mutex
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001420 called bool
1421}
1422
1423func (m *mockDischarger) Discharge(ctx ipc.ServerContext, caveatAny vdlutil.Any, _ security.DischargeImpetus) (vdlutil.Any, error) {
Matt Rosencrantze3464f12014-11-25 17:54:02 -08001424 m.mu.Lock()
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001425 m.called = true
Matt Rosencrantze3464f12014-11-25 17:54:02 -08001426 m.mu.Unlock()
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001427 caveat, ok := caveatAny.(security.ThirdPartyCaveat)
1428 if !ok {
1429 return nil, fmt.Errorf("type %T does not implement security.ThirdPartyCaveat", caveatAny)
1430 }
1431 return ctx.LocalPrincipal().MintDischarge(caveat, security.UnconstrainedUse())
1432}
1433
1434func TestNoDischargesOpt(t *testing.T) {
1435 var (
1436 pdischarger = tsecurity.NewPrincipal("discharger")
1437 pserver = tsecurity.NewPrincipal("server")
1438 pclient = tsecurity.NewPrincipal("client")
1439 )
1440 // Make the client recognize all server blessings
1441 if err := pclient.AddToRoots(pserver.BlessingStore().Default()); err != nil {
1442 t.Fatal(err)
1443 }
1444 if err := pclient.AddToRoots(pdischarger.BlessingStore().Default()); err != nil {
1445 t.Fatal(err)
1446 }
1447
1448 // Bless the client with a ThirdPartyCaveat.
1449 tpcav := mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1450 blessings, err := pserver.Bless(pclient.PublicKey(), pserver.BlessingStore().Default(), "tpcav", tpcav)
1451 if err != nil {
1452 t.Fatalf("failed to create Blessings: %v", err)
1453 }
1454 if _, err = pclient.BlessingStore().Set(blessings, "server"); err != nil {
1455 t.Fatalf("failed to set blessings: %v", err)
1456 }
1457
1458 ns := tnaming.NewSimpleNamespace()
1459 runServer := func(name string, obj interface{}, principal security.Principal) stream.Manager {
1460 rid, err := naming.NewRoutingID()
1461 if err != nil {
1462 t.Fatal(err)
1463 }
1464 sm := imanager.InternalNew(rid)
1465 server, err := InternalNewServer(testContext(), sm, ns, nil, vc.LocalPrincipal{principal})
1466 if err != nil {
1467 t.Fatal(err)
1468 }
1469 if _, err := server.Listen(listenSpec); err != nil {
1470 t.Fatal(err)
1471 }
1472 if err := server.Serve(name, obj, acceptAllAuthorizer{}); err != nil {
1473 t.Fatal(err)
1474 }
1475 return sm
1476 }
1477
1478 // Setup the disharger and test server.
1479 discharger := &mockDischarger{}
1480 defer runServer("mountpoint/discharger", discharger, pdischarger).Shutdown()
1481 defer runServer("mountpoint/testServer", &testServer{}, pserver).Shutdown()
1482
1483 runClient := func(noDischarges bool) {
1484 rid, err := naming.NewRoutingID()
1485 if err != nil {
1486 t.Fatal(err)
1487 }
1488 smc := imanager.InternalNew(rid)
1489 defer smc.Shutdown()
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001490 client, err := InternalNewClient(smc, ns, vc.LocalPrincipal{pclient})
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001491 if err != nil {
1492 t.Fatalf("failed to create client: %v", err)
1493 }
1494 defer client.Close()
1495 var opts []ipc.CallOpt
1496 if noDischarges {
1497 opts = append(opts, vc.NoDischarges{})
1498 }
1499 if _, err = client.StartCall(testContext(), "mountpoint/testServer", "Closure", nil, opts...); err != nil {
1500 t.Fatalf("failed to StartCall: %v", err)
1501 }
1502 }
1503
1504 // Test that when the NoDischarges option is set, mockDischarger does not get called.
1505 if runClient(true); discharger.called {
1506 t.Errorf("did not expect discharger to be called")
1507 }
1508 discharger.called = false
1509 // Test that when the Nodischarges option is not set, mockDischarger does get called.
1510 if runClient(false); !discharger.called {
1511 t.Errorf("expected discharger to be called")
1512 }
1513}
1514
1515func TestNoImplicitDischargeFetching(t *testing.T) {
1516 // This test ensures that discharge clients only fetch discharges for the specified tp caveats and not its own.
1517 var (
1518 pdischarger1 = tsecurity.NewPrincipal("discharger1")
1519 pdischarger2 = tsecurity.NewPrincipal("discharger2")
1520 pdischargeClient = tsecurity.NewPrincipal("dischargeClient")
1521 )
1522
1523 // Bless the client with a ThirdPartyCaveat from discharger1.
1524 tpcav1 := mkThirdPartyCaveat(pdischarger1.PublicKey(), "mountpoint/discharger1", mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1525 blessings, err := pdischarger1.Bless(pdischargeClient.PublicKey(), pdischarger1.BlessingStore().Default(), "tpcav1", tpcav1)
1526 if err != nil {
1527 t.Fatalf("failed to create Blessings: %v", err)
1528 }
1529 if err = pdischargeClient.BlessingStore().SetDefault(blessings); err != nil {
1530 t.Fatalf("failed to set blessings: %v", err)
1531 }
1532
1533 ns := tnaming.NewSimpleNamespace()
1534 runServer := func(name string, obj interface{}, principal security.Principal) stream.Manager {
1535 rid, err := naming.NewRoutingID()
1536 if err != nil {
1537 t.Fatal(err)
1538 }
1539 sm := imanager.InternalNew(rid)
1540 server, err := InternalNewServer(testContext(), sm, ns, nil, vc.LocalPrincipal{principal})
1541 if err != nil {
1542 t.Fatal(err)
1543 }
1544 if _, err := server.Listen(listenSpec); err != nil {
1545 t.Fatal(err)
1546 }
1547 if err := server.Serve(name, obj, acceptAllAuthorizer{}); err != nil {
1548 t.Fatal(err)
1549 }
1550 return sm
1551 }
1552
1553 // Setup the disharger and test server.
1554 discharger1 := &mockDischarger{}
1555 discharger2 := &mockDischarger{}
1556 defer runServer("mountpoint/discharger1", discharger1, pdischarger1).Shutdown()
1557 defer runServer("mountpoint/discharger2", discharger2, pdischarger2).Shutdown()
1558
1559 rid, err := naming.NewRoutingID()
1560 if err != nil {
1561 t.Fatal(err)
1562 }
1563 sm := imanager.InternalNew(rid)
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001564
1565 c, err := InternalNewClient(sm, ns, vc.LocalPrincipal{pdischargeClient})
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001566 if err != nil {
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001567 t.Fatalf("failed to create client: %v", err)
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001568 }
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001569 dc := c.(*client).dc
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001570 tpcav2, err := security.NewPublicKeyCaveat(pdischarger2.PublicKey(), "mountpoint/discharger2", security.ThirdPartyRequirements{}, mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1571 if err != nil {
1572 t.Error(err)
1573 }
Asim Shankarf4864f42014-11-25 18:53:05 -08001574 dc.PrepareDischarges(testContext(), []security.ThirdPartyCaveat{tpcav2}, security.DischargeImpetus{})
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001575
1576 // Ensure that discharger1 was not called and discharger2 was called.
1577 if discharger1.called {
1578 t.Errorf("discharge for caveat on discharge client should not have been fetched.")
1579 }
1580 if !discharger2.called {
1581 t.Errorf("discharge for caveat passed to PrepareDischarges should have been fetched.")
1582 }
1583}
1584
Suharsh Sivakumar720b7042014-12-22 17:33:23 -08001585// TestBlessingsCache tests that the VCCache is used to sucessfully used to cache duplicate
1586// calls blessings.
1587func TestBlessingsCache(t *testing.T) {
1588 var (
1589 pserver = tsecurity.NewPrincipal("server")
1590 pclient = tsecurity.NewPrincipal("client")
1591 )
1592 // Make the client recognize all server blessings
1593 if err := pclient.AddToRoots(pserver.BlessingStore().Default()); err != nil {
1594 t.Fatal(err)
1595 }
1596
1597 ns := tnaming.NewSimpleNamespace()
1598 rid, err := naming.NewRoutingID()
1599 if err != nil {
1600 t.Fatal(err)
1601 }
1602 runServer := func(principal security.Principal, rid naming.RoutingID) (ipc.Server, stream.Manager, naming.Endpoint) {
1603 sm := imanager.InternalNew(rid)
1604 server, err := InternalNewServer(testContext(), sm, ns, nil, vc.LocalPrincipal{principal})
1605 if err != nil {
1606 t.Fatal(err)
1607 }
1608 ep, err := server.Listen(listenSpec)
1609 if err != nil {
1610 t.Fatal(err)
1611 }
1612 return server, sm, ep[0]
1613 }
1614
1615 server, serverSM, serverEP := runServer(pserver, rid)
1616 go server.Serve("mountpoint/testServer", &testServer{}, acceptAllAuthorizer{})
1617 defer serverSM.Shutdown()
1618
1619 newClient := func() ipc.Client {
1620 rid, err := naming.NewRoutingID()
1621 if err != nil {
1622 t.Fatal(err)
1623 }
1624 smc := imanager.InternalNew(rid)
1625 defer smc.Shutdown()
1626 client, err := InternalNewClient(smc, ns, vc.LocalPrincipal{pclient})
1627 if err != nil {
1628 t.Fatalf("failed to create client: %v", err)
1629 }
1630 return client
1631 }
1632
1633 runClient := func(client ipc.Client) {
1634 var call ipc.Call
1635 if call, err = client.StartCall(testContext(), "/"+serverEP.String(), "Closure", nil); err != nil {
1636 t.Fatalf("failed to StartCall: %v", err)
1637 }
1638 if err := call.Finish(); err != nil {
1639 t.Fatal(err)
1640 }
1641 }
1642
1643 cachePrefix := naming.Join("ipc", "server", "routing-id", rid.String(), "security", "blessings", "cache")
1644 cacheHits, err := stats.GetStatsObject(naming.Join(cachePrefix, "hits"))
1645 if err != nil {
1646 t.Fatal(err)
1647 }
1648 cacheAttempts, err := stats.GetStatsObject(naming.Join(cachePrefix, "attempts"))
1649 if err != nil {
1650 t.Fatal(err)
1651 }
1652
1653 // Check that the blessings cache is not used on the first call.
1654 clientA := newClient()
1655 runClient(clientA)
1656 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 1 || gotHits != 0 {
1657 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(1), cacheHits(0)", gotAttempts, gotHits)
1658 }
1659 // Check that the cache is hit on the second call with the same blessings.
1660 runClient(clientA)
1661 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 2 || gotHits != 1 {
1662 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(2), cacheHits(1)", gotAttempts, gotHits)
1663 }
1664 clientA.Close()
1665 // Check that the cache is not used with a different client.
1666 clientB := newClient()
1667 runClient(clientB)
1668 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 3 || gotHits != 1 {
1669 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(3), cacheHits(1)", gotAttempts, gotHits)
1670 }
1671 // clientB changes its blessings, the cache should not be used.
1672 blessings, err := pserver.Bless(pclient.PublicKey(), pserver.BlessingStore().Default(), "cav", mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1673 if err != nil {
1674 t.Fatalf("failed to create Blessings: %v", err)
1675 }
1676 if _, err = pclient.BlessingStore().Set(blessings, "server"); err != nil {
1677 t.Fatalf("failed to set blessings: %v", err)
1678 }
1679 runClient(clientB)
1680 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 4 || gotHits != 1 {
1681 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(4), cacheHits(1)", gotAttempts, gotHits)
1682 }
1683 clientB.Close()
1684}
1685
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001686func init() {
Asim Shankarc920db32014-10-16 19:18:21 -07001687 testutil.Init()
Todd Wang34ed4c62014-11-26 15:15:52 -08001688 vdlutil.Register(fakeTimeCaveat(0))
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001689}