forked from abbot/go-http-auth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
digest_test.go
171 lines (147 loc) · 5.56 KB
/
digest_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package auth
import (
"net/http"
"net/url"
"testing"
"time"
)
func TestAuthDigest(t *testing.T) {
t.Parallel()
secrets := HtdigestFileProvider("test.htdigest")
da := &DigestAuth{Opaque: "U7H+ier3Ae8Skd/g",
Realm: "example.com",
Secrets: secrets,
clients: map[string]*digestClient{}}
r := &http.Request{}
r.Method = "GET"
if u, _ := da.CheckAuth(r); u != "" {
t.Fatal("non-empty auth for empty request header")
}
r.Header = http.Header(make(map[string][]string))
r.Header.Set("Authorization", "Digest blabla")
if u, _ := da.CheckAuth(r); u != "" {
t.Fatal("non-empty auth for bad request header")
}
r.Header.Set("Authorization", `Digest username="test", realm="example.com", nonce="Vb9BP/h81n3GpTTB", uri="/t2", cnonce="NjE4MTM2", nc=00000001, qop="auth", response="ffc357c4eba74773c8687e0bc724c9a3", opaque="U7H+ier3Ae8Skd/g", algorithm=MD5`)
if u, _ := da.CheckAuth(r); u != "" {
t.Fatal("non-empty auth for unknown client")
}
r.URL, _ = url.Parse("/t2")
da.clients["Vb9BP/h81n3GpTTB"] = &digestClient{nc: 0, lastSeen: time.Now().UnixNano()}
if u, _ := da.CheckAuth(r); u != "test" {
t.Fatal("empty auth for legitimate client")
}
// our nc is now 0, client nc is 1
if u, _ := da.CheckAuth(r); u != "" {
t.Fatal("non-empty auth for outdated nc")
}
// try again with nc checking off
da.IgnoreNonceCount = true
if u, _ := da.CheckAuth(r); u != "test" {
t.Fatal("empty auth for outdated nc even though nc checking is off")
}
da.IgnoreNonceCount = false
r.URL, _ = url.Parse("/")
da.clients["Vb9BP/h81n3GpTTB"] = &digestClient{nc: 0, lastSeen: time.Now().UnixNano()}
if u, _ := da.CheckAuth(r); u != "" {
t.Fatal("non-empty auth for bad request path")
}
r.URL, _ = url.Parse("/t3")
da.clients["Vb9BP/h81n3GpTTB"] = &digestClient{nc: 0, lastSeen: time.Now().UnixNano()}
if u, _ := da.CheckAuth(r); u != "" {
t.Fatal("non-empty auth for bad request path")
}
da.clients["+RbVXSbIoa1SaJk1"] = &digestClient{nc: 0, lastSeen: time.Now().UnixNano()}
r.Header.Set("Authorization", `Digest username="test", realm="example.com", nonce="+RbVXSbIoa1SaJk1", uri="/", cnonce="NjE4NDkw", nc=00000001, qop="auth", response="c08918024d7faaabd5424654c4e3ad1c", opaque="U7H+ier3Ae8Skd/g", algorithm=MD5`)
if u, _ := da.CheckAuth(r); u != "test" {
t.Fatal("empty auth for valid request in subpath")
}
}
func TestDigestAuthParams(t *testing.T) {
t.Parallel()
const authorization = `Digest username="test", realm="", nonce="FRPnGdb8lvM1UHhi", uri="/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro", algorithm=MD5, response="fdcdd78e5b306ffed343d0ec3967f2e5", opaque="lEgVjogmIar2fg/t", qop=auth, nc=00000001, cnonce="e76b05db27a3b323"`
params := DigestAuthParams(authorization)
want := "/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro"
if params["uri"] != want {
t.Fatalf("failed to parse uri with embedded commas, got %q want %q", params["uri"], want)
}
}
// TestDigestPurgeOutOfRange tests that when we purge clients from the authenticator we do not purge
// more cache entries than the number of clients we have received.
// This is to avoid regressing and hitting a "slice bounds out of range" panic.
func TestDigestPurgeOutOfRange(t *testing.T) {
t.Parallel()
// Creating dummy clients for the digest authenticator.
nClients := 10
clients := make(map[string]*digestClient, nClients)
for i := 0; i < nClients; i++ {
clients[string(i)] = &digestClient{}
}
secrets := HtdigestFileProvider("test.htdigest")
da := &DigestAuth{
Opaque: "U7H+ier3Ae8Skd/g",
Realm: "example.com",
Secrets: secrets,
ClientCacheTolerance: nClients * 2,
ClientCacheTTL: 0,
clients: clients,
}
// By default this will try purging more than the number of
// clients we have stored.
time.Sleep(time.Nanosecond)
da.Purge()
}
// TestDigestPurgeTTL tests purging the client cache when a TTL is specified.
func TestDigestPurgeTTL(t *testing.T) {
t.Parallel()
nClients := 4
clients := make(map[string]*digestClient, nClients)
for i := 0; i < nClients; i++ {
clients[string(i)] = &digestClient{
lastSeen: time.Now().Add(time.Duration(-i) * time.Hour).UnixNano(),
}
}
secrets := HtdigestFileProvider("test.htdigest")
purgeTTLHours := 2
da := &DigestAuth{
Opaque: "U7H+ier3Ae8Skd/g",
Realm: "example.com",
Secrets: secrets,
ClientCacheTolerance: 2,
ClientCacheTTL: time.Hour * time.Duration(purgeTTLHours),
clients: clients,
}
// Wait a second before we purge to ensure the correct number of client
// entries "expire".
time.Sleep(time.Second)
da.Purge()
if len(da.clients) != 2 {
t.Fatalf("expected %d client entries, got %d", 2, len(da.clients))
}
for _, client := range da.clients {
if time.Unix(0, client.lastSeen).Before(time.Now().Add(time.Duration(-purgeTTLHours) * time.Hour)) {
t.Fatalf("expected entry with lastSeen time of %d to have been purged", client.lastSeen)
}
}
}
// TestDigestPurge tests purging the client cache when no TTL is specified.
func TestDigestPurge(t *testing.T) {
t.Parallel()
nClients := 4
clients := make(map[string]*digestClient, nClients)
for i := 0; i < nClients; i++ {
clients[string(i)] = &digestClient{}
}
secrets := HtdigestFileProvider("test.htdigest")
da := &DigestAuth{
Opaque: "U7H+ier3Ae8Skd/g",
Realm: "example.com",
Secrets: secrets,
ClientCacheTolerance: 1,
clients: clients,
}
da.Purge()
if len(da.clients) != 2 {
t.Fatalf("expected %d client entries, got %d", 2, len(da.clients))
}
}