Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // 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 Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 5 | package rpc |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 6 | |
| 7 | import ( |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 8 | "fmt" |
| 9 | "io" |
Cosmos Nicolaou | 9388ae4 | 2014-11-10 10:57:15 -0800 | [diff] [blame] | 10 | "path/filepath" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 11 | "reflect" |
Cosmos Nicolaou | 9388ae4 | 2014-11-10 10:57:15 -0800 | [diff] [blame] | 12 | "runtime" |
Cosmos Nicolaou | 9fbe7d2 | 2015-01-25 22:13:13 -0800 | [diff] [blame] | 13 | "sort" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 14 | "strings" |
Bogdan Caprita | 2795314 | 2014-05-12 11:41:42 -0700 | [diff] [blame] | 15 | "sync" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 16 | "testing" |
| 17 | "time" |
| 18 | |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 19 | "v.io/v23" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 20 | "v.io/v23/context" |
Matt Rosencrantz | 88be118 | 2015-04-27 13:45:43 -0700 | [diff] [blame] | 21 | "v.io/v23/i18n" |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 22 | "v.io/v23/namespace" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 23 | "v.io/v23/naming" |
| 24 | "v.io/v23/options" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 25 | "v.io/v23/rpc" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 26 | "v.io/v23/security" |
Todd Wang | 387d8a4 | 2015-03-30 17:09:05 -0700 | [diff] [blame] | 27 | "v.io/v23/security/access" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 28 | "v.io/v23/uniqueid" |
| 29 | "v.io/v23/vdl" |
| 30 | "v.io/v23/verror" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 31 | "v.io/v23/vtrace" |
Jiri Simsa | 574ec4b | 2015-08-11 09:31:37 -0700 | [diff] [blame] | 32 | "v.io/x/ref/lib/pubsub" |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 33 | "v.io/x/ref/lib/stats" |
Suharsh Sivakumar | dcc11d7 | 2015-05-11 12:19:20 -0700 | [diff] [blame] | 34 | "v.io/x/ref/runtime/internal/lib/websocket" |
Suharsh Sivakumar | dcc11d7 | 2015-05-11 12:19:20 -0700 | [diff] [blame] | 35 | _ "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 Sivakumar | dcc11d7 | 2015-05-11 12:19:20 -0700 | [diff] [blame] | 40 | tnaming "v.io/x/ref/runtime/internal/testing/mocks/naming" |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 41 | "v.io/x/ref/test/testutil" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 42 | ) |
| 43 | |
Nicolas Lacasse | 0f07c60 | 2015-09-24 16:57:06 -0700 | [diff] [blame] | 44 | //go:generate jiri test generate |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 45 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 46 | var ( |
Jiri Simsa | 074bf36 | 2015-02-17 09:29:45 -0800 | [diff] [blame] | 47 | errMethod = verror.New(verror.ErrAborted, nil) |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 48 | clock = new(fakeClock) |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 49 | 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 Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 53 | ) |
| 54 | |
Andres Erbsen | b7f95f3 | 2014-07-07 12:07:56 -0700 | [diff] [blame] | 55 | type fakeClock struct { |
| 56 | sync.Mutex |
Suharsh Sivakumar | 8a0adbb | 2015-03-06 13:16:34 -0800 | [diff] [blame] | 57 | time int64 |
Andres Erbsen | b7f95f3 | 2014-07-07 12:07:56 -0700 | [diff] [blame] | 58 | } |
| 59 | |
Suharsh Sivakumar | 8a0adbb | 2015-03-06 13:16:34 -0800 | [diff] [blame] | 60 | func (c *fakeClock) Now() int64 { |
Andres Erbsen | b7f95f3 | 2014-07-07 12:07:56 -0700 | [diff] [blame] | 61 | c.Lock() |
| 62 | defer c.Unlock() |
| 63 | return c.time |
| 64 | } |
| 65 | |
| 66 | func (c *fakeClock) Advance(steps uint) { |
| 67 | c.Lock() |
Suharsh Sivakumar | 8a0adbb | 2015-03-06 13:16:34 -0800 | [diff] [blame] | 68 | c.time += int64(steps) |
Andres Erbsen | b7f95f3 | 2014-07-07 12:07:56 -0700 | [diff] [blame] | 69 | c.Unlock() |
| 70 | } |
| 71 | |
Matt Rosencrantz | 5efd782 | 2015-09-15 18:07:17 -0700 | [diff] [blame] | 72 | func testInternalNewServerWithPubsub(ctx *context.T, streamMgr stream.Manager, ns namespace.T, settingsPublisher *pubsub.Publisher, settingsStreamName string, opts ...rpc.ServerOpt) (DeprecatedServer, error) { |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 73 | client := DeprecatedNewClient(streamMgr, ns) |
Matt Rosencrantz | af3c76f | 2015-09-19 17:17:32 -0700 | [diff] [blame] | 74 | return DeprecatedNewServer(ctx, streamMgr, ns, settingsPublisher, settingsStreamName, client, opts...) |
Cosmos Nicolaou | 00fe9a4 | 2015-04-24 14:18:01 -0700 | [diff] [blame] | 75 | } |
| 76 | |
Matt Rosencrantz | 5efd782 | 2015-09-15 18:07:17 -0700 | [diff] [blame] | 77 | func testInternalNewServer(ctx *context.T, streamMgr stream.Manager, ns namespace.T, opts ...rpc.ServerOpt) (DeprecatedServer, error) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 78 | return testInternalNewServerWithPubsub(ctx, streamMgr, ns, nil, "", opts...) |
Suharsh Sivakumar | af99c97 | 2015-01-28 15:28:49 -0800 | [diff] [blame] | 79 | } |
| 80 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 81 | type userType string |
| 82 | |
| 83 | type testServer struct{} |
| 84 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 85 | func (*testServer) Closure(*context.T, rpc.ServerCall) error { |
Todd Wang | e77f995 | 2015-02-18 13:20:50 -0800 | [diff] [blame] | 86 | return nil |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 87 | } |
| 88 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 89 | func (*testServer) Error(*context.T, rpc.ServerCall) error { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 90 | return errMethod |
| 91 | } |
| 92 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 93 | func (*testServer) Echo(_ *context.T, call rpc.ServerCall, arg string) (string, error) { |
Matt Rosencrantz | 311378b | 2015-03-25 15:26:12 -0700 | [diff] [blame] | 94 | return fmt.Sprintf("method:%q,suffix:%q,arg:%q", "Echo", call.Suffix(), arg), nil |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 95 | } |
| 96 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 97 | func (*testServer) EchoUser(_ *context.T, call rpc.ServerCall, arg string, u userType) (string, userType, error) { |
Matt Rosencrantz | 311378b | 2015-03-25 15:26:12 -0700 | [diff] [blame] | 98 | return fmt.Sprintf("method:%q,suffix:%q,arg:%q", "EchoUser", call.Suffix(), arg), u, nil |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 99 | } |
| 100 | |
Matt Rosencrantz | 88be118 | 2015-04-27 13:45:43 -0700 | [diff] [blame] | 101 | func (*testServer) EchoLang(ctx *context.T, call rpc.ServerCall) (string, error) { |
| 102 | return string(i18n.GetLangID(ctx)), nil |
| 103 | } |
| 104 | |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 105 | func (*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 Wang | e77f995 | 2015-02-18 13:20:50 -0800 | [diff] [blame] | 108 | return fmt.Sprintf("%v", local), fmt.Sprintf("%v", remote), nil |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 109 | } |
| 110 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 111 | func (*testServer) EchoGrantedBlessings(_ *context.T, call rpc.ServerCall, arg string) (result, blessing string, _ error) { |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 112 | return arg, fmt.Sprintf("%v", call.GrantedBlessings()), nil |
Asim Shankar | b54d764 | 2014-06-05 13:08:04 -0700 | [diff] [blame] | 113 | } |
| 114 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 115 | func (*testServer) EchoAndError(_ *context.T, call rpc.ServerCall, arg string) (string, error) { |
Matt Rosencrantz | 311378b | 2015-03-25 15:26:12 -0700 | [diff] [blame] | 116 | result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", "EchoAndError", call.Suffix(), arg) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 117 | if arg == "error" { |
| 118 | return result, errMethod |
| 119 | } |
| 120 | return result, nil |
| 121 | } |
| 122 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 123 | func (*testServer) Stream(_ *context.T, call rpc.StreamServerCall, arg string) (string, error) { |
Matt Rosencrantz | 311378b | 2015-03-25 15:26:12 -0700 | [diff] [blame] | 124 | result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", "Stream", call.Suffix(), arg) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 125 | 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 Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 139 | func (*testServer) Unauthorized(*context.T, rpc.StreamServerCall) (string, error) { |
Todd Wang | e77f995 | 2015-02-18 13:20:50 -0800 | [diff] [blame] | 140 | return "UnauthorizedResult", nil |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | type testServerAuthorizer struct{} |
| 144 | |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 145 | func (testServerAuthorizer) Authorize(ctx *context.T, call security.Call) error { |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 146 | // Verify that the Call object seen by the authorizer |
| 147 | // has the necessary fields. |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 148 | lb := call.LocalBlessings() |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 149 | if lb.IsZero() { |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 150 | return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalBlessings", call) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 151 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 152 | 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) |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 154 | |
| 155 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 156 | if call.LocalPrincipal() == nil { |
| 157 | return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalPrincipal", call) |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 158 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 159 | if call.Method() == "" { |
| 160 | return fmt.Errorf("testServerAuthorzer: Call object %v has no Method", call) |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 161 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 162 | if call.LocalEndpoint() == nil { |
| 163 | return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalEndpoint", call) |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 164 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 165 | if call.RemoteEndpoint() == nil { |
| 166 | return fmt.Errorf("testServerAuthorzer: Call object %v has no RemoteEndpoint", call) |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | // Do not authorize the method "Unauthorized". |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 170 | if call.Method() == "Unauthorized" { |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 171 | return fmt.Errorf("testServerAuthorizer denied access") |
| 172 | } |
| 173 | return nil |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | type testServerDisp struct{ server interface{} } |
| 177 | |
Cosmos Nicolaou | 5a3125a | 2015-07-10 11:19:20 -0700 | [diff] [blame] | 178 | func (t testServerDisp) Lookup(_ *context.T, suffix string) (interface{}, security.Authorizer, error) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 179 | // If suffix is "nilAuth" we use default authorization, if it is "aclAuth" we |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 180 | // use an AccessList-based authorizer, and otherwise we use the custom testServerAuthorizer. |
Andres Erbsen | b7f95f3 | 2014-07-07 12:07:56 -0700 | [diff] [blame] | 181 | var authorizer security.Authorizer |
| 182 | switch suffix { |
| 183 | case "discharger": |
Cosmos Nicolaou | 710daa2 | 2014-11-11 19:39:18 -0800 | [diff] [blame] | 184 | return &dischargeServer{}, testServerAuthorizer{}, nil |
Andres Erbsen | b7f95f3 | 2014-07-07 12:07:56 -0700 | [diff] [blame] | 185 | case "nilAuth": |
| 186 | authorizer = nil |
| 187 | case "aclAuth": |
Benjamin Prosnitz | b60efb9 | 2015-03-11 17:47:43 -0700 | [diff] [blame] | 188 | authorizer = &access.AccessList{ |
Ankur | 78b8b2a | 2015-02-04 20:16:28 -0800 | [diff] [blame] | 189 | In: []security.BlessingPattern{"client", "server"}, |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 190 | } |
Andres Erbsen | b7f95f3 | 2014-07-07 12:07:56 -0700 | [diff] [blame] | 191 | default: |
| 192 | authorizer = testServerAuthorizer{} |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 193 | } |
Cosmos Nicolaou | 710daa2 | 2014-11-11 19:39:18 -0800 | [diff] [blame] | 194 | return t.server, authorizer, nil |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 195 | } |
| 196 | |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 197 | type dischargeServer struct { |
| 198 | mu sync.Mutex |
| 199 | called bool |
| 200 | } |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 201 | |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 202 | func (ds *dischargeServer) Discharge(ctx *context.T, call rpc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.Discharge, error) { |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 203 | ds.mu.Lock() |
| 204 | ds.called = true |
| 205 | ds.mu.Unlock() |
Asim Shankar | 19da818 | 2015-02-06 01:41:16 -0800 | [diff] [blame] | 206 | tp := cav.ThirdPartyDetails() |
| 207 | if tp == nil { |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 208 | return security.Discharge{}, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav) |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 209 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 210 | if err := tp.Dischargeable(ctx, call.Security()); err != nil { |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 211 | return security.Discharge{}, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err) |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 212 | } |
| 213 | // Add a fakeTimeCaveat to be able to control discharge expiration via 'clock'. |
Asim Shankar | 7283dd8 | 2015-02-03 19:35:58 -0800 | [diff] [blame] | 214 | expiry, err := security.NewCaveat(fakeTimeCaveat, clock.Now()) |
| 215 | if err != nil { |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 216 | return security.Discharge{}, fmt.Errorf("failed to create an expiration on the discharge: %v", err) |
Asim Shankar | 7283dd8 | 2015-02-03 19:35:58 -0800 | [diff] [blame] | 217 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 218 | return call.Security().LocalPrincipal().MintDischarge(cav, expiry) |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 219 | } |
| 220 | |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 221 | func 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 Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 222 | return startServerWS(t, ctx, principal, sm, ns, name, disp, noWebsocket, opts...) |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 223 | } |
| 224 | |
Cosmos Nicolaou | 9fbe7d2 | 2015-01-25 22:13:13 -0800 | [diff] [blame] | 225 | func 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 Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 234 | func 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 Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 235 | ctx.VI(1).Info("InternalNewServer") |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 236 | ctx, _ = v23.WithPrincipal(ctx, principal) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 237 | server, err := testInternalNewServer(ctx, sm, ns, opts...) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 238 | if err != nil { |
| 239 | t.Errorf("InternalNewServer failed: %v", err) |
| 240 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 241 | ctx.VI(1).Info("server.Listen") |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 242 | spec := listenSpec |
| 243 | if shouldUseWebsocket { |
| 244 | spec = listenWSSpec |
| 245 | } |
Cosmos Nicolaou | 9fbe7d2 | 2015-01-25 22:13:13 -0800 | [diff] [blame] | 246 | eps, err := server.Listen(spec) |
Cosmos Nicolaou | fdc838b | 2014-06-30 21:44:27 -0700 | [diff] [blame] | 247 | if err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 248 | t.Errorf("server.Listen failed: %v", err) |
| 249 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 250 | ctx.VI(1).Info("server.Serve") |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 251 | if err := server.ServeDispatcher(name, disp); err != nil { |
| 252 | t.Errorf("server.ServeDispatcher failed: %v", err) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 253 | } |
Cosmos Nicolaou | 9fbe7d2 | 2015-01-25 22:13:13 -0800 | [diff] [blame] | 254 | |
| 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 Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 264 | } |
| 265 | |
Cosmos Nicolaou | 9388ae4 | 2014-11-10 10:57:15 -0800 | [diff] [blame] | 266 | func loc(d int) string { |
| 267 | _, file, line, _ := runtime.Caller(d + 1) |
| 268 | return fmt.Sprintf("%s:%d", filepath.Base(file), line) |
| 269 | } |
| 270 | |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 271 | func verifyMount(t *testing.T, ctx *context.T, ns namespace.T, name string) []string { |
Cosmos Nicolaou | 33cf898 | 2015-05-26 10:39:49 -0700 | [diff] [blame] | 272 | for { |
| 273 | me, err := ns.Resolve(ctx, name) |
| 274 | if err == nil { |
| 275 | return me.Names() |
| 276 | } |
| 277 | time.Sleep(10 * time.Millisecond) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 278 | } |
| 279 | } |
| 280 | |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 281 | func verifyMountMissing(t *testing.T, ctx *context.T, ns namespace.T, name string) { |
Cosmos Nicolaou | 33cf898 | 2015-05-26 10:39:49 -0700 | [diff] [blame] | 282 | 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 Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 289 | } |
| 290 | } |
| 291 | |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 292 | func stopServer(t *testing.T, ctx *context.T, server rpc.Server, ns namespace.T, name string) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 293 | ctx.VI(1).Info("server.Stop") |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 294 | new_name := "should_appear_in_mt/server" |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 295 | verifyMount(t, ctx, ns, name) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 296 | |
Cosmos Nicolaou | fdc838b | 2014-06-30 21:44:27 -0700 | [diff] [blame] | 297 | // publish a second name |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 298 | if err := server.AddName(new_name); err != nil { |
Cosmos Nicolaou | fdc838b | 2014-06-30 21:44:27 -0700 | [diff] [blame] | 299 | t.Errorf("server.Serve failed: %v", err) |
| 300 | } |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 301 | verifyMount(t, ctx, ns, new_name) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 302 | |
| 303 | if err := server.Stop(); err != nil { |
| 304 | t.Errorf("server.Stop failed: %v", err) |
| 305 | } |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 306 | |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 307 | verifyMountMissing(t, ctx, ns, name) |
| 308 | verifyMountMissing(t, ctx, ns, new_name) |
Cosmos Nicolaou | fdc838b | 2014-06-30 21:44:27 -0700 | [diff] [blame] | 309 | |
| 310 | // Check that we can no longer serve after Stop. |
Cosmos Nicolaou | 92dba58 | 2014-11-05 17:24:10 -0800 | [diff] [blame] | 311 | err := server.AddName("name doesn't matter") |
Todd Wang | 8fa3876 | 2015-03-25 14:04:59 -0700 | [diff] [blame] | 312 | if err == nil || verror.ErrorID(err) != verror.ErrBadState.ID { |
Cosmos Nicolaou | fdc838b | 2014-06-30 21:44:27 -0700 | [diff] [blame] | 313 | t.Errorf("either no error, or a wrong error was returned: %v", err) |
| 314 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 315 | ctx.VI(1).Info("server.Stop DONE") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 316 | } |
| 317 | |
Cosmos Nicolaou | 8bd8e10 | 2015-01-13 21:52:53 -0800 | [diff] [blame] | 318 | // 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 Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 322 | func fakeWSName(ctx *context.T, ns namespace.T, name string) (string, error) { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 323 | // Find the ws endpoint and use that. |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 324 | me, err := ns.Resolve(ctx, name) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 325 | if err != nil { |
| 326 | return "", err |
| 327 | } |
Cosmos Nicolaou | 8bd8e10 | 2015-01-13 21:52:53 -0800 | [diff] [blame] | 328 | names := me.Names() |
| 329 | for _, s := range names { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 330 | if strings.Index(s, "@ws@") != -1 { |
| 331 | return s, nil |
| 332 | } |
| 333 | } |
Cosmos Nicolaou | 8bd8e10 | 2015-01-13 21:52:53 -0800 | [diff] [blame] | 334 | return "", fmt.Errorf("No ws endpoint found %v", names) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 335 | } |
| 336 | |
Bogdan Caprita | 2795314 | 2014-05-12 11:41:42 -0700 | [diff] [blame] | 337 | type bundle struct { |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 338 | client rpc.Client |
| 339 | server rpc.Server |
Cosmos Nicolaou | fdc838b | 2014-06-30 21:44:27 -0700 | [diff] [blame] | 340 | ep naming.Endpoint |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 341 | ns namespace.T |
Bogdan Caprita | 2795314 | 2014-05-12 11:41:42 -0700 | [diff] [blame] | 342 | sm stream.Manager |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 343 | name string |
Bogdan Caprita | 2795314 | 2014-05-12 11:41:42 -0700 | [diff] [blame] | 344 | } |
| 345 | |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 346 | func (b bundle) cleanup(t *testing.T, ctx *context.T) { |
Ankur | a3c9765 | 2014-07-17 20:01:21 -0700 | [diff] [blame] | 347 | if b.server != nil { |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 348 | stopServer(t, ctx, b.server, b.ns, b.name) |
Ankur | a3c9765 | 2014-07-17 20:01:21 -0700 | [diff] [blame] | 349 | } |
| 350 | if b.client != nil { |
| 351 | b.client.Close() |
| 352 | } |
Bogdan Caprita | 2795314 | 2014-05-12 11:41:42 -0700 | [diff] [blame] | 353 | } |
| 354 | |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 355 | func createBundle(t *testing.T, ctx *context.T, server security.Principal, ts interface{}) (b bundle) { |
| 356 | return createBundleWS(t, ctx, server, ts, noWebsocket) |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 357 | } |
| 358 | |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 359 | func createBundleWS(t *testing.T, ctx *context.T, server security.Principal, ts interface{}, shouldUseWebsocket websocketMode) (b bundle) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 360 | b.sm = imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555)) |
Matt Rosencrantz | 9fe6082 | 2014-09-12 10:09:53 -0700 | [diff] [blame] | 361 | b.ns = tnaming.NewSimpleNamespace() |
Ankur | e49a86a | 2014-11-11 18:52:43 -0800 | [diff] [blame] | 362 | b.name = "mountpoint/server" |
Asim Shankar | 8f05c22 | 2014-10-06 22:08:19 -0700 | [diff] [blame] | 363 | if server != nil { |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 364 | b.ep, b.server = startServerWS(t, ctx, server, b.sm, b.ns, b.name, testServerDisp{ts}, shouldUseWebsocket) |
Ankur | a3c9765 | 2014-07-17 20:01:21 -0700 | [diff] [blame] | 365 | } |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 366 | b.client = DeprecatedNewClient(b.sm, b.ns) |
Bogdan Caprita | 2795314 | 2014-05-12 11:41:42 -0700 | [diff] [blame] | 367 | return |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 368 | } |
| 369 | |
Cosmos Nicolaou | 112bf1c | 2014-11-21 15:43:11 -0800 | [diff] [blame] | 370 | func matchesErrorPattern(err error, id verror.IDAction, pattern string) bool { |
Asim Shankar | 558ea01 | 2015-01-28 12:49:36 -0800 | [diff] [blame] | 371 | if len(pattern) > 0 && err != nil && strings.Index(err.Error(), pattern) < 0 { |
| 372 | return false |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 373 | } |
Cosmos Nicolaou | 1bce7d1 | 2015-01-05 17:42:06 -0800 | [diff] [blame] | 374 | if err == nil && id.ID == "" { |
| 375 | return true |
Cosmos Nicolaou | 112bf1c | 2014-11-21 15:43:11 -0800 | [diff] [blame] | 376 | } |
Todd Wang | 8fa3876 | 2015-03-25 14:04:59 -0700 | [diff] [blame] | 377 | return verror.ErrorID(err) == id.ID |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 378 | } |
| 379 | |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 380 | func runServer(t *testing.T, ctx *context.T, ns namespace.T, name string, obj interface{}, opts ...rpc.ServerOpt) stream.Manager { |
Suharsh Sivakumar | 0902b7f | 2015-02-27 19:06:41 -0800 | [diff] [blame] | 381 | rid, err := naming.NewRoutingID() |
| 382 | if err != nil { |
| 383 | t.Fatal(err) |
| 384 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 385 | sm := imanager.InternalNew(ctx, rid) |
| 386 | server, err := testInternalNewServer(ctx, sm, ns, opts...) |
Suharsh Sivakumar | 0902b7f | 2015-02-27 19:06:41 -0800 | [diff] [blame] | 387 | if err != nil { |
| 388 | t.Fatal(err) |
| 389 | } |
| 390 | if _, err := server.Listen(listenSpec); err != nil { |
| 391 | t.Fatal(err) |
| 392 | } |
Asim Shankar | 149b497 | 2015-04-23 13:29:58 -0700 | [diff] [blame] | 393 | if err := server.Serve(name, obj, security.AllowEveryone()); err != nil { |
Suharsh Sivakumar | 0902b7f | 2015-02-27 19:06:41 -0800 | [diff] [blame] | 394 | t.Fatal(err) |
| 395 | } |
| 396 | return sm |
| 397 | } |
| 398 | |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 399 | type websocketMode bool |
| 400 | type closeSendMode bool |
| 401 | |
| 402 | const ( |
| 403 | useWebsocket websocketMode = true |
| 404 | noWebsocket websocketMode = false |
| 405 | |
| 406 | closeSend closeSendMode = true |
| 407 | noCloseSend closeSendMode = false |
| 408 | ) |
| 409 | |
Asim Shankar | f4864f4 | 2014-11-25 18:53:05 -0800 | [diff] [blame] | 410 | // dischargeTestServer implements the discharge service. Always fails to |
| 411 | // issue a discharge, but records the impetus and traceid of the RPC call. |
| 412 | type dischargeTestServer struct { |
| 413 | p security.Principal |
| 414 | impetus []security.DischargeImpetus |
Benjamin Prosnitz | c97fe19 | 2015-02-03 10:33:25 -0800 | [diff] [blame] | 415 | traceid []uniqueid.Id |
Asim Shankar | a94e507 | 2014-08-19 18:18:36 -0700 | [diff] [blame] | 416 | } |
| 417 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 418 | func (s *dischargeTestServer) Discharge(ctx *context.T, _ rpc.ServerCall, cav security.Caveat, impetus security.DischargeImpetus) (security.Discharge, error) { |
Asim Shankar | c8cfcf1 | 2014-11-20 12:26:58 -0800 | [diff] [blame] | 419 | s.impetus = append(s.impetus, impetus) |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 420 | s.traceid = append(s.traceid, vtrace.GetSpan(ctx).Trace()) |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 421 | return security.Discharge{}, fmt.Errorf("discharges not issued") |
Asim Shankar | a94e507 | 2014-08-19 18:18:36 -0700 | [diff] [blame] | 422 | } |
| 423 | |
Benjamin Prosnitz | c97fe19 | 2015-02-03 10:33:25 -0800 | [diff] [blame] | 424 | func (s *dischargeTestServer) Release() ([]security.DischargeImpetus, []uniqueid.Id) { |
Asim Shankar | f4864f4 | 2014-11-25 18:53:05 -0800 | [diff] [blame] | 425 | impetus, traceid := s.impetus, s.traceid |
| 426 | s.impetus, s.traceid = nil, nil |
| 427 | return impetus, traceid |
Asim Shankar | c8cfcf1 | 2014-11-20 12:26:58 -0800 | [diff] [blame] | 428 | } |
| 429 | |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 430 | // singleBlessingStore implements security.BlessingStore. It is a |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 431 | // 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 Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 434 | type singleBlessingStore struct { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 435 | b security.Blessings |
| 436 | } |
| 437 | |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 438 | func (s *singleBlessingStore) Set(b security.Blessings, _ security.BlessingPattern) (security.Blessings, error) { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 439 | s.b = b |
| 440 | return security.Blessings{}, nil |
| 441 | } |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 442 | func (s *singleBlessingStore) ForPeer(...string) security.Blessings { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 443 | return s.b |
| 444 | } |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 445 | func (*singleBlessingStore) SetDefault(b security.Blessings) error { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 446 | return nil |
| 447 | } |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 448 | func (*singleBlessingStore) Default() security.Blessings { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 449 | return security.Blessings{} |
| 450 | } |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 451 | func (*singleBlessingStore) PublicKey() security.PublicKey { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 452 | return nil |
| 453 | } |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 454 | func (*singleBlessingStore) DebugString() string { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 455 | return "" |
| 456 | } |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 457 | func (*singleBlessingStore) PeerBlessings() map[security.BlessingPattern]security.Blessings { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 458 | return nil |
| 459 | } |
Suharsh Sivakumar | d7d4e22 | 2015-06-22 11:10:44 -0700 | [diff] [blame] | 460 | func (*singleBlessingStore) CacheDischarge(security.Discharge, security.Caveat, security.DischargeImpetus) { |
| 461 | return |
| 462 | } |
| 463 | func (*singleBlessingStore) ClearDischarges(...security.Discharge) { |
| 464 | return |
| 465 | } |
| 466 | func (*singleBlessingStore) Discharge(security.Caveat, security.DischargeImpetus) security.Discharge { |
| 467 | return security.Discharge{} |
| 468 | } |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 469 | |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 470 | // singleBlessingPrincipal implements security.Principal. It is a wrapper over |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 471 | // a security.Principal that intercepts all invocations on the |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 472 | // principal's BlessingStore and serves them via a singleBlessingStore. |
| 473 | type singleBlessingPrincipal struct { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 474 | security.Principal |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 475 | b singleBlessingStore |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 476 | } |
| 477 | |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 478 | func (p *singleBlessingPrincipal) BlessingStore() security.BlessingStore { |
Ankur | b905dae | 2015-03-04 12:38:20 -0800 | [diff] [blame] | 479 | return &p.b |
| 480 | } |
| 481 | |
Suharsh Sivakumar | cd743f7 | 2014-10-27 10:03:42 -0700 | [diff] [blame] | 482 | func TestSecurityNone(t *testing.T) { |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 483 | ctx, shutdown := initForTest() |
| 484 | defer shutdown() |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 485 | sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x66666666)) |
Suharsh Sivakumar | cd743f7 | 2014-10-27 10:03:42 -0700 | [diff] [blame] | 486 | defer sm.Shutdown() |
| 487 | ns := tnaming.NewSimpleNamespace() |
Suharsh Sivakumar | 2c5d810 | 2015-03-23 08:49:12 -0700 | [diff] [blame] | 488 | server, err := testInternalNewServer(ctx, sm, ns, nil, options.SecurityNone) |
Suharsh Sivakumar | cd743f7 | 2014-10-27 10:03:42 -0700 | [diff] [blame] | 489 | 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 Nicolaou | 92dba58 | 2014-11-05 17:24:10 -0800 | [diff] [blame] | 496 | if err := server.ServeDispatcher("mp/server", disp); err != nil { |
Suharsh Sivakumar | cd743f7 | 2014-10-27 10:03:42 -0700 | [diff] [blame] | 497 | t.Fatalf("server.Serve failed: %v", err) |
| 498 | } |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 499 | client := DeprecatedNewClient(sm, ns) |
Suharsh Sivakumar | 2c5d810 | 2015-03-23 08:49:12 -0700 | [diff] [blame] | 500 | // When using SecurityNone, all authorization checks should be skipped, so |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 501 | // unauthorized methods should be callable. |
Suharsh Sivakumar | cd743f7 | 2014-10-27 10:03:42 -0700 | [diff] [blame] | 502 | var got string |
Suharsh Sivakumar | 1abd5a8 | 2015-04-10 00:24:14 -0700 | [diff] [blame] | 503 | if err := client.Call(ctx, "mp/server", "Unauthorized", nil, []interface{}{&got}, options.SecurityNone); err != nil { |
| 504 | t.Fatalf("client.Call failed: %v", err) |
Suharsh Sivakumar | cd743f7 | 2014-10-27 10:03:42 -0700 | [diff] [blame] | 505 | } |
| 506 | if want := "UnauthorizedResult"; got != want { |
| 507 | t.Errorf("got (%v), want (%v)", got, want) |
| 508 | } |
| 509 | } |
| 510 | |
Suharsh Sivakumar | 0ed10c2 | 2015-04-06 12:55:55 -0700 | [diff] [blame] | 511 | func TestNoPrincipal(t *testing.T) { |
| 512 | ctx, shutdown := initForTest() |
| 513 | defer shutdown() |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 514 | sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x66666666)) |
Suharsh Sivakumar | 0ed10c2 | 2015-04-06 12:55:55 -0700 | [diff] [blame] | 515 | defer sm.Shutdown() |
| 516 | ns := tnaming.NewSimpleNamespace() |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 517 | ctx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal("server")) |
| 518 | server, err := testInternalNewServer(ctx, sm, ns) |
Suharsh Sivakumar | 0ed10c2 | 2015-04-06 12:55:55 -0700 | [diff] [blame] | 519 | 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 Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 529 | client := DeprecatedNewClient(sm, ns) |
Suharsh Sivakumar | 0ed10c2 | 2015-04-06 12:55:55 -0700 | [diff] [blame] | 530 | |
| 531 | // A call should fail if the principal in the ctx is nil and SecurityNone is not specified. |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 532 | ctx, err = v23.WithPrincipal(ctx, nil) |
Suharsh Sivakumar | 0ed10c2 | 2015-04-06 12:55:55 -0700 | [diff] [blame] | 533 | 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 Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 542 | func TestServerBlessingsOpt(t *testing.T) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 543 | ctx, shutdown := initForTest() |
| 544 | defer shutdown() |
| 545 | |
Asim Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 546 | var ( |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 547 | pserver = testutil.NewPrincipal("server") |
| 548 | pclient = testutil.NewPrincipal("client") |
Asim Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 549 | batman, _ = pserver.BlessSelf("batman") |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 550 | cctx, _ = v23.WithPrincipal(ctx, pclient) |
| 551 | sctx, _ = v23.WithPrincipal(ctx, pserver) |
Asim Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 552 | ) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 553 | |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 554 | // 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 Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 562 | } |
| 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 Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 566 | |
Jiri Simsa | d9a7b3c | 2015-08-12 16:38:27 -0700 | [diff] [blame] | 567 | defer runServer(t, sctx, ns, "mountpoint/batman", &testServer{}, options.ServerBlessings{Blessings: batman}).Shutdown() |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 568 | defer runServer(t, sctx, ns, "mountpoint/default", &testServer{}).Shutdown() |
Asim Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 569 | |
Asim Shankar | b547ea9 | 2015-02-17 18:49:45 -0800 | [diff] [blame] | 570 | // And finally, make an RPC and see that the client sees "batman" |
Asim Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 571 | runClient := func(server string) ([]string, error) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 572 | smc := imanager.InternalNew(ctx, naming.FixedRoutingID(0xc)) |
Asim Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 573 | defer smc.Shutdown() |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 574 | client := DeprecatedNewClient(smc, ns) |
Asim Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 575 | defer client.Close() |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 576 | ctx, _ = v23.WithPrincipal(cctx, pclient) |
| 577 | call, err := client.StartCall(cctx, server, "Closure", nil) |
Asim Shankar | a5b60b2 | 2014-11-06 15:37:07 -0800 | [diff] [blame] | 578 | 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 Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 595 | func TestNoDischargesOpt(t *testing.T) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 596 | ctx, shutdown := initForTest() |
| 597 | defer shutdown() |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 598 | var ( |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 599 | pdischarger = testutil.NewPrincipal("discharger") |
| 600 | pserver = testutil.NewPrincipal("server") |
| 601 | pclient = testutil.NewPrincipal("client") |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 602 | cctx, _ = v23.WithPrincipal(ctx, pclient) |
| 603 | sctx, _ = v23.WithPrincipal(ctx, pserver) |
| 604 | pctx, _ = v23.WithPrincipal(ctx, pdischarger) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 605 | ) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 606 | |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 607 | // 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 Sivakumar | 60b78e9 | 2015-04-23 21:36:49 -0700 | [diff] [blame] | 616 | tpcav := mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour)))) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 617 | 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 Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 626 | |
| 627 | // Setup the disharger and test server. |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 628 | discharger := &dischargeServer{} |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 629 | defer runServer(t, pctx, ns, "mountpoint/discharger", discharger).Shutdown() |
| 630 | defer runServer(t, sctx, ns, "mountpoint/testServer", &testServer{}).Shutdown() |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 631 | |
| 632 | runClient := func(noDischarges bool) { |
| 633 | rid, err := naming.NewRoutingID() |
| 634 | if err != nil { |
| 635 | t.Fatal(err) |
| 636 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 637 | smc := imanager.InternalNew(ctx, rid) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 638 | defer smc.Shutdown() |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 639 | client := DeprecatedNewClient(smc, ns) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 640 | defer client.Close() |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 641 | var opts []rpc.CallOpt |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 642 | if noDischarges { |
Ankur | 50a5f39 | 2015-02-27 18:46:30 -0800 | [diff] [blame] | 643 | opts = append(opts, NoDischarges{}) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 644 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 645 | if _, err = client.StartCall(cctx, "mountpoint/testServer", "Closure", nil, opts...); err != nil { |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 646 | t.Fatalf("failed to StartCall: %v", err) |
| 647 | } |
| 648 | } |
| 649 | |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 650 | // Test that when the NoDischarges option is set, dischargeServer does not get called. |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 651 | if runClient(true); discharger.called { |
| 652 | t.Errorf("did not expect discharger to be called") |
| 653 | } |
| 654 | discharger.called = false |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 655 | // Test that when the Nodischarges option is not set, dischargeServer does get called. |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 656 | if runClient(false); !discharger.called { |
| 657 | t.Errorf("expected discharger to be called") |
| 658 | } |
| 659 | } |
| 660 | |
| 661 | func TestNoImplicitDischargeFetching(t *testing.T) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 662 | ctx, shutdown := initForTest() |
| 663 | defer shutdown() |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 664 | // This test ensures that discharge clients only fetch discharges for the specified tp caveats and not its own. |
| 665 | var ( |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 666 | pdischarger1 = testutil.NewPrincipal("discharger1") |
| 667 | pdischarger2 = testutil.NewPrincipal("discharger2") |
| 668 | pdischargeClient = testutil.NewPrincipal("dischargeClient") |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 669 | p1ctx, _ = v23.WithPrincipal(ctx, pdischarger1) |
| 670 | p2ctx, _ = v23.WithPrincipal(ctx, pdischarger2) |
| 671 | cctx, _ = v23.WithPrincipal(ctx, pdischargeClient) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 672 | ) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 673 | |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 674 | // Bless the client with a ThirdPartyCaveat from discharger1. |
Suharsh Sivakumar | 60b78e9 | 2015-04-23 21:36:49 -0700 | [diff] [blame] | 675 | tpcav1 := mkThirdPartyCaveat(pdischarger1.PublicKey(), "mountpoint/discharger1", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour)))) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 676 | 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 Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 683 | // 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 Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 686 | |
| 687 | ns := tnaming.NewSimpleNamespace() |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 688 | |
| 689 | // Setup the disharger and test server. |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 690 | discharger1 := &dischargeServer{} |
| 691 | discharger2 := &dischargeServer{} |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 692 | defer runServer(t, p1ctx, ns, "mountpoint/discharger1", discharger1).Shutdown() |
| 693 | defer runServer(t, p2ctx, ns, "mountpoint/discharger2", discharger2).Shutdown() |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 694 | |
| 695 | rid, err := naming.NewRoutingID() |
| 696 | if err != nil { |
| 697 | t.Fatal(err) |
| 698 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 699 | sm := imanager.InternalNew(ctx, rid) |
Suharsh Sivakumar | 1b6683e | 2014-12-30 13:00:38 -0800 | [diff] [blame] | 700 | |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 701 | c := DeprecatedNewClient(sm, ns) |
Suharsh Sivakumar | 1b6683e | 2014-12-30 13:00:38 -0800 | [diff] [blame] | 702 | dc := c.(*client).dc |
Suharsh Sivakumar | 60b78e9 | 2015-04-23 21:36:49 -0700 | [diff] [blame] | 703 | tpcav2, err := security.NewPublicKeyCaveat(pdischarger2.PublicKey(), "mountpoint/discharger2", security.ThirdPartyRequirements{}, mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour)))) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 704 | if err != nil { |
| 705 | t.Error(err) |
| 706 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 707 | dc.PrepareDischarges(cctx, []security.Caveat{tpcav2}, security.DischargeImpetus{}) |
Suharsh Sivakumar | 1131687 | 2014-11-25 15:57:00 -0800 | [diff] [blame] | 708 | |
| 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 Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 718 | // TestBlessingsCache tests that the VCCache is used to sucessfully used to cache duplicate |
| 719 | // calls blessings. |
| 720 | func TestBlessingsCache(t *testing.T) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 721 | ctx, shutdown := initForTest() |
| 722 | defer shutdown() |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 723 | var ( |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 724 | pserver = testutil.NewPrincipal("server") |
| 725 | pclient = testutil.NewPrincipal("client") |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 726 | cctx, _ = v23.WithPrincipal(ctx, pclient) |
| 727 | sctx, _ = v23.WithPrincipal(ctx, pserver) |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 728 | ) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 729 | |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 730 | // 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 Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 736 | |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 737 | serverSM := runServer(t, sctx, ns, "mountpoint/testServer", &testServer{}) |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 738 | defer serverSM.Shutdown() |
Suharsh Sivakumar | 0902b7f | 2015-02-27 19:06:41 -0800 | [diff] [blame] | 739 | rid := serverSM.RoutingID() |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 740 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 741 | newClient := func() rpc.Client { |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 742 | rid, err := naming.NewRoutingID() |
| 743 | if err != nil { |
| 744 | t.Fatal(err) |
| 745 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 746 | smc := imanager.InternalNew(sctx, rid) |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 747 | defer smc.Shutdown() |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 748 | return DeprecatedNewClient(smc, ns) |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 749 | } |
| 750 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 751 | runClient := func(client rpc.Client) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 752 | if err := client.Call(cctx, "mountpoint/testServer", "Closure", nil, nil); err != nil { |
Suharsh Sivakumar | 1abd5a8 | 2015-04-10 00:24:14 -0700 | [diff] [blame] | 753 | t.Fatalf("failed to Call: %v", err) |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 754 | } |
| 755 | } |
| 756 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 757 | cachePrefix := naming.Join("rpc", "server", "routing-id", rid.String(), "security", "blessings", "cache") |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 758 | 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 Sivakumar | 60b78e9 | 2015-04-23 21:36:49 -0700 | [diff] [blame] | 786 | blessings, err := pserver.Bless(pclient.PublicKey(), pserver.BlessingStore().Default(), "cav", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour)))) |
Suharsh Sivakumar | 720b704 | 2014-12-22 17:33:23 -0800 | [diff] [blame] | 787 | 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 Shankar | 7283dd8 | 2015-02-03 19:35:58 -0800 | [diff] [blame] | 800 | var 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 Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 803 | } |
Suharsh Sivakumar | 9d17e4a | 2015-02-02 22:42:16 -0800 | [diff] [blame] | 804 | |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 805 | func TestServerPublicKeyOpt(t *testing.T) { |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 806 | ctx, shutdown := initForTest() |
| 807 | defer shutdown() |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 808 | var ( |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 809 | pserver = testutil.NewPrincipal("server") |
| 810 | pother = testutil.NewPrincipal("other") |
| 811 | pclient = testutil.NewPrincipal("client") |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 812 | cctx, _ = v23.WithPrincipal(ctx, pclient) |
| 813 | sctx, _ = v23.WithPrincipal(ctx, pserver) |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 814 | ) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 815 | |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 816 | ns := tnaming.NewSimpleNamespace() |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 817 | mountName := "mountpoint/default" |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 818 | |
| 819 | // Start a server with pserver. |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 820 | defer runServer(t, sctx, ns, mountName, &testServer{}).Shutdown() |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 821 | |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 822 | smc := imanager.InternalNew(sctx, naming.FixedRoutingID(0xc)) |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 823 | client := DeprecatedNewClient(smc, ns) |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 824 | defer smc.Shutdown() |
| 825 | defer client.Close() |
| 826 | |
| 827 | // The call should succeed when the server presents the same public as the opt... |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 828 | var err error |
Jiri Simsa | d9a7b3c | 2015-08-12 16:38:27 -0700 | [diff] [blame] | 829 | if _, err = client.StartCall(cctx, mountName, "Closure", nil, options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{ |
| 830 | PublicKey: pserver.PublicKey(), |
| 831 | }); err != nil { |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 832 | t.Errorf("Expected call to succeed but got %v", err) |
| 833 | } |
| 834 | // ...but fail if they differ. |
Jiri Simsa | d9a7b3c | 2015-08-12 16:38:27 -0700 | [diff] [blame] | 835 | if _, err = client.StartCall(cctx, mountName, "Closure", nil, options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{ |
| 836 | PublicKey: pother.PublicKey(), |
| 837 | }); verror.ErrorID(err) != verror.ErrNotTrusted.ID { |
Jiri Simsa | 074bf36 | 2015-02-17 09:29:45 -0800 | [diff] [blame] | 838 | t.Errorf("got %v, want %v", verror.ErrorID(err), verror.ErrNotTrusted.ID) |
Suharsh Sivakumar | a8633b0 | 2015-02-14 17:08:07 -0800 | [diff] [blame] | 839 | } |
| 840 | } |
| 841 | |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 842 | type expiryDischarger struct { |
| 843 | called bool |
| 844 | } |
| 845 | |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 846 | func (ed *expiryDischarger) Discharge(ctx *context.T, call rpc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.Discharge, error) { |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 847 | tp := cav.ThirdPartyDetails() |
| 848 | if tp == nil { |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 849 | return security.Discharge{}, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 850 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 851 | if err := tp.Dischargeable(ctx, call.Security()); err != nil { |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 852 | return security.Discharge{}, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 853 | } |
| 854 | expDur := 10 * time.Millisecond |
| 855 | if ed.called { |
| 856 | expDur = time.Second |
| 857 | } |
Suharsh Sivakumar | 60b78e9 | 2015-04-23 21:36:49 -0700 | [diff] [blame] | 858 | expiry, err := security.NewExpiryCaveat(time.Now().Add(expDur)) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 859 | if err != nil { |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 860 | return security.Discharge{}, fmt.Errorf("failed to create an expiration on the discharge: %v", err) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 861 | } |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 862 | d, err := call.Security().LocalPrincipal().MintDischarge(cav, expiry) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 863 | if err != nil { |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 864 | return security.Discharge{}, err |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 865 | } |
| 866 | ed.called = true |
Asim Shankar | 0864282 | 2015-03-02 21:21:09 -0800 | [diff] [blame] | 867 | return d, nil |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 868 | } |
| 869 | |
| 870 | func TestDischargeClientFetchExpiredDischarges(t *testing.T) { |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 871 | ctx, shutdown := initForTest() |
| 872 | defer shutdown() |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 873 | var ( |
| 874 | pclient, pdischarger = newClientServerPrincipals() |
Suharsh Sivakumar | 60b78e9 | 2015-04-23 21:36:49 -0700 | [diff] [blame] | 875 | tpcav = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour)))) |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 876 | ns = tnaming.NewSimpleNamespace() |
| 877 | discharger = &expiryDischarger{} |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 878 | pctx, _ = v23.WithPrincipal(ctx, pdischarger) |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 879 | ) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 880 | ctx, _ = v23.WithPrincipal(ctx, pclient) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 881 | |
| 882 | // Setup the disharge server. |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 883 | defer runServer(t, pctx, ns, "mountpoint/discharger", discharger).Shutdown() |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 884 | |
| 885 | // Create a discharge client. |
| 886 | rid, err := naming.NewRoutingID() |
| 887 | if err != nil { |
| 888 | t.Fatal(err) |
| 889 | } |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 890 | smc := imanager.InternalNew(ctx, rid) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 891 | defer smc.Shutdown() |
Matt Rosencrantz | 80752cc | 2015-09-29 16:32:02 -0700 | [diff] [blame^] | 892 | client := DeprecatedNewClient(smc, ns) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 893 | defer client.Close() |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 894 | |
Suharsh Sivakumar | 0891858 | 2015-03-03 15:16:36 -0800 | [diff] [blame] | 895 | dc := InternalNewDischargeClient(ctx, client, 0) |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 896 | |
| 897 | // Fetch discharges for tpcav. |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 898 | dis := dc.PrepareDischarges(ctx, []security.Caveat{tpcav}, security.DischargeImpetus{})[0] |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 899 | // 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 Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 910 | dis = dc.PrepareDischarges(ctx, []security.Caveat{tpcav}, security.DischargeImpetus{})[0] |
Suharsh Sivakumar | cd07e25 | 2015-02-28 01:04:26 -0800 | [diff] [blame] | 911 | if expiry = dis.Expiry(); expiry.Before(now) { |
| 912 | t.Fatalf("discharge has expired %v, but should be fresh", dis) |
| 913 | } |
| 914 | } |
| 915 | |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 916 | // 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). |
| 924 | func newClientServerPrincipals() (client, server security.Principal) { |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 925 | client = testutil.NewPrincipal("client") |
| 926 | server = testutil.NewPrincipal("server") |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 927 | client.AddToRoots(server.BlessingStore().Default()) |
| 928 | server.AddToRoots(client.BlessingStore().Default()) |
| 929 | return |
| 930 | } |
| 931 | |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 932 | func init() { |
Suharsh Sivakumar | 7e93ce5 | 2015-05-07 17:46:13 -0700 | [diff] [blame] | 933 | rpc.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridResolve, websocket.HybridListener) |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 934 | security.RegisterCaveatValidator(fakeTimeCaveat, func(_ *context.T, _ security.Call, t int64) error { |
Suharsh Sivakumar | 8a0adbb | 2015-03-06 13:16:34 -0800 | [diff] [blame] | 935 | if now := clock.Now(); now > t { |
Asim Shankar | 7283dd8 | 2015-02-03 19:35:58 -0800 | [diff] [blame] | 936 | return fmt.Errorf("fakeTimeCaveat expired: now=%d > then=%d", now, t) |
| 937 | } |
| 938 | return nil |
| 939 | }) |
Suharsh Sivakumar | 9d17e4a | 2015-02-02 22:42:16 -0800 | [diff] [blame] | 940 | } |
Matt Rosencrantz | af3c76f | 2015-09-19 17:17:32 -0700 | [diff] [blame] | 941 | |
| 942 | func 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 | } |