digest.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package isapi
  2. import (
  3. "crypto/md5"
  4. "encoding/json"
  5. "fmt"
  6. "log"
  7. "strings"
  8. )
  9. // Challenge WWW-Authorization头部的值
  10. type Challenge struct {
  11. Realm string
  12. Domain string
  13. Nonce string
  14. Opaque string
  15. Stale string
  16. Algorithm string
  17. Qop string
  18. }
  19. // Response 作为Authorization头部的值
  20. type Response struct {
  21. Username string
  22. Realm string
  23. Nonce string
  24. URI string
  25. Qop string
  26. Cnonce string
  27. Nc string
  28. Response string
  29. }
  30. func MD5(s string) string {
  31. return fmt.Sprintf("%x", md5.Sum([]byte(s)))
  32. }
  33. // NewChallenge 根据WWW-Authorization的值生成Challenge
  34. func NewChallenge(header string) *Challenge {
  35. var m = make(map[string]string, 5)
  36. str := header[7:]
  37. split := strings.Split(str, ",")
  38. for _, v := range split {
  39. s := strings.Split(v, "=")
  40. k := strings.Trim(s[0], " ")
  41. m[k] = strings.Trim(s[1], "\"")
  42. }
  43. // Marshall digest
  44. b, err := json.Marshal(m)
  45. if err != nil {
  46. log.Fatalln("Error:", err)
  47. }
  48. // Unmarshall into struct
  49. challenge := Challenge{}
  50. if err := json.Unmarshal(b, &challenge); err != nil {
  51. log.Fatalln("Error:", err)
  52. }
  53. return &challenge
  54. }
  55. // Authorize 生成 Response #客户端需要对服务端认证时cnonce应是变化的#
  56. func (c *Challenge) Authorize(username, password, method, uri string) *Response {
  57. // MD5(<username>:<realm>:<password>)
  58. a1 := MD5(fmt.Sprintf("%s:%s:%s", username, c.Realm, password))
  59. // MD5(<request-method>:<uri>)
  60. a2 := MD5(fmt.Sprintf("%s:%s", method, uri))
  61. // MD5(MD5(A1):<auth>:<nc>:<cnonce>:<qop>:MD5(A2))
  62. response := MD5(fmt.Sprintf("%s:%s:%s:%s:%s:%s", a1, c.Nonce, "00000001", "0a4f113b", c.Qop, a2))
  63. return &Response{
  64. Username: username,
  65. Realm: c.Realm,
  66. Nonce: c.Nonce,
  67. URI: uri,
  68. Qop: c.Qop,
  69. Cnonce: "0a4f113b",
  70. Nc: "00000001",
  71. Response: response,
  72. }
  73. }
  74. // 生成字符串作为Authorization的值
  75. func (r *Response) String() string {
  76. return fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", qop=%s, nc=%s, cnonce="%s", response="%s"`, r.Username, r.Realm, r.Nonce, r.URI, r.Qop, r.Nc, r.Cnonce, r.Response)
  77. }