signer.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // HWS API Gateway Signature
  2. // based on https://github.com/datastream/aws/blob/master/signv4.go
  3. // Copyright (c) 2014, Xianjie
  4. package core
  5. import (
  6. "bytes"
  7. "crypto/hmac"
  8. "crypto/sha256"
  9. "fmt"
  10. "io/ioutil"
  11. "net/http"
  12. "sort"
  13. "strings"
  14. "time"
  15. )
  16. const (
  17. BasicDateFormat = "20060102T150405Z"
  18. Algorithm = "SDK-HMAC-SHA256"
  19. HeaderXDate = "X-Sdk-Date"
  20. HeaderHost = "host"
  21. HeaderAuthorization = "Authorization"
  22. HeaderContentSha256 = "X-Sdk-Content-Sha256"
  23. )
  24. func hmacsha256(key []byte, data string) ([]byte, error) {
  25. h := hmac.New(sha256.New, []byte(key))
  26. if _, err := h.Write([]byte(data)); err != nil {
  27. return nil, err
  28. }
  29. return h.Sum(nil), nil
  30. }
  31. // Build a CanonicalRequest from a regular request string
  32. //
  33. // CanonicalRequest =
  34. // HTTPRequestMethod + '\n' +
  35. // CanonicalURI + '\n' +
  36. // CanonicalQueryString + '\n' +
  37. // CanonicalHeaders + '\n' +
  38. // SignedHeaders + '\n' +
  39. // HexEncode(Hash(RequestPayload))
  40. func CanonicalRequest(r *http.Request, signedHeaders []string) (string, error) {
  41. var hexencode string
  42. var err error
  43. if hex := r.Header.Get(HeaderContentSha256); hex != "" {
  44. hexencode = hex
  45. } else {
  46. data, err := RequestPayload(r)
  47. if err != nil {
  48. return "", err
  49. }
  50. hexencode, err = HexEncodeSHA256Hash(data)
  51. if err != nil {
  52. return "", err
  53. }
  54. }
  55. return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", r.Method, CanonicalURI(r), CanonicalQueryString(r), CanonicalHeaders(r, signedHeaders), strings.Join(signedHeaders, ";"), hexencode), err
  56. }
  57. // CanonicalURI returns request uri
  58. func CanonicalURI(r *http.Request) string {
  59. pattens := strings.Split(r.URL.Path, "/")
  60. var uri []string
  61. for _, v := range pattens {
  62. uri = append(uri, escape(v))
  63. }
  64. urlpath := strings.Join(uri, "/")
  65. if len(urlpath) == 0 || urlpath[len(urlpath)-1] != '/' {
  66. urlpath = urlpath + "/"
  67. }
  68. return urlpath
  69. }
  70. // CanonicalQueryString
  71. func CanonicalQueryString(r *http.Request) string {
  72. var keys []string
  73. query := r.URL.Query()
  74. for key := range query {
  75. keys = append(keys, key)
  76. }
  77. sort.Strings(keys)
  78. var a []string
  79. for _, key := range keys {
  80. k := escape(key)
  81. sort.Strings(query[key])
  82. for _, v := range query[key] {
  83. kv := fmt.Sprintf("%s=%s", k, escape(v))
  84. a = append(a, kv)
  85. }
  86. }
  87. queryStr := strings.Join(a, "&")
  88. r.URL.RawQuery = queryStr
  89. return queryStr
  90. }
  91. // CanonicalHeaders
  92. func CanonicalHeaders(r *http.Request, signerHeaders []string) string {
  93. var a []string
  94. header := make(map[string][]string)
  95. for k, v := range r.Header {
  96. header[strings.ToLower(k)] = v
  97. }
  98. for _, key := range signerHeaders {
  99. value := header[key]
  100. if strings.EqualFold(key, HeaderHost) {
  101. value = []string{r.Host}
  102. }
  103. sort.Strings(value)
  104. for _, v := range value {
  105. a = append(a, key+":"+strings.TrimSpace(v))
  106. }
  107. }
  108. return fmt.Sprintf("%s\n", strings.Join(a, "\n"))
  109. }
  110. // SignedHeaders
  111. func SignedHeaders(r *http.Request) []string {
  112. var a []string
  113. for key := range r.Header {
  114. a = append(a, strings.ToLower(key))
  115. }
  116. sort.Strings(a)
  117. return a
  118. }
  119. // RequestPayload
  120. func RequestPayload(r *http.Request) ([]byte, error) {
  121. if r.Body == nil {
  122. return []byte(""), nil
  123. }
  124. b, err := ioutil.ReadAll(r.Body)
  125. if err != nil {
  126. return []byte(""), err
  127. }
  128. r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
  129. return b, err
  130. }
  131. // Create a "String to Sign".
  132. func StringToSign(canonicalRequest string, t time.Time) (string, error) {
  133. hash := sha256.New()
  134. _, err := hash.Write([]byte(canonicalRequest))
  135. if err != nil {
  136. return "", err
  137. }
  138. return fmt.Sprintf("%s\n%s\n%x",
  139. Algorithm, t.UTC().Format(BasicDateFormat), hash.Sum(nil)), nil
  140. }
  141. // Create the HWS Signature.
  142. func SignStringToSign(stringToSign string, signingKey []byte) (string, error) {
  143. hm, err := hmacsha256(signingKey, stringToSign)
  144. return fmt.Sprintf("%x", hm), err
  145. }
  146. // HexEncodeSHA256Hash returns hexcode of sha256
  147. func HexEncodeSHA256Hash(body []byte) (string, error) {
  148. hash := sha256.New()
  149. if body == nil {
  150. body = []byte("")
  151. }
  152. _, err := hash.Write(body)
  153. return fmt.Sprintf("%x", hash.Sum(nil)), err
  154. }
  155. // Get the finalized value for the "Authorization" header. The signature parameter is the output from SignStringToSign
  156. func AuthHeaderValue(signature, accessKey string, signedHeaders []string) string {
  157. return fmt.Sprintf("%s Access=%s, SignedHeaders=%s, Signature=%s", Algorithm, accessKey, strings.Join(signedHeaders, ";"), signature)
  158. }
  159. // Signature HWS meta
  160. type Signer struct {
  161. Key string
  162. Secret string
  163. }
  164. // SignRequest set Authorization header
  165. func (s *Signer) Sign(r *http.Request) error {
  166. var t time.Time
  167. var err error
  168. var dt string
  169. if dt = r.Header.Get(HeaderXDate); dt != "" {
  170. t, err = time.Parse(BasicDateFormat, dt)
  171. }
  172. if err != nil || dt == "" {
  173. t = time.Now()
  174. r.Header.Set(HeaderXDate, t.UTC().Format(BasicDateFormat))
  175. }
  176. signedHeaders := SignedHeaders(r)
  177. canonicalRequest, err := CanonicalRequest(r, signedHeaders)
  178. if err != nil {
  179. return err
  180. }
  181. stringToSign, err := StringToSign(canonicalRequest, t)
  182. if err != nil {
  183. return err
  184. }
  185. signature, err := SignStringToSign(stringToSign, []byte(s.Secret))
  186. if err != nil {
  187. return err
  188. }
  189. authValue := AuthHeaderValue(signature, s.Key, signedHeaders)
  190. r.Header.Set(HeaderAuthorization, authValue)
  191. return nil
  192. }