forked from xinsnake/go-http-digest-auth-client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
digest_auth_client.go
174 lines (144 loc) · 3.93 KB
/
digest_auth_client.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
172
173
174
package digest_auth_client
import (
"bytes"
"crypto/tls"
"fmt"
"net/http"
"time"
)
type DigestRequest struct {
Body string
Method string
Password string
URI string
Username string
Header http.Header
Auth *authorization
Wa *wwwAuthenticate
CertVal bool
HTTPClient *http.Client
}
type DigestTransport struct {
Password string
Username string
HTTPClient *http.Client
}
// NewRequest creates a new DigestRequest object
func NewRequest(username, password, method, uri, body string) DigestRequest {
dr := DigestRequest{}
dr.UpdateRequest(username, password, method, uri, body)
dr.CertVal = true
return dr
}
// NewTransport creates a new DigestTransport object
func NewTransport(username, password string) DigestTransport {
dt := DigestTransport{}
dt.Password = password
dt.Username = username
return dt
}
func (dr *DigestRequest) getHTTPClient() *http.Client {
if dr.HTTPClient != nil {
return dr.HTTPClient
}
tlsConfig := tls.Config{}
if !dr.CertVal {
tlsConfig.InsecureSkipVerify = true
}
return &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tlsConfig,
},
}
}
// UpdateRequest is called when you want to reuse an existing
// DigestRequest connection with new request information
func (dr *DigestRequest) UpdateRequest(username, password, method, uri, body string) *DigestRequest {
dr.Body = body
dr.Method = method
dr.Password = password
dr.URI = uri
dr.Username = username
dr.Header = make(map[string][]string)
return dr
}
// RoundTrip implements the http.RoundTripper interface
func (dt *DigestTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
username := dt.Username
password := dt.Password
method := req.Method
uri := req.URL.String()
var body string
if req.Body != nil {
buf := new(bytes.Buffer)
buf.ReadFrom(req.Body)
body = buf.String()
}
dr := NewRequest(username, password, method, uri, body)
if dt.HTTPClient != nil {
dr.HTTPClient = dt.HTTPClient
}
dr.Header.Set("User-Agent", req.Header.Get("User-Agent"))
return dr.Execute()
}
// Execute initialise the request and get a response
func (dr *DigestRequest) Execute() (resp *http.Response, err error) {
if dr.Auth != nil {
return dr.executeExistingDigest()
}
var req *http.Request
if req, err = http.NewRequest(dr.Method, dr.URI, bytes.NewReader([]byte(dr.Body))); err != nil {
return nil, err
}
req.Header = dr.Header
client := dr.getHTTPClient()
if resp, err = client.Do(req); err != nil {
return nil, err
}
if resp.StatusCode == 401 {
return dr.executeNewDigest(resp)
}
// return the resp to user to handle resp.body.Close()
return resp, nil
}
func (dr *DigestRequest) executeNewDigest(resp *http.Response) (resp2 *http.Response, err error) {
var (
auth *authorization
wa *wwwAuthenticate
waString string
)
// body not required for authentication, closing
resp.Body.Close()
if waString = resp.Header.Get("WWW-Authenticate"); waString == "" {
return nil, fmt.Errorf("failed to get WWW-Authenticate header, please check your server configuration")
}
wa = newWwwAuthenticate(waString)
dr.Wa = wa
if auth, err = newAuthorization(dr); err != nil {
return nil, err
}
if resp2, err = dr.executeRequest(auth.toString()); err != nil {
return nil, err
}
dr.Auth = auth
return resp2, nil
}
func (dr *DigestRequest) executeExistingDigest() (resp *http.Response, err error) {
var auth *authorization
if auth, err = dr.Auth.refreshAuthorization(dr); err != nil {
return nil, err
}
dr.Auth = auth
return dr.executeRequest(dr.Auth.toString())
}
func (dr *DigestRequest) executeRequest(authString string) (resp *http.Response, err error) {
var req *http.Request
if req, err = http.NewRequest(dr.Method, dr.URI, bytes.NewReader([]byte(dr.Body))); err != nil {
return nil, err
}
req.Header = dr.Header
req.Header.Add("Authorization", authString)
client := dr.getHTTPClient()
return client.Do(req)
}