Skip to content
This repository was archived by the owner on Jun 21, 2022. It is now read-only.

Commit 5419e7f

Browse files
authored
Merge pull request #16 from reinventer/improvements
Case insensitive algorithm name and small optimization
2 parents 366d8cf + 9d6d311 commit 5419e7f

File tree

2 files changed

+194
-11
lines changed

2 files changed

+194
-11
lines changed

authorization.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"hash"
1010
"io"
1111
"net/url"
12-
"regexp"
1312
"strings"
1413
"time"
1514
)
@@ -49,6 +48,13 @@ func newAuthorization(dr *DigestRequest) (*authorization, error) {
4948
return ah.refreshAuthorization(dr)
5049
}
5150

51+
const (
52+
algorithmMD5 = "MD5"
53+
algorithmMD5Sess = "MD5-SESS"
54+
algorithmSHA256 = "SHA-256"
55+
algorithmSHA256Sess = "SHA-256-SESS"
56+
)
57+
5258
func (ah *authorization) refreshAuthorization(dr *DigestRequest) (*authorization, error) {
5359

5460
ah.Username = dr.Username
@@ -82,11 +88,13 @@ func (ah *authorization) computeResponse(dr *DigestRequest) (s string) {
8288

8389
func (ah *authorization) computeA1(dr *DigestRequest) string {
8490

85-
if ah.Algorithm == "" || ah.Algorithm == "MD5" || ah.Algorithm == "SHA-256" {
91+
algorithm := strings.ToUpper(ah.Algorithm)
92+
93+
if algorithm == "" || algorithm == algorithmMD5 || algorithm == algorithmSHA256 {
8694
return fmt.Sprintf("%s:%s:%s", ah.Username, ah.Realm, dr.Password)
8795
}
8896

89-
if ah.Algorithm == "MD5-sess" || ah.Algorithm == "SHA-256-sess" {
97+
if algorithm == algorithmMD5Sess || algorithm == algorithmSHA256Sess {
9098
upHash := ah.hash(fmt.Sprintf("%s:%s:%s", ah.Username, ah.Realm, dr.Password))
9199
return fmt.Sprintf("%s:%s:%s", upHash, ah.Nonce, ah.Cnonce)
92100
}
@@ -96,7 +104,7 @@ func (ah *authorization) computeA1(dr *DigestRequest) string {
96104

97105
func (ah *authorization) computeA2(dr *DigestRequest) string {
98106

99-
if matched, _ := regexp.MatchString("auth-int", dr.Wa.Qop); matched {
107+
if strings.Contains(dr.Wa.Qop, "auth-int") {
100108
ah.Qop = "auth-int"
101109
return fmt.Sprintf("%s:%s:%s", dr.Method, ah.URI, ah.hash(dr.Body))
102110
}
@@ -109,20 +117,21 @@ func (ah *authorization) computeA2(dr *DigestRequest) string {
109117
return ""
110118
}
111119

112-
func (ah *authorization) hash(a string) (s string) {
113-
120+
func (ah *authorization) hash(a string) string {
114121
var h hash.Hash
122+
algorithm := strings.ToUpper(ah.Algorithm)
115123

116-
if ah.Algorithm == "" || ah.Algorithm == "MD5" || ah.Algorithm == "MD5-sess" {
124+
if algorithm == "" || algorithm == algorithmMD5 || algorithm == algorithmMD5Sess {
117125
h = md5.New()
118-
} else if ah.Algorithm == "SHA-256" || ah.Algorithm == "SHA-256-sess" {
126+
} else if algorithm == algorithmSHA256 || algorithm == algorithmSHA256Sess {
119127
h = sha256.New()
128+
} else {
129+
// unknown algorithm
130+
return ""
120131
}
121132

122133
io.WriteString(h, a)
123-
s = hex.EncodeToString(h.Sum(nil))
124-
125-
return
134+
return hex.EncodeToString(h.Sum(nil))
126135
}
127136

128137
func (ah *authorization) toString() string {

authorization_test.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package digest_auth_client
2+
3+
import "testing"
4+
5+
func TestHash(t *testing.T) {
6+
testCases := []struct {
7+
name string
8+
algorithm string
9+
expRes string
10+
}{
11+
{
12+
name: "empty algorithm",
13+
algorithm: "",
14+
expRes: "1a79a4d60de6718e8e5b326e338ae533",
15+
},
16+
{
17+
name: "MD5 algorithm",
18+
algorithm: "MD5",
19+
expRes: "1a79a4d60de6718e8e5b326e338ae533",
20+
},
21+
{
22+
name: "MD5-sess algorithm",
23+
algorithm: "MD5",
24+
expRes: "1a79a4d60de6718e8e5b326e338ae533",
25+
},
26+
{
27+
name: "SHA256 algorithm",
28+
algorithm: "SHA-256",
29+
expRes: "50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c",
30+
},
31+
{
32+
name: "SHA256-sess algorithm",
33+
algorithm: "SHA-256",
34+
expRes: "50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c",
35+
},
36+
{
37+
name: "md5 algorithm",
38+
algorithm: "md5",
39+
expRes: "1a79a4d60de6718e8e5b326e338ae533",
40+
},
41+
{
42+
name: "unknown algorithm",
43+
algorithm: "unknown",
44+
expRes: "",
45+
},
46+
}
47+
48+
for _, tc := range testCases {
49+
t.Run(tc.name, func(t *testing.T) {
50+
ah := &authorization{Algorithm: tc.algorithm}
51+
res := ah.hash("example")
52+
if res != tc.expRes {
53+
t.Errorf("got: %q, want: %q", res, tc.expRes)
54+
}
55+
})
56+
}
57+
}
58+
59+
func TestComputeA1(t *testing.T) {
60+
testCases := []struct {
61+
name string
62+
algorithm string
63+
expRes string
64+
}{
65+
{
66+
name: "empty algorithm",
67+
algorithm: "",
68+
expRes: "username:realm:secret",
69+
},
70+
{
71+
name: "MD5 algorithm",
72+
algorithm: "MD5",
73+
expRes: "username:realm:secret",
74+
},
75+
{
76+
name: "MD5-sess algorithm",
77+
algorithm: "MD5",
78+
expRes: "username:realm:secret",
79+
},
80+
{
81+
name: "SHA256 algorithm",
82+
algorithm: "SHA-256",
83+
expRes: "username:realm:secret",
84+
},
85+
{
86+
name: "SHA256-sess algorithm",
87+
algorithm: "SHA-256",
88+
expRes: "username:realm:secret",
89+
},
90+
{
91+
name: "md5 algorithm",
92+
algorithm: "md5",
93+
expRes: "username:realm:secret",
94+
},
95+
{
96+
name: "unknown algorithm",
97+
algorithm: "unknown",
98+
expRes: "",
99+
},
100+
}
101+
102+
for _, tc := range testCases {
103+
t.Run(tc.name, func(t *testing.T) {
104+
dr := &DigestRequest{Password: "secret"}
105+
ah := &authorization{
106+
Algorithm: tc.algorithm,
107+
Nonce: "nonce",
108+
Cnonce: "cnonce",
109+
Username: "username",
110+
Realm: "realm",
111+
}
112+
res := ah.computeA1(dr)
113+
if res != tc.expRes {
114+
t.Errorf("got: %q, want: %q", res, tc.expRes)
115+
}
116+
})
117+
}
118+
}
119+
120+
func TestComputeA2(t *testing.T) {
121+
testCases := []struct {
122+
name string
123+
qop string
124+
expRes string
125+
expAuthQop string
126+
}{
127+
{
128+
name: "empty qop",
129+
qop: "",
130+
expRes: "method:uri",
131+
expAuthQop: "auth",
132+
},
133+
{
134+
name: "qop is auth",
135+
qop: "auth",
136+
expRes: "method:uri",
137+
expAuthQop: "auth",
138+
},
139+
{
140+
name: "qop is auth-int",
141+
qop: "qop is auth-int",
142+
expRes: "method:uri:841a2d689ad86bd1611447453c22c6fc",
143+
expAuthQop: "auth-int",
144+
},
145+
}
146+
147+
for _, tc := range testCases {
148+
t.Run(tc.name, func(t *testing.T) {
149+
dr := &DigestRequest{
150+
Method: "method",
151+
Body: "body",
152+
Wa: &wwwAuthenticate{
153+
Qop: tc.qop,
154+
},
155+
}
156+
ah := &authorization{
157+
Algorithm: "MD5",
158+
Nonce: "nonce",
159+
Cnonce: "cnonce",
160+
Username: "username",
161+
Realm: "realm",
162+
URI: "uri",
163+
Qop: tc.qop,
164+
}
165+
res := ah.computeA2(dr)
166+
if res != tc.expRes {
167+
t.Errorf("wrong result, got: %q, want: %q", res, tc.expRes)
168+
}
169+
if ah.Qop != tc.expAuthQop {
170+
t.Errorf("wrong qop, got: %q, want: %q", ah.Qop, tc.expAuthQop)
171+
}
172+
})
173+
}
174+
}

0 commit comments

Comments
 (0)