Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: enhance and add feature into digest auth flow #914 #921

Merged
merged 1 commit into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,33 +575,29 @@ func (c *Client) SetAuthScheme(scheme string) *Client {
return c
}

// SetDigestAuth method sets the Digest Access auth scheme for the client. If a server responds with 401 and sends
// a Digest challenge in the WWW-Authenticate header, requests will be resent with the appropriate Authorization header.
// SetDigestAuth method sets the Digest Auth transport with provided credentials in the client.
// If a server responds with 401 and sends a Digest challenge in the header `WWW-Authenticate`,
// the request will be resent with the appropriate digest `Authorization` header.
//
// For Example: To set the Digest scheme with user "Mufasa" and password "Circle Of Life"
//
// client.SetDigestAuth("Mufasa", "Circle Of Life")
//
// Information about Digest Access Authentication can be found in [RFC 7616].
//
// See [Request.SetDigestAuth].
// NOTE:
// - On the QOP `auth-int` scenario, the request body is read into memory to
// compute the body hash that consumes additional memory usage.
// - It is recommended to create a dedicated client instance for digest auth,
// as it does digest auth for all the requests raised by the client.
//
// [RFC 7616]: https://datatracker.ietf.org/doc/html/rfc7616
func (c *Client) SetDigestAuth(username, password string) *Client {
c.lock.Lock()
oldTransport := c.httpClient.Transport
c.lock.Unlock()
c.AddRequestMiddleware(func(c *Client, _ *Request) error {
c.httpClient.Transport = &digestTransport{
credentials: credentials{username, password},
transport: oldTransport,
}
return nil
})
c.AddResponseMiddleware(func(c *Client, _ *Response) error {
c.httpClient.Transport = oldTransport
return nil
})
dt := &digestTransport{
credentials: &credentials{username, password},
transport: c.Transport(),
}
c.SetTransport(dt)
return c
}

Expand Down
73 changes: 0 additions & 73 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,79 +90,6 @@ func TestClientAuthScheme(t *testing.T) {

}

func TestClientDigestAuth(t *testing.T) {
conf := defaultDigestServerConf()
ts := createDigestServer(t, conf)
defer ts.Close()

c := dcnl().
SetBaseURL(ts.URL+"/").
SetDigestAuth(conf.username, conf.password)

resp, err := c.R().
SetResult(&AuthSuccess{}).
Get(conf.uri)
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())

t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}

func TestClientDigestSession(t *testing.T) {
conf := defaultDigestServerConf()
conf.algo = "MD5-sess"
conf.qop = "auth, auth-int"
ts := createDigestServer(t, conf)
defer ts.Close()

c := dcnl().
SetBaseURL(ts.URL+"/").
SetDigestAuth(conf.username, conf.password)

resp, err := c.R().
SetResult(&AuthSuccess{}).
Get(conf.uri)
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())

t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}

func TestClientDigestErrors(t *testing.T) {
type test struct {
mutateConf func(*digestServerConfig)
expect error
}
tests := []test{
{mutateConf: func(c *digestServerConfig) { c.algo = "BAD_ALGO" }, expect: ErrDigestAlgNotSupported},
{mutateConf: func(c *digestServerConfig) { c.qop = "bad-qop" }, expect: ErrDigestQopNotSupported},
{mutateConf: func(c *digestServerConfig) { c.qop = "" }, expect: ErrDigestNoQop},
{mutateConf: func(c *digestServerConfig) { c.charset = "utf-16" }, expect: ErrDigestCharset},
{mutateConf: func(c *digestServerConfig) { c.uri = "/bad" }, expect: ErrDigestBadChallenge},
{mutateConf: func(c *digestServerConfig) { c.uri = "/unknown_param" }, expect: ErrDigestBadChallenge},
{mutateConf: func(c *digestServerConfig) { c.uri = "/missing_value" }, expect: ErrDigestBadChallenge},
{mutateConf: func(c *digestServerConfig) { c.uri = "/unclosed_quote" }, expect: ErrDigestBadChallenge},
{mutateConf: func(c *digestServerConfig) { c.uri = "/no_challenge" }, expect: ErrDigestBadChallenge},
{mutateConf: func(c *digestServerConfig) { c.uri = "/status_500" }, expect: nil},
}

for _, tc := range tests {
conf := defaultDigestServerConf()
tc.mutateConf(conf)
ts := createDigestServer(t, conf)

c := dcnl().
SetBaseURL(ts.URL+"/").
SetDigestAuth(conf.username, conf.password)

_, err := c.R().Get(conf.uri)
assertErrorIs(t, tc.expect, err)
ts.Close()
}
}

func TestClientResponseMiddleware(t *testing.T) {
ts := createGenericServer(t)
defer ts.Close()
Expand Down
Loading