sts_web_identity.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. // AssumeRoleWithWebIdentityResponse contains the result of successful AssumeRoleWithWebIdentity request.
  27. type AssumeRoleWithWebIdentityResponse struct {
  28. XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithWebIdentityResponse" json:"-"`
  29. Result WebIdentityResult `xml:"AssumeRoleWithWebIdentityResult"`
  30. ResponseMetadata struct {
  31. RequestID string `xml:"RequestId,omitempty"`
  32. } `xml:"ResponseMetadata,omitempty"`
  33. }
  34. // WebIdentityResult - Contains the response to a successful AssumeRoleWithWebIdentity
  35. // request, including temporary credentials that can be used to make Minio API requests.
  36. type WebIdentityResult struct {
  37. AssumedRoleUser AssumedRoleUser `xml:",omitempty"`
  38. Audience string `xml:",omitempty"`
  39. Credentials struct {
  40. AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"`
  41. SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"`
  42. Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"`
  43. SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"`
  44. } `xml:",omitempty"`
  45. PackedPolicySize int `xml:",omitempty"`
  46. Provider string `xml:",omitempty"`
  47. SubjectFromWebIdentityToken string `xml:",omitempty"`
  48. }
  49. // WebIdentityToken - web identity token with expiry.
  50. type WebIdentityToken struct {
  51. token string
  52. expiry int
  53. }
  54. // Token - access token returned after authenticating web identity.
  55. func (c *WebIdentityToken) Token() string {
  56. return c.token
  57. }
  58. // Expiry - expiry for the access token returned after authenticating
  59. // web identity.
  60. func (c *WebIdentityToken) Expiry() string {
  61. return fmt.Sprintf("%d", c.expiry)
  62. }
  63. // A STSWebIdentity retrieves credentials from Minio service, and keeps track if
  64. // those credentials are expired.
  65. type STSWebIdentity struct {
  66. Expiry
  67. // Required http Client to use when connecting to Minio STS service.
  68. Client *http.Client
  69. // Minio endpoint to fetch STS credentials.
  70. stsEndpoint string
  71. // getWebIDTokenExpiry function which returns ID tokens
  72. // from IDP. This function should return two values one
  73. // is ID token which is a self contained ID token (JWT)
  74. // and second return value is the expiry associated with
  75. // this token.
  76. // This is a customer provided function and is mandatory.
  77. getWebIDTokenExpiry func() (*WebIdentityToken, error)
  78. }
  79. // NewSTSWebIdentity returns a pointer to a new
  80. // Credentials object wrapping the STSWebIdentity.
  81. func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) {
  82. if stsEndpoint == "" {
  83. return nil, errors.New("STS endpoint cannot be empty")
  84. }
  85. if getWebIDTokenExpiry == nil {
  86. return nil, errors.New("Web ID token and expiry retrieval function should be defined")
  87. }
  88. return New(&STSWebIdentity{
  89. Client: &http.Client{
  90. Transport: http.DefaultTransport,
  91. },
  92. stsEndpoint: stsEndpoint,
  93. getWebIDTokenExpiry: getWebIDTokenExpiry,
  94. }), nil
  95. }
  96. func getWebIdentityCredentials(clnt *http.Client, endpoint string,
  97. getWebIDTokenExpiry func() (*WebIdentityToken, error)) (AssumeRoleWithWebIdentityResponse, error) {
  98. idToken, err := getWebIDTokenExpiry()
  99. if err != nil {
  100. return AssumeRoleWithWebIdentityResponse{}, err
  101. }
  102. v := url.Values{}
  103. v.Set("Action", "AssumeRoleWithWebIdentity")
  104. v.Set("WebIdentityToken", idToken.Token())
  105. v.Set("DurationSeconds", idToken.Expiry())
  106. v.Set("Version", "2011-06-15")
  107. u, err := url.Parse(endpoint)
  108. if err != nil {
  109. return AssumeRoleWithWebIdentityResponse{}, err
  110. }
  111. u.RawQuery = v.Encode()
  112. req, err := http.NewRequest("POST", u.String(), nil)
  113. if err != nil {
  114. return AssumeRoleWithWebIdentityResponse{}, err
  115. }
  116. resp, err := clnt.Do(req)
  117. if err != nil {
  118. return AssumeRoleWithWebIdentityResponse{}, err
  119. }
  120. defer resp.Body.Close()
  121. if resp.StatusCode != http.StatusOK {
  122. return AssumeRoleWithWebIdentityResponse{}, errors.New(resp.Status)
  123. }
  124. a := AssumeRoleWithWebIdentityResponse{}
  125. if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil {
  126. return AssumeRoleWithWebIdentityResponse{}, err
  127. }
  128. return a, nil
  129. }
  130. // Retrieve retrieves credentials from the Minio service.
  131. // Error will be returned if the request fails.
  132. func (m *STSWebIdentity) Retrieve() (Value, error) {
  133. a, err := getWebIdentityCredentials(m.Client, m.stsEndpoint, m.getWebIDTokenExpiry)
  134. if err != nil {
  135. return Value{}, err
  136. }
  137. // Expiry window is set to 10secs.
  138. m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow)
  139. return Value{
  140. AccessKeyID: a.Result.Credentials.AccessKey,
  141. SecretAccessKey: a.Result.Credentials.SecretKey,
  142. SessionToken: a.Result.Credentials.SessionToken,
  143. SignerType: SignatureV4,
  144. }, nil
  145. }