blob: f883ea9d078f39ee84453097725b2e863bbf8bcd [file] [log] [blame]
Jan Schärcc9e4d12025-04-14 10:28:40 +00001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
4package registry
5
6import "testing"
7
8func TestParseAuthenticateHeader(t *testing.T) {
9 testCases := []struct {
10 desc string
11 header []string
12 parsed []authenticateChallenge
13 }{
14 {"absent", nil, nil},
15 {"no params",
16 []string{"Basic, !#$%&'*+-.^_`|~019abzABZ"},
17 []authenticateChallenge{{scheme: "Basic"}, {scheme: "!#$%&'*+-.^_`|~019abzABZ"}}},
18 {"token68",
19 []string{"0 a", "1 abzABZ019-._~+/, 2 abc=, 3 a==="},
20 []authenticateChallenge{
21 {scheme: "0", info: "a"},
22 {scheme: "1", info: "abzABZ019-._~+/"},
23 {scheme: "2", info: "abc="},
24 {scheme: "3", info: "a==="},
25 }},
26 {"params",
27 []string{`0 a="=,", empty = "", escape="\a\\\"", ` + "1 token!#$%&'*+-.^_`|~019abzABZ=!#$%&'*+-.^_`|~019abzABZ"},
28 []authenticateChallenge{
29 {scheme: "0", params: map[string]string{"a": "=,", "empty": "", "escape": `a\"`}},
30 {scheme: "1", params: map[string]string{"token!#$%&'*+-.^_`|~019abzabz": "!#$%&'*+-.^_`|~019abzABZ"}},
31 }},
32 {"duplicate param", []string{`Basic realm="apps", REALM=other`}, nil},
33 {"empty", []string{"", " ", "\t", ",", " , ,,\t ,", "Basic"}, []authenticateChallenge{{scheme: "Basic"}}},
34 {"RFC example",
35 []string{`Basic realm="simple", Newauth realm="apps", type=1, title="Login to \"apps\""`},
36 []authenticateChallenge{
37 {scheme: "Basic", params: map[string]string{"realm": "simple"}},
38 {scheme: "Newauth", params: map[string]string{"realm": "apps", "type": "1", "title": `Login to "apps"`}},
39 }},
40 {"extra commas",
41 []string{` , , Basic , , realm="simple" , , Newauth ,realm="apps",type=1` + "\t" + `, ,title="Login to \"apps\"" , , `},
42 []authenticateChallenge{
43 {scheme: "Basic", params: map[string]string{"realm": "simple"}},
44 {scheme: "Newauth", params: map[string]string{"realm": "apps", "type": "1", "title": `Login to "apps"`}},
45 }},
46 {"missing comma between challenges", []string{"Basic\tBearer"}, nil},
47 {"missing comma between challenges 2", []string{"Basic !"}, nil},
48 {"missing comma after token68", []string{"Basic a Bearer"}, nil},
49 {"missing comma between params", []string{`Basic realm="simple" type=1`}, nil},
50 {"missing quote", []string{`Basic realm="simple`}, nil},
51 {"missing value", []string{`Basic !=`}, nil},
52 }
53 for _, tC := range testCases {
54 t.Run(tC.desc, func(t *testing.T) {
55 actual := parseAuthenticateHeader(tC.header)
56 if want, got := len(tC.parsed), len(actual); want != got {
57 t.Fatalf("Expected %d challenges, got %d", want, got)
58 }
59 for i, actualC := range actual {
60 wantC := tC.parsed[i]
61 if want, got := wantC.scheme, actualC.scheme; want != got {
62 t.Errorf("Expected scheme %q, got %q", want, got)
63 }
64 if want, got := wantC.info, actualC.info; want != got {
65 t.Errorf("Expected info %q, got %q", want, got)
66 }
67 for param, want := range wantC.params {
68 got, ok := actualC.params[param]
69 if !ok {
70 t.Errorf("Scheme %s: Missing param %q", wantC.scheme, param)
71 } else if want != got {
72 t.Errorf("Scheme %s: Expected %s=%q, got %q", wantC.scheme, param, want, got)
73 }
74 }
75 for param := range actualC.params {
76 if _, ok := wantC.params[param]; !ok {
77 t.Errorf("Scheme %s: Extra param %q", wantC.scheme, param)
78 }
79 }
80 }
81 })
82 }
83}