Skip to content

Commit 8b24a96

Browse files
authored
feat!: enhance and add feature into digest auth flow #914 (#921)
- redesign the digest auth internals, cleanup, and improvements - add 'auth-int' QOP support - add and update digest hash functions - remove the 'Request.SetDigestAuth' method, keep the option only at the client level
1 parent c2d0b84 commit 8b24a96

File tree

7 files changed

+608
-402
lines changed

7 files changed

+608
-402
lines changed

client.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -575,33 +575,29 @@ func (c *Client) SetAuthScheme(scheme string) *Client {
575575
return c
576576
}
577577

578-
// SetDigestAuth method sets the Digest Access auth scheme for the client. If a server responds with 401 and sends
579-
// a Digest challenge in the WWW-Authenticate header, requests will be resent with the appropriate Authorization header.
578+
// SetDigestAuth method sets the Digest Auth transport with provided credentials in the client.
579+
// If a server responds with 401 and sends a Digest challenge in the header `WWW-Authenticate`,
580+
// the request will be resent with the appropriate digest `Authorization` header.
580581
//
581582
// For Example: To set the Digest scheme with user "Mufasa" and password "Circle Of Life"
582583
//
583584
// client.SetDigestAuth("Mufasa", "Circle Of Life")
584585
//
585586
// Information about Digest Access Authentication can be found in [RFC 7616].
586587
//
587-
// See [Request.SetDigestAuth].
588+
// NOTE:
589+
// - On the QOP `auth-int` scenario, the request body is read into memory to
590+
// compute the body hash that consumes additional memory usage.
591+
// - It is recommended to create a dedicated client instance for digest auth,
592+
// as it does digest auth for all the requests raised by the client.
588593
//
589594
// [RFC 7616]: https://datatracker.ietf.org/doc/html/rfc7616
590595
func (c *Client) SetDigestAuth(username, password string) *Client {
591-
c.lock.Lock()
592-
oldTransport := c.httpClient.Transport
593-
c.lock.Unlock()
594-
c.AddRequestMiddleware(func(c *Client, _ *Request) error {
595-
c.httpClient.Transport = &digestTransport{
596-
credentials: credentials{username, password},
597-
transport: oldTransport,
598-
}
599-
return nil
600-
})
601-
c.AddResponseMiddleware(func(c *Client, _ *Response) error {
602-
c.httpClient.Transport = oldTransport
603-
return nil
604-
})
596+
dt := &digestTransport{
597+
credentials: &credentials{username, password},
598+
transport: c.Transport(),
599+
}
600+
c.SetTransport(dt)
605601
return c
606602
}
607603

client_test.go

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -90,79 +90,6 @@ func TestClientAuthScheme(t *testing.T) {
9090

9191
}
9292

93-
func TestClientDigestAuth(t *testing.T) {
94-
conf := defaultDigestServerConf()
95-
ts := createDigestServer(t, conf)
96-
defer ts.Close()
97-
98-
c := dcnl().
99-
SetBaseURL(ts.URL+"/").
100-
SetDigestAuth(conf.username, conf.password)
101-
102-
resp, err := c.R().
103-
SetResult(&AuthSuccess{}).
104-
Get(conf.uri)
105-
assertError(t, err)
106-
assertEqual(t, http.StatusOK, resp.StatusCode())
107-
108-
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
109-
logResponse(t, resp)
110-
}
111-
112-
func TestClientDigestSession(t *testing.T) {
113-
conf := defaultDigestServerConf()
114-
conf.algo = "MD5-sess"
115-
conf.qop = "auth, auth-int"
116-
ts := createDigestServer(t, conf)
117-
defer ts.Close()
118-
119-
c := dcnl().
120-
SetBaseURL(ts.URL+"/").
121-
SetDigestAuth(conf.username, conf.password)
122-
123-
resp, err := c.R().
124-
SetResult(&AuthSuccess{}).
125-
Get(conf.uri)
126-
assertError(t, err)
127-
assertEqual(t, http.StatusOK, resp.StatusCode())
128-
129-
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
130-
logResponse(t, resp)
131-
}
132-
133-
func TestClientDigestErrors(t *testing.T) {
134-
type test struct {
135-
mutateConf func(*digestServerConfig)
136-
expect error
137-
}
138-
tests := []test{
139-
{mutateConf: func(c *digestServerConfig) { c.algo = "BAD_ALGO" }, expect: ErrDigestAlgNotSupported},
140-
{mutateConf: func(c *digestServerConfig) { c.qop = "bad-qop" }, expect: ErrDigestQopNotSupported},
141-
{mutateConf: func(c *digestServerConfig) { c.qop = "" }, expect: ErrDigestNoQop},
142-
{mutateConf: func(c *digestServerConfig) { c.charset = "utf-16" }, expect: ErrDigestCharset},
143-
{mutateConf: func(c *digestServerConfig) { c.uri = "/bad" }, expect: ErrDigestBadChallenge},
144-
{mutateConf: func(c *digestServerConfig) { c.uri = "/unknown_param" }, expect: ErrDigestBadChallenge},
145-
{mutateConf: func(c *digestServerConfig) { c.uri = "/missing_value" }, expect: ErrDigestBadChallenge},
146-
{mutateConf: func(c *digestServerConfig) { c.uri = "/unclosed_quote" }, expect: ErrDigestBadChallenge},
147-
{mutateConf: func(c *digestServerConfig) { c.uri = "/no_challenge" }, expect: ErrDigestBadChallenge},
148-
{mutateConf: func(c *digestServerConfig) { c.uri = "/status_500" }, expect: nil},
149-
}
150-
151-
for _, tc := range tests {
152-
conf := defaultDigestServerConf()
153-
tc.mutateConf(conf)
154-
ts := createDigestServer(t, conf)
155-
156-
c := dcnl().
157-
SetBaseURL(ts.URL+"/").
158-
SetDigestAuth(conf.username, conf.password)
159-
160-
_, err := c.R().Get(conf.uri)
161-
assertErrorIs(t, tc.expect, err)
162-
ts.Close()
163-
}
164-
}
165-
16693
func TestClientResponseMiddleware(t *testing.T) {
16794
ts := createGenericServer(t)
16895
defer ts.Close()

0 commit comments

Comments
 (0)