blob: 736e67e016308e17257695d3967931a2ff92d7aa [file] [log] [blame]
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -08001package impl_test
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "os"
8 "reflect"
9 "syscall"
10 "testing"
11
12 "v.io/core/veyron2"
13 "v.io/core/veyron2/context"
14 "v.io/core/veyron2/naming"
15 "v.io/core/veyron2/rt"
16 "v.io/core/veyron2/security"
17 "v.io/core/veyron2/services/mgmt/application"
18 "v.io/core/veyron2/services/security/access"
19 "v.io/core/veyron2/vdl/vdlutil"
20 "v.io/core/veyron2/verror"
21 "v.io/core/veyron2/vlog"
22
23 "v.io/core/veyron/lib/modules"
24 "v.io/core/veyron/lib/signals"
25 "v.io/core/veyron/lib/testutil"
26 tsecurity "v.io/core/veyron/lib/testutil/security"
27 "v.io/core/veyron/services/mgmt/application/impl"
28 mgmttest "v.io/core/veyron/services/mgmt/lib/testutil"
29 "v.io/core/veyron/services/mgmt/repository"
30)
31
32const (
33 repoCmd = "repository"
34)
35
36var globalRT veyron2.Runtime
37var globalCtx *context.T
38
39// This is also a modules world.
40// Insert necessary code here to be a modules test.
41func init() {
42 // TODO(rjkroege): Remove when vom2 is ready.
43 vdlutil.Register(&naming.VDLMountedServer{})
44
45 modules.RegisterChild(repoCmd, "", appRepository)
46 testutil.Init()
47
48 var err error
49 if globalRT, err = rt.New(); err != nil {
50 panic(err)
51 }
52 globalCtx = globalRT.NewContext()
Matt Rosencrantzd599e382015-01-12 11:13:32 -080053 veyron2.GetNamespace(globalCtx).CacheCtl(naming.DisableCache(true))
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -080054}
55
56// TestHelperProcess is the entrypoint for the modules commands in a
57// a test subprocess.
58func TestHelperProcess(t *testing.T) {
59 modules.DispatchInTest()
60}
61
62func appRepository(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
63 args = args[1:]
64 if len(args) < 2 {
65 vlog.Fatalf("repository expected at least name and store arguments and optionally ACL flags per TaggedACLMapFromFlag")
66 }
67 publishName := args[0]
68 storedir := args[1]
69
70 defer fmt.Fprintf(stdout, "%v terminating\n", publishName)
71 defer vlog.VI(1).Infof("%v terminating", publishName)
72 defer globalRT.Cleanup()
Matt Rosencrantz6edab562015-01-12 11:07:55 -080073 server, endpoint := mgmttest.NewServer(globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -080074 defer server.Stop()
75
76 name := naming.JoinAddressName(endpoint, "")
77 vlog.VI(1).Infof("applicationd name: %v", name)
78
79 dispatcher, err := impl.NewDispatcher(storedir)
80 if err != nil {
81 vlog.Fatalf("Failed to create repository dispatcher: %v", err)
82 }
83 if err := server.ServeDispatcher(publishName, dispatcher); err != nil {
84 vlog.Fatalf("Serve(%v) failed: %v", publishName, err)
85 }
86
87 fmt.Fprintf(stdout, "ready:%d\n", os.Getpid())
88 <-signals.ShutdownOnSignals(globalCtx)
89
90 return nil
91}
92
93func TestApplicationUpdateACL(t *testing.T) {
Matt Rosencrantz6edab562015-01-12 11:07:55 -080094 sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -080095 defer deferFn()
96
97 // setup mock up directory to put state in
98 storedir, cleanup := mgmttest.SetupRootDir(t, "application")
99 defer cleanup()
100
Matt Rosencrantzd599e382015-01-12 11:13:32 -0800101 otherRT := mgmttest.NewRuntime(t, globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800102 defer otherRT.Cleanup()
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800103 otherCtx := otherRT.NewContext()
104
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800105 idp := tsecurity.NewIDProvider("root")
106
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800107 // By default, globalRT and otherRT will have blessings generated based on the
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800108 // username/machine name running this process. Since these blessings will appear
109 // in ACLs, give them recognizable names.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800110 if err := idp.Bless(veyron2.GetPrincipal(globalCtx), "self"); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800111 t.Fatal(err)
112 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800113 if err := idp.Bless(veyron2.GetPrincipal(otherCtx), "other"); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800114 t.Fatal(err)
115 }
116
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800117 crDir, crEnv := mgmttest.CredentialsForChild(globalCtx, "repo")
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800118 defer os.RemoveAll(crDir)
119
120 // Make server credentials derived from the test harness.
121 _, nms := mgmttest.RunShellCommand(t, sh, crEnv, repoCmd, "repo", storedir)
122 pid := mgmttest.ReadPID(t, nms)
123 defer syscall.Kill(pid, syscall.SIGINT)
124
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800125 v1stub := repository.ApplicationClient("repo/search/v1")
126 repostub := repository.ApplicationClient("repo")
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800127
128 // Create example envelopes.
129 envelopeV1 := application.Envelope{
130 Args: []string{"--help"},
131 Env: []string{"DEBUG=1"},
132 Binary: "/veyron/name/of/binary",
133 }
134
135 // Envelope putting as other should fail.
136 // TODO(rjkroege): Validate that it is failed with permission denied.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800137 if err := v1stub.Put(otherCtx, []string{"base"}, envelopeV1); err == nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800138 t.Fatalf("Put() wrongly didn't fail")
139 }
140
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800141 // Envelope putting as global should succeed.
142 if err := v1stub.Put(globalCtx, []string{"base"}, envelopeV1); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800143 t.Fatalf("Put() failed: %v", err)
144 }
145
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800146 acl, etag, err := repostub.GetACL(globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800147 if !verror.Is(err, impl.ErrNotFound.ID) {
148 t.Fatalf("GetACL should have failed with ErrNotFound but was: %v", err)
149 }
150 if etag != "default" {
151 t.Fatalf("getACL expected:default, got:%v(%v)", etag, acl)
152 }
153 if acl != nil {
154 t.Fatalf("GetACL got %v, expected %v", acl, nil)
155 }
156
157 vlog.VI(2).Infof("self attempting to give other permission to update application")
158 newACL := make(access.TaggedACLMap)
159 for _, tag := range access.AllTypicalTags() {
160 newACL.Add("root/self", string(tag))
161 newACL.Add("root/other", string(tag))
162 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800163 if err := repostub.SetACL(globalCtx, newACL, ""); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800164 t.Fatalf("SetACL failed: %v", err)
165 }
166
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800167 acl, etag, err = repostub.GetACL(globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800168 if err != nil {
169 t.Fatalf("GetACL should not have failed: %v", err)
170 }
171 expected := newACL
172 if got := acl; !reflect.DeepEqual(expected.Normalize(), got.Normalize()) {
173 t.Errorf("got %#v, exected %#v ", got, expected)
174 }
175
176 // Envelope putting as other should now succeed.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800177 if err := v1stub.Put(otherCtx, []string{"base"}, envelopeV1); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800178 t.Fatalf("Put() wrongly failed: %v", err)
179 }
180
181 // Other takes control.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800182 acl, etag, err = repostub.GetACL(otherCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800183 if err != nil {
184 t.Fatalf("GetACL 2 should not have failed: %v", err)
185 }
186 acl["Admin"] = access.ACL{
187 In: []security.BlessingPattern{"root/other"},
188 NotIn: []string{}}
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800189 if err = repostub.SetACL(otherCtx, acl, etag); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800190 t.Fatalf("SetACL failed: %v", err)
191 }
192
193 // Self is now locked out but other isn't.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800194 if _, _, err = repostub.GetACL(globalCtx); err == nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800195 t.Fatalf("GetACL should not have succeeded")
196 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800197 acl, _, err = repostub.GetACL(otherCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800198 if err != nil {
199 t.Fatalf("GetACL should not have failed: %v", err)
200 }
201 expected = access.TaggedACLMap{
202 "Admin": access.ACL{
203 In: []security.BlessingPattern{"root/other"},
204 NotIn: []string{}},
205 "Read": access.ACL{In: []security.BlessingPattern{"root/other",
206 "root/self"},
207 NotIn: []string{}},
208 "Write": access.ACL{In: []security.BlessingPattern{"root/other",
209 "root/self"},
210 NotIn: []string{}},
211 "Debug": access.ACL{In: []security.BlessingPattern{"root/other",
212 "root/self"},
213 NotIn: []string{}},
214 "Resolve": access.ACL{In: []security.BlessingPattern{"root/other",
215 "root/self"},
216 NotIn: []string{}}}
217
218 if got := acl; !reflect.DeepEqual(expected.Normalize(), got.Normalize()) {
219 t.Errorf("got %#v, exected %#v ", got, expected)
220 }
221}
222
223func TestPerAppACL(t *testing.T) {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800224 sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800225 defer deferFn()
226
227 // setup mock up directory to put state in
228 storedir, cleanup := mgmttest.SetupRootDir(t, "application")
229 defer cleanup()
230
Matt Rosencrantzd599e382015-01-12 11:13:32 -0800231 otherRT := mgmttest.NewRuntime(t, globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800232 defer otherRT.Cleanup()
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800233 otherCtx := otherRT.NewContext()
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800234 idp := tsecurity.NewIDProvider("root")
235
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800236 // By default, globalRT and otherRT will have blessings generated based on the
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800237 // username/machine name running this process. Since these blessings will appear
238 // in ACLs, give them recognizable names.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800239 if err := idp.Bless(veyron2.GetPrincipal(globalCtx), "self"); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800240 t.Fatal(err)
241 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800242 if err := idp.Bless(veyron2.GetPrincipal(otherCtx), "other"); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800243 t.Fatal(err)
244 }
245
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800246 crDir, crEnv := mgmttest.CredentialsForChild(globalCtx, "repo")
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800247 defer os.RemoveAll(crDir)
248
249 // Make a server with the same credential as test harness.
250 _, nms := mgmttest.RunShellCommand(t, sh, crEnv, repoCmd, "repo", storedir)
251 pid := mgmttest.ReadPID(t, nms)
252 defer syscall.Kill(pid, syscall.SIGINT)
253
254 // Create example envelope.
255 envelopeV1 := application.Envelope{
256 Args: []string{"--help"},
257 Env: []string{"DEBUG=1"},
258 Binary: "/veyron/name/of/binary",
259 }
260
261 // Upload the envelope at two different names.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800262 v1stub := repository.ApplicationClient("repo/search/v1")
263 if err := v1stub.Put(globalCtx, []string{"base"}, envelopeV1); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800264 t.Fatalf("Put() failed: %v", err)
265 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800266 v2stub := repository.ApplicationClient("repo/search/v2")
267 if err := v2stub.Put(globalCtx, []string{"base"}, envelopeV1); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800268 t.Fatalf("Put() failed: %v", err)
269 }
270
271 // Self can access ACLs but other can't.
272 for _, path := range []string{"repo/search", "repo/search/v1", "repo/search/v2"} {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800273 stub := repository.ApplicationClient(path)
274 acl, etag, err := stub.GetACL(globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800275 if !verror.Is(err, impl.ErrNotFound.ID) {
276 t.Fatalf("GetACL should have failed with ErrNotFound but was: %v", err)
277 }
278 if etag != "default" {
279 t.Fatalf("GetACL expected:default, got:%v(%v)", etag, acl)
280 }
281 if acl != nil {
282 t.Fatalf("GetACL got %v, expected %v", acl, nil)
283 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800284 if _, _, err := stub.GetACL(otherCtx); err == nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800285 t.Fatalf("GetACL didn't fail for other when it should have.")
286 }
287 }
288
289 // Self gives other full access only to repo/search/v1.
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800290 newACL := make(access.TaggedACLMap)
291 for _, tag := range access.AllTypicalTags() {
292 newACL.Add("root/self", string(tag))
293 newACL.Add("root/other", string(tag))
294 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800295 if err := v1stub.SetACL(globalCtx, newACL, ""); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800296 t.Fatalf("SetACL failed: %v", err)
297 }
298
299 // Other can now access this location.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800300 acl, _, err := v1stub.GetACL(otherCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800301 if err != nil {
302 t.Fatalf("GetACL should not have failed: %v", err)
303 }
304 expected := access.TaggedACLMap{
305 "Admin": access.ACL{
306 In: []security.BlessingPattern{"root/other",
307 "root/self"},
308 NotIn: []string{}},
309 "Read": access.ACL{In: []security.BlessingPattern{"root/other",
310 "root/self"},
311 NotIn: []string{}},
312 "Write": access.ACL{In: []security.BlessingPattern{"root/other",
313 "root/self"},
314 NotIn: []string{}},
315 "Debug": access.ACL{In: []security.BlessingPattern{"root/other",
316 "root/self"},
317 NotIn: []string{}},
318 "Resolve": access.ACL{In: []security.BlessingPattern{"root/other",
319 "root/self"},
320 NotIn: []string{}}}
321 if got := acl; !reflect.DeepEqual(expected.Normalize(), got.Normalize()) {
322 t.Errorf("got %#v, exected %#v ", got, expected)
323 }
324
325 // But other locations should be unaffected and other cannot access.
326 for _, path := range []string{"repo/search", "repo/search/v2"} {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800327 stub := repository.ApplicationClient(path)
328 if _, _, err := stub.GetACL(otherCtx); err == nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800329 t.Fatalf("GetACL didn't fail for other when it should have.")
330 }
331 }
332
333 // Self gives other write perms on base.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800334 repostub := repository.ApplicationClient("repo/")
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800335 newACL = make(access.TaggedACLMap)
336 for _, tag := range access.AllTypicalTags() {
337 newACL.Add("root/self", string(tag))
338 }
339 newACL["Write"] = access.ACL{In: []security.BlessingPattern{"root/other", "root/self"}}
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800340 if err := repostub.SetACL(globalCtx, newACL, ""); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800341 t.Fatalf("SetACL failed: %v", err)
342 }
343
344 // Other can now upload an envelope at both locations.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800345 for _, stub := range []repository.ApplicationClientStub{v1stub, v2stub} {
346 if err := stub.Put(otherCtx, []string{"base"}, envelopeV1); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800347 t.Fatalf("Put() failed: %v", err)
348 }
349 }
350
351 // But self didn't give other ACL modification permissions.
352 for _, path := range []string{"repo/search", "repo/search/v2"} {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800353 stub := repository.ApplicationClient(path)
354 if _, _, err := stub.GetACL(otherCtx); err == nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800355 t.Fatalf("GetACL didn't fail for other when it should have.")
356 }
357 }
358}
359
360func TestInitialACLSet(t *testing.T) {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800361 sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800362 defer deferFn()
363
364 // Setup mock up directory to put state in.
365 storedir, cleanup := mgmttest.SetupRootDir(t, "application")
366 defer cleanup()
367
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800368 idp := tsecurity.NewIDProvider("root")
369
370 // Make a recognizable principal name.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800371 if err := idp.Bless(veyron2.GetPrincipal(globalCtx), "self"); err != nil {
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800372 t.Fatal(err)
373 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800374 crDir, crEnv := mgmttest.CredentialsForChild(globalCtx, "repo")
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800375 defer os.RemoveAll(crDir)
376
377 // Make an TAM for use on the command line.
378 expected := access.TaggedACLMap{
379 "Admin": access.ACL{
380 In: []security.BlessingPattern{"root/rubberchicken",
381 "root/self"},
382 NotIn: []string{},
383 },
384 }
385
386 b := new(bytes.Buffer)
387 if err := expected.WriteTo(b); err != nil {
388 t.Fatal(err)
389 }
390
391 // Start a server with the same credential as test harness.
392 _, nms := mgmttest.RunShellCommand(t, sh, crEnv, repoCmd, "--veyron.acl.literal", b.String(), "repo", storedir)
393 pid := mgmttest.ReadPID(t, nms)
394 defer syscall.Kill(pid, syscall.SIGINT)
395
396 // It should have the correct starting ACLs from the command line.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800397 stub := repository.ApplicationClient("repo")
398 acl, _, err := stub.GetACL(globalCtx)
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800399 if err != nil {
400 t.Fatalf("GetACL should not have failed: %v", err)
401 }
402 if got := acl; !reflect.DeepEqual(expected.Normalize(), got.Normalize()) {
403 t.Errorf("got %#v, exected %#v ", got, expected)
404 }
405}