sts_client_grants.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Minio Go Library for Amazon S3 Compatible Cloud Storage
  3. * Copyright 2019 Minio, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package credentials
  18. import (
  19. "encoding/xml"
  20. "errors"
  21. "fmt"
  22. "net/http"
  23. "net/url"
  24. "time"
  25. )
  26. // AssumedRoleUser - The identifiers for the temporary security credentials that
  27. // the operation returns. Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumedRoleUser
  28. type AssumedRoleUser struct {
  29. Arn string
  30. AssumedRoleID string `xml:"AssumeRoleId"`
  31. }
  32. // AssumeRoleWithClientGrantsResponse contains the result of successful AssumeRoleWithClientGrants request.
  33. type AssumeRoleWithClientGrantsResponse struct {
  34. XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithClientGrantsResponse" json:"-"`
  35. Result ClientGrantsResult `xml:"AssumeRoleWithClientGrantsResult"`
  36. ResponseMetadata struct {
  37. RequestID string `xml:"RequestId,omitempty"`
  38. } `xml:"ResponseMetadata,omitempty"`
  39. }
  40. // ClientGrantsResult - Contains the response to a successful AssumeRoleWithClientGrants
  41. // request, including temporary credentials that can be used to make Minio API requests.
  42. type ClientGrantsResult struct {
  43. AssumedRoleUser AssumedRoleUser `xml:",omitempty"`
  44. Audience string `xml:",omitempty"`
  45. Credentials struct {
  46. AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"`
  47. SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"`
  48. Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"`
  49. SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"`
  50. } `xml:",omitempty"`
  51. PackedPolicySize int `xml:",omitempty"`
  52. Provider string `xml:",omitempty"`
  53. SubjectFromClientGrantsToken string `xml:",omitempty"`
  54. }
  55. // ClientGrantsToken - client grants token with expiry.
  56. type ClientGrantsToken struct {
  57. token string
  58. expiry int
  59. }
  60. // Token - access token returned after authenticating client grants.
  61. func (c *ClientGrantsToken) Token() string {
  62. return c.token
  63. }
  64. // Expiry - expiry for the access token returned after authenticating
  65. // client grants.
  66. func (c *ClientGrantsToken) Expiry() string {
  67. return fmt.Sprintf("%d", c.expiry)
  68. }
  69. // A STSClientGrants retrieves credentials from Minio service, and keeps track if
  70. // those credentials are expired.
  71. type STSClientGrants struct {
  72. Expiry
  73. // Required http Client to use when connecting to Minio STS service.
  74. Client *http.Client
  75. // Minio endpoint to fetch STS credentials.
  76. stsEndpoint string
  77. // getClientGrantsTokenExpiry function to retrieve tokens
  78. // from IDP This function should return two values one is
  79. // accessToken which is a self contained access token (JWT)
  80. // and second return value is the expiry associated with
  81. // this token. This is a customer provided function and
  82. // is mandatory.
  83. getClientGrantsTokenExpiry func() (*ClientGrantsToken, error)
  84. }
  85. // NewSTSClientGrants returns a pointer to a new
  86. // Credentials object wrapping the STSClientGrants.
  87. func NewSTSClientGrants(stsEndpoint string, getClientGrantsTokenExpiry func() (*ClientGrantsToken, error)) (*Credentials, error) {
  88. if stsEndpoint == "" {
  89. return nil, errors.New("STS endpoint cannot be empty")
  90. }
  91. if getClientGrantsTokenExpiry == nil {
  92. return nil, errors.New("Client grants access token and expiry retrieval function should be defined")
  93. }
  94. return New(&STSClientGrants{
  95. Client: &http.Client{
  96. Transport: http.DefaultTransport,
  97. },
  98. stsEndpoint: stsEndpoint,
  99. getClientGrantsTokenExpiry: getClientGrantsTokenExpiry,
  100. }), nil
  101. }
  102. func getClientGrantsCredentials(clnt *http.Client, endpoint string,
  103. getClientGrantsTokenExpiry func() (*ClientGrantsToken, error)) (AssumeRoleWithClientGrantsResponse, error) {
  104. accessToken, err := getClientGrantsTokenExpiry()
  105. if err != nil {
  106. return AssumeRoleWithClientGrantsResponse{}, err
  107. }
  108. v := url.Values{}
  109. v.Set("Action", "AssumeRoleWithClientGrants")
  110. v.Set("Token", accessToken.Token())
  111. v.Set("DurationSeconds", accessToken.Expiry())
  112. v.Set("Version", "2011-06-15")
  113. u, err := url.Parse(endpoint)
  114. if err != nil {
  115. return AssumeRoleWithClientGrantsResponse{}, err
  116. }
  117. u.RawQuery = v.Encode()
  118. req, err := http.NewRequest("POST", u.String(), nil)
  119. if err != nil {
  120. return AssumeRoleWithClientGrantsResponse{}, err
  121. }
  122. resp, err := clnt.Do(req)
  123. if err != nil {
  124. return AssumeRoleWithClientGrantsResponse{}, err
  125. }
  126. defer resp.Body.Close()
  127. if resp.StatusCode != http.StatusOK {
  128. return AssumeRoleWithClientGrantsResponse{}, errors.New(resp.Status)
  129. }
  130. a := AssumeRoleWithClientGrantsResponse{}
  131. if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil {
  132. return AssumeRoleWithClientGrantsResponse{}, err
  133. }
  134. return a, nil
  135. }
  136. // Retrieve retrieves credentials from the Minio service.
  137. // Error will be returned if the request fails.
  138. func (m *STSClientGrants) Retrieve() (Value, error) {
  139. a, err := getClientGrantsCredentials(m.Client, m.stsEndpoint, m.getClientGrantsTokenExpiry)
  140. if err != nil {
  141. return Value{}, err
  142. }
  143. // Expiry window is set to 10secs.
  144. m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow)
  145. return Value{
  146. AccessKeyID: a.Result.Credentials.AccessKey,
  147. SecretAccessKey: a.Result.Credentials.SecretKey,
  148. SessionToken: a.Result.Credentials.SessionToken,
  149. SignerType: SignatureV4,
  150. }, nil
  151. }