blob: 6dfe4866ac847ac703fcf77b774b0563bf4715fb [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Matt Rosencrantz94502cf2015-03-18 09:43:44 -07005package rpc
Jiri Simsa5293dcb2014-05-10 09:56:38 -07006
7import (
Jiri Simsa5293dcb2014-05-10 09:56:38 -07008 "fmt"
9 "io"
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -080010 "path/filepath"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070011 "reflect"
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -080012 "runtime"
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -080013 "sort"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070014 "strings"
Bogdan Caprita27953142014-05-12 11:41:42 -070015 "sync"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070016 "testing"
17 "time"
18
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -070019 "v.io/v23"
Jiri Simsa6ac95222015-02-23 16:11:49 -080020 "v.io/v23/context"
Matt Rosencrantz88be1182015-04-27 13:45:43 -070021 "v.io/v23/i18n"
Todd Wang5082a552015-04-02 10:56:11 -070022 "v.io/v23/namespace"
Jiri Simsa6ac95222015-02-23 16:11:49 -080023 "v.io/v23/naming"
24 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070025 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080026 "v.io/v23/security"
Todd Wang387d8a42015-03-30 17:09:05 -070027 "v.io/v23/security/access"
Jiri Simsa6ac95222015-02-23 16:11:49 -080028 "v.io/v23/uniqueid"
29 "v.io/v23/vdl"
30 "v.io/v23/verror"
Jiri Simsa6ac95222015-02-23 16:11:49 -080031 "v.io/v23/vtrace"
Jiri Simsa574ec4b2015-08-11 09:31:37 -070032 "v.io/x/ref/lib/pubsub"
Jiri Simsaffceefa2015-02-28 11:03:34 -080033 "v.io/x/ref/lib/stats"
Suharsh Sivakumardcc11d72015-05-11 12:19:20 -070034 "v.io/x/ref/runtime/internal/lib/websocket"
Suharsh Sivakumardcc11d72015-05-11 12:19:20 -070035 _ "v.io/x/ref/runtime/internal/rpc/protocols/tcp"
36 _ "v.io/x/ref/runtime/internal/rpc/protocols/ws"
37 _ "v.io/x/ref/runtime/internal/rpc/protocols/wsh"
38 "v.io/x/ref/runtime/internal/rpc/stream"
39 imanager "v.io/x/ref/runtime/internal/rpc/stream/manager"
Suharsh Sivakumardcc11d72015-05-11 12:19:20 -070040 tnaming "v.io/x/ref/runtime/internal/testing/mocks/naming"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070041 "v.io/x/ref/test/testutil"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070042)
43
Nicolas Lacasse0f07c602015-09-24 16:57:06 -070044//go:generate jiri test generate
Suharsh Sivakumard19c95d2015-02-19 14:44:50 -080045
Jiri Simsa5293dcb2014-05-10 09:56:38 -070046var (
Jiri Simsa074bf362015-02-17 09:29:45 -080047 errMethod = verror.New(verror.ErrAborted, nil)
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080048 clock = new(fakeClock)
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070049 listenAddrs = rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}
50 listenWSAddrs = rpc.ListenAddrs{{"ws", "127.0.0.1:0"}, {"tcp", "127.0.0.1:0"}}
51 listenSpec = rpc.ListenSpec{Addrs: listenAddrs}
52 listenWSSpec = rpc.ListenSpec{Addrs: listenWSAddrs}
Jiri Simsa5293dcb2014-05-10 09:56:38 -070053)
54
Andres Erbsenb7f95f32014-07-07 12:07:56 -070055type fakeClock struct {
56 sync.Mutex
Suharsh Sivakumar8a0adbb2015-03-06 13:16:34 -080057 time int64
Andres Erbsenb7f95f32014-07-07 12:07:56 -070058}
59
Suharsh Sivakumar8a0adbb2015-03-06 13:16:34 -080060func (c *fakeClock) Now() int64 {
Andres Erbsenb7f95f32014-07-07 12:07:56 -070061 c.Lock()
62 defer c.Unlock()
63 return c.time
64}
65
66func (c *fakeClock) Advance(steps uint) {
67 c.Lock()
Suharsh Sivakumar8a0adbb2015-03-06 13:16:34 -080068 c.time += int64(steps)
Andres Erbsenb7f95f32014-07-07 12:07:56 -070069 c.Unlock()
70}
71
Matt Rosencrantz5efd7822015-09-15 18:07:17 -070072func testInternalNewServerWithPubsub(ctx *context.T, streamMgr stream.Manager, ns namespace.T, settingsPublisher *pubsub.Publisher, settingsStreamName string, opts ...rpc.ServerOpt) (DeprecatedServer, error) {
Matt Rosencrantz80752cc2015-09-29 16:32:02 -070073 client := DeprecatedNewClient(streamMgr, ns)
Matt Rosencrantzaf3c76f2015-09-19 17:17:32 -070074 return DeprecatedNewServer(ctx, streamMgr, ns, settingsPublisher, settingsStreamName, client, opts...)
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070075}
76
Matt Rosencrantz5efd7822015-09-15 18:07:17 -070077func testInternalNewServer(ctx *context.T, streamMgr stream.Manager, ns namespace.T, opts ...rpc.ServerOpt) (DeprecatedServer, error) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -070078 return testInternalNewServerWithPubsub(ctx, streamMgr, ns, nil, "", opts...)
Suharsh Sivakumaraf99c972015-01-28 15:28:49 -080079}
80
Jiri Simsa5293dcb2014-05-10 09:56:38 -070081type userType string
82
83type testServer struct{}
84
Todd Wang54feabe2015-04-15 23:38:26 -070085func (*testServer) Closure(*context.T, rpc.ServerCall) error {
Todd Wange77f9952015-02-18 13:20:50 -080086 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -070087}
88
Todd Wang54feabe2015-04-15 23:38:26 -070089func (*testServer) Error(*context.T, rpc.ServerCall) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070090 return errMethod
91}
92
Todd Wang54feabe2015-04-15 23:38:26 -070093func (*testServer) Echo(_ *context.T, call rpc.ServerCall, arg string) (string, error) {
Matt Rosencrantz311378b2015-03-25 15:26:12 -070094 return fmt.Sprintf("method:%q,suffix:%q,arg:%q", "Echo", call.Suffix(), arg), nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -070095}
96
Todd Wang54feabe2015-04-15 23:38:26 -070097func (*testServer) EchoUser(_ *context.T, call rpc.ServerCall, arg string, u userType) (string, userType, error) {
Matt Rosencrantz311378b2015-03-25 15:26:12 -070098 return fmt.Sprintf("method:%q,suffix:%q,arg:%q", "EchoUser", call.Suffix(), arg), u, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -070099}
100
Matt Rosencrantz88be1182015-04-27 13:45:43 -0700101func (*testServer) EchoLang(ctx *context.T, call rpc.ServerCall) (string, error) {
102 return string(i18n.GetLangID(ctx)), nil
103}
104
Todd Wang4264e4b2015-04-16 22:43:40 -0700105func (*testServer) EchoBlessings(ctx *context.T, call rpc.ServerCall) (server, client string, _ error) {
106 local := security.LocalBlessingNames(ctx, call.Security())
107 remote, _ := security.RemoteBlessingNames(ctx, call.Security())
Todd Wange77f9952015-02-18 13:20:50 -0800108 return fmt.Sprintf("%v", local), fmt.Sprintf("%v", remote), nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700109}
110
Todd Wang54feabe2015-04-15 23:38:26 -0700111func (*testServer) EchoGrantedBlessings(_ *context.T, call rpc.ServerCall, arg string) (result, blessing string, _ error) {
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800112 return arg, fmt.Sprintf("%v", call.GrantedBlessings()), nil
Asim Shankarb54d7642014-06-05 13:08:04 -0700113}
114
Todd Wang54feabe2015-04-15 23:38:26 -0700115func (*testServer) EchoAndError(_ *context.T, call rpc.ServerCall, arg string) (string, error) {
Matt Rosencrantz311378b2015-03-25 15:26:12 -0700116 result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", "EchoAndError", call.Suffix(), arg)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700117 if arg == "error" {
118 return result, errMethod
119 }
120 return result, nil
121}
122
Todd Wang54feabe2015-04-15 23:38:26 -0700123func (*testServer) Stream(_ *context.T, call rpc.StreamServerCall, arg string) (string, error) {
Matt Rosencrantz311378b2015-03-25 15:26:12 -0700124 result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", "Stream", call.Suffix(), arg)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700125 var u userType
126 var err error
127 for err = call.Recv(&u); err == nil; err = call.Recv(&u) {
128 result += " " + string(u)
129 if err := call.Send(u); err != nil {
130 return "", err
131 }
132 }
133 if err == io.EOF {
134 err = nil
135 }
136 return result, err
137}
138
Todd Wang54feabe2015-04-15 23:38:26 -0700139func (*testServer) Unauthorized(*context.T, rpc.StreamServerCall) (string, error) {
Todd Wange77f9952015-02-18 13:20:50 -0800140 return "UnauthorizedResult", nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700141}
142
143type testServerAuthorizer struct{}
144
Todd Wang4264e4b2015-04-16 22:43:40 -0700145func (testServerAuthorizer) Authorize(ctx *context.T, call security.Call) error {
Ankuredd74ee2015-03-04 16:38:45 -0800146 // Verify that the Call object seen by the authorizer
147 // has the necessary fields.
Todd Wang4264e4b2015-04-16 22:43:40 -0700148 lb := call.LocalBlessings()
Ankuredd74ee2015-03-04 16:38:45 -0800149 if lb.IsZero() {
Todd Wang4264e4b2015-04-16 22:43:40 -0700150 return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalBlessings", call)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700151 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700152 if tpcavs := lb.ThirdPartyCaveats(); len(tpcavs) > 0 && call.LocalDischarges() == nil {
153 return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalDischarges even when LocalBlessings have third-party caveats", call)
Ankuredd74ee2015-03-04 16:38:45 -0800154
155 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700156 if call.LocalPrincipal() == nil {
157 return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalPrincipal", call)
Ankuredd74ee2015-03-04 16:38:45 -0800158 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700159 if call.Method() == "" {
160 return fmt.Errorf("testServerAuthorzer: Call object %v has no Method", call)
Ankuredd74ee2015-03-04 16:38:45 -0800161 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700162 if call.LocalEndpoint() == nil {
163 return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalEndpoint", call)
Ankuredd74ee2015-03-04 16:38:45 -0800164 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700165 if call.RemoteEndpoint() == nil {
166 return fmt.Errorf("testServerAuthorzer: Call object %v has no RemoteEndpoint", call)
Ankuredd74ee2015-03-04 16:38:45 -0800167 }
168
169 // Do not authorize the method "Unauthorized".
Todd Wang4264e4b2015-04-16 22:43:40 -0700170 if call.Method() == "Unauthorized" {
Ankuredd74ee2015-03-04 16:38:45 -0800171 return fmt.Errorf("testServerAuthorizer denied access")
172 }
173 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700174}
175
176type testServerDisp struct{ server interface{} }
177
Cosmos Nicolaou5a3125a2015-07-10 11:19:20 -0700178func (t testServerDisp) Lookup(_ *context.T, suffix string) (interface{}, security.Authorizer, error) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700179 // If suffix is "nilAuth" we use default authorization, if it is "aclAuth" we
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700180 // use an AccessList-based authorizer, and otherwise we use the custom testServerAuthorizer.
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700181 var authorizer security.Authorizer
182 switch suffix {
183 case "discharger":
Cosmos Nicolaou710daa22014-11-11 19:39:18 -0800184 return &dischargeServer{}, testServerAuthorizer{}, nil
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700185 case "nilAuth":
186 authorizer = nil
187 case "aclAuth":
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700188 authorizer = &access.AccessList{
Ankur78b8b2a2015-02-04 20:16:28 -0800189 In: []security.BlessingPattern{"client", "server"},
Asim Shankar68885192014-11-26 12:48:35 -0800190 }
Andres Erbsenb7f95f32014-07-07 12:07:56 -0700191 default:
192 authorizer = testServerAuthorizer{}
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700193 }
Cosmos Nicolaou710daa22014-11-11 19:39:18 -0800194 return t.server, authorizer, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700195}
196
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800197type dischargeServer struct {
198 mu sync.Mutex
199 called bool
200}
Ankure49a86a2014-11-11 18:52:43 -0800201
Todd Wang4264e4b2015-04-16 22:43:40 -0700202func (ds *dischargeServer) Discharge(ctx *context.T, call rpc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.Discharge, error) {
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800203 ds.mu.Lock()
204 ds.called = true
205 ds.mu.Unlock()
Asim Shankar19da8182015-02-06 01:41:16 -0800206 tp := cav.ThirdPartyDetails()
207 if tp == nil {
Asim Shankar08642822015-03-02 21:21:09 -0800208 return security.Discharge{}, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav)
Ankure49a86a2014-11-11 18:52:43 -0800209 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700210 if err := tp.Dischargeable(ctx, call.Security()); err != nil {
Asim Shankar08642822015-03-02 21:21:09 -0800211 return security.Discharge{}, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err)
Ankure49a86a2014-11-11 18:52:43 -0800212 }
213 // Add a fakeTimeCaveat to be able to control discharge expiration via 'clock'.
Asim Shankar7283dd82015-02-03 19:35:58 -0800214 expiry, err := security.NewCaveat(fakeTimeCaveat, clock.Now())
215 if err != nil {
Asim Shankar08642822015-03-02 21:21:09 -0800216 return security.Discharge{}, fmt.Errorf("failed to create an expiration on the discharge: %v", err)
Asim Shankar7283dd82015-02-03 19:35:58 -0800217 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700218 return call.Security().LocalPrincipal().MintDischarge(cav, expiry)
Ankure49a86a2014-11-11 18:52:43 -0800219}
220
Todd Wang5082a552015-04-02 10:56:11 -0700221func startServer(t *testing.T, ctx *context.T, principal security.Principal, sm stream.Manager, ns namespace.T, name string, disp rpc.Dispatcher, opts ...rpc.ServerOpt) (naming.Endpoint, rpc.Server) {
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700222 return startServerWS(t, ctx, principal, sm, ns, name, disp, noWebsocket, opts...)
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800223}
224
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -0800225func endpointsToStrings(eps []naming.Endpoint) []string {
226 r := make([]string, len(eps))
227 for i, e := range eps {
228 r[i] = e.String()
229 }
230 sort.Strings(r)
231 return r
232}
233
Todd Wang5082a552015-04-02 10:56:11 -0700234func startServerWS(t *testing.T, ctx *context.T, principal security.Principal, sm stream.Manager, ns namespace.T, name string, disp rpc.Dispatcher, shouldUseWebsocket websocketMode, opts ...rpc.ServerOpt) (naming.Endpoint, rpc.Server) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700235 ctx.VI(1).Info("InternalNewServer")
Todd Wangad492042015-04-17 15:58:40 -0700236 ctx, _ = v23.WithPrincipal(ctx, principal)
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700237 server, err := testInternalNewServer(ctx, sm, ns, opts...)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700238 if err != nil {
239 t.Errorf("InternalNewServer failed: %v", err)
240 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700241 ctx.VI(1).Info("server.Listen")
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800242 spec := listenSpec
243 if shouldUseWebsocket {
244 spec = listenWSSpec
245 }
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -0800246 eps, err := server.Listen(spec)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700247 if err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700248 t.Errorf("server.Listen failed: %v", err)
249 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700250 ctx.VI(1).Info("server.Serve")
Ankure49a86a2014-11-11 18:52:43 -0800251 if err := server.ServeDispatcher(name, disp); err != nil {
252 t.Errorf("server.ServeDispatcher failed: %v", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700253 }
Cosmos Nicolaou9fbe7d22015-01-25 22:13:13 -0800254
255 status := server.Status()
256 if got, want := endpointsToStrings(status.Endpoints), endpointsToStrings(eps); !reflect.DeepEqual(got, want) {
257 t.Fatalf("got %v, want %v", got, want)
258 }
259 names := status.Mounts.Names()
260 if len(names) != 1 || names[0] != name {
261 t.Fatalf("unexpected names: %v", names)
262 }
263 return eps[0], server
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700264}
265
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -0800266func loc(d int) string {
267 _, file, line, _ := runtime.Caller(d + 1)
268 return fmt.Sprintf("%s:%d", filepath.Base(file), line)
269}
270
Todd Wang5082a552015-04-02 10:56:11 -0700271func verifyMount(t *testing.T, ctx *context.T, ns namespace.T, name string) []string {
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700272 for {
273 me, err := ns.Resolve(ctx, name)
274 if err == nil {
275 return me.Names()
276 }
277 time.Sleep(10 * time.Millisecond)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700278 }
279}
280
Todd Wang5082a552015-04-02 10:56:11 -0700281func verifyMountMissing(t *testing.T, ctx *context.T, ns namespace.T, name string) {
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700282 for {
283 if _, err := ns.Resolve(ctx, name); err != nil {
284 // Assume that any error (since we're using a mock namespace) means
285 // that the name is no longer present.
286 return
287 }
288 time.Sleep(10 * time.Millisecond)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700289 }
290}
291
Todd Wang5082a552015-04-02 10:56:11 -0700292func stopServer(t *testing.T, ctx *context.T, server rpc.Server, ns namespace.T, name string) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700293 ctx.VI(1).Info("server.Stop")
Ankure49a86a2014-11-11 18:52:43 -0800294 new_name := "should_appear_in_mt/server"
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700295 verifyMount(t, ctx, ns, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700296
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700297 // publish a second name
Ankure49a86a2014-11-11 18:52:43 -0800298 if err := server.AddName(new_name); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700299 t.Errorf("server.Serve failed: %v", err)
300 }
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700301 verifyMount(t, ctx, ns, new_name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700302
303 if err := server.Stop(); err != nil {
304 t.Errorf("server.Stop failed: %v", err)
305 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700306
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700307 verifyMountMissing(t, ctx, ns, name)
308 verifyMountMissing(t, ctx, ns, new_name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700309
310 // Check that we can no longer serve after Stop.
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800311 err := server.AddName("name doesn't matter")
Todd Wang8fa38762015-03-25 14:04:59 -0700312 if err == nil || verror.ErrorID(err) != verror.ErrBadState.ID {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700313 t.Errorf("either no error, or a wrong error was returned: %v", err)
314 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700315 ctx.VI(1).Info("server.Stop DONE")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700316}
317
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800318// fakeWSName creates a name containing a endpoint address that forces
319// the use of websockets. It does so by resolving the original name
320// and choosing the 'ws' endpoint from the set of endpoints returned.
321// It must return a name since it'll be passed to StartCall.
Todd Wang5082a552015-04-02 10:56:11 -0700322func fakeWSName(ctx *context.T, ns namespace.T, name string) (string, error) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800323 // Find the ws endpoint and use that.
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700324 me, err := ns.Resolve(ctx, name)
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800325 if err != nil {
326 return "", err
327 }
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800328 names := me.Names()
329 for _, s := range names {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800330 if strings.Index(s, "@ws@") != -1 {
331 return s, nil
332 }
333 }
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800334 return "", fmt.Errorf("No ws endpoint found %v", names)
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800335}
336
Bogdan Caprita27953142014-05-12 11:41:42 -0700337type bundle struct {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700338 client rpc.Client
339 server rpc.Server
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700340 ep naming.Endpoint
Todd Wang5082a552015-04-02 10:56:11 -0700341 ns namespace.T
Bogdan Caprita27953142014-05-12 11:41:42 -0700342 sm stream.Manager
Ankure49a86a2014-11-11 18:52:43 -0800343 name string
Bogdan Caprita27953142014-05-12 11:41:42 -0700344}
345
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700346func (b bundle) cleanup(t *testing.T, ctx *context.T) {
Ankura3c97652014-07-17 20:01:21 -0700347 if b.server != nil {
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700348 stopServer(t, ctx, b.server, b.ns, b.name)
Ankura3c97652014-07-17 20:01:21 -0700349 }
350 if b.client != nil {
351 b.client.Close()
352 }
Bogdan Caprita27953142014-05-12 11:41:42 -0700353}
354
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700355func createBundle(t *testing.T, ctx *context.T, server security.Principal, ts interface{}) (b bundle) {
356 return createBundleWS(t, ctx, server, ts, noWebsocket)
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800357}
358
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700359func createBundleWS(t *testing.T, ctx *context.T, server security.Principal, ts interface{}, shouldUseWebsocket websocketMode) (b bundle) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700360 b.sm = imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
Matt Rosencrantz9fe60822014-09-12 10:09:53 -0700361 b.ns = tnaming.NewSimpleNamespace()
Ankure49a86a2014-11-11 18:52:43 -0800362 b.name = "mountpoint/server"
Asim Shankar8f05c222014-10-06 22:08:19 -0700363 if server != nil {
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700364 b.ep, b.server = startServerWS(t, ctx, server, b.sm, b.ns, b.name, testServerDisp{ts}, shouldUseWebsocket)
Ankura3c97652014-07-17 20:01:21 -0700365 }
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700366 b.client = DeprecatedNewClient(b.sm, b.ns)
Bogdan Caprita27953142014-05-12 11:41:42 -0700367 return
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700368}
369
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800370func matchesErrorPattern(err error, id verror.IDAction, pattern string) bool {
Asim Shankar558ea012015-01-28 12:49:36 -0800371 if len(pattern) > 0 && err != nil && strings.Index(err.Error(), pattern) < 0 {
372 return false
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700373 }
Cosmos Nicolaou1bce7d12015-01-05 17:42:06 -0800374 if err == nil && id.ID == "" {
375 return true
Cosmos Nicolaou112bf1c2014-11-21 15:43:11 -0800376 }
Todd Wang8fa38762015-03-25 14:04:59 -0700377 return verror.ErrorID(err) == id.ID
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700378}
379
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700380func runServer(t *testing.T, ctx *context.T, ns namespace.T, name string, obj interface{}, opts ...rpc.ServerOpt) stream.Manager {
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -0800381 rid, err := naming.NewRoutingID()
382 if err != nil {
383 t.Fatal(err)
384 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700385 sm := imanager.InternalNew(ctx, rid)
386 server, err := testInternalNewServer(ctx, sm, ns, opts...)
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -0800387 if err != nil {
388 t.Fatal(err)
389 }
390 if _, err := server.Listen(listenSpec); err != nil {
391 t.Fatal(err)
392 }
Asim Shankar149b4972015-04-23 13:29:58 -0700393 if err := server.Serve(name, obj, security.AllowEveryone()); err != nil {
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -0800394 t.Fatal(err)
395 }
396 return sm
397}
398
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800399type websocketMode bool
400type closeSendMode bool
401
402const (
403 useWebsocket websocketMode = true
404 noWebsocket websocketMode = false
405
406 closeSend closeSendMode = true
407 noCloseSend closeSendMode = false
408)
409
Asim Shankarf4864f42014-11-25 18:53:05 -0800410// dischargeTestServer implements the discharge service. Always fails to
411// issue a discharge, but records the impetus and traceid of the RPC call.
412type dischargeTestServer struct {
413 p security.Principal
414 impetus []security.DischargeImpetus
Benjamin Prosnitzc97fe192015-02-03 10:33:25 -0800415 traceid []uniqueid.Id
Asim Shankara94e5072014-08-19 18:18:36 -0700416}
417
Todd Wang54feabe2015-04-15 23:38:26 -0700418func (s *dischargeTestServer) Discharge(ctx *context.T, _ rpc.ServerCall, cav security.Caveat, impetus security.DischargeImpetus) (security.Discharge, error) {
Asim Shankarc8cfcf12014-11-20 12:26:58 -0800419 s.impetus = append(s.impetus, impetus)
Todd Wang54feabe2015-04-15 23:38:26 -0700420 s.traceid = append(s.traceid, vtrace.GetSpan(ctx).Trace())
Asim Shankar08642822015-03-02 21:21:09 -0800421 return security.Discharge{}, fmt.Errorf("discharges not issued")
Asim Shankara94e5072014-08-19 18:18:36 -0700422}
423
Benjamin Prosnitzc97fe192015-02-03 10:33:25 -0800424func (s *dischargeTestServer) Release() ([]security.DischargeImpetus, []uniqueid.Id) {
Asim Shankarf4864f42014-11-25 18:53:05 -0800425 impetus, traceid := s.impetus, s.traceid
426 s.impetus, s.traceid = nil, nil
427 return impetus, traceid
Asim Shankarc8cfcf12014-11-20 12:26:58 -0800428}
429
Asim Shankar263c73b2015-03-19 18:31:26 -0700430// singleBlessingStore implements security.BlessingStore. It is a
Ankurb905dae2015-03-04 12:38:20 -0800431// BlessingStore that marks the last blessing that was set on it as
432// shareable with any peer. It does not care about the public key that
433// blessing being set is bound to.
Asim Shankar263c73b2015-03-19 18:31:26 -0700434type singleBlessingStore struct {
Ankurb905dae2015-03-04 12:38:20 -0800435 b security.Blessings
436}
437
Asim Shankar263c73b2015-03-19 18:31:26 -0700438func (s *singleBlessingStore) Set(b security.Blessings, _ security.BlessingPattern) (security.Blessings, error) {
Ankurb905dae2015-03-04 12:38:20 -0800439 s.b = b
440 return security.Blessings{}, nil
441}
Asim Shankar263c73b2015-03-19 18:31:26 -0700442func (s *singleBlessingStore) ForPeer(...string) security.Blessings {
Ankurb905dae2015-03-04 12:38:20 -0800443 return s.b
444}
Asim Shankar263c73b2015-03-19 18:31:26 -0700445func (*singleBlessingStore) SetDefault(b security.Blessings) error {
Ankurb905dae2015-03-04 12:38:20 -0800446 return nil
447}
Asim Shankar263c73b2015-03-19 18:31:26 -0700448func (*singleBlessingStore) Default() security.Blessings {
Ankurb905dae2015-03-04 12:38:20 -0800449 return security.Blessings{}
450}
Asim Shankar263c73b2015-03-19 18:31:26 -0700451func (*singleBlessingStore) PublicKey() security.PublicKey {
Ankurb905dae2015-03-04 12:38:20 -0800452 return nil
453}
Asim Shankar263c73b2015-03-19 18:31:26 -0700454func (*singleBlessingStore) DebugString() string {
Ankurb905dae2015-03-04 12:38:20 -0800455 return ""
456}
Asim Shankar263c73b2015-03-19 18:31:26 -0700457func (*singleBlessingStore) PeerBlessings() map[security.BlessingPattern]security.Blessings {
Ankurb905dae2015-03-04 12:38:20 -0800458 return nil
459}
Suharsh Sivakumard7d4e222015-06-22 11:10:44 -0700460func (*singleBlessingStore) CacheDischarge(security.Discharge, security.Caveat, security.DischargeImpetus) {
461 return
462}
463func (*singleBlessingStore) ClearDischarges(...security.Discharge) {
464 return
465}
466func (*singleBlessingStore) Discharge(security.Caveat, security.DischargeImpetus) security.Discharge {
467 return security.Discharge{}
468}
Ankurb905dae2015-03-04 12:38:20 -0800469
Asim Shankar263c73b2015-03-19 18:31:26 -0700470// singleBlessingPrincipal implements security.Principal. It is a wrapper over
Ankurb905dae2015-03-04 12:38:20 -0800471// a security.Principal that intercepts all invocations on the
Asim Shankar263c73b2015-03-19 18:31:26 -0700472// principal's BlessingStore and serves them via a singleBlessingStore.
473type singleBlessingPrincipal struct {
Ankurb905dae2015-03-04 12:38:20 -0800474 security.Principal
Asim Shankar263c73b2015-03-19 18:31:26 -0700475 b singleBlessingStore
Ankurb905dae2015-03-04 12:38:20 -0800476}
477
Asim Shankar263c73b2015-03-19 18:31:26 -0700478func (p *singleBlessingPrincipal) BlessingStore() security.BlessingStore {
Ankurb905dae2015-03-04 12:38:20 -0800479 return &p.b
480}
481
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -0700482func TestSecurityNone(t *testing.T) {
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700483 ctx, shutdown := initForTest()
484 defer shutdown()
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700485 sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x66666666))
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -0700486 defer sm.Shutdown()
487 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumar2c5d8102015-03-23 08:49:12 -0700488 server, err := testInternalNewServer(ctx, sm, ns, nil, options.SecurityNone)
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -0700489 if err != nil {
490 t.Fatalf("InternalNewServer failed: %v", err)
491 }
492 if _, err = server.Listen(listenSpec); err != nil {
493 t.Fatalf("server.Listen failed: %v", err)
494 }
495 disp := &testServerDisp{&testServer{}}
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800496 if err := server.ServeDispatcher("mp/server", disp); err != nil {
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -0700497 t.Fatalf("server.Serve failed: %v", err)
498 }
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700499 client := DeprecatedNewClient(sm, ns)
Suharsh Sivakumar2c5d8102015-03-23 08:49:12 -0700500 // When using SecurityNone, all authorization checks should be skipped, so
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800501 // unauthorized methods should be callable.
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -0700502 var got string
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700503 if err := client.Call(ctx, "mp/server", "Unauthorized", nil, []interface{}{&got}, options.SecurityNone); err != nil {
504 t.Fatalf("client.Call failed: %v", err)
Suharsh Sivakumarcd743f72014-10-27 10:03:42 -0700505 }
506 if want := "UnauthorizedResult"; got != want {
507 t.Errorf("got (%v), want (%v)", got, want)
508 }
509}
510
Suharsh Sivakumar0ed10c22015-04-06 12:55:55 -0700511func TestNoPrincipal(t *testing.T) {
512 ctx, shutdown := initForTest()
513 defer shutdown()
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700514 sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x66666666))
Suharsh Sivakumar0ed10c22015-04-06 12:55:55 -0700515 defer sm.Shutdown()
516 ns := tnaming.NewSimpleNamespace()
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700517 ctx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal("server"))
518 server, err := testInternalNewServer(ctx, sm, ns)
Suharsh Sivakumar0ed10c22015-04-06 12:55:55 -0700519 if err != nil {
520 t.Fatalf("InternalNewServer failed: %v", err)
521 }
522 if _, err = server.Listen(listenSpec); err != nil {
523 t.Fatalf("server.Listen failed: %v", err)
524 }
525 disp := &testServerDisp{&testServer{}}
526 if err := server.ServeDispatcher("mp/server", disp); err != nil {
527 t.Fatalf("server.Serve failed: %v", err)
528 }
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700529 client := DeprecatedNewClient(sm, ns)
Suharsh Sivakumar0ed10c22015-04-06 12:55:55 -0700530
531 // A call should fail if the principal in the ctx is nil and SecurityNone is not specified.
Todd Wangad492042015-04-17 15:58:40 -0700532 ctx, err = v23.WithPrincipal(ctx, nil)
Suharsh Sivakumar0ed10c22015-04-06 12:55:55 -0700533 if err != nil {
534 t.Fatalf("failed to set principal: %v", err)
535 }
536 _, err = client.StartCall(ctx, "mp/server", "Echo", []interface{}{"foo"})
537 if err == nil || verror.ErrorID(err) != errNoPrincipal.ID {
538 t.Fatalf("Expected errNoPrincipal, got %v", err)
539 }
540}
541
Asim Shankara5b60b22014-11-06 15:37:07 -0800542func TestServerBlessingsOpt(t *testing.T) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700543 ctx, shutdown := initForTest()
544 defer shutdown()
545
Asim Shankara5b60b22014-11-06 15:37:07 -0800546 var (
Asim Shankar4a698282015-03-21 21:59:18 -0700547 pserver = testutil.NewPrincipal("server")
548 pclient = testutil.NewPrincipal("client")
Asim Shankara5b60b22014-11-06 15:37:07 -0800549 batman, _ = pserver.BlessSelf("batman")
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700550 cctx, _ = v23.WithPrincipal(ctx, pclient)
551 sctx, _ = v23.WithPrincipal(ctx, pserver)
Asim Shankara5b60b22014-11-06 15:37:07 -0800552 )
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700553
Asim Shankar7171a252015-03-07 14:41:40 -0800554 // Client and server recognize the servers blessings
555 for _, p := range []security.Principal{pserver, pclient} {
556 if err := p.AddToRoots(pserver.BlessingStore().Default()); err != nil {
557 t.Fatal(err)
558 }
559 if err := p.AddToRoots(batman); err != nil {
560 t.Fatal(err)
561 }
Asim Shankara5b60b22014-11-06 15:37:07 -0800562 }
563 // Start a server that uses the ServerBlessings option to configure itself
564 // to act as batman (as opposed to using the default blessing).
565 ns := tnaming.NewSimpleNamespace()
Asim Shankara5b60b22014-11-06 15:37:07 -0800566
Jiri Simsad9a7b3c2015-08-12 16:38:27 -0700567 defer runServer(t, sctx, ns, "mountpoint/batman", &testServer{}, options.ServerBlessings{Blessings: batman}).Shutdown()
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700568 defer runServer(t, sctx, ns, "mountpoint/default", &testServer{}).Shutdown()
Asim Shankara5b60b22014-11-06 15:37:07 -0800569
Asim Shankarb547ea92015-02-17 18:49:45 -0800570 // And finally, make an RPC and see that the client sees "batman"
Asim Shankara5b60b22014-11-06 15:37:07 -0800571 runClient := func(server string) ([]string, error) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700572 smc := imanager.InternalNew(ctx, naming.FixedRoutingID(0xc))
Asim Shankara5b60b22014-11-06 15:37:07 -0800573 defer smc.Shutdown()
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700574 client := DeprecatedNewClient(smc, ns)
Asim Shankara5b60b22014-11-06 15:37:07 -0800575 defer client.Close()
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700576 ctx, _ = v23.WithPrincipal(cctx, pclient)
577 call, err := client.StartCall(cctx, server, "Closure", nil)
Asim Shankara5b60b22014-11-06 15:37:07 -0800578 if err != nil {
579 return nil, err
580 }
581 blessings, _ := call.RemoteBlessings()
582 return blessings, nil
583 }
584
585 // When talking to mountpoint/batman, should see "batman"
586 // When talking to mountpoint/default, should see "server"
587 if got, err := runClient("mountpoint/batman"); err != nil || len(got) != 1 || got[0] != "batman" {
588 t.Errorf("Got (%v, %v) wanted 'batman'", got, err)
589 }
590 if got, err := runClient("mountpoint/default"); err != nil || len(got) != 1 || got[0] != "server" {
591 t.Errorf("Got (%v, %v) wanted 'server'", got, err)
592 }
593}
594
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800595func TestNoDischargesOpt(t *testing.T) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700596 ctx, shutdown := initForTest()
597 defer shutdown()
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800598 var (
Asim Shankar4a698282015-03-21 21:59:18 -0700599 pdischarger = testutil.NewPrincipal("discharger")
600 pserver = testutil.NewPrincipal("server")
601 pclient = testutil.NewPrincipal("client")
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700602 cctx, _ = v23.WithPrincipal(ctx, pclient)
603 sctx, _ = v23.WithPrincipal(ctx, pserver)
604 pctx, _ = v23.WithPrincipal(ctx, pdischarger)
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800605 )
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700606
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800607 // Make the client recognize all server blessings
608 if err := pclient.AddToRoots(pserver.BlessingStore().Default()); err != nil {
609 t.Fatal(err)
610 }
611 if err := pclient.AddToRoots(pdischarger.BlessingStore().Default()); err != nil {
612 t.Fatal(err)
613 }
614
615 // Bless the client with a ThirdPartyCaveat.
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -0700616 tpcav := mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour))))
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800617 blessings, err := pserver.Bless(pclient.PublicKey(), pserver.BlessingStore().Default(), "tpcav", tpcav)
618 if err != nil {
619 t.Fatalf("failed to create Blessings: %v", err)
620 }
621 if _, err = pclient.BlessingStore().Set(blessings, "server"); err != nil {
622 t.Fatalf("failed to set blessings: %v", err)
623 }
624
625 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800626
627 // Setup the disharger and test server.
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800628 discharger := &dischargeServer{}
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700629 defer runServer(t, pctx, ns, "mountpoint/discharger", discharger).Shutdown()
630 defer runServer(t, sctx, ns, "mountpoint/testServer", &testServer{}).Shutdown()
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800631
632 runClient := func(noDischarges bool) {
633 rid, err := naming.NewRoutingID()
634 if err != nil {
635 t.Fatal(err)
636 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700637 smc := imanager.InternalNew(ctx, rid)
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800638 defer smc.Shutdown()
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700639 client := DeprecatedNewClient(smc, ns)
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800640 defer client.Close()
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700641 var opts []rpc.CallOpt
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800642 if noDischarges {
Ankur50a5f392015-02-27 18:46:30 -0800643 opts = append(opts, NoDischarges{})
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800644 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700645 if _, err = client.StartCall(cctx, "mountpoint/testServer", "Closure", nil, opts...); err != nil {
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800646 t.Fatalf("failed to StartCall: %v", err)
647 }
648 }
649
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800650 // Test that when the NoDischarges option is set, dischargeServer does not get called.
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800651 if runClient(true); discharger.called {
652 t.Errorf("did not expect discharger to be called")
653 }
654 discharger.called = false
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800655 // Test that when the Nodischarges option is not set, dischargeServer does get called.
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800656 if runClient(false); !discharger.called {
657 t.Errorf("expected discharger to be called")
658 }
659}
660
661func TestNoImplicitDischargeFetching(t *testing.T) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700662 ctx, shutdown := initForTest()
663 defer shutdown()
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800664 // This test ensures that discharge clients only fetch discharges for the specified tp caveats and not its own.
665 var (
Asim Shankar4a698282015-03-21 21:59:18 -0700666 pdischarger1 = testutil.NewPrincipal("discharger1")
667 pdischarger2 = testutil.NewPrincipal("discharger2")
668 pdischargeClient = testutil.NewPrincipal("dischargeClient")
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700669 p1ctx, _ = v23.WithPrincipal(ctx, pdischarger1)
670 p2ctx, _ = v23.WithPrincipal(ctx, pdischarger2)
671 cctx, _ = v23.WithPrincipal(ctx, pdischargeClient)
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800672 )
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700673
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800674 // Bless the client with a ThirdPartyCaveat from discharger1.
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -0700675 tpcav1 := mkThirdPartyCaveat(pdischarger1.PublicKey(), "mountpoint/discharger1", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour))))
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800676 blessings, err := pdischarger1.Bless(pdischargeClient.PublicKey(), pdischarger1.BlessingStore().Default(), "tpcav1", tpcav1)
677 if err != nil {
678 t.Fatalf("failed to create Blessings: %v", err)
679 }
680 if err = pdischargeClient.BlessingStore().SetDefault(blessings); err != nil {
681 t.Fatalf("failed to set blessings: %v", err)
682 }
Asim Shankar263c73b2015-03-19 18:31:26 -0700683 // The client will only talk to the discharge services if it recognizes them.
684 pdischargeClient.AddToRoots(pdischarger1.BlessingStore().Default())
685 pdischargeClient.AddToRoots(pdischarger2.BlessingStore().Default())
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800686
687 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800688
689 // Setup the disharger and test server.
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800690 discharger1 := &dischargeServer{}
691 discharger2 := &dischargeServer{}
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700692 defer runServer(t, p1ctx, ns, "mountpoint/discharger1", discharger1).Shutdown()
693 defer runServer(t, p2ctx, ns, "mountpoint/discharger2", discharger2).Shutdown()
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800694
695 rid, err := naming.NewRoutingID()
696 if err != nil {
697 t.Fatal(err)
698 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700699 sm := imanager.InternalNew(ctx, rid)
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -0800700
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700701 c := DeprecatedNewClient(sm, ns)
Suharsh Sivakumar1b6683e2014-12-30 13:00:38 -0800702 dc := c.(*client).dc
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -0700703 tpcav2, err := security.NewPublicKeyCaveat(pdischarger2.PublicKey(), "mountpoint/discharger2", security.ThirdPartyRequirements{}, mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour))))
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800704 if err != nil {
705 t.Error(err)
706 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700707 dc.PrepareDischarges(cctx, []security.Caveat{tpcav2}, security.DischargeImpetus{})
Suharsh Sivakumar11316872014-11-25 15:57:00 -0800708
709 // Ensure that discharger1 was not called and discharger2 was called.
710 if discharger1.called {
711 t.Errorf("discharge for caveat on discharge client should not have been fetched.")
712 }
713 if !discharger2.called {
714 t.Errorf("discharge for caveat passed to PrepareDischarges should have been fetched.")
715 }
716}
717
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800718// TestBlessingsCache tests that the VCCache is used to sucessfully used to cache duplicate
719// calls blessings.
720func TestBlessingsCache(t *testing.T) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700721 ctx, shutdown := initForTest()
722 defer shutdown()
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800723 var (
Asim Shankar4a698282015-03-21 21:59:18 -0700724 pserver = testutil.NewPrincipal("server")
725 pclient = testutil.NewPrincipal("client")
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700726 cctx, _ = v23.WithPrincipal(ctx, pclient)
727 sctx, _ = v23.WithPrincipal(ctx, pserver)
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800728 )
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700729
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800730 // Make the client recognize all server blessings
731 if err := pclient.AddToRoots(pserver.BlessingStore().Default()); err != nil {
732 t.Fatal(err)
733 }
734
735 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800736
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700737 serverSM := runServer(t, sctx, ns, "mountpoint/testServer", &testServer{})
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800738 defer serverSM.Shutdown()
Suharsh Sivakumar0902b7f2015-02-27 19:06:41 -0800739 rid := serverSM.RoutingID()
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800740
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700741 newClient := func() rpc.Client {
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800742 rid, err := naming.NewRoutingID()
743 if err != nil {
744 t.Fatal(err)
745 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700746 smc := imanager.InternalNew(sctx, rid)
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800747 defer smc.Shutdown()
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700748 return DeprecatedNewClient(smc, ns)
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800749 }
750
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700751 runClient := func(client rpc.Client) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700752 if err := client.Call(cctx, "mountpoint/testServer", "Closure", nil, nil); err != nil {
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700753 t.Fatalf("failed to Call: %v", err)
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800754 }
755 }
756
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700757 cachePrefix := naming.Join("rpc", "server", "routing-id", rid.String(), "security", "blessings", "cache")
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800758 cacheHits, err := stats.GetStatsObject(naming.Join(cachePrefix, "hits"))
759 if err != nil {
760 t.Fatal(err)
761 }
762 cacheAttempts, err := stats.GetStatsObject(naming.Join(cachePrefix, "attempts"))
763 if err != nil {
764 t.Fatal(err)
765 }
766
767 // Check that the blessings cache is not used on the first call.
768 clientA := newClient()
769 runClient(clientA)
770 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 1 || gotHits != 0 {
771 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(1), cacheHits(0)", gotAttempts, gotHits)
772 }
773 // Check that the cache is hit on the second call with the same blessings.
774 runClient(clientA)
775 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 2 || gotHits != 1 {
776 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(2), cacheHits(1)", gotAttempts, gotHits)
777 }
778 clientA.Close()
779 // Check that the cache is not used with a different client.
780 clientB := newClient()
781 runClient(clientB)
782 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 3 || gotHits != 1 {
783 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(3), cacheHits(1)", gotAttempts, gotHits)
784 }
785 // clientB changes its blessings, the cache should not be used.
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -0700786 blessings, err := pserver.Bless(pclient.PublicKey(), pserver.BlessingStore().Default(), "cav", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour))))
Suharsh Sivakumar720b7042014-12-22 17:33:23 -0800787 if err != nil {
788 t.Fatalf("failed to create Blessings: %v", err)
789 }
790 if _, err = pclient.BlessingStore().Set(blessings, "server"); err != nil {
791 t.Fatalf("failed to set blessings: %v", err)
792 }
793 runClient(clientB)
794 if gotAttempts, gotHits := cacheAttempts.Value().(int64), cacheHits.Value().(int64); gotAttempts != 4 || gotHits != 1 {
795 t.Errorf("got cacheAttempts(%v), cacheHits(%v), expected cacheAttempts(4), cacheHits(1)", gotAttempts, gotHits)
796 }
797 clientB.Close()
798}
799
Asim Shankar7283dd82015-02-03 19:35:58 -0800800var fakeTimeCaveat = security.CaveatDescriptor{
801 Id: uniqueid.Id{0x18, 0xba, 0x6f, 0x84, 0xd5, 0xec, 0xdb, 0x9b, 0xf2, 0x32, 0x19, 0x5b, 0x53, 0x92, 0x80, 0x0},
802 ParamType: vdl.TypeOf(int64(0)),
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700803}
Suharsh Sivakumar9d17e4a2015-02-02 22:42:16 -0800804
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800805func TestServerPublicKeyOpt(t *testing.T) {
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700806 ctx, shutdown := initForTest()
807 defer shutdown()
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800808 var (
Asim Shankar4a698282015-03-21 21:59:18 -0700809 pserver = testutil.NewPrincipal("server")
810 pother = testutil.NewPrincipal("other")
811 pclient = testutil.NewPrincipal("client")
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700812 cctx, _ = v23.WithPrincipal(ctx, pclient)
813 sctx, _ = v23.WithPrincipal(ctx, pserver)
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800814 )
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700815
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800816 ns := tnaming.NewSimpleNamespace()
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800817 mountName := "mountpoint/default"
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800818
819 // Start a server with pserver.
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700820 defer runServer(t, sctx, ns, mountName, &testServer{}).Shutdown()
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800821
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700822 smc := imanager.InternalNew(sctx, naming.FixedRoutingID(0xc))
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700823 client := DeprecatedNewClient(smc, ns)
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800824 defer smc.Shutdown()
825 defer client.Close()
826
827 // The call should succeed when the server presents the same public as the opt...
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700828 var err error
Jiri Simsad9a7b3c2015-08-12 16:38:27 -0700829 if _, err = client.StartCall(cctx, mountName, "Closure", nil, options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{
830 PublicKey: pserver.PublicKey(),
831 }); err != nil {
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800832 t.Errorf("Expected call to succeed but got %v", err)
833 }
834 // ...but fail if they differ.
Jiri Simsad9a7b3c2015-08-12 16:38:27 -0700835 if _, err = client.StartCall(cctx, mountName, "Closure", nil, options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{
836 PublicKey: pother.PublicKey(),
837 }); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
Jiri Simsa074bf362015-02-17 09:29:45 -0800838 t.Errorf("got %v, want %v", verror.ErrorID(err), verror.ErrNotTrusted.ID)
Suharsh Sivakumara8633b02015-02-14 17:08:07 -0800839 }
840}
841
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800842type expiryDischarger struct {
843 called bool
844}
845
Todd Wang4264e4b2015-04-16 22:43:40 -0700846func (ed *expiryDischarger) Discharge(ctx *context.T, call rpc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.Discharge, error) {
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800847 tp := cav.ThirdPartyDetails()
848 if tp == nil {
Asim Shankar08642822015-03-02 21:21:09 -0800849 return security.Discharge{}, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav)
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800850 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700851 if err := tp.Dischargeable(ctx, call.Security()); err != nil {
Asim Shankar08642822015-03-02 21:21:09 -0800852 return security.Discharge{}, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err)
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800853 }
854 expDur := 10 * time.Millisecond
855 if ed.called {
856 expDur = time.Second
857 }
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -0700858 expiry, err := security.NewExpiryCaveat(time.Now().Add(expDur))
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800859 if err != nil {
Asim Shankar08642822015-03-02 21:21:09 -0800860 return security.Discharge{}, fmt.Errorf("failed to create an expiration on the discharge: %v", err)
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800861 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700862 d, err := call.Security().LocalPrincipal().MintDischarge(cav, expiry)
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800863 if err != nil {
Asim Shankar08642822015-03-02 21:21:09 -0800864 return security.Discharge{}, err
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800865 }
866 ed.called = true
Asim Shankar08642822015-03-02 21:21:09 -0800867 return d, nil
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800868}
869
870func TestDischargeClientFetchExpiredDischarges(t *testing.T) {
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700871 ctx, shutdown := initForTest()
872 defer shutdown()
Asim Shankar263c73b2015-03-19 18:31:26 -0700873 var (
874 pclient, pdischarger = newClientServerPrincipals()
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -0700875 tpcav = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour))))
Asim Shankar263c73b2015-03-19 18:31:26 -0700876 ns = tnaming.NewSimpleNamespace()
877 discharger = &expiryDischarger{}
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700878 pctx, _ = v23.WithPrincipal(ctx, pdischarger)
Asim Shankar263c73b2015-03-19 18:31:26 -0700879 )
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700880 ctx, _ = v23.WithPrincipal(ctx, pclient)
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800881
882 // Setup the disharge server.
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700883 defer runServer(t, pctx, ns, "mountpoint/discharger", discharger).Shutdown()
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800884
885 // Create a discharge client.
886 rid, err := naming.NewRoutingID()
887 if err != nil {
888 t.Fatal(err)
889 }
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700890 smc := imanager.InternalNew(ctx, rid)
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800891 defer smc.Shutdown()
Matt Rosencrantz80752cc2015-09-29 16:32:02 -0700892 client := DeprecatedNewClient(smc, ns)
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800893 defer client.Close()
Cosmos Nicolaoue9c622d2015-07-10 11:09:42 -0700894
Suharsh Sivakumar08918582015-03-03 15:16:36 -0800895 dc := InternalNewDischargeClient(ctx, client, 0)
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800896
897 // Fetch discharges for tpcav.
Asim Shankar263c73b2015-03-19 18:31:26 -0700898 dis := dc.PrepareDischarges(ctx, []security.Caveat{tpcav}, security.DischargeImpetus{})[0]
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800899 // Check that the discharges is not yet expired, but is expired after 100 milliseconds.
900 expiry := dis.Expiry()
901 // The discharge should expire.
902 select {
903 case <-time.After(time.Now().Sub(expiry)):
904 break
905 case <-time.After(time.Second):
906 t.Fatalf("discharge didn't expire within a second")
907 }
908 // Preparing Discharges again to get fresh discharges.
909 now := time.Now()
Asim Shankar263c73b2015-03-19 18:31:26 -0700910 dis = dc.PrepareDischarges(ctx, []security.Caveat{tpcav}, security.DischargeImpetus{})[0]
Suharsh Sivakumarcd07e252015-02-28 01:04:26 -0800911 if expiry = dis.Expiry(); expiry.Before(now) {
912 t.Fatalf("discharge has expired %v, but should be fresh", dis)
913 }
914}
915
Asim Shankar263c73b2015-03-19 18:31:26 -0700916// newClientServerPrincipals creates a pair of principals and sets them up to
917// recognize each others default blessings.
918//
919// If the client does not recognize the blessings presented by the server,
920// then it will not even send it the request.
921//
922// If the server does not recognize the blessings presented by the client,
923// it is likely to deny access (unless the server authorizes all principals).
924func newClientServerPrincipals() (client, server security.Principal) {
Asim Shankar4a698282015-03-21 21:59:18 -0700925 client = testutil.NewPrincipal("client")
926 server = testutil.NewPrincipal("server")
Asim Shankar263c73b2015-03-19 18:31:26 -0700927 client.AddToRoots(server.BlessingStore().Default())
928 server.AddToRoots(client.BlessingStore().Default())
929 return
930}
931
Suharsh Sivakumard19c95d2015-02-19 14:44:50 -0800932func init() {
Suharsh Sivakumar7e93ce52015-05-07 17:46:13 -0700933 rpc.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridResolve, websocket.HybridListener)
Todd Wang4264e4b2015-04-16 22:43:40 -0700934 security.RegisterCaveatValidator(fakeTimeCaveat, func(_ *context.T, _ security.Call, t int64) error {
Suharsh Sivakumar8a0adbb2015-03-06 13:16:34 -0800935 if now := clock.Now(); now > t {
Asim Shankar7283dd82015-02-03 19:35:58 -0800936 return fmt.Errorf("fakeTimeCaveat expired: now=%d > then=%d", now, t)
937 }
938 return nil
939 })
Suharsh Sivakumar9d17e4a2015-02-02 22:42:16 -0800940}
Matt Rosencrantzaf3c76f2015-09-19 17:17:32 -0700941
942func TestServerStates(t *testing.T) {
943 ctx, shutdown := initForTest()
944 defer shutdown()
945 sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
946 defer sm.Shutdown()
947 ns := tnaming.NewSimpleNamespace()
948 sctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
949 expectBadState := func(err error) {
950 if verror.ErrorID(err) != verror.ErrBadState.ID {
951 t.Fatalf("%s: unexpected error: %v", loc(1), err)
952 }
953 }
954
955 expectNoError := func(err error) {
956 if err != nil {
957 t.Fatalf("%s: unexpected error: %v", loc(1), err)
958 }
959 }
960
961 server, err := testInternalNewServer(sctx, sm, ns)
962 expectNoError(err)
963 defer server.Stop()
964
965 expectState := func(s rpc.ServerState) {
966 if got, want := server.Status().State, s; got != want {
967 t.Fatalf("%s: got %s, want %s", loc(1), got, want)
968 }
969 }
970
971 expectState(rpc.ServerActive)
972
973 // Need to call Listen first.
974 err = server.Serve("", &testServer{}, nil)
975 expectBadState(err)
976 err = server.AddName("a")
977 expectBadState(err)
978
979 _, err = server.Listen(rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}})
980 expectNoError(err)
981
982 expectState(rpc.ServerActive)
983
984 err = server.Serve("", &testServer{}, nil)
985 expectNoError(err)
986
987 err = server.Serve("", &testServer{}, nil)
988 expectBadState(err)
989
990 expectState(rpc.ServerActive)
991
992 err = server.AddName("a")
993 expectNoError(err)
994
995 expectState(rpc.ServerActive)
996
997 server.RemoveName("a")
998
999 expectState(rpc.ServerActive)
1000
1001 err = server.Stop()
1002 expectNoError(err)
1003 err = server.Stop()
1004 expectNoError(err)
1005
1006 err = server.AddName("a")
1007 expectBadState(err)
1008}