Skip to content

Commit

Permalink
Merge pull request #822 from docker/passphrase-delegation-alias
Browse files Browse the repository at this point in the history
Only use delegation passphrase env var for non-base roles
  • Loading branch information
riyazdf authored Jul 19, 2016
2 parents 1023a94 + 7a98a07 commit 0abcc1b
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 6 deletions.
4 changes: 3 additions & 1 deletion cmd/notary/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/notary"
"github.com/docker/notary/passphrase"
"github.com/docker/notary/tuf/data"
"github.com/docker/notary/version"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -234,7 +235,8 @@ func getPassphraseRetriever() notary.PassRetriever {
// For delegation roles, we can also try the "delegation" alias if it is specified
// Note that we don't check if the role name is for a delegation to allow for names like "user"
// since delegation keys can be shared across repositories
if v := env["delegation"]; v != "" {
// This cannot be a base role or imported key, though.
if v := env["delegation"]; !data.IsBaseRole(alias) && v != "" {
return v, numAttempts > 1, nil
}
return baseRetriever(keyName, alias, createNew, numAttempts)
Expand Down
64 changes: 59 additions & 5 deletions cmd/notary/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,16 +523,34 @@ func TestConfigFileTrustPinning(t *testing.T) {
}

func TestPassphraseRetrieverCaching(t *testing.T) {
// Set up passphrase environment vars
// Only set up one passphrase environment var first for root
require.NoError(t, os.Setenv("NOTARY_ROOT_PASSPHRASE", "root_passphrase"))
defer os.Clearenv()

// Check that root is cached
retriever := getPassphraseRetriever()
passphrase, giveup, err := retriever("key", data.CanonicalRootRole, false, 0)
require.NoError(t, err)
require.False(t, giveup)
require.Equal(t, passphrase, "root_passphrase")

passphrase, giveup, err = retriever("key", "user", false, 0)
require.Error(t, err)
passphrase, giveup, err = retriever("key", data.CanonicalTargetsRole, false, 0)
require.Error(t, err)
passphrase, giveup, err = retriever("key", data.CanonicalSnapshotRole, false, 0)
require.Error(t, err)
passphrase, giveup, err = retriever("key", "targets/delegation", false, 0)
require.Error(t, err)

// Set up the rest of them
require.NoError(t, os.Setenv("NOTARY_TARGETS_PASSPHRASE", "targets_passphrase"))
require.NoError(t, os.Setenv("NOTARY_SNAPSHOT_PASSPHRASE", "snapshot_passphrase"))
require.NoError(t, os.Setenv("NOTARY_DELEGATION_PASSPHRASE", "delegation_passphrase"))

defer os.Clearenv()
// Check the caching
retriever := getPassphraseRetriever()
passphrase, giveup, err := retriever("key", data.CanonicalRootRole, false, 0)
// Get a new retriever and check the caching
retriever = getPassphraseRetriever()
passphrase, giveup, err = retriever("key", data.CanonicalRootRole, false, 0)
require.NoError(t, err)
require.False(t, giveup)
require.Equal(t, passphrase, "root_passphrase")
Expand All @@ -558,3 +576,39 @@ func TestPassphraseRetrieverCaching(t *testing.T) {
require.False(t, giveup)
require.Equal(t, passphrase, "delegation_passphrase")
}

func TestPassphraseRetrieverDelegationRoleCaching(t *testing.T) {
// Only set up one passphrase environment var first for delegations
require.NoError(t, os.Setenv("NOTARY_DELEGATION_PASSPHRASE", "delegation_passphrase"))
defer os.Clearenv()

// Check that any delegation role is cached
retriever := getPassphraseRetriever()

passphrase, giveup, err := retriever("key", "targets/releases", false, 0)
require.NoError(t, err)
require.False(t, giveup)
require.Equal(t, passphrase, "delegation_passphrase")
passphrase, giveup, err = retriever("key", "targets/delegation", false, 0)
require.NoError(t, err)
require.False(t, giveup)
require.Equal(t, passphrase, "delegation_passphrase")
passphrase, giveup, err = retriever("key", "targets/a/b/c/d", false, 0)
require.NoError(t, err)
require.False(t, giveup)
require.Equal(t, passphrase, "delegation_passphrase")

// Also check arbitrary usernames that are non-BaseRoles or imported so that this can be shared across keys
passphrase, giveup, err = retriever("key", "user", false, 0)
require.NoError(t, err)
require.False(t, giveup)
require.Equal(t, passphrase, "delegation_passphrase")

// Make sure base roles fail
_, _, err = retriever("key", data.CanonicalRootRole, false, 0)
require.Error(t, err)
_, _, err = retriever("key", data.CanonicalTargetsRole, false, 0)
require.Error(t, err)
_, _, err = retriever("key", data.CanonicalSnapshotRole, false, 0)
require.Error(t, err)
}
10 changes: 10 additions & 0 deletions tuf/data/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ func IsDelegation(role string) bool {
isClean
}

// IsBaseRole checks if the role is a base role
func IsBaseRole(role string) bool {
for _, baseRole := range BaseRoles {
if role == baseRole {
return true
}
}
return false
}

// BaseRole is an internal representation of a root/targets/snapshot/timestamp role, with its public keys included
type BaseRole struct {
Keys map[string]PublicKey
Expand Down
11 changes: 11 additions & 0 deletions tuf/data/roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,17 @@ func TestValidRoleFunction(t *testing.T) {
require.False(t, ValidRole(path.Join("role")))
}

func TestIsBaseRole(t *testing.T) {
for _, role := range BaseRoles {
require.True(t, IsBaseRole(role))
}
require.False(t, IsBaseRole("user"))
require.False(t, IsBaseRole(
path.Join(CanonicalTargetsRole, "level1", "level2", "level3")))
require.False(t, IsBaseRole(path.Join(CanonicalTargetsRole, "level1")))
require.False(t, IsBaseRole(""))
}

func TestBaseRoleEquals(t *testing.T) {
fakeKeyHello := NewRSAPublicKey([]byte("hello"))
fakeKeyThere := NewRSAPublicKey([]byte("there"))
Expand Down

0 comments on commit 0abcc1b

Please sign in to comment.