-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
challenge.go
96 lines (86 loc) · 2.86 KB
/
challenge.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
package goHttpDigestClient
import (
"fmt"
"strings"
)
const (
KEY_DIGEST = "Digest"
KEY_AUTH_SCHEMA = "auth_schema"
KEY_QOP = "qop"
KEY_NONCE = "nonce"
KEY_CNONCE = "cnonce"
KEY_USERNAME = "username"
KEY_NONCE_COUNT = "nc"
KEY_OPAQUE = "opaque"
KEY_RESPONSE = "response"
KEY_REALM = "realm"
KEY_AUTHORIZATION = "Authorization"
KEY_URI = "uri"
KEY_WWW_Authenticate = "WWW-Authenticate"
)
//The 401 (Unauthorized) response message is used by an origin server
//to challenge the authorization of a user agent.
//
// And the CHALLENGE will include informations about auth
type Challenge map[string]string
func NewChallenge(wwwAuthHeader string) Challenge {
r := Challenge{}
wwwAuthArr := strings.Split(strings.Replace(wwwAuthHeader, ",", "", -1), " ")
wwwAuthArrLen := len(wwwAuthArr)
if wwwAuthArrLen > 1 {
r[KEY_AUTH_SCHEMA] = wwwAuthArr[0]
for i := 1; i < wwwAuthArrLen; i++ {
itemArr := strings.Split(wwwAuthArr[i], "=")
r.SetChallengeItem(itemArr[0], itemArr[1])
}
}
return r
}
func (info Challenge) IsDigestAuth() bool {
return info[KEY_AUTH_SCHEMA] == KEY_DIGEST
}
func (info Challenge) SetChallengeItem(itemKey string, itemValue string) {
info[itemKey] = itemValue
}
func (info Challenge) GetChallengeItemPure(itemKey string) string {
return strings.Replace(info[itemKey], `"`, "", -1)
}
// some specific key, will add qutation mark
func (info Challenge) GetChallengeItemFormat(itemKey string) string {
r := info.GetChallengeItemPure(itemKey)
switch itemKey {
case KEY_QOP, KEY_NONCE_COUNT:
return r
default:
return fmt.Sprintf(`"%s"`, r)
}
}
// format challenge header to authorization header
//
// MAYBE you should computeResponseFirst()
func (info Challenge) ToAuthorizationStr() string {
auth_schema := KEY_DIGEST
authorization_content := ""
// how to specify the sequence
for k, _ := range info {
if k != KEY_AUTH_SCHEMA {
authorization_content += fmt.Sprintf(", %s=%s", k, info.GetChallengeItemFormat(k))
}
}
return auth_schema + strings.Replace(authorization_content, ",", "", 1)
}
// base challenge to compute the response, and the response will be checking by server
func (h Challenge) ComputeResponse(method, uri, entity, username, password string) Challenge {
qop := h.GetChallengeItemPure(KEY_QOP)
realm := h.GetChallengeItemPure(KEY_REALM)
nonce := h.GetChallengeItemPure(KEY_NONCE)
nonceCount := h.GetChallengeItemPure(KEY_NONCE_COUNT)
cNonce := h.GetChallengeItemPure(KEY_CNONCE)
response, cNonce, nonceCount := computeResponse(qop, realm, nonce, nonceCount, cNonce, method, uri, entity, username, password)
h.SetChallengeItem(KEY_USERNAME, username)
h.SetChallengeItem(KEY_URI, uri)
h.SetChallengeItem(KEY_CNONCE, cNonce)
h.SetChallengeItem(KEY_NONCE_COUNT, nonceCount)
h.SetChallengeItem(KEY_RESPONSE, response)
return h
}