blob: bb927b1cff3536fee6ba50d11a48fa9dd0c50e6d [file] [log] [blame]
package impl_test
import (
"syscall"
"testing"
"v.io/v23/context"
"v.io/v23/naming"
"v.io/v23/security"
"v.io/v23/services/security/access"
"v.io/v23/verror"
mgmttest "v.io/x/ref/services/mgmt/lib/testutil"
"v.io/x/ref/test/testutil"
)
func updateAccessList(t *testing.T, ctx *context.T, blessing, right string, name ...string) {
acl, etag, err := appStub(name...).GetPermissions(ctx)
if err != nil {
t.Fatalf(testutil.FormatLogLine(2, "GetACL(%v) failed %v", name, err))
}
acl.Add(security.BlessingPattern(blessing), right)
if err = appStub(name...).SetPermissions(ctx, acl, etag); err != nil {
t.Fatalf(testutil.FormatLogLine(2, "SetPermissions(%v, %v, %v) failed: %v", name, blessing, right, err))
}
}
func testAccessFail(t *testing.T, expected verror.ID, ctx *context.T, who string, name ...string) {
if _, err := statsStub(name...).Value(ctx); !verror.Is(err, expected) {
t.Fatalf(testutil.FormatLogLine(2, "%s got error %v but expected %v", who, err, expected))
}
}
func TestDebugPermissionsPropagation(t *testing.T) {
cleanup, ctx, sh, envelope, root, helperPath, idp := startupHelper(t)
defer cleanup()
// Set up the device manager.
dmh := mgmttest.RunCommand(t, sh, nil, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
mgmttest.ReadPID(t, dmh)
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 AccessLists 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.
updateAccessList(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.
updateAccessList(t, bobCtx, "root/alice/$", string(access.Read), appID, bobApp)
// Create some globbing test vectors.
globtests := []globTestVector{
{naming.Join("dm", "apps", appID, bobApp), "*",
[]string{"logs", "pprof", "stats"},
},
{naming.Join("dm", "apps", appID, bobApp, "stats", "system"),
"start-time*",
[]string{"start-time-rfc1123", "start-time-unix"},
},
{naming.Join("dm", "apps", appID, bobApp, "logs"),
"*",
[]string{
"STDERR-<timestamp>",
"STDOUT-<timestamp>",
"app.INFO",
"app.<*>.INFO.<timestamp>",
},
},
}
appGlobtests := []globTestVector{
{naming.Join("appV1", "__debug"), "*",
[]string{"logs", "pprof", "stats", "vtrace"},
},
{naming.Join("appV1", "__debug", "stats", "system"),
"start-time*",
[]string{"start-time-rfc1123", "start-time-unix"},
},
{naming.Join("appV1", "__debug", "logs"),
"*",
[]string{
"STDERR-<timestamp>",
"STDOUT-<timestamp>",
"app.INFO",
"app.<*>.INFO.<timestamp>",
},
},
}
globtestminus := globtests[1:]
res := newGlobTestRegexHelper("app")
// Confirm that self can access __debug names.
verifyGlob(t, selfCtx, "app", globtests, res)
verifyStatsValues(t, selfCtx, "dm", "apps", appID, bobApp, "stats/system/start-time*")
verifyLog(t, selfCtx, "dm", "apps", appID, bobApp, "logs", "*")
verifyPProfCmdLine(t, selfCtx, "app", "dm", "apps", appID, bobApp, "pprof")
// Bob started the app so selfCtx can't connect to the app.
verifyFailGlob(t, selfCtx, appGlobtests)
testAccessFail(t, verror.ErrNoAccess.ID, selfCtx, "self", "appV1", "__debug", "stats/system/pid")
// hackerjoe (for example) can't either.
verifyFailGlob(t, hjCtx, appGlobtests)
testAccessFail(t, verror.ErrNoAccess.ID, hjCtx, "hackerjoe", "appV1", "__debug", "stats/system/pid")
// Bob has an issue with his app and tries to use the debug output to figure it out.
verifyGlob(t, bobCtx, "app", globtests, res)
verifyStatsValues(t, bobCtx, "dm", "apps", appID, bobApp, "stats/system/start-time*")
verifyLog(t, bobCtx, "dm", "apps", appID, bobApp, "logs", "*")
verifyPProfCmdLine(t, bobCtx, "app", "dm", "apps", appID, bobApp, "pprof")
// Bob can also connect directly to his app.
verifyGlob(t, bobCtx, "app", appGlobtests, res)
verifyStatsValues(t, bobCtx, "appV1", "__debug", "stats/system/start-time*")
// But Bob can't figure it out and hopes that hackerjoe can debug it.
updateAccessList(t, bobCtx, "root/hackerjoe/$", string(access.Debug), appID, bobApp)
// Fortunately the device manager permits hackerjoe to access the stats.
// But hackerjoe can't solve Bob's problem.
// Because hackerjoe has Debug, hackerjoe can glob the __debug resources
// of Bob's app but can't glob Bob's app.
verifyGlob(t, hjCtx, "app", globtestminus, res)
verifyFailGlob(t, hjCtx, globtests[0:1])
verifyStatsValues(t, hjCtx, "dm", "apps", appID, bobApp, "stats", "system/start-time*")
verifyLog(t, hjCtx, "dm", "apps", appID, bobApp, "logs", "*")
verifyPProfCmdLine(t, hjCtx, "app", "dm", "apps", appID, bobApp, "pprof")
// TODO(rjkroege): Propagate the permission lists such that they are the same for hackerjoe
// directly connecting to the app.
verifyFailGlob(t, hjCtx, appGlobtests)
testAccessFail(t, verror.ErrNoAccess.ID, hjCtx, "hackerjoe", "appV1", "__debug", "stats/system/pid")
// Alice might be able to help but Bob didn't give Alice access to the debug ACLs.
testAccessFail(t, verror.ErrNoAccess.ID, aliceCtx, "Alice", "dm", "apps", appID, bobApp, "stats/system/pid")
// Bob forgets that Alice can't read the stats when he can.
verifyGlob(t, bobCtx, "app", globtests, res)
verifyStatsValues(t, bobCtx, "dm", "apps", appID, bobApp, "stats/system/start-time*")
// So Bob changes the permissions so that Alice can help debug too.
updateAccessList(t, bobCtx, "root/alice/$", string(access.Debug), appID, bobApp)
// Alice can access __debug content.
verifyGlob(t, aliceCtx, "app", globtestminus, res)
verifyFailGlob(t, aliceCtx, globtests[0:1])
verifyStatsValues(t, aliceCtx, "dm", "apps", appID, bobApp, "stats", "system/start-time*")
verifyLog(t, aliceCtx, "dm", "apps", appID, bobApp, "logs", "*")
verifyPProfCmdLine(t, aliceCtx, "app", "dm", "apps", appID, bobApp, "pprof")
// TODO(rjkroege): Propagate the permission lists such that they are the same for Alice
// directly connecting to the app.
verifyFailGlob(t, aliceCtx, appGlobtests)
// Bob is glum because no one can help him fix his app so he stops it.
stopApp(t, bobCtx, appID, bobApp)
// Cleanly shut down the device manager.
syscall.Kill(dmh.Pid(), syscall.SIGINT)
dmh.Expect("dm terminated")
dmh.ExpectEOF()
}