Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

274 rindas
6.6 KiB

  1. //
  2. // sts: This package provides types and functions to interact with the AWS STS API
  3. //
  4. // Depends on https://github.com/goamz/goamz
  5. //
  6. package sts
  7. import (
  8. "encoding/xml"
  9. "fmt"
  10. "log"
  11. "net/http"
  12. "net/http/httputil"
  13. "net/url"
  14. "strconv"
  15. "strings"
  16. "time"
  17. "github.com/goamz/goamz/aws"
  18. )
  19. // The STS type encapsulates operations within a specific EC2 region.
  20. type STS struct {
  21. aws.Auth
  22. aws.Region
  23. private byte // Reserve the right of using private data.
  24. }
  25. // New creates a new STS Client.
  26. // We can only use us-east for region because AWS..
  27. func New(auth aws.Auth, region aws.Region) *STS {
  28. // Make sure we can run the package tests
  29. if region.Name == "" {
  30. return &STS{auth, region, 0}
  31. }
  32. return &STS{auth, aws.Regions["us-east-1"], 0}
  33. }
  34. const debug = false
  35. // ----------------------------------------------------------------------------
  36. // Request dispatching logic.
  37. // Error encapsulates an error returned by the AWS STS API.
  38. //
  39. // See http://goo.gl/zDZbuQ for more details.
  40. type Error struct {
  41. // HTTP status code (200, 403, ...)
  42. StatusCode int
  43. // STS error code
  44. Code string
  45. // The human-oriented error message
  46. Message string
  47. RequestId string `xml:"RequestID"`
  48. }
  49. func (err *Error) Error() string {
  50. if err.Code == "" {
  51. return err.Message
  52. }
  53. return fmt.Sprintf("%s (%s)", err.Message, err.Code)
  54. }
  55. type xmlErrors struct {
  56. RequestId string `xml:"RequestId"`
  57. Errors []Error `xml:"Error"`
  58. }
  59. func (sts *STS) query(params map[string]string, resp interface{}) error {
  60. params["Version"] = "2011-06-15"
  61. data := strings.NewReader(multimap(params).Encode())
  62. hreq, err := http.NewRequest("POST", sts.Region.STSEndpoint+"/", data)
  63. if err != nil {
  64. return err
  65. }
  66. hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
  67. token := sts.Auth.Token()
  68. if token != "" {
  69. hreq.Header.Set("X-Amz-Security-Token", token)
  70. }
  71. signer := aws.NewV4Signer(sts.Auth, "sts", sts.Region)
  72. signer.Sign(hreq)
  73. if debug {
  74. log.Printf("%v -> {\n", hreq)
  75. }
  76. r, err := http.DefaultClient.Do(hreq)
  77. if err != nil {
  78. log.Printf("Error calling Amazon")
  79. return err
  80. }
  81. defer r.Body.Close()
  82. if debug {
  83. dump, _ := httputil.DumpResponse(r, true)
  84. log.Printf("response:\n")
  85. log.Printf("%v\n}\n", string(dump))
  86. }
  87. if r.StatusCode != 200 {
  88. return buildError(r)
  89. }
  90. err = xml.NewDecoder(r.Body).Decode(resp)
  91. return err
  92. }
  93. func buildError(r *http.Response) error {
  94. var (
  95. err Error
  96. errors xmlErrors
  97. )
  98. xml.NewDecoder(r.Body).Decode(&errors)
  99. if len(errors.Errors) > 0 {
  100. err = errors.Errors[0]
  101. }
  102. err.RequestId = errors.RequestId
  103. err.StatusCode = r.StatusCode
  104. if err.Message == "" {
  105. err.Message = r.Status
  106. }
  107. return &err
  108. }
  109. func makeParams(action string) map[string]string {
  110. params := make(map[string]string)
  111. params["Action"] = action
  112. return params
  113. }
  114. func multimap(p map[string]string) url.Values {
  115. q := make(url.Values, len(p))
  116. for k, v := range p {
  117. q[k] = []string{v}
  118. }
  119. return q
  120. }
  121. // options for the AssumeRole function
  122. //
  123. // See http://goo.gl/Ld6Dbk for details
  124. type AssumeRoleParams struct {
  125. DurationSeconds int
  126. ExternalId string
  127. Policy string
  128. RoleArn string
  129. RoleSessionName string
  130. }
  131. type AssumedRoleUser struct {
  132. Arn string `xml:"Arn"`
  133. AssumedRoleId string `xml:"AssumedRoleId"`
  134. }
  135. type Credentials struct {
  136. AccessKeyId string `xml:"AccessKeyId"`
  137. Expiration time.Time `xml:"Expiration"`
  138. SecretAccessKey string `xml:"SecretAccessKey"`
  139. SessionToken string `xml:"SessionToken"`
  140. }
  141. type AssumeRoleResult struct {
  142. AssumedRoleUser AssumedRoleUser `xml:"AssumeRoleResult>AssumedRoleUser"`
  143. Credentials Credentials `xml:"AssumeRoleResult>Credentials"`
  144. PackedPolicySize int `xml:"AssumeRoleResult>PackedPolicySize"`
  145. RequestId string `xml:"ResponseMetadata>RequestId"`
  146. }
  147. // AssumeRole assumes the specified role
  148. //
  149. // See http://goo.gl/zDZbuQ for more details.
  150. func (sts *STS) AssumeRole(options *AssumeRoleParams) (resp *AssumeRoleResult, err error) {
  151. params := makeParams("AssumeRole")
  152. params["RoleArn"] = options.RoleArn
  153. params["RoleSessionName"] = options.RoleSessionName
  154. if options.DurationSeconds != 0 {
  155. params["DurationSeconds"] = strconv.Itoa(options.DurationSeconds)
  156. }
  157. if options.ExternalId != "" {
  158. params["ExternalId"] = options.ExternalId
  159. }
  160. if options.Policy != "" {
  161. params["Policy"] = options.Policy
  162. }
  163. resp = new(AssumeRoleResult)
  164. if err := sts.query(params, resp); err != nil {
  165. return nil, err
  166. }
  167. return resp, nil
  168. }
  169. // FederatedUser presents dentifiers for the federated user that is associated with the credentials.
  170. //
  171. // See http://goo.gl/uPtr7V for more details
  172. type FederatedUser struct {
  173. Arn string `xml:"Arn"`
  174. FederatedUserId string `xml:"FederatedUserId"`
  175. }
  176. // GetFederationToken wraps GetFederationToken response
  177. //
  178. // See http://goo.gl/Iujjeg for more details
  179. type GetFederationTokenResult struct {
  180. Credentials Credentials `xml:"GetFederationTokenResult>Credentials"`
  181. FederatedUser FederatedUser `xml:"GetFederationTokenResult>FederatedUser"`
  182. PackedPolicySize int `xml:"GetFederationTokenResult>PackedPolicySize"`
  183. RequestId string `xml:"ResponseMetadata>RequestId"`
  184. }
  185. // GetFederationToken returns a set of temporary credentials for an AWS account or IAM user
  186. //
  187. // See http://goo.gl/Iujjeg for more details
  188. func (sts *STS) GetFederationToken(name, policy string, durationSeconds int) (
  189. resp *GetFederationTokenResult, err error) {
  190. params := makeParams("GetFederationToken")
  191. params["Name"] = name
  192. if durationSeconds != 0 {
  193. params["DurationSeconds"] = strconv.Itoa(durationSeconds)
  194. }
  195. if policy != "" {
  196. params["Policy"] = policy
  197. }
  198. resp = new(GetFederationTokenResult)
  199. if err := sts.query(params, resp); err != nil {
  200. return nil, err
  201. }
  202. return resp, nil
  203. }
  204. // GetSessionToken wraps GetSessionToken response
  205. //
  206. // See http://goo.gl/v8s5Y for more details
  207. type GetSessionTokenResult struct {
  208. Credentials Credentials `xml:"GetSessionTokenResult>Credentials"`
  209. RequestId string `xml:"ResponseMetadata>RequestId"`
  210. }
  211. // GetSessionToken returns a set of temporary credentials for an AWS account or IAM user
  212. //
  213. // See http://goo.gl/v8s5Y for more details
  214. func (sts *STS) GetSessionToken(durationSeconds int, serialnNumber, tokenCode string) (
  215. resp *GetSessionTokenResult, err error) {
  216. params := makeParams("GetSessionToken")
  217. if durationSeconds != 0 {
  218. params["DurationSeconds"] = strconv.Itoa(durationSeconds)
  219. }
  220. if serialnNumber != "" {
  221. params["SerialNumber"] = serialnNumber
  222. }
  223. if tokenCode != "" {
  224. params["TokenCode"] = tokenCode
  225. }
  226. resp = new(GetSessionTokenResult)
  227. if err := sts.query(params, resp); err != nil {
  228. return nil, err
  229. }
  230. return resp, nil
  231. }