From ec1263db2f56e2c3155e5540a8a641d406f01a45 Mon Sep 17 00:00:00 2001 From: Vitalii Date: Tue, 10 Jul 2018 19:51:11 +0300 Subject: [PATCH] all cases of Digest authorization was implemented (#19) Digest authentication was improved --- digestAuth.go | 76 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/digestAuth.go b/digestAuth.go index dbf8660..a75fdf2 100644 --- a/digestAuth.go +++ b/digestAuth.go @@ -44,12 +44,15 @@ func (d *DigestAuth) Authorize(c *Client, method string, path string) { func digestParts(resp *http.Response) map[string]string { result := map[string]string{} if len(resp.Header["Www-Authenticate"]) > 0 { - wantedHeaders := []string{"nonce", "realm", "qop", "opaque"} + wantedHeaders := []string{"nonce", "realm", "qop", "opaque", "algorithm", "entityBody"} responseHeaders := strings.Split(resp.Header["Www-Authenticate"][0], ",") for _, r := range responseHeaders { for _, w := range wantedHeaders { if strings.Contains(r, w) { - result[w] = strings.Split(r, `"`)[1] + result[w] = strings.Trim( + strings.SplitN(r, `=`, 2)[1], + `"`, + ) } } } @@ -72,13 +75,68 @@ func getCnonce() string { func getDigestAuthorization(digestParts map[string]string) string { d := digestParts // These are the correct ha1 and ha2 for qop=auth. We should probably check for other types of qop. - ha1 := getMD5(d["username"] + ":" + d["realm"] + ":" + d["password"]) - ha2 := getMD5(d["method"] + ":" + d["uri"]) - nonceCount := 00000001 - cnonce := getCnonce() - response := getMD5(fmt.Sprintf("%s:%s:%v:%s:%s:%s", ha1, d["nonce"], nonceCount, cnonce, d["qop"], ha2)) - authorization := fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", qop=%s, nc=%v, cnonce="%s", response="%s"`, - d["username"], d["realm"], d["nonce"], d["uri"], d["qop"], nonceCount, cnonce, response) + + var ( + ha1 string + ha2 string + nonceCount = 00000001 + cnonce = getCnonce() + response string + ) + + // 'ha1' value depends on value of "algorithm" field + switch d["algorithm"] { + case "MD5", "": + ha1 = getMD5(d["username"] + ":" + d["realm"] + ":" + d["password"]) + case "MD5-sess": + ha1 = getMD5( + fmt.Sprintf("%s:%v:%s", + getMD5(d["username"] + ":" + d["realm"] + ":" + d["password"]), + nonceCount, + cnonce, + ), + ) + } + + // 'ha2' value depends on value of "qop" field + switch d["qop"] { + case "auth", "": + ha2 = getMD5(d["method"] + ":" + d["uri"]) + case "auth-int": + if d["entityBody"] != "" { + ha2 = getMD5(d["method"] + ":" + d["uri"] + ":" + getMD5(d["entityBody"])) + } + } + + // 'response' value depends on value of "qop" field + switch d["qop"] { + case "": + response = getMD5( + fmt.Sprintf("%s:%s:%s", + ha1, + d["nonce"], + ha2, + ), + ) + case "auth", "auth-int": + response = getMD5( + fmt.Sprintf("%s:%s:%v:%s:%s:%s", + ha1, + d["nonce"], + nonceCount, + cnonce, + d["qop"], + ha2, + ), + ) + } + + authorization := fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", nc=%v, cnonce="%s", response="%s"`, + d["username"], d["realm"], d["nonce"], d["uri"], nonceCount, cnonce, response) + + if d["qop"] != "" { + authorization += fmt.Sprintf(`, qop=%s`, d["qop"]) + } if d["opaque"] != "" { authorization += fmt.Sprintf(`, opaque="%s"`, d["opaque"])