services/mgmt/device/impl/* Test to show lack of ACL propagation.
This test shows the necessity of ACL propagation for names under an
application's __debug point: the instantiator of an app instance
cannot control access to the app's __debug information.
Change-Id: I1a3a2603bcf2a3c7e818232287bbc35906c94db1
diff --git a/services/mgmt/device/impl/debug_acls_test.go b/services/mgmt/device/impl/debug_acls_test.go
new file mode 100644
index 0000000..30eb9a6
--- /dev/null
+++ b/services/mgmt/device/impl/debug_acls_test.go
@@ -0,0 +1,112 @@
+package impl_test
+
+import (
+ "syscall"
+ "testing"
+
+ "v.io/v23/context"
+ "v.io/v23/security"
+ "v.io/v23/services/security/access"
+ "v.io/v23/vdl"
+
+ mgmttest "v.io/x/ref/services/mgmt/lib/testutil"
+)
+
+func updateACL(t *testing.T, ctx *context.T, blessing, right string, name ...string) {
+ acl, etag, err := appStub(name...).GetACL(ctx)
+ if err != nil {
+ t.Fatalf("GetACL(%v) failed %v", name, err)
+ }
+ acl.Add(security.BlessingPattern(blessing), right)
+ if err = appStub(name...).SetACL(ctx, acl, etag); err != nil {
+ t.Fatalf("SetACL(%v, %v, %v) failed: %v", name, blessing, right, err)
+ }
+}
+
+func TestDebugACLPropagation(t *testing.T) {
+ cleanup, ctx, sh, envelope, root, helperPath, idp := startupHelper(t)
+ defer cleanup()
+
+ // Set up the device manager.
+ dmh, dms := mgmttest.RunShellCommand(t, sh, nil, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
+ mgmttest.ReadPID(t, dms)
+ claimDevice(t, ctx, "dm", "mydevice", noPairingToken)
+
+ // Create the local server that the app uses to let us know it's ready.
+ pingCh, cleanup := setupPingServer(t, ctx)
+ defer cleanup()
+ resolve(t, ctx, "pingserver", 1)
+
+ // Make some users.
+ selfCtx := ctx
+ bobCtx := ctxWithNewPrincipal(t, selfCtx, idp, "bob")
+ hjCtx := ctxWithNewPrincipal(t, selfCtx, idp, "hackerjoe")
+ aliceCtx := ctxWithNewPrincipal(t, selfCtx, idp, "alice")
+
+ // TODO(rjkroege): Set ACLs here that conflict with the one provided by the device
+ // manager and show that the one set here is overridden.
+ // Create the envelope for the first version of the app.
+ *envelope = envelopeFromShell(sh, nil, appCmd, "google naps", "appV1")
+
+ // Install the app.
+ appID := installApp(t, ctx)
+
+ // Give bob rights to start an app.
+ updateACL(t, selfCtx, "root/bob/$", string(access.Read), appID)
+
+ // Bob starts an instance of the app.
+ bobApp := startApp(t, bobCtx, appID)
+ verifyPingArgs(t, pingCh, userName(t), "default", "")
+
+ // Bob permits Alice to read from his app.
+ updateACL(t, bobCtx, "root/alice/$", string(access.Read), appID, bobApp)
+
+ // Confirm that self can access stats name (i.e. apps proxied from
+ // the __debug space of the app.
+ // TODO(rjkroege): validate each of the services under __debug.
+ v, err := statsStub(appID, bobApp, "stats/system/pid").Value(ctx)
+ if err != nil {
+ t.Fatalf("Value() failed: %v\n", err)
+ }
+ var pid int
+ if err := vdl.Convert(&pid, v); err != nil {
+ t.Fatalf("pid returned from stats interface is not an int: %v", err)
+ }
+
+ // Bob has an issue with his app and tries to use the debug output to figure it out.
+ // TODO(rjkroege): Invert this test when ACLs are correctly propagated.
+ if _, err = statsStub(appID, bobApp, "stats/system/pid").Value(bobCtx); err == nil {
+ t.Fatalf("This ought not to work yet! Something is wrong.")
+ }
+
+ // But Bob can't figure it out and hopes that hackerjoe can debug it.
+ updateACL(t, bobCtx, "root/hackerjoe/$", string(access.Debug), appID, bobApp)
+
+ // But the device manager doesn't support this so hackerjoe can't help.
+ // TODO(rjkroege): Invert this test when ACLs are propagated..
+ if _, err = statsStub(appID, bobApp, "stats/system/pid").Value(hjCtx); err == nil {
+ t.Fatalf("This ought not to work yet! Something is wrong.")
+ }
+
+ // Alice might be able to help but Bob didn't give Alice access to the debug ACLs.
+ if _, err = statsStub(appID, bobApp, "stats/system/pid").Value(hjCtx); err == nil {
+ t.Fatalf("Alice could wrongly access the stats without perms.")
+ }
+
+ // Bob changes the permissions so that Alice can help debug too.
+ updateACL(t, bobCtx, "root/alice/$", string(access.Debug), appID, bobApp)
+
+ // But the device manager doesn't support this so Alice can't help either.
+ // TODO(rjkroege): Invert this test when ACLs are propagated..
+ if _, err = statsStub(appID, bobApp, "stats/system/pid").Value(aliceCtx); err == nil {
+ t.Fatalf("This ought not to work yet! Something is wrong.")
+ }
+
+ // Bob is glum so stops his app.
+ stopApp(t, bobCtx, appID, bobApp)
+
+ // Cleanly shut down the device manager.
+ syscall.Kill(dmh.Pid(), syscall.SIGINT)
+ dms.Expect("dm terminated")
+ dms.ExpectEOF()
+}
diff --git a/services/mgmt/device/impl/instance_reaping_test.go b/services/mgmt/device/impl/instance_reaping_test.go
index 0f52a0b..8ccbedf 100644
--- a/services/mgmt/device/impl/instance_reaping_test.go
+++ b/services/mgmt/device/impl/instance_reaping_test.go
@@ -7,49 +7,17 @@
"syscall"
"testing"
- "v.io/v23"
"v.io/v23/context"
"v.io/v23/naming"
- "v.io/v23/services/mgmt/application"
"v.io/v23/services/mgmt/stats"
"v.io/v23/vdl"
"v.io/x/ref/lib/flags/consts"
- "v.io/x/ref/lib/modules"
- "v.io/x/ref/lib/testutil"
- "v.io/x/ref/services/mgmt/device/impl"
mgmttest "v.io/x/ref/services/mgmt/lib/testutil"
)
-// TODO(rjkroege): This helper is generally useful. Move to util_test.go
-// and use it to reduce boiler plate across all tests here.
-func startupHelper(t *testing.T) (func(), *context.T, *modules.Shell, *application.Envelope, string, string) {
- ctx, shutdown := testutil.InitForTest()
- v23.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
-
- sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
-
- // Set up mock application and binary repositories.
- envelope, envCleanup := startMockRepos(t, ctx)
-
- root, rootCleanup := mgmttest.SetupRootDir(t, "devicemanager")
- if err := impl.SaveCreatorInfo(root); err != nil {
- t.Fatal(err)
- }
-
- // Create a script wrapping the test target that implements suidhelper.
- helperPath := generateSuidHelperScript(t, root)
-
- return func() {
- rootCleanup()
- envCleanup()
- deferFn()
- shutdown()
- }, ctx, sh, envelope, root, helperPath
-}
-
func TestReaperNoticesAppDeath(t *testing.T) {
- cleanup, ctx, sh, envelope, root, helperPath := startupHelper(t)
+ cleanup, ctx, sh, envelope, root, helperPath, _ := startupHelper(t)
defer cleanup()
// Set up the device manager. Since we won't do device manager updates,
@@ -120,7 +88,7 @@
}
func TestReapReconciliation(t *testing.T) {
- cleanup, ctx, sh, envelope, root, helperPath := startupHelper(t)
+ cleanup, ctx, sh, envelope, root, helperPath, _ := startupHelper(t)
defer cleanup()
// Start a device manager.
diff --git a/services/mgmt/device/impl/util_test.go b/services/mgmt/device/impl/util_test.go
index 6e8fe15..9d4b7eb 100644
--- a/services/mgmt/device/impl/util_test.go
+++ b/services/mgmt/device/impl/util_test.go
@@ -18,6 +18,7 @@
"v.io/v23/security"
"v.io/v23/services/mgmt/application"
"v.io/v23/services/mgmt/device"
+ "v.io/v23/services/mgmt/stats"
"v.io/v23/verror"
"v.io/x/lib/vlog"
tsecurity "v.io/x/ref/lib/testutil/security"
@@ -26,6 +27,7 @@
"v.io/x/ref/lib/testutil"
_ "v.io/x/ref/profiles/roaming"
"v.io/x/ref/services/mgmt/device/impl"
+ mgmttest "v.io/x/ref/services/mgmt/lib/testutil"
)
const (
@@ -181,6 +183,12 @@
return device.ApplicationClient(appName)
}
+func statsStub(nameComponents ...string) stats.StatsClientMethods {
+ baseName := "dm/apps"
+ statsName := naming.Join(append([]string{baseName}, nameComponents...)...)
+ return stats.StatsClient(statsName)
+}
+
func installApp(t *testing.T, ctx *context.T, opt ...interface{}) string {
appID, err := appStub().Install(ctx, mockApplicationRepoName, ocfg(opt), opkg(opt))
if err != nil {
@@ -383,3 +391,34 @@
}
return ret
}
+
+// TODO(rjkroege): This helper is generally useful. Use it to reduce
+// boiler plate across all device manager tests.
+func startupHelper(t *testing.T) (func(), *context.T, *modules.Shell, *application.Envelope, string, string, *tsecurity.IDProvider) {
+ ctx, shutdown := testutil.InitForTest()
+ v23.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
+
+ // Make a new identity context.
+ idp := tsecurity.NewIDProvider("root")
+ ctx = ctxWithNewPrincipal(t, ctx, idp, "self")
+
+ sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
+
+ // Set up mock application and binary repositories.
+ envelope, envCleanup := startMockRepos(t, ctx)
+
+ root, rootCleanup := mgmttest.SetupRootDir(t, "devicemanager")
+ if err := impl.SaveCreatorInfo(root); err != nil {
+ t.Fatal(err)
+ }
+
+ // Create a script wrapping the test target that implements suidhelper.
+ helperPath := generateSuidHelperScript(t, root)
+
+ return func() {
+ rootCleanup()
+ envCleanup()
+ deferFn()
+ shutdown()
+ }, ctx, sh, envelope, root, helperPath, idp
+}