// loadProfiles loads from the file pointed to by shared credentials filename for profile. // The credentials retrieved from the profile will be returned or error. Error will be // returned if it fails to read from the file, or the data is invalid. func loadProfile(filename, profile string) (Value, error) { config, err := ini.LoadFile(filename) if err != nil { return Value{}, apierr.New("SharedCredsLoad", "failed to load shared credentials file", err) } iniProfile := config.Section(profile) id, ok := iniProfile["aws_access_key_id"] if !ok { return Value{}, apierr.New("SharedCredsAccessKey", fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename), nil) } secret, ok := iniProfile["aws_secret_access_key"] if !ok { return Value{}, apierr.New("SharedCredsSecret", fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename), nil) } token := iniProfile["aws_session_token"] return Value{ AccessKeyID: id, SecretAccessKey: secret, SessionToken: token, }, nil }
func unmarshalError(req *Request) { bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body) if err != nil { req.Error = apierr.New("UnmarshaleError", req.HTTPResponse.Status, err) return } if len(bodyBytes) == 0 { req.Error = apierr.NewRequestError( apierr.New("UnmarshaleError", req.HTTPResponse.Status, fmt.Errorf("empty body")), req.HTTPResponse.StatusCode, "", ) return } var jsonErr jsonErrorResponse if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { req.Error = apierr.New("UnmarshaleError", "JSON unmarshal", err) return } req.Error = apierr.NewRequestError( apierr.New(jsonErr.Code, jsonErr.Message, nil), req.HTTPResponse.StatusCode, "", ) }
// UnmarshalError unmarshals a response error for the REST JSON protocol. func UnmarshalError(r *aws.Request) { code := r.HTTPResponse.Header.Get("X-Amzn-Errortype") bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body) if err != nil { r.Error = apierr.New("Unmarshal", "failed reading REST JSON error response", err) return } if len(bodyBytes) == 0 { r.Error = apierr.NewRequestError( apierr.New("Unmarshal", r.HTTPResponse.Status, nil), r.HTTPResponse.StatusCode, "", ) return } var jsonErr jsonErrorResponse if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { r.Error = apierr.New("Unmarshal", "failed decoding REST JSON error response", err) return } if code == "" { code = jsonErr.Code } codes := strings.SplitN(code, ":", 2) r.Error = apierr.NewRequestError( apierr.New(codes[0], jsonErr.Message, nil), r.HTTPResponse.StatusCode, "", ) }
// upload will perform a multipart upload using the firstPart buffer containing // the first chunk of data. func (u *multiuploader) upload(firstPart []byte) (*UploadOutput, error) { params := &s3.CreateMultipartUploadInput{} awsutil.Copy(params, u.in) // Create the multipart resp, err := u.s.CreateMultipartUpload(params) if err != nil { return nil, err } u.uploadID = *resp.UploadID // Create the workers ch := make(chan chunk, u.opts.Concurrency) for i := 0; i < u.opts.Concurrency; i++ { u.wg.Add(1) go u.readChunk(ch) } // Send part 1 to the workers var num int64 = 1 ch <- chunk{buf: firstPart, num: num} // Read and queue the rest of the parts for u.geterr() == nil { num++ packet := make([]byte, u.opts.PartSize) n, err := io.ReadFull(u.in.Body, packet) ch <- chunk{buf: packet[0:n], num: num} if err != nil { if err != io.EOF && err != io.ErrUnexpectedEOF { u.seterr(apierr.New("ReadRequestBody", "read multipart upload data failed", err)) } break } } // Close the channel, wait for workers, and complete upload close(ch) u.wg.Wait() complete := u.complete() if err := u.geterr(); err != nil { return nil, &multiUploadError{ BaseError: apierr.New("MultipartUpload", "upload multipart failed", err), uploadID: u.uploadID, } } return &UploadOutput{ Location: *complete.Location, UploadID: u.uploadID, }, nil }
func TestChainProviderWithNoValidProvider(t *testing.T) { p := &ChainProvider{ Providers: []Provider{ &stubProvider{err: apierr.New("FirstError", "first provider error", nil)}, &stubProvider{err: apierr.New("SecondError", "second provider error", nil)}, }, } assert.True(t, p.IsExpired(), "Expect expired with no providers") _, err := p.Retrieve() assert.Equal(t, ErrNoValidProvidersFoundInChain, err, "Expect no providers error returned") }
// UnmarshalError unmarshals a response error for the EC2 protocol. func UnmarshalError(r *aws.Request) { defer r.HTTPResponse.Body.Close() resp := &xmlErrorResponse{} err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp) if err != nil && err != io.EOF { r.Error = apierr.New("Unmarshal", "failed decoding EC2 Query error response", err) } else { r.Error = apierr.NewRequestError( apierr.New(resp.Code, resp.Message, nil), r.HTTPResponse.StatusCode, resp.RequestID, ) } }
// Retrieve retrieves credentials from the EC2 service. // Error will be returned if the request fails, or unable to extract // the desired credentials. func (m *EC2RoleProvider) Retrieve() (Value, error) { if m.Client == nil { m.Client = http.DefaultClient } if m.Endpoint == "" { m.Endpoint = metadataCredentialsEndpoint } credsList, err := requestCredList(m.Client, m.Endpoint) if err != nil { return Value{}, err } if len(credsList) == 0 { return Value{}, apierr.New("EmptyEC2RoleList", "empty EC2 Role list", nil) } credsName := credsList[0] roleCreds, err := requestCred(m.Client, m.Endpoint, credsName) if err != nil { return Value{}, err } m.expiresOn = roleCreds.Expiration if m.ExpiryWindow > 0 { // Offset based on expiry window if set. m.expiresOn = m.expiresOn.Add(-m.ExpiryWindow) } return Value{ AccessKeyID: roleCreds.AccessKeyID, SecretAccessKey: roleCreds.SecretAccessKey, SessionToken: roleCreds.Token, }, nil }
func buildQueryString(r *aws.Request, v reflect.Value, name string, query url.Values) { str, err := convertType(v) if err != nil { r.Error = apierr.New("Marshal", "failed to encode REST request", err) } else if str != nil { query.Set(name, *str) } }
func buildHeader(r *aws.Request, v reflect.Value, name string) { str, err := convertType(v) if err != nil { r.Error = apierr.New("Marshal", "failed to encode REST request", err) } else if str != nil { r.HTTPRequest.Header.Add(name, *str) } }
// requestCred requests the credentials for a specific credentials from the EC2 service. // // If the credentials cannot be found, or there is an error reading the response // and error will be returned. func requestCred(client *http.Client, endpoint, credsName string) (*ec2RoleCredRespBody, error) { resp, err := client.Get(endpoint + credsName) if err != nil { return nil, apierr.New("GetEC2RoleCredentials", fmt.Sprintf("failed to get %s EC2 Role credentials", credsName), err) } defer resp.Body.Close() respCreds := &ec2RoleCredRespBody{} if err := json.NewDecoder(resp.Body).Decode(respCreds); err != nil { return nil, apierr.New("DecodeEC2RoleCredentials", fmt.Sprintf("failed to decode %s EC2 Role credentials", credsName), err) } return respCreds, nil }
func buildHeaderMap(r *aws.Request, v reflect.Value, prefix string) { for _, key := range v.MapKeys() { str, err := convertType(v.MapIndex(key)) if err != nil { r.Error = apierr.New("Marshal", "failed to encode REST request", err) } else if str != nil { r.HTTPRequest.Header.Add(prefix+key.String(), *str) } } }
// requestCredList requests a list of credentials from the EC2 service. // If there are no credentials, or there is an error making or receiving the request func requestCredList(client *http.Client, endpoint string) ([]string, error) { resp, err := client.Get(endpoint) if err != nil { return nil, apierr.New("ListEC2Role", "failed to list EC2 Roles", err) } defer resp.Body.Close() credsList := []string{} s := bufio.NewScanner(resp.Body) for s.Scan() { credsList = append(credsList, s.Text()) } if err := s.Err(); err != nil { return nil, apierr.New("ReadEC2Role", "failed to read list of EC2 Roles", err) } return credsList, nil }
func buildURI(r *aws.Request, v reflect.Value, name string) { value, err := convertType(v) if err != nil { r.Error = apierr.New("Marshal", "failed to encode REST request", err) } else if value != nil { uri := r.HTTPRequest.URL.Path uri = strings.Replace(uri, "{"+name+"}", EscapePath(*value, true), -1) uri = strings.Replace(uri, "{"+name+"+}", EscapePath(*value, false), -1) r.HTTPRequest.URL.Path = uri } }
// Unmarshal unmarshals a response body for the EC2 protocol. func Unmarshal(r *aws.Request) { defer r.HTTPResponse.Body.Close() if r.DataFilled() { decoder := xml.NewDecoder(r.HTTPResponse.Body) err := xmlutil.UnmarshalXML(r.Data, decoder, "") if err != nil { r.Error = apierr.New("Unmarshal", "failed decoding EC2 Query response", err) return } } }
// Unmarshal unmarshals a payload response for the REST XML protocol. func Unmarshal(r *aws.Request) { if t := rest.PayloadType(r.Data); t == "structure" || t == "" { defer r.HTTPResponse.Body.Close() decoder := xml.NewDecoder(r.HTTPResponse.Body) err := xmlutil.UnmarshalXML(r.Data, decoder, "") if err != nil { r.Error = apierr.New("Unmarshal", "failed to decode REST XML response", err) return } } }
func TestChainProviderGet(t *testing.T) { p := &ChainProvider{ Providers: []Provider{ &stubProvider{err: apierr.New("FirstError", "first provider error", nil)}, &stubProvider{err: apierr.New("SecondError", "second provider error", nil)}, &stubProvider{ creds: Value{ AccessKeyID: "AKID", SecretAccessKey: "SECRET", SessionToken: "", }, }, }, } creds, err := p.Retrieve() assert.Nil(t, err, "Expect no error") assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match") assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match") assert.Empty(t, creds.SessionToken, "Expect session token to be empty") }
func unmarshalBody(r *aws.Request, v reflect.Value) { if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok { if payloadName := field.Tag.Get("payload"); payloadName != "" { pfield, _ := v.Type().FieldByName(payloadName) if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" { payload := v.FieldByName(payloadName) if payload.IsValid() { switch payload.Interface().(type) { case []byte: b, err := ioutil.ReadAll(r.HTTPResponse.Body) if err != nil { r.Error = apierr.New("Unmarshal", "failed to decode REST response", err) } else { payload.Set(reflect.ValueOf(b)) } case *string: b, err := ioutil.ReadAll(r.HTTPResponse.Body) if err != nil { r.Error = apierr.New("Unmarshal", "failed to decode REST response", err) } else { str := string(b) payload.Set(reflect.ValueOf(&str)) } default: switch payload.Type().String() { case "io.ReadSeeker": payload.Set(reflect.ValueOf(aws.ReadSeekCloser(r.HTTPResponse.Body))) case "aws.ReadSeekCloser", "io.ReadCloser": payload.Set(reflect.ValueOf(r.HTTPResponse.Body)) default: r.Error = apierr.New("Unmarshal", "failed to decode REST response", fmt.Errorf("unknown payload type %s", payload.Type())) } } } } } } }
// Build builds a request payload for the REST XML protocol. func Build(r *aws.Request) { rest.Build(r) if t := rest.PayloadType(r.Params); t == "structure" || t == "" { var buf bytes.Buffer err := xmlutil.BuildXML(r.Params, xml.NewEncoder(&buf)) if err != nil { r.Error = apierr.New("Marshal", "failed to enode rest XML request", err) return } r.SetBufferBody(buf.Bytes()) } }
// internal logic for deciding whether to upload a single part or use a // multipart upload. func (u *uploader) upload() (*UploadOutput, error) { // Do one read to determine if we have more than one part packet := make([]byte, u.opts.PartSize) n, err := io.ReadFull(u.in.Body, packet) if err == io.EOF || err == io.ErrUnexpectedEOF { // single part return u.singlePart(packet[0:n]) } else if err != nil { return nil, apierr.New("ReadRequestBody", "read upload data failed", err) } mu := multiuploader{uploader: u} return mu.upload(packet) }
// contentMD5 computes and sets the HTTP Content-MD5 header for requests that // require it. func contentMD5(r *aws.Request) { h := md5.New() // hash the body. seek back to the first position after reading to reset // the body for transmission. copy errors may be assumed to be from the // body. _, err := io.Copy(h, r.Body) if err != nil { r.Error = apierr.New("ContentMD5", "failed to read body", err) return } _, err = r.Body.Seek(0, 0) if err != nil { r.Error = apierr.New("ContentMD5", "failed to seek body", err) return } // encode the md5 checksum in base64 and set the request header. sum := h.Sum(nil) sum64 := make([]byte, base64.StdEncoding.EncodedLen(len(sum))) base64.StdEncoding.Encode(sum64, sum) r.HTTPRequest.Header.Set("Content-MD5", string(sum64)) }
func unmarshalLocationElements(r *aws.Request, v reflect.Value) { for i := 0; i < v.NumField(); i++ { m, field := v.Field(i), v.Type().Field(i) if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) { continue } if m.IsValid() { name := field.Tag.Get("locationName") if name == "" { name = field.Name } switch field.Tag.Get("location") { case "statusCode": unmarshalStatusCode(m, r.HTTPResponse.StatusCode) case "header": err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name)) if err != nil { r.Error = apierr.New("Unmarshal", "failed to decode REST response", err) break } case "headers": prefix := field.Tag.Get("locationName") err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix) if err != nil { r.Error = apierr.New("Unmarshal", "failed to decode REST response", err) break } } } if r.Error != nil { return } } }
func buildGetBucketLocation(r *aws.Request) { if r.DataFilled() { out := r.Data.(*GetBucketLocationOutput) b, err := ioutil.ReadAll(r.HTTPResponse.Body) if err != nil { r.Error = apierr.New("Unmarshal", "failed reading response body", err) return } match := reBucketLocation.FindSubmatch(b) if len(match) > 1 { loc := string(match[1]) out.LocationConstraint = &loc } } }
// Build builds a request for an AWS Query service. func Build(r *aws.Request) { body := url.Values{ "Action": {r.Operation.Name}, "Version": {r.Service.APIVersion}, } if err := queryutil.Parse(body, r.Params, false); err != nil { r.Error = apierr.New("Marshal", "failed encoding Query request", err) return } if r.ExpireTime == 0 { r.HTTPRequest.Method = "POST" r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") r.SetBufferBody([]byte(body.Encode())) } else { // This is a pre-signed request r.HTTPRequest.Method = "GET" r.HTTPRequest.URL.RawQuery = body.Encode() } }
func validateCRC32(r *aws.Request) { if r.Error != nil { return // already have an error, no need to verify CRC } // Checksum validation is off, skip if r.Service.Config.DisableComputeChecksums { return } // Try to get CRC from response header := r.HTTPResponse.Header.Get("X-Amz-Crc32") if header == "" { return // No header, skip } expected, err := strconv.ParseUint(header, 10, 32) if err != nil { return // Could not determine CRC value, skip } buf, err := drainBody(r.HTTPResponse.Body) if err != nil { // failed to read the response body, skip return } // Reset body for subsequent reads r.HTTPResponse.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes())) // Compute the CRC checksum crc := crc32.ChecksumIEEE(buf.Bytes()) if crc != uint32(expected) { // CRC does not match, set a retryable error r.Retryable.Set(true) r.Error = apierr.New("CRC32CheckFailed", "CRC32 integrity check failed", nil) } }
// SendHandler is a request handler to send service request using HTTP client. func SendHandler(r *Request) { var err error r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest) if err != nil { // Capture the case where url.Error is returned for error processing // response. e.g. 301 without location header comes back as string // error and r.HTTPResponse is nil. Other url redirect errors will // comeback in a similar method. if e, ok := err.(*url.Error); ok { if s := reStatusCode.FindStringSubmatch(e.Error()); s != nil { code, _ := strconv.ParseInt(s[1], 10, 64) r.HTTPResponse = &http.Response{ StatusCode: int(code), Status: http.StatusText(int(code)), Body: ioutil.NopCloser(bytes.NewReader([]byte{})), } return } } // Catch all other request errors. r.Error = apierr.New("RequestError", "send request failed", err) } }
func buildBody(r *aws.Request, v reflect.Value) { if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok { if payloadName := field.Tag.Get("payload"); payloadName != "" { pfield, _ := v.Type().FieldByName(payloadName) if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" { payload := reflect.Indirect(v.FieldByName(payloadName)) if payload.IsValid() && payload.Interface() != nil { switch reader := payload.Interface().(type) { case io.ReadSeeker: r.SetReaderBody(reader) case []byte: r.SetBufferBody(reader) case string: r.SetStringBody(reader) default: r.Error = apierr.New("Marshal", "failed to encode REST request", fmt.Errorf("unknown payload type %s", payload.Type())) } } } } } }
package credentials import ( "fmt" "os" "path/filepath" "github.com/convox/kernel/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/apierr" "github.com/convox/kernel/Godeps/_workspace/src/github.com/vaughan0/go-ini" ) var ( // ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found. ErrSharedCredentialsHomeNotFound = apierr.New("UserHomeNotFound", "user home directory not found.", nil) ) // A SharedCredentialsProvider retrieves credentials from the current user's home // directory, and keeps track if those credentials are expired. // // Profile ini file example: $HOME/.aws/credentials type SharedCredentialsProvider struct { // Path to the shared credentials file. If empty will default to current user's // home directory. Filename string // AWS Profile to extract credentials from the shared credentials file. If empty // will default to environment variable "AWS_PROFILE" or "default" if // environment variable is also not set. Profile string // retrieved states if the credentials have been successfully retrieved.
package credentials import ( "github.com/convox/kernel/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/apierr" "os" ) var ( // ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be // found in the process's environment. ErrAccessKeyIDNotFound = apierr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil) // ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key // can't be found in the process's environment. ErrSecretAccessKeyNotFound = apierr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil) ) // A EnvProvider retrieves credentials from the environment variables of the // running process. Environment credentials never expire. // // Environment variables used: // - Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY // - Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY type EnvProvider struct { retrieved bool } // NewEnvCredentials returns a pointer to a new Credentials object // wrapping the environment variable provider. func NewEnvCredentials() *Credentials { return NewCredentials(&EnvProvider{}) }
if err, ok := r.Error.(awserr.Error); ok && err.Code() == "ExpiredTokenException" { r.Config.Credentials.Expire() // The credentials will need to be resigned with new credentials r.signed = false } } r.RetryCount++ r.Error = nil } } var ( // ErrMissingRegion is an error that is returned if region configuration is // not found. ErrMissingRegion error = apierr.New("MissingRegion", "could not find region configuration", nil) // ErrMissingEndpoint is an error that is returned if an endpoint cannot be // resolved for a service. ErrMissingEndpoint error = apierr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil) ) // ValidateEndpointHandler is a request handler to validate a request had the // appropriate Region and Endpoint set. Will set r.Error if the endpoint or // region is not valid. func ValidateEndpointHandler(r *Request) { if r.Service.SigningRegion == "" && r.Service.Config.Region == "" { r.Error = ErrMissingRegion } else if r.Service.Endpoint == "" { r.Error = ErrMissingEndpoint }
// ValidateResponseHandler is a request handler to validate service response. func ValidateResponseHandler(r *Request) { if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 { // this may be replaced by an UnmarshalError handler r.Error = apierr.New("UnknownError", "unknown error", nil) } }