init
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMintParseRoundTrip(t *testing.T) {
|
||||
seen := map[string]bool{}
|
||||
for i := 0; i < 100; i++ {
|
||||
token, keyID, hash, err := Mint()
|
||||
if err != nil {
|
||||
t.Fatalf("Mint: %v", err)
|
||||
}
|
||||
if seen[keyID] {
|
||||
t.Fatalf("Mint reused key id %q", keyID)
|
||||
}
|
||||
seen[keyID] = true
|
||||
|
||||
if !strings.HasPrefix(token, Prefix+"_") {
|
||||
t.Errorf("token %q lacks the %q prefix", token, Prefix)
|
||||
}
|
||||
gotID, secret, err := Parse(token)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse(%q): %v", token, err)
|
||||
}
|
||||
if gotID != keyID {
|
||||
t.Errorf("Parse key id = %q, want %q", gotID, keyID)
|
||||
}
|
||||
if len(gotID) != KeyIDLen {
|
||||
t.Errorf("key id length = %d, want %d", len(gotID), KeyIDLen)
|
||||
}
|
||||
if !SecretMatches(secret, hash[:]) {
|
||||
t.Error("minted secret does not match its own hash")
|
||||
}
|
||||
if strings.Contains(token, keyID+"_"+keyID) {
|
||||
t.Error("secret must not repeat the key id")
|
||||
}
|
||||
if !ValidKeyID(keyID) {
|
||||
t.Errorf("ValidKeyID rejected a minted id %q", keyID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRejectsMalformed(t *testing.T) {
|
||||
good, keyID, _, err := Mint()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, secret, err := Parse(good)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
token string
|
||||
}{
|
||||
{"empty", ""},
|
||||
{"no prefix", keyID + "_" + secret},
|
||||
{"wrong prefix", "xyz_" + keyID + "_" + secret},
|
||||
{"prefix only", "pgs_"},
|
||||
{"no separator", "pgs_" + keyID + secret},
|
||||
{"short key id", "pgs_" + keyID[:15] + "_" + secret},
|
||||
{"long key id", "pgs_" + keyID + "a_" + secret},
|
||||
{"short secret", "pgs_" + keyID + "_" + secret[:42]},
|
||||
{"long secret", "pgs_" + keyID + "_" + secret + "a"},
|
||||
{"uppercase key id", "pgs_" + strings.ToUpper(keyID) + "_" + secret},
|
||||
{"key id with 0 (not in base32)", "pgs_0" + keyID[1:] + "_" + secret},
|
||||
{"key id with 1 (not in base32)", "pgs_1" + keyID[1:] + "_" + secret},
|
||||
{"secret with padding", "pgs_" + keyID + "_" + secret[:42] + "="},
|
||||
{"secret with slash", "pgs_" + keyID + "_" + secret[:42] + "/"},
|
||||
{"secret with plus", "pgs_" + keyID + "_" + secret[:42] + "+"},
|
||||
{"embedded NUL", "pgs_" + keyID + "_" + secret[:42] + "\x00"},
|
||||
{"leading space", " " + good},
|
||||
{"newline", good + "\n"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if _, _, err := Parse(tc.token); err == nil {
|
||||
t.Errorf("Parse(%q) accepted a malformed token", tc.token)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// The parse error must never quote the input: these errors reach logs.
|
||||
if _, _, err := Parse(good[:len(good)-1] + "x"); err != nil {
|
||||
if strings.Contains(err.Error(), secret[:20]) {
|
||||
t.Error("parse error leaks part of the presented secret")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecretMatches(t *testing.T) {
|
||||
hash := HashSecret("correct horse battery staple")
|
||||
if !SecretMatches("correct horse battery staple", hash[:]) {
|
||||
t.Error("matching secret rejected")
|
||||
}
|
||||
if SecretMatches("correct horse battery stapl", hash[:]) {
|
||||
t.Error("truncated secret accepted")
|
||||
}
|
||||
if SecretMatches("", hash[:]) {
|
||||
t.Error("empty secret accepted")
|
||||
}
|
||||
if SecretMatches("correct horse battery staple", nil) {
|
||||
t.Error("nil stored hash accepted")
|
||||
}
|
||||
if SecretMatches("correct horse battery staple", hash[:16]) {
|
||||
t.Error("truncated stored hash accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidKeyID(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
want bool
|
||||
}{
|
||||
{"abcdefghijklmnop", true},
|
||||
{"234567234567abcd", true},
|
||||
{"", false},
|
||||
{"abcdefghijklmno", false}, // 15
|
||||
{"abcdefghijklmnopq", false}, // 17
|
||||
{"ABCDEFGHIJKLMNOP", false},
|
||||
{"abcdefghijklmno0", false},
|
||||
{"abcdefghijklmno1", false},
|
||||
{"abcdefghijklmno8", false},
|
||||
{"abcdefghijklmno-", false},
|
||||
{"abcdefghijklmn/p", false},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
if got := ValidKeyID(tc.in); got != tc.want {
|
||||
t.Errorf("ValidKeyID(%q) = %v, want %v", tc.in, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user