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 18package credentials 19 20import ( 21 "encoding/xml" 22 "errors" 23 "fmt" 24 "net/http" 25 "net/url" 26 "strconv" 27 "time" 28) 29 30// AssumeRoleWithWebIdentityResponse contains the result of successful AssumeRoleWithWebIdentity request. 31type AssumeRoleWithWebIdentityResponse struct { 32 XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithWebIdentityResponse" json:"-"` 33 Result WebIdentityResult `xml:"AssumeRoleWithWebIdentityResult"` 34 ResponseMetadata struct { 35 RequestID string `xml:"RequestId,omitempty"` 36 } `xml:"ResponseMetadata,omitempty"` 37} 38 39// WebIdentityResult - Contains the response to a successful AssumeRoleWithWebIdentity 40// request, including temporary credentials that can be used to make MinIO API requests. 41type WebIdentityResult struct { 42 AssumedRoleUser AssumedRoleUser `xml:",omitempty"` 43 Audience string `xml:",omitempty"` 44 Credentials struct { 45 AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` 46 SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` 47 Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` 48 SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` 49 } `xml:",omitempty"` 50 PackedPolicySize int `xml:",omitempty"` 51 Provider string `xml:",omitempty"` 52 SubjectFromWebIdentityToken string `xml:",omitempty"` 53} 54 55// WebIdentityToken - web identity token with expiry. 56type WebIdentityToken struct { 57 Token string 58 Expiry int 59} 60 61// A STSWebIdentity retrieves credentials from MinIO service, and keeps track if 62// those credentials are expired. 63type STSWebIdentity struct { 64 Expiry 65 66 // Required http Client to use when connecting to MinIO STS service. 67 Client *http.Client 68 69 // Exported STS endpoint to fetch STS credentials. 70 STSEndpoint string 71 72 // Exported GetWebIDTokenExpiry function which returns ID 73 // tokens from IDP. This function should return two values 74 // one is ID token which is a self contained ID token (JWT) 75 // and second return value is the expiry associated with 76 // this token. 77 // This is a customer provided function and is mandatory. 78 GetWebIDTokenExpiry func() (*WebIdentityToken, error) 79 80 // roleARN is the Amazon Resource Name (ARN) of the role that the caller is 81 // assuming. 82 roleARN string 83 84 // roleSessionName is the identifier for the assumed role session. 85 roleSessionName string 86} 87 88// NewSTSWebIdentity returns a pointer to a new 89// Credentials object wrapping the STSWebIdentity. 90func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { 91 if stsEndpoint == "" { 92 return nil, errors.New("STS endpoint cannot be empty") 93 } 94 if getWebIDTokenExpiry == nil { 95 return nil, errors.New("Web ID token and expiry retrieval function should be defined") 96 } 97 return New(&STSWebIdentity{ 98 Client: &http.Client{ 99 Transport: http.DefaultTransport, 100 }, 101 STSEndpoint: stsEndpoint, 102 GetWebIDTokenExpiry: getWebIDTokenExpiry, 103 }), nil 104} 105 106func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSessionName string, 107 getWebIDTokenExpiry func() (*WebIdentityToken, error)) (AssumeRoleWithWebIdentityResponse, error) { 108 idToken, err := getWebIDTokenExpiry() 109 if err != nil { 110 return AssumeRoleWithWebIdentityResponse{}, err 111 } 112 113 v := url.Values{} 114 v.Set("Action", "AssumeRoleWithWebIdentity") 115 if len(roleARN) > 0 { 116 v.Set("RoleArn", roleARN) 117 118 if len(roleSessionName) == 0 { 119 roleSessionName = strconv.FormatInt(time.Now().UnixNano(), 10) 120 } 121 v.Set("RoleSessionName", roleSessionName) 122 } 123 v.Set("WebIdentityToken", idToken.Token) 124 if idToken.Expiry > 0 { 125 v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry)) 126 } 127 v.Set("Version", STSVersion) 128 129 u, err := url.Parse(endpoint) 130 if err != nil { 131 return AssumeRoleWithWebIdentityResponse{}, err 132 } 133 134 u.RawQuery = v.Encode() 135 136 req, err := http.NewRequest(http.MethodPost, u.String(), nil) 137 if err != nil { 138 return AssumeRoleWithWebIdentityResponse{}, err 139 } 140 141 resp, err := clnt.Do(req) 142 if err != nil { 143 return AssumeRoleWithWebIdentityResponse{}, err 144 } 145 146 defer resp.Body.Close() 147 if resp.StatusCode != http.StatusOK { 148 return AssumeRoleWithWebIdentityResponse{}, errors.New(resp.Status) 149 } 150 151 a := AssumeRoleWithWebIdentityResponse{} 152 if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil { 153 return AssumeRoleWithWebIdentityResponse{}, err 154 } 155 156 return a, nil 157} 158 159// Retrieve retrieves credentials from the MinIO service. 160// Error will be returned if the request fails. 161func (m *STSWebIdentity) Retrieve() (Value, error) { 162 a, err := getWebIdentityCredentials(m.Client, m.STSEndpoint, m.roleARN, m.roleSessionName, m.GetWebIDTokenExpiry) 163 if err != nil { 164 return Value{}, err 165 } 166 167 // Expiry window is set to 10secs. 168 m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) 169 170 return Value{ 171 AccessKeyID: a.Result.Credentials.AccessKey, 172 SecretAccessKey: a.Result.Credentials.SecretKey, 173 SessionToken: a.Result.Credentials.SessionToken, 174 SignerType: SignatureV4, 175 }, nil 176} 177 178// Expiration returns the expiration time of the credentials 179func (m *STSWebIdentity) Expiration() time.Time { 180 return m.expiration 181} 182