blob: a9c9702bdaaeb60288534c7dad0decfc1dcea3d0 [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 Nicolaou9388ae42014-11-10 10:57:15 -08009 "path/filepath"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070010 "reflect"
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -080011 "runtime"
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -080012 "sort"
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 Simsa6ac95222015-02-23 16:11:49 -080018 "v.io/v23/context"
19 "v.io/v23/ipc"
20 "v.io/v23/naming"
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -080021 "v.io/v23/naming/ns"
Jiri Simsa6ac95222015-02-23 16:11:49 -080022 "v.io/v23/options"
23 "v.io/v23/security"
24 "v.io/v23/services/security/access"
25 "v.io/v23/uniqueid"
26 "v.io/v23/vdl"
27 "v.io/v23/verror"
Jiri Simsa6ac95222015-02-23 16:11:49 -080028 "v.io/v23/vtrace"
Jiri Simsa337af232015-02-27 14:36:46 -080029 "v.io/x/lib/vlog"
Jiri Simsaffceefa2015-02-28 11:03:34 -080030 "v.io/x/ref/runtimes/google/ipc/stream"
Cosmos Nicolaouf889c732014-10-16 20:46:54 -070031
Jiri Simsaffceefa2015-02-28 11:03:34 -080032 "v.io/x/ref/lib/flags"
33 "v.io/x/ref/lib/netstate"
34 "v.io/x/ref/lib/stats"
35 "v.io/x/ref/lib/testutil"
36 tsecurity "v.io/x/ref/lib/testutil/security"
37 _ "v.io/x/ref/runtimes/google/ipc/protocols/tcp"
38 imanager "v.io/x/ref/runtimes/google/ipc/stream/manager"
39 "v.io/x/ref/runtimes/google/ipc/stream/vc"
40 "v.io/x/ref/runtimes/google/lib/publisher"
41 inaming "v.io/x/ref/runtimes/google/naming"
42 tnaming "v.io/x/ref/runtimes/google/testing/mocks/naming"
43 ivtrace "v.io/x/ref/runtimes/google/vtrace"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070044)
45
Suharsh Sivakumard19c95d2015-02-19 14:44:50 -080046//go:generate v23 test generate
47
Jiri Simsa5293dcb2014-05-10 09:56:38 -070048var (
Jiri Simsa074bf362015-02-17 09:29:45 -080049 errMethod = verror.New(verror.ErrAborted, nil)
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080050 clock = new(fakeClock)
51 listenAddrs = ipc.ListenAddrs{{"tcp", "127.0.0.1:0"}}
52 listenWSAddrs = ipc.ListenAddrs{{"ws", "127.0.0.1:0"}, {"tcp", "127.0.0.1:0"}}
53 listenSpec = ipc.ListenSpec{Addrs: listenAddrs}
54 listenWSSpec = ipc.ListenSpec{Addrs: listenWSAddrs}
Jiri Simsa5293dcb2014-05-10 09:56:38 -070055)
56
Andres Erbsenb7f95f32014-07-07 12:07:56 -070057type fakeClock struct {
58 sync.Mutex
59 time int
60}
61
62func (c *fakeClock) Now() int {
63 c.Lock()
64 defer c.Unlock()
65 return c.time
66}
67
68func (c *fakeClock) Advance(steps uint) {
69 c.Lock()
70 c.time += int(steps)
71 c.Unlock()
72}
73
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -080074func testContextWithoutDeadline() *context.T {
Matt Rosencrantz1094d062015-01-30 06:43:12 -080075 ctx, _ := context.RootContext()
Matt Rosencrantzf7b00e22015-01-13 13:44:56 -080076 ctx, err := ivtrace.Init(ctx, flags.VtraceFlags{})
77 if err != nil {
78 panic(err)
79 }
Matt Rosencrantz5f98d942015-01-08 13:48:30 -080080 ctx, _ = vtrace.SetNewTrace(ctx)
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -080081 return ctx
82}
83
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -080084func testInternalNewServer(ctx *context.T, streamMgr stream.Manager, ns ns.Namespace, opts ...ipc.ServerOpt) (ipc.Server, error) {
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -080085 client, err := InternalNewClient(streamMgr, ns)
86 if err != nil {
87 return nil, err
88 }
89 return InternalNewServer(ctx, streamMgr, ns, client, opts...)
90}
91
Jiri Simsa5293dcb2014-05-10 09:56:38 -070092type userType string
93
94type testServer struct{}
95
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -080096func (*testServer) Closure(ctx ipc.ServerCall) error {
Todd Wange77f9952015-02-18 13:20:50 -080097 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -070098}
99
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -0800100func (*testServer) Error(ctx ipc.ServerCall) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700101 return errMethod
102}
103
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -0800104func (*testServer) Echo(ctx ipc.ServerCall, arg string) (string, error) {
Todd Wange77f9952015-02-18 13:20:50 -0800105 return fmt.Sprintf("method:%q,suffix:%q,arg:%q", ctx.Method(), ctx.Suffix(), arg), nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700106}
107
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -0800108func (*testServer) EchoUser(ctx ipc.ServerCall, arg string, u userType) (string, userType, error) {
Todd Wange77f9952015-02-18 13:20:50 -0800109 return fmt.Sprintf("method:%q,suffix:%q,arg:%q", ctx.Method(), ctx.Suffix(), arg), u, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700110}
111
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -0800112func (*testServer) EchoBlessings(ctx ipc.ServerCall) (server, client string, _ error) {
113 local, _ := ctx.LocalBlessings().ForCall(ctx)
114 remote, _ := ctx.RemoteBlessings().ForCall(ctx)
Todd Wange77f9952015-02-18 13:20:50 -0800115 return fmt.Sprintf("%v", local), fmt.Sprintf("%v", remote), nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700116}
117
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -0800118func (*testServer) EchoGrantedBlessings(ctx ipc.ServerCall, arg string) (result, blessing string, _ error) {
Suharsh Sivakumar380bf342015-02-27 15:38:27 -0800119 return arg, fmt.Sprintf("%v", ctx.GrantedBlessings()), nil
Asim Shankarb54d7642014-06-05 13:08:04 -0700120}
121
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -0800122func (*testServer) EchoAndError(ctx ipc.ServerCall, arg string) (string, error) {
Todd Wang1fe7cdd2014-11-12 12:51:49 -0800123 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
Matt Rosencrantz1dcd0a92015-02-27 11:05:59 -0800130func (*testServer) Stream(call ipc.StreamServerCall, arg string) (string, error) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700131 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
Matt Rosencrantz1dcd0a92015-02-27 11:05:59 -0800146func (*testServer) Unauthorized(ipc.StreamServerCall) (string, error) {
Todd Wange77f9952015-02-18 13:20:50 -0800147 return "UnauthorizedResult", nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700148}
149
150type testServerAuthorizer struct{}
151
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -0800152func (testServerAuthorizer) Authorize(c security.Call) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700153 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 Shankar68885192014-11-26 12:48:35 -0800171 authorizer = &access.ACL{
Ankur78b8b2a2015-02-04 20:16:28 -0800172 In: []security.BlessingPattern{"client", "server"},
Asim Shankar68885192014-11-26 12:48:35 -0800173 }
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700174 default:
175 authorizer = testServerAuthorizer{}
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700176 }
Cosmos Nicolaou710daa22014-11-11 19:39:18 -0800177 return t.server, authorizer, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700178}
179
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800180type dischargeServer struct {
181 mu sync.Mutex
182 called bool
183}
Ankure49a86a2014-11-11 18:52:43 -0800184
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800185func (ds *dischargeServer) Discharge(ctx ipc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.WireDischarge, error) {
186 ds.mu.Lock()
187 ds.called = true
188 ds.mu.Unlock()
Asim Shankar19da8182015-02-06 01:41:16 -0800189 tp := cav.ThirdPartyDetails()
190 if tp == nil {
191 return nil, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav)
Ankure49a86a2014-11-11 18:52:43 -0800192 }
Asim Shankar19da8182015-02-06 01:41:16 -0800193 if err := tp.Dischargeable(ctx); err != nil {
Asim Shankar7283dd82015-02-03 19:35:58 -0800194 return nil, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err)
Ankure49a86a2014-11-11 18:52:43 -0800195 }
196 // Add a fakeTimeCaveat to be able to control discharge expiration via 'clock'.
Asim Shankar7283dd82015-02-03 19:35:58 -0800197 expiry, err := security.NewCaveat(fakeTimeCaveat, clock.Now())
198 if err != nil {
199 return nil, fmt.Errorf("failed to create an expiration on the discharge: %v", err)
200 }
Asim Shankaref951492015-02-11 11:41:03 -0800201 d, err := ctx.LocalPrincipal().MintDischarge(cav, expiry)
202 if err != nil {
203 return nil, err
204 }
205 return security.MarshalDischarge(d), nil
Ankure49a86a2014-11-11 18:52:43 -0800206}
207
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -0800208func startServer(t *testing.T, principal security.Principal, sm stream.Manager, ns ns.Namespace, name string, disp ipc.Dispatcher, opts ...ipc.ServerOpt) (naming.Endpoint, ipc.Server) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800209 return startServerWS(t, principal, sm, ns, name, disp, noWebsocket, opts...)
210}
211
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -0800212func endpointsToStrings(eps []naming.Endpoint) []string {
213 r := make([]string, len(eps))
214 for i, e := range eps {
215 r[i] = e.String()
216 }
217 sort.Strings(r)
218 return r
219}
220
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -0800221func startServerWS(t *testing.T, principal security.Principal, sm stream.Manager, ns ns.Namespace, name string, disp ipc.Dispatcher, shouldUseWebsocket websocketMode, opts ...ipc.ServerOpt) (naming.Endpoint, ipc.Server) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700222 vlog.VI(1).Info("InternalNewServer")
Ankure49a86a2014-11-11 18:52:43 -0800223 opts = append(opts, vc.LocalPrincipal{principal})
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800224 ctx := testContext()
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -0800225 server, err := testInternalNewServer(ctx, sm, ns, opts...)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700226 if err != nil {
227 t.Errorf("InternalNewServer failed: %v", err)
228 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700229 vlog.VI(1).Info("server.Listen")
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800230 spec := listenSpec
231 if shouldUseWebsocket {
232 spec = listenWSSpec
233 }
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -0800234 eps, err := server.Listen(spec)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700235 if err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700236 t.Errorf("server.Listen failed: %v", err)
237 }
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700238 vlog.VI(1).Info("server.Serve")
Ankure49a86a2014-11-11 18:52:43 -0800239 if err := server.ServeDispatcher(name, disp); err != nil {
240 t.Errorf("server.ServeDispatcher failed: %v", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700241 }
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -0800242
243 status := server.Status()
244 if got, want := endpointsToStrings(status.Endpoints), endpointsToStrings(eps); !reflect.DeepEqual(got, want) {
245 t.Fatalf("got %v, want %v", got, want)
246 }
247 names := status.Mounts.Names()
248 if len(names) != 1 || names[0] != name {
249 t.Fatalf("unexpected names: %v", names)
250 }
251 return eps[0], server
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700252}
253
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -0800254func loc(d int) string {
255 _, file, line, _ := runtime.Caller(d + 1)
256 return fmt.Sprintf("%s:%d", filepath.Base(file), line)
257}
258
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -0800259func verifyMount(t *testing.T, ns ns.Namespace, name string) []string {
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -0800260 me, err := ns.Resolve(testContext(), name)
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -0800261 if err != nil {
262 t.Errorf("%s: %s not found in mounttable", loc(1), name)
263 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700264 }
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800265 return me.Names()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700266}
267
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -0800268func verifyMountMissing(t *testing.T, ns ns.Namespace, name string) {
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -0800269 if me, err := ns.Resolve(testContext(), name); err == nil {
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800270 names := me.Names()
Asim Shankarb547ea92015-02-17 18:49:45 -0800271 t.Errorf("%s: %s not supposed to be found in mounttable; got %d servers instead: %v (%+v)", loc(1), name, len(names), names, me)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700272 }
273}
274
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -0800275func stopServer(t *testing.T, server ipc.Server, ns ns.Namespace, name string) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700276 vlog.VI(1).Info("server.Stop")
Ankure49a86a2014-11-11 18:52:43 -0800277 new_name := "should_appear_in_mt/server"
278 verifyMount(t, ns, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700279
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700280 // publish a second name
Ankure49a86a2014-11-11 18:52:43 -0800281 if err := server.AddName(new_name); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700282 t.Errorf("server.Serve failed: %v", err)
283 }
Ankure49a86a2014-11-11 18:52:43 -0800284 verifyMount(t, ns, new_name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700285
286 if err := server.Stop(); err != nil {
287 t.Errorf("server.Stop failed: %v", err)
288 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700289
Ankure49a86a2014-11-11 18:52:43 -0800290 verifyMountMissing(t, ns, name)
291 verifyMountMissing(t, ns, new_name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700292
293 // Check that we can no longer serve after Stop.
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800294 err := server.AddName("name doesn't matter")
Jiri Simsa074bf362015-02-17 09:29:45 -0800295 if err == nil || !verror.Is(err, verror.ErrBadState.ID) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700296 t.Errorf("either no error, or a wrong error was returned: %v", err)
297 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700298 vlog.VI(1).Info("server.Stop DONE")
299}
300
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800301// fakeWSName creates a name containing a endpoint address that forces
302// the use of websockets. It does so by resolving the original name
303// and choosing the 'ws' endpoint from the set of endpoints returned.
304// It must return a name since it'll be passed to StartCall.
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -0800305func fakeWSName(ns ns.Namespace, name string) (string, error) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800306 // Find the ws endpoint and use that.
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -0800307 me, err := ns.Resolve(testContext(), name)
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800308 if err != nil {
309 return "", err
310 }
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800311 names := me.Names()
312 for _, s := range names {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800313 if strings.Index(s, "@ws@") != -1 {
314 return s, nil
315 }
316 }
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800317 return "", fmt.Errorf("No ws endpoint found %v", names)
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800318}
319
Bogdan Caprita27953142014-05-12 11:41:42 -0700320type bundle struct {
321 client ipc.Client
322 server ipc.Server
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700323 ep naming.Endpoint
David Why Use Two When One Will Do Presottod424c212015-02-25 11:05:26 -0800324 ns ns.Namespace
Bogdan Caprita27953142014-05-12 11:41:42 -0700325 sm stream.Manager
Ankure49a86a2014-11-11 18:52:43 -0800326 name string
Bogdan Caprita27953142014-05-12 11:41:42 -0700327}
328
329func (b bundle) cleanup(t *testing.T) {
Ankura3c97652014-07-17 20:01:21 -0700330 if b.server != nil {
Ankure49a86a2014-11-11 18:52:43 -0800331 stopServer(t, b.server, b.ns, b.name)
Ankura3c97652014-07-17 20:01:21 -0700332 }
333 if b.client != nil {
334 b.client.Close()
335 }
Bogdan Caprita27953142014-05-12 11:41:42 -0700336}
337
Asim Shankar8f05c222014-10-06 22:08:19 -0700338func createBundle(t *testing.T, client, server security.Principal, ts interface{}) (b bundle) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800339 return createBundleWS(t, client, server, ts, noWebsocket)
340}
341
342func createBundleWS(t *testing.T, client, server security.Principal, ts interface{}, shouldUseWebsocket websocketMode) (b bundle) {
Bogdan Caprita27953142014-05-12 11:41:42 -0700343 b.sm = imanager.InternalNew(naming.FixedRoutingID(0x555555555))
Matt Rosencrantz9fe60822014-09-12 10:09:53 -0700344 b.ns = tnaming.NewSimpleNamespace()
Ankure49a86a2014-11-11 18:52:43 -0800345 b.name = "mountpoint/server"
Asim Shankar8f05c222014-10-06 22:08:19 -0700346 if server != nil {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800347 b.ep, b.server = startServerWS(t, server, b.sm, b.ns, b.name, testServerDisp{ts}, shouldUseWebsocket)
Ankura3c97652014-07-17 20:01:21 -0700348 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700349 if client != nil {
Ankura3c97652014-07-17 20:01:21 -0700350 var err error
Asim Shankar8f05c222014-10-06 22:08:19 -0700351 if b.client, err = InternalNewClient(b.sm, b.ns, vc.LocalPrincipal{client}); err != nil {
Ankura3c97652014-07-17 20:01:21 -0700352 t.Fatalf("InternalNewClient failed: %v", err)
353 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700354 }
Bogdan Caprita27953142014-05-12 11:41:42 -0700355 return
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700356}
357
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800358func matchesErrorPattern(err error, id verror.IDAction, pattern string) bool {
Asim Shankar558ea012015-01-28 12:49:36 -0800359 if len(pattern) > 0 && err != nil && strings.Index(err.Error(), pattern) < 0 {
360 return false
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700361 }
Cosmos Nicolaou1bce7d12015-01-05 17:42:06 -0800362 if err == nil && id.ID == "" {
363 return true
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800364 }
365 return verror.Is(err, id.ID)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700366}
367
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -0800368func runServer(t *testing.T, ns ns.Namespace, name string, obj interface{}, opts ...ipc.ServerOpt) stream.Manager {
369 rid, err := naming.NewRoutingID()
370 if err != nil {
371 t.Fatal(err)
372 }
373 sm := imanager.InternalNew(rid)
374 server, err := testInternalNewServer(testContext(), sm, ns, opts...)
375 if err != nil {
376 t.Fatal(err)
377 }
378 if _, err := server.Listen(listenSpec); err != nil {
379 t.Fatal(err)
380 }
381 if err := server.Serve(name, obj, acceptAllAuthorizer{}); err != nil {
382 t.Fatal(err)
383 }
384 return sm
385}
386
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800387func TestMultipleCallsToServeAndName(t *testing.T) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700388 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
Matt Rosencrantz9fe60822014-09-12 10:09:53 -0700389 ns := tnaming.NewSimpleNamespace()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800390 ctx := testContext()
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -0800391 server, err := testInternalNewServer(ctx, sm, ns, vc.LocalPrincipal{tsecurity.NewPrincipal()})
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700392 if err != nil {
393 t.Errorf("InternalNewServer failed: %v", err)
394 }
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -0700395 _, err = server.Listen(listenSpec)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700396 if err != nil {
397 t.Errorf("server.Listen failed: %v", err)
398 }
399
400 disp := &testServerDisp{&testServer{}}
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800401 if err := server.ServeDispatcher("mountpoint/server", disp); err != nil {
402 t.Errorf("server.ServeDispatcher failed: %v", err)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700403 }
404
405 n1 := "mountpoint/server"
406 n2 := "should_appear_in_mt/server"
407 n3 := "should_appear_in_mt/server"
408 n4 := "should_not_appear_in_mt/server"
409
410 verifyMount(t, ns, n1)
411
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800412 if server.ServeDispatcher(n2, disp) == nil {
413 t.Errorf("server.ServeDispatcher should have failed")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700414 }
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800415
416 if err := server.Serve(n2, &testServer{}, nil); err == nil {
417 t.Errorf("server.Serve should have failed")
418 }
419
420 if err := server.AddName(n3); err != nil {
421 t.Errorf("server.AddName failed: %v", err)
422 }
423
424 if err := server.AddName(n3); err != nil {
425 t.Errorf("server.AddName failed: %v", err)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700426 }
427 verifyMount(t, ns, n2)
428 verifyMount(t, ns, n3)
429
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -0800430 server.RemoveName(n1)
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800431 verifyMountMissing(t, ns, n1)
432
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -0800433 server.RemoveName("some randome name")
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800434
435 if err := server.ServeDispatcher(n4, &testServerDisp{&testServer{}}); err == nil {
436 t.Errorf("server.ServeDispatcher should have failed")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700437 }
438 verifyMountMissing(t, ns, n4)
439
440 if err := server.Stop(); err != nil {
441 t.Errorf("server.Stop failed: %v", err)
442 }
443
444 verifyMountMissing(t, ns, n1)
445 verifyMountMissing(t, ns, n2)
446 verifyMountMissing(t, ns, n3)
447}
448
Ankure49a86a2014-11-11 18:52:43 -0800449func TestRPCServerAuthorization(t *testing.T) {
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700450 const (
Ankur50a5f392015-02-27 18:46:30 -0800451 publicKeyErr = "not matched by server key"
452 forPeerErr = "no blessings tagged for peer"
453 nameErr = "do not match pattern"
454 allowedErr = "do not match any allowed server patterns"
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700455 )
456 var (
Ankure49a86a2014-11-11 18:52:43 -0800457 pprovider, pclient, pserver = tsecurity.NewPrincipal("root"), tsecurity.NewPrincipal(), tsecurity.NewPrincipal()
458 pdischarger = pprovider
Asim Shankar558ea012015-01-28 12:49:36 -0800459 now = time.Now()
460 noErrID verror.IDAction
Ankure49a86a2014-11-11 18:52:43 -0800461
462 // Third-party caveats on blessings presented by server.
Asim Shankar558ea012015-01-28 12:49:36 -0800463 cavTPValid = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/dischargeserver", mkCaveat(security.ExpiryCaveat(now.Add(24*time.Hour))))
464 cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/dischargeserver", mkCaveat(security.ExpiryCaveat(now.Add(-1*time.Second))))
Ankure49a86a2014-11-11 18:52:43 -0800465
466 // Server blessings.
467 bServer = bless(pprovider, pserver, "server")
468 bServerExpired = bless(pprovider, pserver, "server", mkCaveat(security.ExpiryCaveat(time.Now().Add(-1*time.Second))))
469 bServerTPValid = bless(pprovider, pserver, "serverWithTPCaveats", cavTPValid)
470 bServerTPExpired = bless(pprovider, pserver, "serverWithTPCaveats", cavTPExpired)
Asim Shankar558ea012015-01-28 12:49:36 -0800471 bTwoBlessings, _ = security.UnionOfBlessings(bServer, bServerTPValid)
Asim Shankar8f05c222014-10-06 22:08:19 -0700472
473 mgr = imanager.InternalNew(naming.FixedRoutingID(0x1111111))
474 ns = tnaming.NewSimpleNamespace()
475 tests = []struct {
Ankur50a5f392015-02-27 18:46:30 -0800476 server security.Blessings // blessings presented by the server to the client.
477 name string // name provided by the client to StartCall
478 opt ipc.CallOpt // option provided to StartCall.
479 errID verror.IDAction
480 err string
Asim Shankar8f05c222014-10-06 22:08:19 -0700481 }{
Asim Shankar558ea012015-01-28 12:49:36 -0800482 // Client accepts talking to the server only if the
483 // server's blessings match the provided pattern
Asim Shankarb547ea92015-02-17 18:49:45 -0800484 {bServer, "[...]mountpoint/server", nil, noErrID, ""},
Asim Shankar558ea012015-01-28 12:49:36 -0800485 {bServer, "[root/server]mountpoint/server", nil, noErrID, ""},
Jiri Simsa074bf362015-02-17 09:29:45 -0800486 {bServer, "[root/otherserver]mountpoint/server", nil, verror.ErrNotTrusted, nameErr},
487 {bServer, "[otherroot/server]mountpoint/server", nil, verror.ErrNotTrusted, nameErr},
Asim Shankar8f05c222014-10-06 22:08:19 -0700488
Asim Shankar558ea012015-01-28 12:49:36 -0800489 // and, if the server's blessing has third-party
490 // caveats then the server provides appropriate
491 // discharges.
Asim Shankarb547ea92015-02-17 18:49:45 -0800492 {bServerTPValid, "[...]mountpoint/server", nil, noErrID, ""},
Asim Shankar558ea012015-01-28 12:49:36 -0800493 {bServerTPValid, "[root/serverWithTPCaveats]mountpoint/server", nil, noErrID, ""},
Jiri Simsa074bf362015-02-17 09:29:45 -0800494 {bServerTPValid, "[root/otherserver]mountpoint/server", nil, verror.ErrNotTrusted, nameErr},
495 {bServerTPValid, "[otherroot/server]mountpoint/server", nil, verror.ErrNotTrusted, nameErr},
Ankure49a86a2014-11-11 18:52:43 -0800496
Asim Shankar558ea012015-01-28 12:49:36 -0800497 // Client does not talk to a server that presents
498 // expired blessings (because the blessing store is
Asim Shankarb547ea92015-02-17 18:49:45 -0800499 // configured to only talk to root).
Ankur50a5f392015-02-27 18:46:30 -0800500 {bServerExpired, "[...]mountpoint/server", nil, verror.ErrNotTrusted, forPeerErr},
Ankure49a86a2014-11-11 18:52:43 -0800501
Asim Shankar558ea012015-01-28 12:49:36 -0800502 // Client does not talk to a server that fails to
503 // provide discharges for third-party caveats on the
504 // blessings presented by it.
Ankur50a5f392015-02-27 18:46:30 -0800505 {bServerTPExpired, "[...]mountpoint/server", nil, verror.ErrNotTrusted, forPeerErr},
Asim Shankar558ea012015-01-28 12:49:36 -0800506
507 // Testing the AllowedServersPolicy option.
Asim Shankarb547ea92015-02-17 18:49:45 -0800508 {bServer, "[...]mountpoint/server", options.AllowedServersPolicy{"otherroot"}, verror.ErrNotTrusted, allowedErr},
Jiri Simsa074bf362015-02-17 09:29:45 -0800509 {bServer, "[root/server]mountpoint/server", options.AllowedServersPolicy{"otherroot"}, verror.ErrNotTrusted, allowedErr},
510 {bServer, "[otherroot/server]mountpoint/server", options.AllowedServersPolicy{"root/server"}, verror.ErrNotTrusted, nameErr},
Ankur78b8b2a2015-02-04 20:16:28 -0800511 {bServer, "[root/server]mountpoint/server", options.AllowedServersPolicy{"root"}, noErrID, ""},
Ankur50a5f392015-02-27 18:46:30 -0800512
513 // Test the ServerPublicKey option.
514 {bServer, "[...]mountpoint/server", options.ServerPublicKey{bServer.PublicKey()}, noErrID, ""},
515 {bServer, "[...]mountpoint/server", options.ServerPublicKey{tsecurity.NewPrincipal("irrelevant").PublicKey()}, verror.ErrNotTrusted, publicKeyErr},
Asim Shankar558ea012015-01-28 12:49:36 -0800516 // Server presents two blessings: One that satisfies
517 // the pattern provided to StartCall and one that
518 // satisfies the AllowedServersPolicy, so the server is
519 // authorized.
520 {bTwoBlessings, "[root/serverWithTPCaveats]mountpoint/server", options.AllowedServersPolicy{"root/server"}, noErrID, ""},
Asim Shankar8f05c222014-10-06 22:08:19 -0700521 }
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700522 )
Ankure49a86a2014-11-11 18:52:43 -0800523
Asim Shankar558ea012015-01-28 12:49:36 -0800524 _, server := startServer(t, pserver, mgr, ns, "mountpoint/server", testServerDisp{&testServer{}})
525 defer stopServer(t, server, ns, "mountpoint/server")
Ankure49a86a2014-11-11 18:52:43 -0800526
527 // Start the discharge server.
Asim Shankar558ea012015-01-28 12:49:36 -0800528 _, dischargeServer := startServer(t, pdischarger, mgr, ns, "mountpoint/dischargeserver", testutil.LeafDispatcher(&dischargeServer{}, &acceptAllAuthorizer{}))
529 defer stopServer(t, dischargeServer, ns, "mountpoint/dischargeserver")
Ankure49a86a2014-11-11 18:52:43 -0800530
Asim Shankar558ea012015-01-28 12:49:36 -0800531 // Make the client and server principals trust root certificates from
532 // pprovider
Asim Shankar8f05c222014-10-06 22:08:19 -0700533 pclient.AddToRoots(pprovider.BlessingStore().Default())
534 pserver.AddToRoots(pprovider.BlessingStore().Default())
Asim Shankar558ea012015-01-28 12:49:36 -0800535 // Set a blessing that the client is willing to share with servers with
536 // blessings from pprovider.
Ankur78b8b2a2015-02-04 20:16:28 -0800537 pclient.BlessingStore().Set(bless(pprovider, pclient, "client"), "root")
Asim Shankar558ea012015-01-28 12:49:36 -0800538
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800539 for i, test := range tests {
Ankur50a5f392015-02-27 18:46:30 -0800540 name := fmt.Sprintf("(#%d: Name:%q, Server:%q, opt:%v)", i, test.name, test.server, test.opt)
Ankure49a86a2014-11-11 18:52:43 -0800541 if err := pserver.BlessingStore().SetDefault(test.server); err != nil {
542 t.Fatalf("SetDefault failed on server's BlessingStore: %v", err)
543 }
Ankur78b8b2a2015-02-04 20:16:28 -0800544 if _, err := pserver.BlessingStore().Set(test.server, "root"); err != nil {
Ankure49a86a2014-11-11 18:52:43 -0800545 t.Fatalf("Set failed on server's BlessingStore: %v", err)
546 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700547 // Recreate client in each test (so as to not re-use VCs to the server).
548 client, err := InternalNewClient(mgr, ns, vc.LocalPrincipal{pclient})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700549 if err != nil {
Asim Shankara5b60b22014-11-06 15:37:07 -0800550 t.Errorf("%s: failed to create client: %v", name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700551 continue
552 }
Asim Shankar558ea012015-01-28 12:49:36 -0800553 ctx, cancel := context.WithTimeout(testContextWithoutDeadline(), 10*time.Second)
Ankur50a5f392015-02-27 18:46:30 -0800554 call, err := client.StartCall(ctx, test.name, "Method", nil, test.opt)
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800555 if !matchesErrorPattern(err, test.errID, test.err) {
Asim Shankarb547ea92015-02-17 18:49:45 -0800556 t.Errorf(`%s: client.StartCall: got error "%v", want to match "%v"`, name, err, test.err)
Asim Shankar2d731a92014-09-29 17:46:38 -0700557 } else if call != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700558 blessings, proof := call.RemoteBlessings()
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800559 if proof.IsZero() {
560 t.Errorf("%s: Returned zero value for remote blessings", name)
Asim Shankar8f05c222014-10-06 22:08:19 -0700561 }
Asim Shankar558ea012015-01-28 12:49:36 -0800562 // Currently all tests are configured so that the only
563 // blessings presented by the server that are
564 // recognized by the client match the pattern
Ankur78b8b2a2015-02-04 20:16:28 -0800565 // "root"
566 if len(blessings) < 1 || !security.BlessingPattern("root").MatchedBy(blessings...) {
567 t.Errorf("%s: Client sees server as %v, expected a single blessing matching root", name, blessings)
Asim Shankar2d731a92014-09-29 17:46:38 -0700568 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700569 }
Matt Rosencrantzcc922c12014-11-28 20:28:59 -0800570 cancel()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700571 client.Close()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700572 }
573}
574
Asim Shankarb547ea92015-02-17 18:49:45 -0800575func TestServerManInTheMiddleAttack(t *testing.T) {
576 // Test scenario: A server mounts itself, but then some other service
577 // somehow "takes over" the endpoint, thus trying to steal traffic.
578
579 // Start up the attacker's server.
580 attacker, err := testInternalNewServer(
581 testContext(),
582 imanager.InternalNew(naming.FixedRoutingID(0xaaaaaaaaaaaaaaaa)),
583 // (To prevent the attacker for legitimately mounting on the
584 // namespace that the client will use, provide it with a
585 // different namespace).
586 tnaming.NewSimpleNamespace(),
587 vc.LocalPrincipal{tsecurity.NewPrincipal("attacker")})
588 if err != nil {
589 t.Fatal(err)
590 }
591 if _, err := attacker.Listen(listenSpec); err != nil {
592 t.Fatal(err)
593 }
594 if err := attacker.ServeDispatcher("mountpoint/server", testServerDisp{&testServer{}}); err != nil {
595 t.Fatal(err)
596 }
597 var ep naming.Endpoint
598 if status := attacker.Status(); len(status.Endpoints) < 1 {
599 t.Fatalf("Attacker server does not have an endpoint: %+v", status)
600 } else {
601 ep = status.Endpoints[0]
602 }
603
604 // The legitimate server would have mounted the same endpoint on the
605 // namespace.
606 ns := tnaming.NewSimpleNamespace()
607 if err := ns.Mount(testContext(), "mountpoint/server", ep.Name(), time.Hour, naming.MountedServerBlessingsOpt{"server"}); err != nil {
608 t.Fatal(err)
609 }
610
611 // The RPC call should fail because the blessings presented by the
612 // (attacker's) server are not consistent with the ones registered in
613 // the mounttable trusted by the client.
614 client, err := InternalNewClient(
615 imanager.InternalNew(naming.FixedRoutingID(0xcccccccccccccccc)),
616 ns,
617 vc.LocalPrincipal{tsecurity.NewPrincipal("client")})
618 if err != nil {
619 t.Fatal(err)
620 }
621 defer client.Close()
622 if _, err := client.StartCall(testContext(), "mountpoint/server", "Closure", nil); !verror.Is(err, verror.ErrNotTrusted.ID) {
623 t.Errorf("Got error %v (errorid=%v), want errorid=%v", err, verror.ErrorID(err), verror.ErrNotTrusted.ID)
624 }
625 // But the RPC should succeed if the client explicitly
626 // decided to skip server authorization.
627 if _, err := client.StartCall(testContext(), "mountpoint/server", "Closure", nil, options.SkipResolveAuthorization{}); err != nil {
628 t.Errorf("Unexpected error(%v) when skipping server authorization", err)
629 }
630}
631
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800632type websocketMode bool
633type closeSendMode bool
634
635const (
636 useWebsocket websocketMode = true
637 noWebsocket websocketMode = false
638
639 closeSend closeSendMode = true
640 noCloseSend closeSendMode = false
641)
642
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700643func TestRPC(t *testing.T) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800644 testRPC(t, closeSend, noWebsocket)
645}
646
647func TestRPCWithWebsocket(t *testing.T) {
648 testRPC(t, closeSend, useWebsocket)
Tilak Sharma0c766112014-05-20 17:47:27 -0700649}
650
651// TestCloseSendOnFinish tests that Finish informs the server that no more
652// inputs will be sent by the client if CloseSend has not already done so.
653func TestRPCCloseSendOnFinish(t *testing.T) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800654 testRPC(t, noCloseSend, noWebsocket)
Tilak Sharma0c766112014-05-20 17:47:27 -0700655}
656
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800657func TestRPCCloseSendOnFinishWithWebsocket(t *testing.T) {
658 testRPC(t, noCloseSend, useWebsocket)
659}
660
661func testRPC(t *testing.T, shouldCloseSend closeSendMode, shouldUseWebsocket websocketMode) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700662 type v []interface{}
663 type testcase struct {
664 name string
665 method string
666 args v
667 streamArgs v
668 startErr error
669 results v
670 finishErr error
671 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700672 var (
673 tests = []testcase{
674 {"mountpoint/server/suffix", "Closure", nil, nil, nil, nil, nil},
Todd Wange77f9952015-02-18 13:20:50 -0800675 {"mountpoint/server/suffix", "Error", nil, nil, nil, nil, errMethod},
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700676
Asim Shankar8f05c222014-10-06 22:08:19 -0700677 {"mountpoint/server/suffix", "Echo", v{"foo"}, nil, nil, v{`method:"Echo",suffix:"suffix",arg:"foo"`}, nil},
678 {"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 -0700679
Asim Shankar8f05c222014-10-06 22:08:19 -0700680 {"mountpoint/server/suffix", "EchoUser", v{"foo", userType("bar")}, nil, nil, v{`method:"EchoUser",suffix:"suffix",arg:"foo"`, userType("bar")}, nil},
681 {"mountpoint/server/suffix/abc", "EchoUser", v{"baz", userType("bla")}, nil, nil, v{`method:"EchoUser",suffix:"suffix/abc",arg:"baz"`, userType("bla")}, nil},
Todd Wange77f9952015-02-18 13:20:50 -0800682 {"mountpoint/server/suffix", "Stream", v{"foo"}, v{userType("bar"), userType("baz")}, nil, v{`method:"Stream",suffix:"suffix",arg:"foo" bar baz`}, nil},
683 {"mountpoint/server/suffix/abc", "Stream", v{"123"}, v{userType("456"), userType("789")}, nil, v{`method:"Stream",suffix:"suffix/abc",arg:"123" 456 789`}, nil},
Asim Shankar8f05c222014-10-06 22:08:19 -0700684 {"mountpoint/server/suffix", "EchoBlessings", nil, nil, nil, v{"[server]", "[client]"}, nil},
Todd Wange77f9952015-02-18 13:20:50 -0800685 {"mountpoint/server/suffix", "EchoAndError", v{"bugs bunny"}, nil, nil, v{`method:"EchoAndError",suffix:"suffix",arg:"bugs bunny"`}, nil},
686 {"mountpoint/server/suffix", "EchoAndError", v{"error"}, nil, nil, nil, errMethod},
Asim Shankar8f05c222014-10-06 22:08:19 -0700687 }
688 name = func(t testcase) string {
689 return fmt.Sprintf("%s.%s(%v)", t.name, t.method, t.args)
690 }
691
Ankure49a86a2014-11-11 18:52:43 -0800692 pserver = tsecurity.NewPrincipal("server")
693 pclient = tsecurity.NewPrincipal("client")
Asim Shankar8f05c222014-10-06 22:08:19 -0700694
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800695 b = createBundleWS(t, pclient, pserver, &testServer{}, shouldUseWebsocket)
Asim Shankar8f05c222014-10-06 22:08:19 -0700696 )
Bogdan Caprita27953142014-05-12 11:41:42 -0700697 defer b.cleanup(t)
Asim Shankar8f05c222014-10-06 22:08:19 -0700698 // The server needs to recognize the client's root certificate.
699 pserver.AddToRoots(pclient.BlessingStore().Default())
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700700 for _, test := range tests {
701 vlog.VI(1).Infof("%s client.StartCall", name(test))
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800702 vname := test.name
703 if shouldUseWebsocket {
704 var err error
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800705 vname, err = fakeWSName(b.ns, vname)
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800706 if err != nil && err != test.startErr {
707 t.Errorf(`%s ns.Resolve got error "%v", want "%v"`, name(test), err, test.startErr)
708 continue
709 }
710 }
711 call, err := b.client.StartCall(testContext(), vname, test.method, test.args)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700712 if err != test.startErr {
713 t.Errorf(`%s client.StartCall got error "%v", want "%v"`, name(test), err, test.startErr)
714 continue
715 }
716 for _, sarg := range test.streamArgs {
717 vlog.VI(1).Infof("%s client.Send(%v)", name(test), sarg)
718 if err := call.Send(sarg); err != nil {
719 t.Errorf(`%s call.Send(%v) got unexpected error "%v"`, name(test), sarg, err)
720 }
721 var u userType
722 if err := call.Recv(&u); err != nil {
723 t.Errorf(`%s call.Recv(%v) got unexpected error "%v"`, name(test), sarg, err)
724 }
725 if !reflect.DeepEqual(u, sarg) {
726 t.Errorf("%s call.Recv got value %v, want %v", name(test), u, sarg)
727 }
728 }
Tilak Sharma0c766112014-05-20 17:47:27 -0700729 if shouldCloseSend {
730 vlog.VI(1).Infof("%s call.CloseSend", name(test))
Asim Shankar062d4222014-08-18 11:14:42 -0700731 // When the method does not involve streaming
732 // arguments, the server gets all the arguments in
733 // StartCall and then sends a response without
734 // (unnecessarily) waiting for a CloseSend message from
735 // the client. If the server responds before the
736 // CloseSend call is made at the client, the CloseSend
737 // call will fail. Thus, only check for errors on
738 // CloseSend if there are streaming arguments to begin
739 // with (i.e., only if the server is expected to wait
740 // for the CloseSend notification).
741 if err := call.CloseSend(); err != nil && len(test.streamArgs) > 0 {
Tilak Sharma0c766112014-05-20 17:47:27 -0700742 t.Errorf(`%s call.CloseSend got unexpected error "%v"`, name(test), err)
743 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700744 }
745 vlog.VI(1).Infof("%s client.Finish", name(test))
746 results := makeResultPtrs(test.results)
747 err = call.Finish(results...)
Todd Wange77f9952015-02-18 13:20:50 -0800748 if got, want := err, test.finishErr; (got == nil) != (want == nil) {
749 t.Errorf(`%s call.Finish got error "%v", want "%v'`, name(test), got, want)
750 } else if want != nil && !verror.Is(got, verror.ErrorID(want)) {
751 t.Errorf(`%s call.Finish got error "%v", want "%v"`, name(test), got, want)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700752 }
753 checkResultPtrs(t, name(test), results, test.results)
754 }
755}
756
Ken Ashcraft2b8309a2014-09-09 10:44:43 -0700757func TestMultipleFinish(t *testing.T) {
758 type v []interface{}
Ankure49a86a2014-11-11 18:52:43 -0800759 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), &testServer{})
Ken Ashcraft2b8309a2014-09-09 10:44:43 -0700760 defer b.cleanup(t)
761 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "Echo", v{"foo"})
762 if err != nil {
763 t.Fatalf(`client.StartCall got error "%v"`, err)
764 }
765 var results string
766 err = call.Finish(&results)
767 if err != nil {
768 t.Fatalf(`call.Finish got error "%v"`, err)
769 }
770 // Calling Finish a second time should result in a useful error.
Jiri Simsa074bf362015-02-17 09:29:45 -0800771 if err = call.Finish(&results); !matchesErrorPattern(err, verror.ErrBadState, "Finish has already been called") {
772 t.Fatalf(`got "%v", want "%v"`, err, verror.ErrBadState)
Ken Ashcraft2b8309a2014-09-09 10:44:43 -0700773 }
774}
775
Asim Shankar8f05c222014-10-06 22:08:19 -0700776// granter implements ipc.Granter, returning a fixed (security.Blessings, error) pair.
Asim Shankarb54d7642014-06-05 13:08:04 -0700777type granter struct {
778 ipc.CallOpt
Asim Shankar8f05c222014-10-06 22:08:19 -0700779 b security.Blessings
Asim Shankarb54d7642014-06-05 13:08:04 -0700780 err error
781}
782
Asim Shankar8f05c222014-10-06 22:08:19 -0700783func (g granter) Grant(id security.Blessings) (security.Blessings, error) { return g.b, g.err }
Asim Shankarb54d7642014-06-05 13:08:04 -0700784
Asim Shankar8f05c222014-10-06 22:08:19 -0700785func TestGranter(t *testing.T) {
786 var (
Ankure49a86a2014-11-11 18:52:43 -0800787 pclient = tsecurity.NewPrincipal("client")
788 pserver = tsecurity.NewPrincipal("server")
Asim Shankar8f05c222014-10-06 22:08:19 -0700789 b = createBundle(t, pclient, pserver, &testServer{})
790 )
Asim Shankarb54d7642014-06-05 13:08:04 -0700791 defer b.cleanup(t)
792
793 tests := []struct {
Asim Shankar8f05c222014-10-06 22:08:19 -0700794 granter ipc.Granter
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800795 startErrID, finishErrID verror.IDAction
Asim Shankarb54d7642014-06-05 13:08:04 -0700796 blessing, starterr, finisherr string
797 }{
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800798 {blessing: ""},
Asim Shankarb18a44f2014-10-21 20:25:07 -0700799 {granter: granter{b: bless(pclient, pserver, "blessed")}, blessing: "client/blessed"},
Jiri Simsa074bf362015-02-17 09:29:45 -0800800 {granter: granter{err: errors.New("hell no")}, startErrID: verror.ErrNotTrusted, starterr: "hell no"},
801 {granter: granter{b: pclient.BlessingStore().Default()}, finishErrID: verror.ErrNoAccess, finisherr: "blessing granted not bound to this server"},
Asim Shankarb54d7642014-06-05 13:08:04 -0700802 }
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800803 for i, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -0700804 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "EchoGrantedBlessings", []interface{}{"argument"}, test.granter)
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800805 if !matchesErrorPattern(err, test.startErrID, test.starterr) {
806 t.Errorf("%d: %+v: StartCall returned error %v", i, test, err)
Asim Shankarb54d7642014-06-05 13:08:04 -0700807 }
808 if err != nil {
809 continue
810 }
811 var result, blessing string
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800812 if err = call.Finish(&result, &blessing); !matchesErrorPattern(err, test.finishErrID, test.finisherr) {
Asim Shankarb54d7642014-06-05 13:08:04 -0700813 t.Errorf("%+v: Finish returned error %v", test, err)
814 }
815 if err != nil {
816 continue
817 }
818 if result != "argument" || blessing != test.blessing {
819 t.Errorf("%+v: Got (%q, %q)", test, result, blessing)
820 }
821 }
822}
823
Asim Shankar8f05c222014-10-06 22:08:19 -0700824func mkThirdPartyCaveat(discharger security.PublicKey, location string, c security.Caveat) security.Caveat {
825 tpc, err := security.NewPublicKeyCaveat(discharger, location, security.ThirdPartyRequirements{}, c)
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700826 if err != nil {
827 panic(err)
828 }
Asim Shankar7283dd82015-02-03 19:35:58 -0800829 return tpc
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700830}
831
Asim Shankarf4864f42014-11-25 18:53:05 -0800832// dischargeTestServer implements the discharge service. Always fails to
833// issue a discharge, but records the impetus and traceid of the RPC call.
834type dischargeTestServer struct {
835 p security.Principal
836 impetus []security.DischargeImpetus
Benjamin Prosnitzc97fe192015-02-03 10:33:25 -0800837 traceid []uniqueid.Id
Asim Shankara94e5072014-08-19 18:18:36 -0700838}
839
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -0800840func (s *dischargeTestServer) Discharge(ctx ipc.ServerCall, cav security.Caveat, impetus security.DischargeImpetus) (security.WireDischarge, error) {
Asim Shankarc8cfcf12014-11-20 12:26:58 -0800841 s.impetus = append(s.impetus, impetus)
Matt Rosencrantz5f98d942015-01-08 13:48:30 -0800842 s.traceid = append(s.traceid, vtrace.GetSpan(ctx.Context()).Trace())
Asim Shankara94e5072014-08-19 18:18:36 -0700843 return nil, fmt.Errorf("discharges not issued")
844}
845
Benjamin Prosnitzc97fe192015-02-03 10:33:25 -0800846func (s *dischargeTestServer) Release() ([]security.DischargeImpetus, []uniqueid.Id) {
Asim Shankarf4864f42014-11-25 18:53:05 -0800847 impetus, traceid := s.impetus, s.traceid
848 s.impetus, s.traceid = nil, nil
849 return impetus, traceid
Asim Shankarc8cfcf12014-11-20 12:26:58 -0800850}
851
Asim Shankarf4864f42014-11-25 18:53:05 -0800852func TestDischargeImpetusAndContextPropagation(t *testing.T) {
Asim Shankara94e5072014-08-19 18:18:36 -0700853 var (
Ankure49a86a2014-11-11 18:52:43 -0800854 pserver = tsecurity.NewPrincipal("server")
Asim Shankarf4864f42014-11-25 18:53:05 -0800855 pdischarger = tsecurity.NewPrincipal("discharger")
856 pclient = tsecurity.NewPrincipal("client")
Asim Shankar8f05c222014-10-06 22:08:19 -0700857 sm = imanager.InternalNew(naming.FixedRoutingID(0x555555555))
858 ns = tnaming.NewSimpleNamespace()
Asim Shankara94e5072014-08-19 18:18:36 -0700859
Asim Shankar8f05c222014-10-06 22:08:19 -0700860 mkClient = func(req security.ThirdPartyRequirements) vc.LocalPrincipal {
Asim Shankarf4864f42014-11-25 18:53:05 -0800861 // Setup the client so that it shares a blessing with a third-party caveat with the server.
Asim Shankar7283dd82015-02-03 19:35:58 -0800862 cav, err := security.NewPublicKeyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", req, security.UnconstrainedUse())
Asim Shankara94e5072014-08-19 18:18:36 -0700863 if err != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -0700864 t.Fatalf("Failed to create ThirdPartyCaveat(%+v): %v", req, err)
Asim Shankara94e5072014-08-19 18:18:36 -0700865 }
Asim Shankarf4864f42014-11-25 18:53:05 -0800866 b, err := pclient.BlessSelf("client_for_server", cav)
Asim Shankar8f05c222014-10-06 22:08:19 -0700867 if err != nil {
868 t.Fatalf("BlessSelf failed: %v", err)
869 }
Asim Shankar8f05c222014-10-06 22:08:19 -0700870 pclient.BlessingStore().Set(b, "server")
871 return vc.LocalPrincipal{pclient}
Asim Shankara94e5072014-08-19 18:18:36 -0700872 }
873 )
Asim Shankarf4864f42014-11-25 18:53:05 -0800874 // Initialize the client principal.
875 // It trusts both the application server and the discharger.
876 pclient.AddToRoots(pserver.BlessingStore().Default())
877 pclient.AddToRoots(pdischarger.BlessingStore().Default())
878 // Share a blessing without any third-party caveats with the discharger.
879 // It could share the same blessing as generated by setupClientBlessing, but
880 // that will lead to possibly debugging confusion (since it will try to fetch
881 // a discharge to talk to the discharge service).
882 if b, err := pclient.BlessSelf("client_for_discharger"); err != nil {
883 t.Fatalf("BlessSelf failed: %v", err)
884 } else {
885 pclient.BlessingStore().Set(b, "discharger")
886 }
887
888 // Setup the discharge server.
889 var tester dischargeTestServer
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800890 ctx := testContext()
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -0800891 dischargeServer, err := testInternalNewServer(ctx, sm, ns, vc.LocalPrincipal{pdischarger})
Asim Shankara94e5072014-08-19 18:18:36 -0700892 if err != nil {
893 t.Fatal(err)
894 }
Asim Shankarf4864f42014-11-25 18:53:05 -0800895 defer dischargeServer.Stop()
896 if _, err := dischargeServer.Listen(listenSpec); err != nil {
897 t.Fatal(err)
898 }
899 if err := dischargeServer.Serve("mountpoint/discharger", &tester, &testServerAuthorizer{}); err != nil {
Asim Shankara94e5072014-08-19 18:18:36 -0700900 t.Fatal(err)
901 }
902
Asim Shankarf4864f42014-11-25 18:53:05 -0800903 // Setup the application server.
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -0800904 appServer, err := testInternalNewServer(ctx, sm, ns, vc.LocalPrincipal{pserver})
Asim Shankarf4864f42014-11-25 18:53:05 -0800905 if err != nil {
906 t.Fatal(err)
907 }
908 defer appServer.Stop()
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800909 eps, err := appServer.Listen(listenSpec)
Asim Shankarf4864f42014-11-25 18:53:05 -0800910 if err != nil {
911 t.Fatal(err)
912 }
913 // TODO(bjornick,cnicolaou,ashankar): This is a hack to workaround the
914 // fact that a single Listen on the "tcp" protocol followed by a call
915 // to Serve(<name>, ...) transparently creates two endpoints (one for
916 // tcp, one for websockets) and maps both to <name> via a mount.
917 // Because all endpoints to a name are tried in a parallel, this
918 // transparency makes this test hard to follow (many discharge fetch
919 // attempts are made - one for VIF authentication, one for VC
920 // authentication and one for the actual RPC - and having them be made
921 // to two different endpoints in parallel leads to a lot of
922 // non-determinism). The last plan of record known by the author of
923 // this comment was to stop this sly creation of two endpoints and
924 // require that they be done explicitly. When that happens, this hack
925 // can go away, but till then, this workaround allows the test to be
926 // more predictable by ensuring there is only one VIF/VC/Flow to the
927 // server.
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800928 object := naming.JoinAddressName(eps[0].String(), "object") // instead of "mountpoint/object"
Asim Shankarf4864f42014-11-25 18:53:05 -0800929 if err := appServer.Serve("mountpoint/object", &testServer{}, &testServerAuthorizer{}); err != nil {
930 t.Fatal(err)
931 }
Asim Shankara94e5072014-08-19 18:18:36 -0700932 tests := []struct {
933 Requirements security.ThirdPartyRequirements
934 Impetus security.DischargeImpetus
935 }{
936 { // No requirements, no impetus
937 Requirements: security.ThirdPartyRequirements{},
938 Impetus: security.DischargeImpetus{},
939 },
940 { // Require everything
941 Requirements: security.ThirdPartyRequirements{ReportServer: true, ReportMethod: true, ReportArguments: true},
Todd Wangb31da592015-02-20 12:50:39 -0800942 Impetus: security.DischargeImpetus{Server: []security.BlessingPattern{"server"}, Method: "Method", Arguments: []*vdl.Value{vdl.StringValue("argument")}},
Asim Shankara94e5072014-08-19 18:18:36 -0700943 },
944 { // Require only the method name
945 Requirements: security.ThirdPartyRequirements{ReportMethod: true},
946 Impetus: security.DischargeImpetus{Method: "Method"},
947 },
948 }
949
Ankur50a5f392015-02-27 18:46:30 -0800950 for _, test := range tests {
Ankure49a86a2014-11-11 18:52:43 -0800951 pclient := mkClient(test.Requirements)
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -0800952 client, err := InternalNewClient(sm, ns, pclient)
Asim Shankara94e5072014-08-19 18:18:36 -0700953 if err != nil {
954 t.Fatalf("InternalNewClient(%+v) failed: %v", test.Requirements, err)
955 }
956 defer client.Close()
Asim Shankarf4864f42014-11-25 18:53:05 -0800957 ctx := testContext()
Matt Rosencrantz5f98d942015-01-08 13:48:30 -0800958 tid := vtrace.GetSpan(ctx).Trace()
Asim Shankara94e5072014-08-19 18:18:36 -0700959 // 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 -0800960 if _, err := client.StartCall(ctx, object, "Method", []interface{}{"argument"}); err != nil {
Asim Shankara94e5072014-08-19 18:18:36 -0700961 t.Errorf("StartCall(%+v) failed: %v", test.Requirements, err)
962 continue
963 }
Asim Shankarf4864f42014-11-25 18:53:05 -0800964 impetus, traceid := tester.Release()
Ankur50a5f392015-02-27 18:46:30 -0800965 // There should have been exactly 1 attempt to fetch discharges when making
966 // the RPC to the remote object.
967 if len(impetus) != 1 || len(traceid) != 1 {
968 t.Errorf("Test %+v: Got (%d, %d) (#impetus, #traceid), wanted exactly one", test.Requirements, len(impetus), len(traceid))
Asim Shankarf4864f42014-11-25 18:53:05 -0800969 continue
970 }
971 // VC creation does not have any "impetus", it is established without
972 // knowledge of the context of the RPC. So ignore that.
973 //
974 // TODO(ashankar): Should the impetus of the RPC that initiated the
975 // VIF/VC creation be propagated?
976 if got, want := impetus[len(impetus)-1], test.Impetus; !reflect.DeepEqual(got, want) {
977 t.Errorf("Test %+v: Got impetus %v, want %v", test.Requirements, got, want)
978 }
979 // But the context used for all of this should be the same
980 // (thereby allowing debug traces to link VIF/VC creation with
981 // the RPC that initiated them).
982 for idx, got := range traceid {
983 if !reflect.DeepEqual(got, tid) {
984 t.Errorf("Test %+v: %d - Got trace id %q, want %q", test.Requirements, idx, hex.EncodeToString(got[:]), hex.EncodeToString(tid[:]))
985 }
Asim Shankara94e5072014-08-19 18:18:36 -0700986 }
987 }
988}
989
Ankure49a86a2014-11-11 18:52:43 -0800990func TestRPCClientAuthorization(t *testing.T) {
991 type v []interface{}
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700992 var (
Asim Shankar8f05c222014-10-06 22:08:19 -0700993 // Principals
Ankure49a86a2014-11-11 18:52:43 -0800994 pclient, pserver = tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server")
995 pdischarger = pserver
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700996
Asim Shankar8f05c222014-10-06 22:08:19 -0700997 now = time.Now()
998
Ankure49a86a2014-11-11 18:52:43 -0800999 serverName = "mountpoint/server"
1000 dischargeServerName = "mountpoint/dischargeserver"
1001
Asim Shankar8f05c222014-10-06 22:08:19 -07001002 // Caveats on blessings to the client: First-party caveats
1003 cavOnlyEcho = mkCaveat(security.MethodCaveat("Echo"))
1004 cavExpired = mkCaveat(security.ExpiryCaveat(now.Add(-1 * time.Second)))
1005 // Caveats on blessings to the client: Third-party caveats
1006 cavTPValid = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", mkCaveat(security.ExpiryCaveat(now.Add(24*time.Hour))))
1007 cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", mkCaveat(security.ExpiryCaveat(now.Add(-1*time.Second))))
1008
1009 // Client blessings that will be tested.
1010 bServerClientOnlyEcho = bless(pserver, pclient, "onlyecho", cavOnlyEcho)
1011 bServerClientExpired = bless(pserver, pclient, "expired", cavExpired)
1012 bServerClientTPValid = bless(pserver, pclient, "dischargeable_third_party_caveat", cavTPValid)
1013 bServerClientTPExpired = bless(pserver, pclient, "expired_third_party_caveat", cavTPExpired)
1014 bClient = pclient.BlessingStore().Default()
1015 bRandom, _ = pclient.BlessSelf("random")
Ankure49a86a2014-11-11 18:52:43 -08001016
1017 mgr = imanager.InternalNew(naming.FixedRoutingID(0x1111111))
1018 ns = tnaming.NewSimpleNamespace()
1019 tests = []struct {
1020 blessings security.Blessings // Blessings used by the client
1021 name string // object name on which the method is invoked
1022 method string
1023 args v
1024 results v
1025 authorized bool // Whether or not the RPC should be authorized by the server.
1026 }{
1027 // There are three different authorization policies (security.Authorizer implementations)
1028 // used by the server, depending on the suffix (see testServerDisp.Lookup):
1029 // - nilAuth suffix: the default authorization policy (only delegates of or delegators of the server can call RPCs)
Ankur78b8b2a2015-02-04 20:16:28 -08001030 // - aclAuth suffix: the ACL only allows blessings matching the patterns "server" or "client"
Ankure49a86a2014-11-11 18:52:43 -08001031 // - other suffixes: testServerAuthorizer allows any principal to call any method except "Unauthorized"
1032
1033 // Expired blessings should fail nilAuth and aclAuth (which care about names), but should succeed on
1034 // other suffixes (which allow all blessings), unless calling the Unauthorized method.
1035 {bServerClientExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
1036 {bServerClientExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
1037 {bServerClientExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
1038 {bServerClientExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
1039
1040 // Same for blessings that should fail to obtain a discharge for the third party caveat.
1041 {bServerClientTPExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
1042 {bServerClientTPExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
1043 {bServerClientTPExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
1044 {bServerClientTPExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
1045
1046 // The "server/client" blessing (with MethodCaveat("Echo")) should satisfy all authorization policies
1047 // when "Echo" is called.
1048 {bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
1049 {bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
1050 {bServerClientOnlyEcho, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
1051
1052 // The "server/client" blessing (with MethodCaveat("Echo")) should satisfy no authorization policy
1053 // when any other method is invoked, except for the testServerAuthorizer policy (which will
1054 // not recognize the blessing "server/onlyecho", but it would authorize anyone anyway).
1055 {bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Closure", nil, nil, false},
1056 {bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Closure", nil, nil, false},
1057 {bServerClientOnlyEcho, "mountpoint/server/suffix", "Closure", nil, nil, true},
1058
1059 // The "client" blessing doesn't satisfy the default authorization policy, but does satisfy
1060 // the ACL and the testServerAuthorizer policy.
1061 {bClient, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
1062 {bClient, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
1063 {bClient, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
1064 {bClient, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
1065
1066 // The "random" blessing does not satisfy either the default policy or the ACL, but does
1067 // satisfy testServerAuthorizer.
1068 {bRandom, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
1069 {bRandom, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
1070 {bRandom, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
1071 {bRandom, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
1072
1073 // The "server/dischargeable_third_party_caveat" blessing satisfies all policies.
1074 // (the discharges should be fetched).
1075 {bServerClientTPValid, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
1076 {bServerClientTPValid, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
1077 {bServerClientTPValid, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
1078 {bServerClientTPValid, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
1079 }
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001080 )
Ankure49a86a2014-11-11 18:52:43 -08001081 // Start the main server.
1082 _, server := startServer(t, pserver, mgr, ns, serverName, testServerDisp{&testServer{}})
1083 defer stopServer(t, server, ns, serverName)
1084
1085 // Start the discharge server.
Bogdan Caprita7590a6d2015-01-08 13:43:40 -08001086 _, dischargeServer := startServer(t, pdischarger, mgr, ns, dischargeServerName, testutil.LeafDispatcher(&dischargeServer{}, &acceptAllAuthorizer{}))
Ankure49a86a2014-11-11 18:52:43 -08001087 defer stopServer(t, dischargeServer, ns, dischargeServerName)
1088
Ankur78b8b2a2015-02-04 20:16:28 -08001089 // The server should recognize the client principal as an authority on "client" and "random" blessings.
Asim Shankar8f05c222014-10-06 22:08:19 -07001090 pserver.AddToRoots(bClient)
1091 pserver.AddToRoots(bRandom)
Ankure49a86a2014-11-11 18:52:43 -08001092 // And the client needs to recognize the server's and discharger's blessings to decide which of its
1093 // own blessings to share.
Asim Shankar8f05c222014-10-06 22:08:19 -07001094 pclient.AddToRoots(pserver.BlessingStore().Default())
Ankure49a86a2014-11-11 18:52:43 -08001095 // tsecurity.NewPrincipal sets up a principal that shares blessings with all servers, undo that.
Asim Shankar2bf7b1e2015-02-27 00:45:12 -08001096 pclient.BlessingStore().Set(security.Blessings{}, security.AllPrincipals)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001097
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001098 for _, test := range tests {
Asim Shankar8f05c222014-10-06 22:08:19 -07001099 name := fmt.Sprintf("%q.%s(%v) by %v", test.name, test.method, test.args, test.blessings)
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001100 client, err := InternalNewClient(mgr, ns, vc.LocalPrincipal{pclient})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001101 if err != nil {
1102 t.Fatalf("InternalNewClient failed: %v", err)
1103 }
1104 defer client.Close()
Ankure49a86a2014-11-11 18:52:43 -08001105
Asim Shankar8f05c222014-10-06 22:08:19 -07001106 pclient.BlessingStore().Set(test.blessings, "server")
Matt Rosencrantzbf85d542014-08-22 13:31:14 -07001107 call, err := client.StartCall(testContext(), test.name, test.method, test.args)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001108 if err != nil {
Asim Shankar8f05c222014-10-06 22:08:19 -07001109 t.Errorf(`%s client.StartCall got unexpected error: "%v"`, name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001110 continue
1111 }
Ankure49a86a2014-11-11 18:52:43 -08001112
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001113 results := makeResultPtrs(test.results)
1114 err = call.Finish(results...)
Asim Shankar8f05c222014-10-06 22:08:19 -07001115 if err != nil && test.authorized {
1116 t.Errorf(`%s call.Finish got error: "%v", wanted the RPC to succeed`, name, err)
1117 } else if err == nil && !test.authorized {
1118 t.Errorf("%s call.Finish succeeded, expected authorization failure", name)
Jiri Simsa074bf362015-02-17 09:29:45 -08001119 } else if !test.authorized && !verror.Is(err, verror.ErrNoAccess.ID) {
1120 t.Errorf("%s. call.Finish returned error %v(%v), wanted %v", name, verror.ErrorID(verror.Convert(verror.ErrNoAccess, nil, err)), err, verror.ErrNoAccess)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001121 }
1122 }
1123}
1124
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001125func TestDischargePurgeFromCache(t *testing.T) {
1126 var (
Ankure49a86a2014-11-11 18:52:43 -08001127 pserver = tsecurity.NewPrincipal("server")
Asim Shankar8f05c222014-10-06 22:08:19 -07001128 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 -08001129 pclient = tsecurity.NewPrincipal("client")
Asim Shankar8f05c222014-10-06 22:08:19 -07001130 // Client is blessed with a third-party caveat. The discharger service issues discharges with a fakeTimeCaveat.
1131 // This blessing is presented to "server".
1132 bclient = bless(pserver, pclient, "client", mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", security.UnconstrainedUse()))
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001133 )
Asim Shankar8f05c222014-10-06 22:08:19 -07001134 // Setup the client to recognize the server's blessing and present bclient to it.
1135 pclient.AddToRoots(pserver.BlessingStore().Default())
1136 pclient.BlessingStore().Set(bclient, "server")
1137
Ankure49a86a2014-11-11 18:52:43 -08001138 b := createBundle(t, nil, pserver, &testServer{})
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001139 defer b.cleanup(t)
1140
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001141 var err error
1142 if b.client, err = InternalNewClient(b.sm, b.ns, vc.LocalPrincipal{pclient}); err != nil {
Ankure49a86a2014-11-11 18:52:43 -08001143 t.Fatalf("InternalNewClient failed: %v", err)
1144 }
Mike Burrowsdc6b3602015-02-05 15:52:12 -08001145 call := func() error {
Asim Shankar8f05c222014-10-06 22:08:19 -07001146 call, err := b.client.StartCall(testContext(), "mountpoint/server/aclAuth", "Echo", []interface{}{"batman"})
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001147 if err != nil {
Mike Burrows2a548352015-02-06 18:24:02 -08001148 return err //fmt.Errorf("client.StartCall failed: %v", err)
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001149 }
1150 var got string
1151 if err := call.Finish(&got); err != nil {
Mike Burrows2a548352015-02-06 18:24:02 -08001152 return err //fmt.Errorf("client.Finish failed: %v", err)
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001153 }
Asim Shankar8f05c222014-10-06 22:08:19 -07001154 if want := `method:"Echo",suffix:"aclAuth",arg:"batman"`; got != want {
Jiri Simsa074bf362015-02-17 09:29:45 -08001155 return verror.Convert(verror.ErrBadArg, nil, fmt.Errorf("Got [%v] want [%v]", got, want))
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001156 }
1157 return nil
1158 }
1159
1160 // First call should succeed
1161 if err := call(); err != nil {
1162 t.Fatal(err)
1163 }
1164 // Advance virtual clock, which will invalidate the discharge
1165 clock.Advance(1)
Jiri Simsa074bf362015-02-17 09:29:45 -08001166 if err, want := call(), "not authorized"; !matchesErrorPattern(err, verror.ErrNoAccess, want) {
Asim Shankar8f05c222014-10-06 22:08:19 -07001167 t.Errorf("Got error [%v] wanted to match pattern %q", err, want)
Andres Erbsenb7f95f32014-07-07 12:07:56 -07001168 }
1169 // But retrying will succeed since the discharge should be purged from cache and refreshed
1170 if err := call(); err != nil {
1171 t.Fatal(err)
1172 }
1173}
1174
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001175type cancelTestServer struct {
1176 started chan struct{}
1177 cancelled chan struct{}
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001178 t *testing.T
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001179}
1180
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001181func newCancelTestServer(t *testing.T) *cancelTestServer {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001182 return &cancelTestServer{
1183 started: make(chan struct{}),
1184 cancelled: make(chan struct{}),
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001185 t: t,
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001186 }
1187}
1188
Matt Rosencrantz1dcd0a92015-02-27 11:05:59 -08001189func (s *cancelTestServer) CancelStreamReader(call ipc.StreamServerCall) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001190 close(s.started)
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001191 var b []byte
1192 if err := call.Recv(&b); err != io.EOF {
1193 s.t.Errorf("Got error %v, want io.EOF", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001194 }
Matt Rosencrantz8f9fca12014-12-19 14:02:31 -08001195 <-call.Context().Done()
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001196 close(s.cancelled)
1197 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001198}
1199
1200// CancelStreamIgnorer doesn't read from it's input stream so all it's
Matt Rosencrantz137b8d22014-08-18 09:56:15 -07001201// buffers fill. The intention is to show that call.Done() is closed
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001202// even when the stream is stalled.
Matt Rosencrantz1dcd0a92015-02-27 11:05:59 -08001203func (s *cancelTestServer) CancelStreamIgnorer(call ipc.StreamServerCall) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001204 close(s.started)
Matt Rosencrantz8f9fca12014-12-19 14:02:31 -08001205 <-call.Context().Done()
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001206 close(s.cancelled)
1207 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001208}
1209
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001210func waitForCancel(t *testing.T, ts *cancelTestServer, cancel context.CancelFunc) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001211 <-ts.started
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001212 cancel()
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001213 <-ts.cancelled
1214}
1215
1216// TestCancel tests cancellation while the server is reading from a stream.
1217func TestCancel(t *testing.T) {
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001218 ts := newCancelTestServer(t)
Ankure49a86a2014-11-11 18:52:43 -08001219 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), ts)
Bogdan Caprita27953142014-05-12 11:41:42 -07001220 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001221
Matt Rosencrantz89445a42015-01-05 13:32:37 -08001222 ctx, cancel := context.WithCancel(testContext())
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001223 _, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "CancelStreamReader", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001224 if err != nil {
1225 t.Fatalf("Start call failed: %v", err)
1226 }
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001227 waitForCancel(t, ts, cancel)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001228}
1229
1230// TestCancelWithFullBuffers tests that even if the writer has filled the buffers and
1231// the server is not reading that the cancel message gets through.
1232func TestCancelWithFullBuffers(t *testing.T) {
Matt Rosencrantzbae08212014-10-03 08:04:17 -07001233 ts := newCancelTestServer(t)
Ankure49a86a2014-11-11 18:52:43 -08001234 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), ts)
Bogdan Caprita27953142014-05-12 11:41:42 -07001235 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001236
Matt Rosencrantz89445a42015-01-05 13:32:37 -08001237 ctx, cancel := context.WithCancel(testContext())
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001238 call, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "CancelStreamIgnorer", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001239 if err != nil {
1240 t.Fatalf("Start call failed: %v", err)
1241 }
1242 // Fill up all the write buffers to ensure that cancelling works even when the stream
1243 // is blocked.
1244 call.Send(make([]byte, vc.MaxSharedBytes))
1245 call.Send(make([]byte, vc.DefaultBytesBufferedPerFlow))
1246
Matt Rosencrantz9346b412014-12-18 15:59:19 -08001247 waitForCancel(t, ts, cancel)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001248}
1249
1250type streamRecvInGoroutineServer struct{ c chan error }
1251
Matt Rosencrantz1dcd0a92015-02-27 11:05:59 -08001252func (s *streamRecvInGoroutineServer) RecvInGoroutine(call ipc.StreamServerCall) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001253 // Spawn a goroutine to read streaming data from the client.
1254 go func() {
1255 var i interface{}
1256 for {
1257 err := call.Recv(&i)
1258 if err != nil {
1259 s.c <- err
1260 return
1261 }
1262 }
1263 }()
1264 // Imagine the server did some processing here and now that it is done,
1265 // it does not care to see what else the client has to say.
1266 return nil
1267}
1268
1269func TestStreamReadTerminatedByServer(t *testing.T) {
1270 s := &streamRecvInGoroutineServer{c: make(chan error, 1)}
Ankure49a86a2014-11-11 18:52:43 -08001271 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), s)
Bogdan Caprita27953142014-05-12 11:41:42 -07001272 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001273
Matt Rosencrantzbf85d542014-08-22 13:31:14 -07001274 call, err := b.client.StartCall(testContext(), "mountpoint/server/suffix", "RecvInGoroutine", []interface{}{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001275 if err != nil {
1276 t.Fatalf("StartCall failed: %v", err)
1277 }
1278
1279 c := make(chan error, 1)
1280 go func() {
1281 for i := 0; true; i++ {
1282 if err := call.Send(i); err != nil {
1283 c <- err
1284 return
1285 }
1286 }
1287 }()
1288
1289 // The goroutine at the server executing "Recv" should have terminated
1290 // with EOF.
1291 if err := <-s.c; err != io.EOF {
1292 t.Errorf("Got %v at server, want io.EOF", err)
1293 }
1294 // The client Send should have failed since the RPC has been
1295 // terminated.
1296 if err := <-c; err == nil {
1297 t.Errorf("Client Send should fail as the server should have closed the flow")
1298 }
1299}
1300
1301// TestConnectWithIncompatibleServers tests that clients ignore incompatible endpoints.
1302func TestConnectWithIncompatibleServers(t *testing.T) {
Ankure49a86a2014-11-11 18:52:43 -08001303 b := createBundle(t, tsecurity.NewPrincipal("client"), tsecurity.NewPrincipal("server"), &testServer{})
Bogdan Caprita27953142014-05-12 11:41:42 -07001304 defer b.cleanup(t)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001305
1306 // Publish some incompatible endpoints.
Matt Rosencrantzbf85d542014-08-22 13:31:14 -07001307 publisher := publisher.New(testContext(), b.ns, publishPeriod)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001308 defer publisher.WaitForStop()
1309 defer publisher.Stop()
1310 publisher.AddName("incompatible")
David Why Use Two When One Will Do Presotto3da1c792014-10-03 11:15:53 -07001311 publisher.AddServer("/@2@tcp@localhost:10000@@1000000@2000000@@", false)
1312 publisher.AddServer("/@2@tcp@localhost:10001@@2000000@3000000@@", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001313
Matt Rosencrantz89445a42015-01-05 13:32:37 -08001314 ctx, _ := context.WithTimeout(testContext(), 100*time.Millisecond)
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -08001315
1316 _, err := b.client.StartCall(ctx, "incompatible/suffix", "Echo", []interface{}{"foo"})
Jiri Simsa074bf362015-02-17 09:29:45 -08001317 if !verror.Is(err, verror.ErrNoServers.ID) {
1318 t.Errorf("Expected error %s, found: %v", verror.ErrNoServers, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001319 }
1320
1321 // 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 -07001322 publisher.AddServer("/"+b.ep.String(), false)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -07001323 publisher.AddName("incompatible")
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001324
Matt Rosencrantzbf85d542014-08-22 13:31:14 -07001325 call, err := b.client.StartCall(testContext(), "incompatible/suffix", "Echo", []interface{}{"foo"})
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001326 if err != nil {
Asim Shankar3a8a7e22014-05-12 18:01:44 -07001327 t.Fatal(err)
1328 }
1329 var result string
1330 if err = call.Finish(&result); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001331 t.Errorf("Unexpected error finishing call %v", err)
1332 }
Asim Shankar3a8a7e22014-05-12 18:01:44 -07001333 expected := `method:"Echo",suffix:"suffix",arg:"foo"`
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001334 if result != expected {
1335 t.Errorf("Wrong result returned. Got %s, wanted %s", result, expected)
1336 }
1337}
1338
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001339func TestPreferredAddress(t *testing.T) {
1340 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
1341 defer sm.Shutdown()
Matt Rosencrantz9fe60822014-09-12 10:09:53 -07001342 ns := tnaming.NewSimpleNamespace()
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -07001343 pa := func(string, []ipc.Address) ([]ipc.Address, error) {
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001344 a := &net.IPAddr{}
1345 a.IP = net.ParseIP("1.1.1.1")
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -07001346 return []ipc.Address{&netstate.AddrIfc{Addr: a}}, nil
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001347 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001348 ctx := testContext()
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -08001349 server, err := testInternalNewServer(ctx, sm, ns, vc.LocalPrincipal{tsecurity.NewPrincipal("server")})
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001350 if err != nil {
1351 t.Errorf("InternalNewServer failed: %v", err)
1352 }
1353 defer server.Stop()
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001354
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -08001355 spec := ipc.ListenSpec{
1356 Addrs: ipc.ListenAddrs{{"tcp", ":0"}},
1357 AddressChooser: pa,
1358 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001359 eps, err := server.Listen(spec)
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -08001360 if err != nil {
1361 t.Errorf("unexpected error: %s", err)
1362 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001363 iep := eps[0].(*inaming.Endpoint)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001364 host, _, err := net.SplitHostPort(iep.Address)
1365 if err != nil {
1366 t.Errorf("unexpected error: %s", err)
1367 }
1368 if got, want := host, "1.1.1.1"; got != want {
1369 t.Errorf("got %q, want %q", got, want)
1370 }
1371 // Won't override the specified address.
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001372 eps, err = server.Listen(listenSpec)
1373 iep = eps[0].(*inaming.Endpoint)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001374 host, _, err = net.SplitHostPort(iep.Address)
1375 if err != nil {
1376 t.Errorf("unexpected error: %s", err)
1377 }
1378 if got, want := host, "127.0.0.1"; got != want {
1379 t.Errorf("got %q, want %q", got, want)
1380 }
1381}
1382
1383func TestPreferredAddressErrors(t *testing.T) {
1384 sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
1385 defer sm.Shutdown()
Matt Rosencrantz9fe60822014-09-12 10:09:53 -07001386 ns := tnaming.NewSimpleNamespace()
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -07001387 paerr := func(_ string, a []ipc.Address) ([]ipc.Address, error) {
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001388 return nil, fmt.Errorf("oops")
1389 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001390 ctx := testContext()
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -08001391 server, err := testInternalNewServer(ctx, sm, ns, vc.LocalPrincipal{tsecurity.NewPrincipal("server")})
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001392 if err != nil {
1393 t.Errorf("InternalNewServer failed: %v", err)
1394 }
1395 defer server.Stop()
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -08001396 spec := ipc.ListenSpec{
1397 Addrs: ipc.ListenAddrs{{"tcp", ":0"}},
1398 AddressChooser: paerr,
1399 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -08001400 eps, err := server.Listen(spec)
1401 iep := eps[0].(*inaming.Endpoint)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001402 host, _, err := net.SplitHostPort(iep.Address)
1403 if err != nil {
1404 t.Errorf("unexpected error: %s", err)
1405 }
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -07001406 ip := net.ParseIP(host)
1407 if ip == nil {
1408 t.Fatalf("failed to parse IP address: %q", host)
1409 }
1410 if !ip.IsUnspecified() {
1411 t.Errorf("IP: %q is not unspecified", ip)
Cosmos Nicolaoubae615a2014-08-27 23:32:31 -07001412 }
1413}
1414
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001415func TestSecurityNone(t *testing.T) {
1416 sm := imanager.InternalNew(naming.FixedRoutingID(0x66666666))
1417 defer sm.Shutdown()
1418 ns := tnaming.NewSimpleNamespace()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001419 ctx := testContext()
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -08001420 server, err := testInternalNewServer(ctx, sm, ns, options.VCSecurityNone)
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001421 if err != nil {
1422 t.Fatalf("InternalNewServer failed: %v", err)
1423 }
1424 if _, err = server.Listen(listenSpec); err != nil {
1425 t.Fatalf("server.Listen failed: %v", err)
1426 }
1427 disp := &testServerDisp{&testServer{}}
Cosmos Nicolaou92dba582014-11-05 17:24:10 -08001428 if err := server.ServeDispatcher("mp/server", disp); err != nil {
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001429 t.Fatalf("server.Serve failed: %v", err)
1430 }
Suharsh Sivakumarae774a52015-01-09 14:26:32 -08001431 client, err := InternalNewClient(sm, ns)
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001432 if err != nil {
1433 t.Fatalf("InternalNewClient failed: %v", err)
1434 }
1435 // When using VCSecurityNone, all authorization checks should be skipped, so
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001436 // unauthorized methods should be callable.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001437 call, err := client.StartCall(ctx, "mp/server", "Unauthorized", nil, options.VCSecurityNone)
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001438 if err != nil {
1439 t.Fatalf("client.StartCall failed: %v", err)
1440 }
1441 var got string
Todd Wange77f9952015-02-18 13:20:50 -08001442 if err := call.Finish(&got); err != nil {
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -07001443 t.Errorf("call.Finish failed: %v", err)
1444 }
1445 if want := "UnauthorizedResult"; got != want {
1446 t.Errorf("got (%v), want (%v)", got, want)
1447 }
1448}
1449
Matt Rosencrantz321a51d2014-10-30 10:37:56 -07001450func TestCallWithNilContext(t *testing.T) {
1451 sm := imanager.InternalNew(naming.FixedRoutingID(0x66666666))
1452 defer sm.Shutdown()
1453 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumarae774a52015-01-09 14:26:32 -08001454 client, err := InternalNewClient(sm, ns)
Matt Rosencrantz321a51d2014-10-30 10:37:56 -07001455 if err != nil {
1456 t.Fatalf("InternalNewClient failed: %v", err)
1457 }
Suharsh Sivakumarae774a52015-01-09 14:26:32 -08001458 call, err := client.StartCall(nil, "foo", "bar", []interface{}{}, options.VCSecurityNone)
Matt Rosencrantz321a51d2014-10-30 10:37:56 -07001459 if call != nil {
1460 t.Errorf("Expected nil interface got: %#v", call)
1461 }
Jiri Simsa074bf362015-02-17 09:29:45 -08001462 if !verror.Is(err, verror.ErrBadArg.ID) {
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -08001463 t.Errorf("Expected an BadArg error, got: %s", err.Error())
Matt Rosencrantz321a51d2014-10-30 10:37:56 -07001464 }
1465}
1466
Asim Shankara5b60b22014-11-06 15:37:07 -08001467func TestServerBlessingsOpt(t *testing.T) {
1468 var (
Ankure49a86a2014-11-11 18:52:43 -08001469 pserver = tsecurity.NewPrincipal("server")
1470 pclient = tsecurity.NewPrincipal("client")
Asim Shankara5b60b22014-11-06 15:37:07 -08001471 batman, _ = pserver.BlessSelf("batman")
1472 )
1473 // Make the client recognize all server blessings
1474 if err := pclient.AddToRoots(batman); err != nil {
1475 t.Fatal(err)
1476 }
1477 if err := pclient.AddToRoots(pserver.BlessingStore().Default()); err != nil {
1478 t.Fatal(err)
1479 }
1480 // Start a server that uses the ServerBlessings option to configure itself
1481 // to act as batman (as opposed to using the default blessing).
1482 ns := tnaming.NewSimpleNamespace()
Asim Shankara5b60b22014-11-06 15:37:07 -08001483
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -08001484 popt := vc.LocalPrincipal{pserver}
1485 defer runServer(t, ns, "mountpoint/batman", &testServer{}, popt, options.ServerBlessings{batman}).Shutdown()
1486 defer runServer(t, ns, "mountpoint/default", &testServer{}, popt).Shutdown()
Asim Shankara5b60b22014-11-06 15:37:07 -08001487
Asim Shankarb547ea92015-02-17 18:49:45 -08001488 // And finally, make an RPC and see that the client sees "batman"
Asim Shankara5b60b22014-11-06 15:37:07 -08001489 runClient := func(server string) ([]string, error) {
1490 smc := imanager.InternalNew(naming.FixedRoutingID(0xc))
1491 defer smc.Shutdown()
1492 client, err := InternalNewClient(
1493 smc,
1494 ns,
1495 vc.LocalPrincipal{pclient})
1496 if err != nil {
1497 return nil, err
1498 }
1499 defer client.Close()
1500 call, err := client.StartCall(testContext(), server, "Closure", nil)
1501 if err != nil {
1502 return nil, err
1503 }
1504 blessings, _ := call.RemoteBlessings()
1505 return blessings, nil
1506 }
1507
1508 // When talking to mountpoint/batman, should see "batman"
1509 // When talking to mountpoint/default, should see "server"
1510 if got, err := runClient("mountpoint/batman"); err != nil || len(got) != 1 || got[0] != "batman" {
1511 t.Errorf("Got (%v, %v) wanted 'batman'", got, err)
1512 }
1513 if got, err := runClient("mountpoint/default"); err != nil || len(got) != 1 || got[0] != "server" {
1514 t.Errorf("Got (%v, %v) wanted 'server'", got, err)
1515 }
1516}
1517
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001518func TestNoDischargesOpt(t *testing.T) {
1519 var (
1520 pdischarger = tsecurity.NewPrincipal("discharger")
1521 pserver = tsecurity.NewPrincipal("server")
1522 pclient = tsecurity.NewPrincipal("client")
1523 )
1524 // Make the client recognize all server blessings
1525 if err := pclient.AddToRoots(pserver.BlessingStore().Default()); err != nil {
1526 t.Fatal(err)
1527 }
1528 if err := pclient.AddToRoots(pdischarger.BlessingStore().Default()); err != nil {
1529 t.Fatal(err)
1530 }
1531
1532 // Bless the client with a ThirdPartyCaveat.
1533 tpcav := mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1534 blessings, err := pserver.Bless(pclient.PublicKey(), pserver.BlessingStore().Default(), "tpcav", tpcav)
1535 if err != nil {
1536 t.Fatalf("failed to create Blessings: %v", err)
1537 }
1538 if _, err = pclient.BlessingStore().Set(blessings, "server"); err != nil {
1539 t.Fatalf("failed to set blessings: %v", err)
1540 }
1541
1542 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001543
1544 // Setup the disharger and test server.
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -08001545 discharger := &dischargeServer{}
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -08001546 defer runServer(t, ns, "mountpoint/discharger", discharger, vc.LocalPrincipal{pdischarger}).Shutdown()
1547 defer runServer(t, ns, "mountpoint/testServer", &testServer{}, vc.LocalPrincipal{pserver}).Shutdown()
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001548
1549 runClient := func(noDischarges bool) {
1550 rid, err := naming.NewRoutingID()
1551 if err != nil {
1552 t.Fatal(err)
1553 }
1554 smc := imanager.InternalNew(rid)
1555 defer smc.Shutdown()
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001556 client, err := InternalNewClient(smc, ns, vc.LocalPrincipal{pclient})
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001557 if err != nil {
1558 t.Fatalf("failed to create client: %v", err)
1559 }
1560 defer client.Close()
1561 var opts []ipc.CallOpt
1562 if noDischarges {
Ankur50a5f392015-02-27 18:46:30 -08001563 opts = append(opts, NoDischarges{})
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001564 }
1565 if _, err = client.StartCall(testContext(), "mountpoint/testServer", "Closure", nil, opts...); err != nil {
1566 t.Fatalf("failed to StartCall: %v", err)
1567 }
1568 }
1569
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -08001570 // Test that when the NoDischarges option is set, dischargeServer does not get called.
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001571 if runClient(true); discharger.called {
1572 t.Errorf("did not expect discharger to be called")
1573 }
1574 discharger.called = false
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -08001575 // Test that when the Nodischarges option is not set, dischargeServer does get called.
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001576 if runClient(false); !discharger.called {
1577 t.Errorf("expected discharger to be called")
1578 }
1579}
1580
1581func TestNoImplicitDischargeFetching(t *testing.T) {
1582 // This test ensures that discharge clients only fetch discharges for the specified tp caveats and not its own.
1583 var (
1584 pdischarger1 = tsecurity.NewPrincipal("discharger1")
1585 pdischarger2 = tsecurity.NewPrincipal("discharger2")
1586 pdischargeClient = tsecurity.NewPrincipal("dischargeClient")
1587 )
1588
1589 // Bless the client with a ThirdPartyCaveat from discharger1.
1590 tpcav1 := mkThirdPartyCaveat(pdischarger1.PublicKey(), "mountpoint/discharger1", mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1591 blessings, err := pdischarger1.Bless(pdischargeClient.PublicKey(), pdischarger1.BlessingStore().Default(), "tpcav1", tpcav1)
1592 if err != nil {
1593 t.Fatalf("failed to create Blessings: %v", err)
1594 }
1595 if err = pdischargeClient.BlessingStore().SetDefault(blessings); err != nil {
1596 t.Fatalf("failed to set blessings: %v", err)
1597 }
1598
1599 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001600
1601 // Setup the disharger and test server.
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -08001602 discharger1 := &dischargeServer{}
1603 discharger2 := &dischargeServer{}
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -08001604 defer runServer(t, ns, "mountpoint/discharger1", discharger1, vc.LocalPrincipal{pdischarger1}).Shutdown()
1605 defer runServer(t, ns, "mountpoint/discharger2", discharger2, vc.LocalPrincipal{pdischarger2}).Shutdown()
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001606
1607 rid, err := naming.NewRoutingID()
1608 if err != nil {
1609 t.Fatal(err)
1610 }
1611 sm := imanager.InternalNew(rid)
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001612
1613 c, err := InternalNewClient(sm, ns, vc.LocalPrincipal{pdischargeClient})
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001614 if err != nil {
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001615 t.Fatalf("failed to create client: %v", err)
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001616 }
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -08001617 dc := c.(*client).dc
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001618 tpcav2, err := security.NewPublicKeyCaveat(pdischarger2.PublicKey(), "mountpoint/discharger2", security.ThirdPartyRequirements{}, mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1619 if err != nil {
1620 t.Error(err)
1621 }
Asim Shankar19da8182015-02-06 01:41:16 -08001622 dc.PrepareDischarges(testContext(), []security.Caveat{tpcav2}, security.DischargeImpetus{})
Suharsh Sivakumar11316872014-11-25 15:57:00 -08001623
1624 // Ensure that discharger1 was not called and discharger2 was called.
1625 if discharger1.called {
1626 t.Errorf("discharge for caveat on discharge client should not have been fetched.")
1627 }
1628 if !discharger2.called {
1629 t.Errorf("discharge for caveat passed to PrepareDischarges should have been fetched.")
1630 }
1631}
1632
Suharsh Sivakumar720b7042014-12-22 17:33:23 -08001633// TestBlessingsCache tests that the VCCache is used to sucessfully used to cache duplicate
1634// calls blessings.
1635func TestBlessingsCache(t *testing.T) {
1636 var (
1637 pserver = tsecurity.NewPrincipal("server")
1638 pclient = tsecurity.NewPrincipal("client")
1639 )
1640 // Make the client recognize all server blessings
1641 if err := pclient.AddToRoots(pserver.BlessingStore().Default()); err != nil {
1642 t.Fatal(err)
1643 }
1644
1645 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumar720b7042014-12-22 17:33:23 -08001646
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -08001647 serverSM := runServer(t, ns, "mountpoint/testServer", &testServer{}, vc.LocalPrincipal{pserver})
Suharsh Sivakumar720b7042014-12-22 17:33:23 -08001648 defer serverSM.Shutdown()
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -08001649 rid := serverSM.RoutingID()
Suharsh Sivakumar720b7042014-12-22 17:33:23 -08001650
1651 newClient := func() ipc.Client {
1652 rid, err := naming.NewRoutingID()
1653 if err != nil {
1654 t.Fatal(err)
1655 }
1656 smc := imanager.InternalNew(rid)
1657 defer smc.Shutdown()
1658 client, err := InternalNewClient(smc, ns, vc.LocalPrincipal{pclient})
1659 if err != nil {
1660 t.Fatalf("failed to create client: %v", err)
1661 }
1662 return client
1663 }
1664
1665 runClient := func(client ipc.Client) {
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -08001666 if call, err := client.StartCall(testContext(), "mountpoint/testServer", "Closure", nil); err != nil {
Suharsh Sivakumar720b7042014-12-22 17:33:23 -08001667 t.Fatalf("failed to StartCall: %v", err)
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -08001668 } else if err := call.Finish(); err != nil {
Suharsh Sivakumar720b7042014-12-22 17:33:23 -08001669 t.Fatal(err)
1670 }
1671 }
1672
1673 cachePrefix := naming.Join("ipc", "server", "routing-id", rid.String(), "security", "blessings", "cache")
1674 cacheHits, err := stats.GetStatsObject(naming.Join(cachePrefix, "hits"))
1675 if err != nil {
1676 t.Fatal(err)
1677 }
1678 cacheAttempts, err := stats.GetStatsObject(naming.Join(cachePrefix, "attempts"))
1679 if err != nil {
1680 t.Fatal(err)
1681 }
1682
1683 // Check that the blessings cache is not used on the first call.
1684 clientA := newClient()
1685 runClient(clientA)
1686 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 1 || gotHits != 0 {
1687 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(1), cacheHits(0)", gotAttempts, gotHits)
1688 }
1689 // Check that the cache is hit on the second call with the same blessings.
1690 runClient(clientA)
1691 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 2 || gotHits != 1 {
1692 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(2), cacheHits(1)", gotAttempts, gotHits)
1693 }
1694 clientA.Close()
1695 // Check that the cache is not used with a different client.
1696 clientB := newClient()
1697 runClient(clientB)
1698 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 3 || gotHits != 1 {
1699 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(3), cacheHits(1)", gotAttempts, gotHits)
1700 }
1701 // clientB changes its blessings, the cache should not be used.
1702 blessings, err := pserver.Bless(pclient.PublicKey(), pserver.BlessingStore().Default(), "cav", mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1703 if err != nil {
1704 t.Fatalf("failed to create Blessings: %v", err)
1705 }
1706 if _, err = pclient.BlessingStore().Set(blessings, "server"); err != nil {
1707 t.Fatalf("failed to set blessings: %v", err)
1708 }
1709 runClient(clientB)
1710 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 4 || gotHits != 1 {
1711 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(4), cacheHits(1)", gotAttempts, gotHits)
1712 }
1713 clientB.Close()
1714}
1715
Asim Shankar7283dd82015-02-03 19:35:58 -08001716var fakeTimeCaveat = security.CaveatDescriptor{
1717 Id: uniqueid.Id{0x18, 0xba, 0x6f, 0x84, 0xd5, 0xec, 0xdb, 0x9b, 0xf2, 0x32, 0x19, 0x5b, 0x53, 0x92, 0x80, 0x0},
1718 ParamType: vdl.TypeOf(int64(0)),
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001719}
Suharsh Sivakumar9d17e4a2015-02-02 22:42:16 -08001720
Suharsh Sivakumara8633b02015-02-14 17:08:07 -08001721func TestServerPublicKeyOpt(t *testing.T) {
1722 var (
1723 pserver = tsecurity.NewPrincipal("server")
1724 pother = tsecurity.NewPrincipal("other")
1725 pclient = tsecurity.NewPrincipal("client")
1726 )
1727
1728 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumara8633b02015-02-14 17:08:07 -08001729 mountName := "mountpoint/default"
Suharsh Sivakumara8633b02015-02-14 17:08:07 -08001730
1731 // Start a server with pserver.
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -08001732 defer runServer(t, ns, mountName, &testServer{}, vc.LocalPrincipal{pserver}).Shutdown()
Suharsh Sivakumara8633b02015-02-14 17:08:07 -08001733
1734 smc := imanager.InternalNew(naming.FixedRoutingID(0xc))
1735 client, err := InternalNewClient(
1736 smc,
1737 ns,
1738 vc.LocalPrincipal{pclient})
1739 if err != nil {
1740 t.Fatal(err)
1741 }
1742 defer smc.Shutdown()
1743 defer client.Close()
1744
1745 // The call should succeed when the server presents the same public as the opt...
1746 if _, err = client.StartCall(testContext(), mountName, "Closure", nil, options.ServerPublicKey{pserver.PublicKey()}); err != nil {
1747 t.Errorf("Expected call to succeed but got %v", err)
1748 }
1749 // ...but fail if they differ.
Jiri Simsa074bf362015-02-17 09:29:45 -08001750 if _, err = client.StartCall(testContext(), mountName, "Closure", nil, options.ServerPublicKey{pother.PublicKey()}); !verror.Is(err, verror.ErrNotTrusted.ID) {
1751 t.Errorf("got %v, want %v", verror.ErrorID(err), verror.ErrNotTrusted.ID)
Suharsh Sivakumara8633b02015-02-14 17:08:07 -08001752 }
1753}
1754
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -08001755type expiryDischarger struct {
1756 called bool
1757}
1758
1759func (ed *expiryDischarger) Discharge(ctx ipc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.WireDischarge, error) {
1760 tp := cav.ThirdPartyDetails()
1761 if tp == nil {
1762 return nil, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav)
1763 }
1764 if err := tp.Dischargeable(ctx); err != nil {
1765 return nil, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err)
1766 }
1767 expDur := 10 * time.Millisecond
1768 if ed.called {
1769 expDur = time.Second
1770 }
1771 expiry, err := security.ExpiryCaveat(time.Now().Add(expDur))
1772 if err != nil {
1773 return nil, fmt.Errorf("failed to create an expiration on the discharge: %v", err)
1774 }
1775 d, err := ctx.LocalPrincipal().MintDischarge(cav, expiry)
1776 if err != nil {
1777 return nil, err
1778 }
1779 ed.called = true
1780 return security.MarshalDischarge(d), nil
1781}
1782
1783func TestDischargeClientFetchExpiredDischarges(t *testing.T) {
1784 var (
1785 pdischarger = tsecurity.NewPrincipal("discharger")
1786 )
1787
1788 // Bless the client with a ThirdPartyCaveat.
1789 tpcav := mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", mkCaveat(security.ExpiryCaveat(time.Now().Add(time.Hour))))
1790
1791 ns := tnaming.NewSimpleNamespace()
1792 ctx := testContext()
1793
1794 // Setup the disharge server.
1795 discharger := &expiryDischarger{}
1796 defer runServer(t, ns, "mountpoint/discharger", discharger, vc.LocalPrincipal{pdischarger}).Shutdown()
1797
1798 // Create a discharge client.
1799 rid, err := naming.NewRoutingID()
1800 if err != nil {
1801 t.Fatal(err)
1802 }
1803 smc := imanager.InternalNew(rid)
1804 defer smc.Shutdown()
1805 client, err := InternalNewClient(smc, ns)
1806 if err != nil {
1807 t.Fatalf("failed to create client: %v", err)
1808 }
1809 defer client.Close()
1810 dc := InternalNewDischargeClient(ctx, client)
1811
1812 // Fetch discharges for tpcav.
1813 dis := dc.PrepareDischarges(nil, []security.Caveat{tpcav}, security.DischargeImpetus{})[0]
1814 // Check that the discharges is not yet expired, but is expired after 100 milliseconds.
1815 expiry := dis.Expiry()
1816 // The discharge should expire.
1817 select {
1818 case <-time.After(time.Now().Sub(expiry)):
1819 break
1820 case <-time.After(time.Second):
1821 t.Fatalf("discharge didn't expire within a second")
1822 }
1823 // Preparing Discharges again to get fresh discharges.
1824 now := time.Now()
1825 dis = dc.PrepareDischarges(nil, []security.Caveat{tpcav}, security.DischargeImpetus{})[0]
1826 if expiry = dis.Expiry(); expiry.Before(now) {
1827 t.Fatalf("discharge has expired %v, but should be fresh", dis)
1828 }
1829}
1830
Suharsh Sivakumard19c95d2015-02-19 14:44:50 -08001831func init() {
Matt Rosencrantz5c7ed212015-02-27 22:42:35 -08001832 security.RegisterCaveatValidator(fakeTimeCaveat, func(_ security.Call, t int64) error {
Asim Shankar7283dd82015-02-03 19:35:58 -08001833 if now := clock.Now(); now > int(t) {
1834 return fmt.Errorf("fakeTimeCaveat expired: now=%d > then=%d", now, t)
1835 }
1836 return nil
1837 })
Suharsh Sivakumar9d17e4a2015-02-02 22:42:16 -08001838}