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

Commit 3a02c39

Browse files
committed
kind of done
1 parent 7be037b commit 3a02c39

File tree

3 files changed

+93
-54
lines changed

3 files changed

+93
-54
lines changed

authorization.go

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import (
44
"bytes"
55
"crypto/md5"
66
"crypto/sha256"
7+
"encoding/hex"
78
"fmt"
89
"hash"
910
"io"
11+
"net/url"
1012
"regexp"
13+
"strings"
1114
"time"
1215
)
1316

@@ -26,64 +29,79 @@ type authorization struct {
2629
Username_ string // quoted
2730
}
2831

29-
func newAuthorization(wa *wwwAuthenticate, dr *DigestRequest) (*authorization, error) {
32+
func newAuthorization(dr *DigestRequest) *authorization {
3033

31-
auth := authorization{
34+
ah := authorization{
3235
Algorithm: wa.Algorithm,
3336
Cnonce: "",
34-
Nc: 1, // TODO
37+
Nc: 0,
3538
Nonce: wa.Nonce,
3639
Opaque: wa.Opaque,
3740
Qop: "",
3841
Realm: wa.Realm,
3942
Response: "",
40-
Uri: dr.Uri,
43+
Uri: "",
4144
Userhash: wa.Userhash,
4245
Username: dr.Username,
4346
Username_: "", // TODO
4447
}
4548

46-
auth.Cnonce = auth.hash(fmt.Sprintf("%d:%s:dfjosbn3kjd01", time.Now().UnixNano(), dr.Username))
49+
if ah.Userhash {
50+
ah.Username = ah.hash(fmt.Sprintf("%s:%s", ah.Username, ah.Realm))
51+
}
52+
53+
ah.refreshAuthorization(dr)
54+
55+
return &ah
56+
}
57+
58+
func (ah *authorization) refreshAuthorization(dr *DigestRequest) (*authorization, error) {
59+
60+
ah.Nc++
61+
62+
ah.Cnonce = ah.hash(fmt.Sprintf("%d:%s:my_value", time.Now().UnixNano(), dr.Username))
4763

48-
if auth.Userhash {
49-
auth.Username = auth.hash(fmt.Sprintf("%s:%s", auth.Username, auth.Realm))
64+
url, err := url.Parse(dr.Uri)
65+
if err != nil {
66+
return nil, err
5067
}
68+
ah.Uri = url.RequestURI()
5169

52-
auth.Response = auth.computeResponse(wa, dr)
70+
ah.Response = ah.computeResponse(dr)
5371

54-
return &auth, nil
72+
return ah, nil
5573
}
5674

57-
func (ah *authorization) computeResponse(wa *wwwAuthenticate, dr *DigestRequest) (s string) {
75+
func (ah *authorization) computeResponse(dr *DigestRequest) (s string) {
5876

59-
kdSecret := ah.hash(ah.computeA1(wa, dr))
60-
kdData := fmt.Sprintf("%s:%s:%s:%s:%s", ah.Nonce, ah.Nc, ah.Cnonce, ah.Qop, ah.hash(ah.computeA2(wa, dr)))
77+
kdSecret := ah.hash(ah.computeA1(dr))
78+
kdData := fmt.Sprintf("%s:%08x:%s:%s:%s", ah.Nonce, ah.Nc, ah.Cnonce, ah.Qop, ah.hash(ah.computeA2(dr)))
6179

6280
return ah.hash(fmt.Sprintf("%s:%s", kdSecret, kdData))
6381
}
6482

65-
func (ah *authorization) computeA1(wa *wwwAuthenticate, dr *DigestRequest) string {
83+
func (ah *authorization) computeA1(dr *DigestRequest) string {
6684

6785
if ah.Algorithm == "" || ah.Algorithm == "MD5" || ah.Algorithm == "SHA-256" {
6886
return fmt.Sprintf("%s:%s:%s", ah.Username, ah.Realm, dr.Password)
6987
}
7088

7189
if ah.Algorithm == "MD5-sess" || ah.Algorithm == "SHA-256-sess" {
7290
upHash := ah.hash(fmt.Sprintf("%s:%s:%s", ah.Username, ah.Realm, dr.Password))
73-
return fmt.Sprintf("%s:%s:%s", upHash, ah.Nc)
91+
return fmt.Sprintf("%s:%s:%s", upHash, ah.Nonce, ah.Cnonce)
7492
}
7593

7694
return ""
7795
}
7896

79-
func (ah *authorization) computeA2(wa *wwwAuthenticate, dr *DigestRequest) string {
97+
func (ah *authorization) computeA2(dr *DigestRequest) string {
8098

8199
if matched, _ := regexp.MatchString("auth-int", wa.Qop); matched {
82100
ah.Qop = "auth-int"
83101
return fmt.Sprintf("%s:%s:%s", dr.Method, ah.Uri, ah.hash(dr.Body))
84102
}
85103

86-
if ah.Qop == "auth" || ah.Qop == "" {
104+
if wa.Qop == "auth" || wa.Qop == "" {
87105
ah.Qop = "auth"
88106
return fmt.Sprintf("%s:%s", dr.Method, ah.Uri)
89107
}
@@ -95,14 +113,14 @@ func (ah *authorization) hash(a string) (s string) {
95113

96114
var h hash.Hash
97115

98-
if ah.Algorithm == "MD5" || ah.Algorithm == "MD5-sess" {
116+
if ah.Algorithm == "" || ah.Algorithm == "MD5" || ah.Algorithm == "MD5-sess" {
99117
h = md5.New()
100118
} else if ah.Algorithm == "SHA-256" || ah.Algorithm == "SHA-256-sess" {
101119
h = sha256.New()
102120
}
103121

104122
io.WriteString(h, a)
105-
s = string(h.Sum(nil))
123+
s = hex.EncodeToString(h.Sum(nil))
106124

107125
return
108126
}
@@ -121,13 +139,17 @@ func (ah *authorization) toString() string {
121139
}
122140

123141
if ah.Nc != 0 {
124-
buffer.WriteString(fmt.Sprintf("nc=%08d, ", ah.Nc))
142+
buffer.WriteString(fmt.Sprintf("nc=%08x, ", ah.Nc))
125143
}
126144

127145
if ah.Opaque != "" {
128146
buffer.WriteString(fmt.Sprintf("opaque=\"%s\", ", ah.Opaque))
129147
}
130148

149+
if ah.Nonce != "" {
150+
buffer.WriteString(fmt.Sprintf("nonce=\"%s\", ", ah.Nonce))
151+
}
152+
131153
if ah.Qop != "" {
132154
buffer.WriteString(fmt.Sprintf("qop=%s, ", ah.Qop))
133155
}
@@ -140,10 +162,6 @@ func (ah *authorization) toString() string {
140162
buffer.WriteString(fmt.Sprintf("response=\"%s\", ", ah.Response))
141163
}
142164

143-
if ah.Response != "" {
144-
buffer.WriteString(fmt.Sprintf("response=\"%s\", ", ah.Response))
145-
}
146-
147165
if ah.Uri != "" {
148166
buffer.WriteString(fmt.Sprintf("uri=\"%s\", ", ah.Uri))
149167
}
@@ -156,5 +174,7 @@ func (ah *authorization) toString() string {
156174
buffer.WriteString(fmt.Sprintf("username=\"%s\", ", ah.Username))
157175
}
158176

159-
return buffer.String()
177+
s := buffer.String()
178+
179+
return strings.TrimSuffix(s, ", ")
160180
}

digest_auth_client.go

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ import (
77
"time"
88
)
99

10+
var (
11+
auth *authorization
12+
wa *wwwAuthenticate
13+
)
14+
1015
type DigestRequest struct {
1116
Body string
1217
Method string
@@ -15,62 +20,76 @@ type DigestRequest struct {
1520
Username string
1621
}
1722

18-
func (dr *DigestRequest) NewRequest(
19-
username string, password string, method string, uri string, body string) DigestRequest {
23+
func NewRequest(username string, password string, method string, uri string, body string) DigestRequest {
24+
25+
dr := DigestRequest{}
2026

2127
dr.Body = body
2228
dr.Method = method
2329
dr.Password = password
2430
dr.Uri = uri
25-
dr.Body = body
31+
dr.Username = username
2632

27-
return *dr
33+
return dr
2834
}
2935

3036
func (dr *DigestRequest) Execute() (resp *http.Response, err error) {
31-
var req *http.Request
32-
if req, err = http.NewRequest(dr.Method, dr.Uri, bytes.NewReader([]byte(dr.Body))); err != nil {
33-
return nil, err
34-
}
35-
36-
client := &http.Client{
37-
Timeout: 30 * time.Second,
38-
}
39-
resp, err = client.Do(req)
4037

41-
if resp.StatusCode == 401 {
42-
return dr.executeDigest(resp)
38+
if auth == nil {
39+
var req *http.Request
40+
if req, err = http.NewRequest(dr.Method, dr.Uri, bytes.NewReader([]byte(dr.Body))); err != nil {
41+
return nil, err
42+
}
43+
44+
client := &http.Client{
45+
Timeout: 30 * time.Second,
46+
}
47+
resp, err = client.Do(req)
48+
49+
if resp.StatusCode == 401 {
50+
return dr.executeNewDigest(resp)
51+
}
52+
return
4353
}
4454

45-
return
55+
return dr.executeExistingDigest()
4656
}
4757

48-
func (dr *DigestRequest) executeDigest(resp *http.Response) (*http.Response, error) {
49-
var (
50-
err error
51-
wa *wwwAuthenticate
52-
auth *authorization
53-
req *http.Request
54-
)
58+
func (dr *DigestRequest) executeNewDigest(resp *http.Response) (*http.Response, error) {
5559

5660
waString := resp.Header.Get("WWW-Authenticate")
5761
if waString == "" {
5862
return nil, fmt.Errorf("Failed to get WWW-Authenticate header, please check your server configuration.")
5963
}
64+
wa = newWwwAuthenticate(waString)
6065

61-
if wa, err = newWwwAuthenticate(waString); err != nil {
62-
return nil, err
63-
}
66+
authString := newAuthorization(dr).toString()
67+
68+
return dr.executeRequest(authString)
69+
}
70+
71+
func (dr *DigestRequest) executeExistingDigest() (*http.Response, error) {
72+
var err error
6473

65-
if auth, err = newAuthorization(wa, dr); err != nil {
74+
if auth, err = auth.refreshAuthorization(dr); err != nil {
6675
return nil, err
6776
}
6877

69-
authString := fmt.Sprintf("Digest %s", auth.toString())
78+
authString := auth.toString()
79+
return dr.executeRequest(authString)
80+
}
81+
82+
func (dr *DigestRequest) executeRequest(authString string) (*http.Response, error) {
83+
var (
84+
err error
85+
req *http.Request
86+
)
87+
7088
if req, err = http.NewRequest(dr.Method, dr.Uri, bytes.NewReader([]byte(dr.Body))); err != nil {
7189
return nil, err
7290
}
7391

92+
fmt.Printf("AUTHSTRING: %s\n\n", authString)
7493
req.Header.Add("Authorization", authString)
7594

7695
client := &http.Client{

www_authenticate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type wwwAuthenticate struct {
1717
Userhash bool // quoted
1818
}
1919

20-
func newWwwAuthenticate(s string) (*wwwAuthenticate, error) {
20+
func newWwwAuthenticate(s string) *wwwAuthenticate {
2121

2222
var wa = wwwAuthenticate{}
2323

@@ -75,5 +75,5 @@ func newWwwAuthenticate(s string) (*wwwAuthenticate, error) {
7575
wa.Userhash = (strings.ToLower(userhashMatch[1]) == "true")
7676
}
7777

78-
return &wa, nil
78+
return &wa
7979
}

0 commit comments

Comments
 (0)