Skip to content
This repository was archived by the owner on Jul 31, 2025. It is now read-only.

Commit 30c07bd

Browse files
authored
Merge pull request #972 from cyli/fix-error-messages
Fix auth login error messages and messaging when witnessing a delegation with 0 valid keys
2 parents 85f320e + 220cfb5 commit 30c07bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1384
-451
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# Changelog
22

3-
## [v0.4.0](https://github.com/docker/notary/releases/tag/v0.4.0) 8/11/2016
3+
## [v0.4.1](https://github.com/docker/notary/releases/tag/v0.4.0) 9/27/2016
4+
+ Preliminary Windows support for notary client [#970](https://github.com/docker/notary/pull/970)
5+
+ Output message to CLI when repo changes have been successfully published [#974](https://github.com/docker/notary/pull/974)
6+
+ Improved error messages for client authentication errors and for the witness command [#972](https://github.com/docker/notary/pull/972)
7+
8+
## [v0.4.0](https://github.com/docker/notary/releases/tag/v0.4.0) 9/21/2016
49
+ Server-managed key rotations [#889](https://github.com/docker/notary/pull/889)
510
+ Remove `timestamp_keys` table, which stored redundant information [#889](https://github.com/docker/notary/pull/889)
611
+ Introduce `notary delete` command to delete local and/or remote repo data [#895](https://github.com/docker/notary/pull/895)

Godeps/Godeps.json

Lines changed: 69 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

NOTARY_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.4
1+
0.4.1

client/witness.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package client
22

33
import (
4+
"path/filepath"
5+
46
"github.com/docker/notary/client/changelist"
57
"github.com/docker/notary/tuf"
68
"github.com/docker/notary/tuf/data"
7-
"path/filepath"
89
)
910

1011
// Witness creates change objects to witness (i.e. re-sign) the given
@@ -41,7 +42,18 @@ func witnessTargets(repo *tuf.Repo, invalid *tuf.Repo, role string) error {
4142
r.Dirty = true
4243
return nil
4344
}
44-
if invalid != nil {
45+
46+
if roleObj, err := repo.GetDelegationRole(role); err == nil && invalid != nil {
47+
// A role with a threshold > len(keys) is technically invalid, but we let it build in the builder because
48+
// we want to be able to download the role (which may still have targets on it), add more keys, and then
49+
// witness the role, thus bringing it back to valid. However, if no keys have been added before witnessing,
50+
// then it is still an invalid role, and can't be witnessed because nothing can bring it back to valid.
51+
if roleObj.Threshold > len(roleObj.Keys) {
52+
return data.ErrInvalidRole{
53+
Role: role,
54+
Reason: "role does not specify enough valid signing keys to meet its required threshold",
55+
}
56+
}
4557
if r, ok := invalid.Targets[role]; ok {
4658
// role is recognized but invalid, move to valid data and mark for re-signing
4759
repo.Targets[role] = r

cmd/notary/integration_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,8 @@ func TestPurgeSingleKey(t *testing.T) {
14711471
// 11. witness an invalid role and check for error on publish
14721472
// 12. check non-targets base roles all fail
14731473
// 13. test auto-publish functionality
1474+
// 14. remove all keys from the delegation and publish
1475+
// 15. witnessing the delegation should now fail
14741476
func TestWitness(t *testing.T) {
14751477
setUp(t)
14761478

@@ -1637,6 +1639,12 @@ func TestWitness(t *testing.T) {
16371639
require.NoError(t, err)
16381640
require.Contains(t, output, targetName)
16391641
require.Contains(t, output, targetHash)
1642+
1643+
_, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "remove", "-p", "gun", delgName, keyID, keyID2)
1644+
require.NoError(t, err)
1645+
_, err = runCommand(t, tempDir, "-s", server.URL, "witness", "-p", "gun", delgName)
1646+
require.Error(t, err)
1647+
require.Contains(t, err.Error(), "role does not specify enough valid signing keys to meet its required threshold")
16401648
}
16411649

16421650
func generateCertPrivKeyPair(t *testing.T, gun, keyAlgorithm string) (*x509.Certificate, data.PrivateKey, string) {

cmd/notary/tuf.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"strings"
1414
"time"
1515

16+
"golang.org/x/crypto/ssh/terminal"
17+
1618
"github.com/Sirupsen/logrus"
1719
"github.com/docker/distribution/registry/client/auth"
1820
"github.com/docker/distribution/registry/client/transport"
@@ -755,7 +757,8 @@ type passwordStore struct {
755757
}
756758

757759
func (ps passwordStore) Basic(u *url.URL) (string, string) {
758-
if ps.anonymous {
760+
// if it's not a terminal, don't wait on input
761+
if ps.anonymous || !terminal.IsTerminal(int(os.Stdin.Fd())) {
759762
return "", ""
760763
}
761764

@@ -795,6 +798,15 @@ func (ps passwordStore) Basic(u *url.URL) (string, string) {
795798
return username, password
796799
}
797800

801+
// to comply with the CredentialStore interface
802+
func (ps passwordStore) RefreshToken(u *url.URL, service string) string {
803+
return ""
804+
}
805+
806+
// to comply with the CredentialStore interface
807+
func (ps passwordStore) SetRefreshToken(u *url.URL, service string, token string) {
808+
}
809+
798810
type httpAccess int
799811

800812
const (

cmd/notary/tuf_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package main
33
import (
44
"net/http"
55
"net/http/httptest"
6+
"net/url"
67
"os"
78
"path/filepath"
89
"testing"
910

11+
"github.com/docker/distribution/registry/client/auth"
1012
"github.com/spf13/cobra"
1113
"github.com/spf13/viper"
1214
"github.com/stretchr/testify/require"
@@ -219,3 +221,18 @@ func TestGetTrustPinningErrors(t *testing.T) {
219221
tc.sha256 = "88b76b34ab83a9e4d5abe3697950fb73f940aab1aa5b534f80cf9de9708942be"
220222
require.Error(t, tc.tufAddByHash(&cobra.Command{}, []string{"gun", "test1", "100"}))
221223
}
224+
225+
func TestPasswordStore(t *testing.T) {
226+
myurl, err := url.Parse("https://docker.io")
227+
require.NoError(t, err)
228+
229+
// whether or not we're anonymous, because this isn't a terminal,
230+
for _, ps := range []auth.CredentialStore{passwordStore{}, passwordStore{anonymous: true}} {
231+
username, passwd := ps.Basic(myurl)
232+
require.Equal(t, "", username)
233+
require.Equal(t, "", passwd)
234+
235+
ps.SetRefreshToken(myurl, "someService", "token") // doesn't return an error, just want to make sure no state changes
236+
require.Equal(t, "", ps.RefreshToken(myurl, "someService"))
237+
}
238+
}

tuf/signed/errors.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ type ErrInsufficientSignatures struct {
1414
}
1515

1616
func (e ErrInsufficientSignatures) Error() string {
17-
candidates := strings.Join(e.MissingKeyIDs, ", ")
17+
candidates := ""
18+
if len(e.MissingKeyIDs) > 0 {
19+
candidates = fmt.Sprintf(" (%s)", strings.Join(e.MissingKeyIDs, ", "))
20+
}
21+
1822
if e.FoundKeys == 0 {
19-
return fmt.Sprintf("signing keys not available, need %d keys out of: %s", e.NeededKeys, candidates)
23+
return fmt.Sprintf("signing keys not available: need %d keys from %d possible keys%s",
24+
e.NeededKeys, len(e.MissingKeyIDs), candidates)
2025
}
21-
return fmt.Sprintf("not enough signing keys: got %d of %d needed keys, other candidates: %s",
22-
e.FoundKeys, e.NeededKeys, candidates)
26+
return fmt.Sprintf("not enough signing keys: found %d of %d needed keys - %d other possible keys%s",
27+
e.FoundKeys, e.NeededKeys, len(e.MissingKeyIDs), candidates)
2328
}
2429

2530
// ErrExpired indicates a piece of metadata has expired

tuf/signed/sign_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,16 @@ func TestSignFailingKeys(t *testing.T) {
345345
require.Error(t, err)
346346
require.IsType(t, FailingPrivateKeyErr{}, err)
347347
}
348+
349+
// make sure we produce readable error messages
350+
func TestErrInsufficientSignaturesMessaging(t *testing.T) {
351+
require.Contains(t,
352+
ErrInsufficientSignatures{NeededKeys: 2, MissingKeyIDs: []string{"ID1", "ID2"}}.Error(),
353+
"need 2 keys from 2 possible keys (ID1, ID2)")
354+
require.Contains(t,
355+
ErrInsufficientSignatures{FoundKeys: 1, NeededKeys: 2, MissingKeyIDs: []string{"ID1", "ID2"}}.Error(),
356+
"found 1 of 2 needed keys - 2 other possible keys (ID1, ID2)")
357+
require.Contains(t,
358+
ErrInsufficientSignatures{FoundKeys: 1, NeededKeys: 2, MissingKeyIDs: []string{}}.Error(),
359+
"found 1 of 2 needed keys - 0 other possible keys")
360+
}

vendor/github.com/docker/distribution/.drone.yml

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)