sts.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package oss
  2. import (
  3. "context"
  4. "crypto/hmac"
  5. "crypto/sha1"
  6. "crypto/tls"
  7. "gd_admin/common.in/utils"
  8. "encoding/base64"
  9. "encoding/json"
  10. "fmt"
  11. "go.uber.org/zap"
  12. "io/ioutil"
  13. "net/http"
  14. "net/url"
  15. "strconv"
  16. "time"
  17. )
  18. // ServiceError sts service error
  19. type ServiceError struct {
  20. Code string
  21. Message string
  22. RequestId string
  23. HostId string
  24. RawMessage string
  25. StatusCode int
  26. }
  27. // Credentials the credentials obtained by AssumedRole,
  28. // used for the peration of Alibaba Cloud service.
  29. type Credentials struct {
  30. AccessKeyId string
  31. AccessKeySecret string
  32. Expiration time.Time
  33. SecurityToken string
  34. }
  35. // AssumedRoleUser the user to AssumedRole
  36. type AssumedRoleUser struct {
  37. Arn string
  38. AssumedRoleId string
  39. }
  40. // Response the response of AssumeRole
  41. type Response struct {
  42. Credentials Credentials
  43. AssumedRoleUser AssumedRoleUser
  44. RequestId string
  45. }
  46. // Error implement interface error
  47. func (e *ServiceError) Error() string {
  48. return fmt.Sprintf("oss: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=%s, RequestId=%s",
  49. e.StatusCode, e.Code, e.Message, e.RequestId)
  50. }
  51. const (
  52. // StsSignVersion sts sign version
  53. StsSignVersion = "1.0"
  54. // StsAPIVersion sts api version
  55. StsAPIVersion = "2015-04-01"
  56. // StsHost sts host
  57. StsHost = "https://sts.cn-shanghai.aliyuncs.com/"
  58. // TimeFormat time fomrat
  59. TimeFormat = "2006-01-02T15:04:05Z"
  60. // RespBodyFormat respone body format
  61. RespBodyFormat = "JSON"
  62. // PercentEncode '/'
  63. PercentEncode = "%2F"
  64. // HTTPGet http get method
  65. HTTPGet = "GET"
  66. accessKeyId = "LTAI4Fjs1bNMd8k8LT41Fxxn"
  67. accessKeySecret = "WlQJwVbxHIY4TIZwMIFA5QCye6n0Pl"
  68. //accessKeyId = "LTAI4FrygJpD6m4BW1hQ88iE"
  69. //accessKeySecret = "GN3kTVcTvoa4QhFTo7sSqTsxW4WUtR"
  70. roleArn = "acs:ram::1889646856784226:role/aliyunosstokengeneratorrole"
  71. sessionName = "gd-username"
  72. expiredTime = 900 // 15分钟
  73. )
  74. // AssumeRole assume role
  75. func AssumeRole(ctx context.Context) (result *Response, err error) {
  76. defer func() {
  77. if l != nil {
  78. l.Info("thirdparty",
  79. zap.String("api", StsHost),
  80. zap.String("request", utils.MarshalJsonString(accessKeyId, accessKeySecret, roleArn, sessionName, expiredTime)),
  81. zap.String("response", utils.MarshalJsonString(result)))
  82. }
  83. }()
  84. url, err := generateSignedURL()
  85. if err != nil {
  86. return nil, err
  87. }
  88. body, status, err := sendRequest(url)
  89. if err != nil {
  90. return nil, err
  91. }
  92. result, err = handleResponse(body, status)
  93. return
  94. }
  95. // Private function
  96. func generateSignedURL() (string, error) {
  97. queryStr := "SignatureVersion=" + StsSignVersion
  98. queryStr += "&Format=" + RespBodyFormat
  99. queryStr += "&Timestamp=" + url.QueryEscape(time.Now().UTC().Format(TimeFormat))
  100. queryStr += "&RoleArn=" + url.QueryEscape(roleArn)
  101. queryStr += "&RoleSessionName=" + sessionName
  102. queryStr += "&AccessKeyId=" + accessKeyId
  103. queryStr += "&SignatureMethod=HMAC-SHA1"
  104. queryStr += "&Version=" + StsAPIVersion
  105. queryStr += "&Action=AssumeRole"
  106. queryStr += "&SignatureNonce=" + string(Krand(32, KC_RAND_KIND_ALL)) // uuid.NewV4().String()
  107. queryStr += "&DurationSeconds=" + strconv.FormatUint((uint64)(expiredTime), 10)
  108. // Sort query string
  109. queryParams, err := url.ParseQuery(queryStr)
  110. if err != nil {
  111. return "", err
  112. }
  113. result := queryParams.Encode()
  114. strToSign := HTTPGet + "&" + PercentEncode + "&" + url.QueryEscape(result)
  115. // Generate signature
  116. hashSign := hmac.New(sha1.New, []byte(accessKeySecret+"&"))
  117. hashSign.Write([]byte(strToSign))
  118. signature := base64.StdEncoding.EncodeToString(hashSign.Sum(nil))
  119. // Build url
  120. assumeURL := StsHost + "?" + queryStr + "&Signature=" + url.QueryEscape(signature)
  121. return assumeURL, nil
  122. }
  123. func sendRequest(url string) ([]byte, int, error) {
  124. tr := &http.Transport{
  125. TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
  126. }
  127. client := &http.Client{Transport: tr}
  128. resp, err := client.Get(url)
  129. if err != nil {
  130. return nil, -1, err
  131. }
  132. defer resp.Body.Close()
  133. body, err := ioutil.ReadAll(resp.Body)
  134. return body, resp.StatusCode, err
  135. }
  136. func handleResponse(responseBody []byte, statusCode int) (*Response, error) {
  137. if statusCode != http.StatusOK {
  138. se := ServiceError{StatusCode: statusCode, RawMessage: string(responseBody)}
  139. err := json.Unmarshal(responseBody, &se)
  140. if err != nil {
  141. return nil, err
  142. }
  143. return nil, &se
  144. }
  145. resp := Response{}
  146. err := json.Unmarshal(responseBody, &resp)
  147. if err != nil {
  148. return nil, err
  149. }
  150. return &resp, nil
  151. }