Updating aws-sdk-go to version 1.4.22
Signed-off-by: Laura Frank <ljfrank@gmail.com> Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
72ec0f3488
commit
ba4e0c328f
46 changed files with 7013 additions and 767 deletions
|
@ -127,7 +127,7 @@ clone git github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c
|
|||
clone git gopkg.in/fsnotify.v1 v1.2.11
|
||||
|
||||
# awslogs deps
|
||||
clone git github.com/aws/aws-sdk-go v1.1.30
|
||||
clone git github.com/aws/aws-sdk-go v1.4.22
|
||||
clone git github.com/go-ini/ini 060d7da055ba6ec5ea7a31f116332fe5efa04ce0
|
||||
clone git github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ type Error interface {
|
|||
|
||||
// BatchError is a batch of errors which also wraps lower level errors with
|
||||
// code, message, and original errors. Calling Error() will include all errors
|
||||
// that occured in the batch.
|
||||
// that occurred in the batch.
|
||||
//
|
||||
// Deprecated: Replaced with BatchedErrors. Only defined for backwards
|
||||
// compatibility.
|
||||
|
@ -64,7 +64,7 @@ type BatchError interface {
|
|||
|
||||
// BatchedErrors is a batch of errors which also wraps lower level errors with
|
||||
// code, message, and original errors. Calling Error() will include all errors
|
||||
// that occured in the batch.
|
||||
// that occurred in the batch.
|
||||
//
|
||||
// Replaces BatchError
|
||||
type BatchedErrors interface {
|
||||
|
|
|
@ -98,7 +98,7 @@ func (b baseError) OrigErr() error {
|
|||
return NewBatchError(err.Code(), err.Message(), b.errs[1:])
|
||||
}
|
||||
return NewBatchError("BatchedErrors",
|
||||
"multiple errors occured", b.errs)
|
||||
"multiple errors occurred", b.errs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package awsutil
|
|||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Copy deeply copies a src structure to dst. Useful for copying request and
|
||||
|
@ -49,7 +50,14 @@ func rcopy(dst, src reflect.Value, root bool) {
|
|||
} else {
|
||||
e := src.Type().Elem()
|
||||
if dst.CanSet() && !src.IsNil() {
|
||||
dst.Set(reflect.New(e))
|
||||
if _, ok := src.Interface().(*time.Time); !ok {
|
||||
dst.Set(reflect.New(e))
|
||||
} else {
|
||||
tempValue := reflect.New(e)
|
||||
tempValue.Elem().Set(src.Elem())
|
||||
// Sets time.Time's unexported values
|
||||
dst.Set(tempValue)
|
||||
}
|
||||
}
|
||||
if src.Elem().IsValid() {
|
||||
// Keep the current root state since the depth hasn't changed
|
||||
|
|
|
@ -106,8 +106,8 @@ func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTer
|
|||
|
||||
if indexStar || index != nil {
|
||||
nextvals = []reflect.Value{}
|
||||
for _, value := range values {
|
||||
value := reflect.Indirect(value)
|
||||
for _, valItem := range values {
|
||||
value := reflect.Indirect(valItem)
|
||||
if value.Kind() != reflect.Slice {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package client
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
@ -87,16 +86,24 @@ const logReqMsg = `DEBUG: Request %s/%s Details:
|
|||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
const logReqErrMsg = `DEBUG ERROR: Request %s/%s:
|
||||
---[ REQUEST DUMP ERROR ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logRequest(r *request.Request) {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
dumpedBody, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
if logBody {
|
||||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||
|
@ -107,11 +114,21 @@ const logRespMsg = `DEBUG: Response %s/%s Details:
|
|||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
|
||||
---[ RESPONSE DUMP ERROR ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logResponse(r *request.Request) {
|
||||
var msg = "no response data"
|
||||
if r.HTTPResponse != nil {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||
dumpedBody, err := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
msg = string(dumpedBody)
|
||||
} else if r.Error != nil {
|
||||
msg = r.Error.Error()
|
||||
|
|
131
vendor/src/github.com/aws/aws-sdk-go/aws/config.go
vendored
131
vendor/src/github.com/aws/aws-sdk-go/aws/config.go
vendored
|
@ -7,24 +7,36 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
// UseServiceDefaultRetries instructs the config to use the service's own default
|
||||
// number of retries. This will be the default action if Config.MaxRetries
|
||||
// is nil also.
|
||||
// UseServiceDefaultRetries instructs the config to use the service's own
|
||||
// default number of retries. This will be the default action if
|
||||
// Config.MaxRetries is nil also.
|
||||
const UseServiceDefaultRetries = -1
|
||||
|
||||
// RequestRetryer is an alias for a type that implements the request.Retryer interface.
|
||||
// RequestRetryer is an alias for a type that implements the request.Retryer
|
||||
// interface.
|
||||
type RequestRetryer interface{}
|
||||
|
||||
// A Config provides service configuration for service clients. By default,
|
||||
// all clients will use the {defaults.DefaultConfig} structure.
|
||||
// all clients will use the defaults.DefaultConfig tructure.
|
||||
//
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess, err := session.NewSession(&aws.Config{
|
||||
// MaxRetries: aws.Int(3),
|
||||
// })
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// Region: aws.String("us-west-2"),
|
||||
// })
|
||||
type Config struct {
|
||||
// Enables verbose error printing of all credential chain errors.
|
||||
// Should be used when wanting to see all errors while attempting to retreive
|
||||
// credentials.
|
||||
// Should be used when wanting to see all errors while attempting to
|
||||
// retrieve credentials.
|
||||
CredentialsChainVerboseErrors *bool
|
||||
|
||||
// The credentials object to use when signing requests. Defaults to
|
||||
// a chain of credential providers to search for credentials in environment
|
||||
// The credentials object to use when signing requests. Defaults to a
|
||||
// chain of credential providers to search for credentials in environment
|
||||
// variables, shared credential file, and EC2 Instance Roles.
|
||||
Credentials *credentials.Credentials
|
||||
|
||||
|
@ -63,11 +75,12 @@ type Config struct {
|
|||
Logger Logger
|
||||
|
||||
// The maximum number of times that a request will be retried for failures.
|
||||
// Defaults to -1, which defers the max retry setting to the service specific
|
||||
// configuration.
|
||||
// Defaults to -1, which defers the max retry setting to the service
|
||||
// specific configuration.
|
||||
MaxRetries *int
|
||||
|
||||
// Retryer guides how HTTP requests should be retried in case of recoverable failures.
|
||||
// Retryer guides how HTTP requests should be retried in case of
|
||||
// recoverable failures.
|
||||
//
|
||||
// When nil or the value does not implement the request.Retryer interface,
|
||||
// the request.DefaultRetryer will be used.
|
||||
|
@ -82,8 +95,8 @@ type Config struct {
|
|||
//
|
||||
Retryer RequestRetryer
|
||||
|
||||
// Disables semantic parameter validation, which validates input for missing
|
||||
// required fields and/or other semantic request input errors.
|
||||
// Disables semantic parameter validation, which validates input for
|
||||
// missing required fields and/or other semantic request input errors.
|
||||
DisableParamValidation *bool
|
||||
|
||||
// Disables the computation of request and response checksums, e.g.,
|
||||
|
@ -91,8 +104,8 @@ type Config struct {
|
|||
DisableComputeChecksums *bool
|
||||
|
||||
// Set this to `true` to force the request to use path-style addressing,
|
||||
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client will
|
||||
// use virtual hosted bucket addressing when possible
|
||||
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client
|
||||
// will use virtual hosted bucket addressing when possible
|
||||
// (`http://BUCKET.s3.amazonaws.com/KEY`).
|
||||
//
|
||||
// @note This configuration option is specific to the Amazon S3 service.
|
||||
|
@ -109,44 +122,81 @@ type Config struct {
|
|||
// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html
|
||||
//
|
||||
// 100-Continue is only enabled for Go 1.6 and above. See `http.Transport`'s
|
||||
// `ExpectContinueTimeout` for information on adjusting the continue wait timeout.
|
||||
// https://golang.org/pkg/net/http/#Transport
|
||||
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
||||
// timeout. https://golang.org/pkg/net/http/#Transport
|
||||
//
|
||||
// You should use this flag to disble 100-Continue if you experiance issues
|
||||
// with proxies or thrid party S3 compatible services.
|
||||
// You should use this flag to disble 100-Continue if you experience issues
|
||||
// with proxies or third party S3 compatible services.
|
||||
S3Disable100Continue *bool
|
||||
|
||||
// Set this to `true` to enable S3 Accelerate feature. For all operations compatible
|
||||
// with S3 Accelerate will use the accelerate endpoint for requests. Requests not compatible
|
||||
// will fall back to normal S3 requests.
|
||||
// Set this to `true` to enable S3 Accelerate feature. For all operations
|
||||
// compatible with S3 Accelerate will use the accelerate endpoint for
|
||||
// requests. Requests not compatible will fall back to normal S3 requests.
|
||||
//
|
||||
// The bucket must be enable for accelerate to be used with S3 client with accelerate
|
||||
// enabled. If the bucket is not enabled for accelerate an error will be returned.
|
||||
// The bucket name must be DNS compatible to also work with accelerate.
|
||||
// The bucket must be enable for accelerate to be used with S3 client with
|
||||
// accelerate enabled. If the bucket is not enabled for accelerate an error
|
||||
// will be returned. The bucket name must be DNS compatible to also work
|
||||
// with accelerate.
|
||||
S3UseAccelerate *bool
|
||||
|
||||
// Set this to `true` to disable the EC2Metadata client from overriding the
|
||||
// default http.Client's Timeout. This is helpful if you do not want the EC2Metadata
|
||||
// client to create a new http.Client. This options is only meaningful if you're not
|
||||
// already using a custom HTTP client with the SDK. Enabled by default.
|
||||
// default http.Client's Timeout. This is helpful if you do not want the
|
||||
// EC2Metadata client to create a new http.Client. This options is only
|
||||
// meaningful if you're not already using a custom HTTP client with the
|
||||
// SDK. Enabled by default.
|
||||
//
|
||||
// Must be set and provided to the session.New() in order to disable the EC2Metadata
|
||||
// overriding the timeout for default credentials chain.
|
||||
// Must be set and provided to the session.NewSession() in order to disable
|
||||
// the EC2Metadata overriding the timeout for default credentials chain.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.New(aws.NewConfig().WithEC2MetadataDiableTimeoutOverride(true))
|
||||
// sess, err := session.NewSession(aws.NewConfig().WithEC2MetadataDiableTimeoutOverride(true))
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
//
|
||||
EC2MetadataDisableTimeoutOverride *bool
|
||||
|
||||
// Instructs the endpiont to be generated for a service client to
|
||||
// be the dual stack endpoint. The dual stack endpoint will support
|
||||
// both IPv4 and IPv6 addressing.
|
||||
//
|
||||
// Setting this for a service which does not support dual stack will fail
|
||||
// to make requets. It is not recommended to set this value on the session
|
||||
// as it will apply to all service clients created with the session. Even
|
||||
// services which don't support dual stack endpoints.
|
||||
//
|
||||
// If the Endpoint config value is also provided the UseDualStack flag
|
||||
// will be ignored.
|
||||
//
|
||||
// Only supported with.
|
||||
//
|
||||
// sess, err := session.NewSession()
|
||||
//
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// UseDualStack: aws.Bool(true),
|
||||
// })
|
||||
UseDualStack *bool
|
||||
|
||||
// SleepDelay is an override for the func the SDK will call when sleeping
|
||||
// during the lifecycle of a request. Specifically this will be used for
|
||||
// request delays. This value should only be used for testing. To adjust
|
||||
// the delay of a request see the aws/client.DefaultRetryer and
|
||||
// aws/request.Retryer.
|
||||
SleepDelay func(time.Duration)
|
||||
}
|
||||
|
||||
// NewConfig returns a new Config pointer that can be chained with builder methods to
|
||||
// set multiple configuration values inline without using pointers.
|
||||
// NewConfig returns a new Config pointer that can be chained with builder
|
||||
// methods to set multiple configuration values inline without using pointers.
|
||||
//
|
||||
// svc := s3.New(aws.NewConfig().WithRegion("us-west-2").WithMaxRetries(10))
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess, err := session.NewSession(aws.NewConfig().
|
||||
// WithMaxRetries(3),
|
||||
// )
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, aws.NewConfig().
|
||||
// WithRegion("us-west-2"),
|
||||
// )
|
||||
func NewConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
@ -249,6 +299,13 @@ func (c *Config) WithS3UseAccelerate(enable bool) *Config {
|
|||
return c
|
||||
}
|
||||
|
||||
// WithUseDualStack sets a config UseDualStack value returning a Config
|
||||
// pointer for chaining.
|
||||
func (c *Config) WithUseDualStack(enable bool) *Config {
|
||||
c.UseDualStack = &enable
|
||||
return c
|
||||
}
|
||||
|
||||
// WithEC2MetadataDisableTimeoutOverride sets a config EC2MetadataDisableTimeoutOverride value
|
||||
// returning a Config pointer for chaining.
|
||||
func (c *Config) WithEC2MetadataDisableTimeoutOverride(enable bool) *Config {
|
||||
|
@ -335,6 +392,10 @@ func mergeInConfig(dst *Config, other *Config) {
|
|||
dst.S3UseAccelerate = other.S3UseAccelerate
|
||||
}
|
||||
|
||||
if other.UseDualStack != nil {
|
||||
dst.UseDualStack = other.UseDualStack
|
||||
}
|
||||
|
||||
if other.EC2MetadataDisableTimeoutOverride != nil {
|
||||
dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package aws
|
|||
|
||||
import "time"
|
||||
|
||||
// String returns a pointer to of the string value passed in.
|
||||
// String returns a pointer to the string value passed in.
|
||||
func String(v string) *string {
|
||||
return &v
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ func StringValueMap(src map[string]*string) map[string]string {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Bool returns a pointer to of the bool value passed in.
|
||||
// Bool returns a pointer to the bool value passed in.
|
||||
func Bool(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ func BoolValueMap(src map[string]*bool) map[string]bool {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Int returns a pointer to of the int value passed in.
|
||||
// Int returns a pointer to the int value passed in.
|
||||
func Int(v int) *int {
|
||||
return &v
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ func IntValueMap(src map[string]*int) map[string]int {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Int64 returns a pointer to of the int64 value passed in.
|
||||
// Int64 returns a pointer to the int64 value passed in.
|
||||
func Int64(v int64) *int64 {
|
||||
return &v
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ func Int64ValueMap(src map[string]*int64) map[string]int64 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Float64 returns a pointer to of the float64 value passed in.
|
||||
// Float64 returns a pointer to the float64 value passed in.
|
||||
func Float64(v float64) *float64 {
|
||||
return &v
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ func Float64ValueMap(src map[string]*float64) map[string]float64 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Time returns a pointer to of the time.Time value passed in.
|
||||
// Time returns a pointer to the time.Time value passed in.
|
||||
func Time(v time.Time) *time.Time {
|
||||
return &v
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ import (
|
|||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
|
@ -67,6 +69,34 @@ var SDKVersionUserAgentHandler = request.NamedHandler{
|
|||
|
||||
var reStatusCode = regexp.MustCompile(`^(\d{3})`)
|
||||
|
||||
// ValidateReqSigHandler is a request handler to ensure that the request's
|
||||
// signature doesn't expire before it is sent. This can happen when a request
|
||||
// is built and signed signficantly before it is sent. Or signficant delays
|
||||
// occur whne retrying requests that would cause the signature to expire.
|
||||
var ValidateReqSigHandler = request.NamedHandler{
|
||||
Name: "core.ValidateReqSigHandler",
|
||||
Fn: func(r *request.Request) {
|
||||
// Unsigned requests are not signed
|
||||
if r.Config.Credentials == credentials.AnonymousCredentials {
|
||||
return
|
||||
}
|
||||
|
||||
signedTime := r.Time
|
||||
if !r.LastSignedAt.IsZero() {
|
||||
signedTime = r.LastSignedAt
|
||||
}
|
||||
|
||||
// 10 minutes to allow for some clock skew/delays in transmission.
|
||||
// Would be improved with aws/aws-sdk-go#423
|
||||
if signedTime.Add(10 * time.Minute).After(time.Now()) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("request expired, resigning")
|
||||
r.Sign()
|
||||
},
|
||||
}
|
||||
|
||||
// SendHandler is a request handler to send service request using HTTP client.
|
||||
var SendHandler = request.NamedHandler{Name: "core.SendHandler", Fn: func(r *request.Request) {
|
||||
var err error
|
||||
|
|
|
@ -34,7 +34,7 @@ var (
|
|||
//
|
||||
// Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider.
|
||||
// In this example EnvProvider will first check if any credentials are available
|
||||
// vai the environment variables. If there are none ChainProvider will check
|
||||
// via the environment variables. If there are none ChainProvider will check
|
||||
// the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider
|
||||
// does not return any credentials ChainProvider will return the error
|
||||
// ErrNoValidProvidersFoundInChain
|
||||
|
|
191
vendor/src/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
vendored
Normal file
191
vendor/src/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
// Package endpointcreds provides support for retrieving credentials from an
|
||||
// arbitrary HTTP endpoint.
|
||||
//
|
||||
// The credentials endpoint Provider can receive both static and refreshable
|
||||
// credentials that will expire. Credentials are static when an "Expiration"
|
||||
// value is not provided in the endpoint's response.
|
||||
//
|
||||
// Static credentials will never expire once they have been retrieved. The format
|
||||
// of the static credentials response:
|
||||
// {
|
||||
// "AccessKeyId" : "MUA...",
|
||||
// "SecretAccessKey" : "/7PC5om....",
|
||||
// }
|
||||
//
|
||||
// Refreshable credentials will expire within the "ExpiryWindow" of the Expiration
|
||||
// value in the response. The format of the refreshable credentials response:
|
||||
// {
|
||||
// "AccessKeyId" : "MUA...",
|
||||
// "SecretAccessKey" : "/7PC5om....",
|
||||
// "Token" : "AQoDY....=",
|
||||
// "Expiration" : "2016-02-25T06:03:31Z"
|
||||
// }
|
||||
//
|
||||
// Errors should be returned in the following format and only returned with 400
|
||||
// or 500 HTTP status codes.
|
||||
// {
|
||||
// "code": "ErrorCode",
|
||||
// "message": "Helpful error message."
|
||||
// }
|
||||
package endpointcreds
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// ProviderName is the name of the credentials provider.
|
||||
const ProviderName = `CredentialsEndpointProvider`
|
||||
|
||||
// Provider satisfies the credentials.Provider interface, and is a client to
|
||||
// retrieve credentials from an arbitrary endpoint.
|
||||
type Provider struct {
|
||||
staticCreds bool
|
||||
credentials.Expiry
|
||||
|
||||
// Requires a AWS Client to make HTTP requests to the endpoint with.
|
||||
// the Endpoint the request will be made to is provided by the aws.Config's
|
||||
// Endpoint value.
|
||||
Client *client.Client
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
// with expiring credentials do not cause request to fail unexpectedly
|
||||
// due to ExpiredTokenException exceptions.
|
||||
//
|
||||
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||
// 10 seconds before the credentials are actually expired.
|
||||
//
|
||||
// If ExpiryWindow is 0 or less it will be ignored.
|
||||
ExpiryWindow time.Duration
|
||||
}
|
||||
|
||||
// NewProviderClient returns a credentials Provider for retrieving AWS credentials
|
||||
// from arbitrary endpoint.
|
||||
func NewProviderClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) credentials.Provider {
|
||||
p := &Provider{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "CredentialsEndpoint",
|
||||
Endpoint: endpoint,
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
p.Client.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||
p.Client.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
p.Client.Handlers.Validate.Clear()
|
||||
p.Client.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// NewCredentialsClient returns a Credentials wrapper for retrieving credentials
|
||||
// from an arbitrary endpoint concurrently. The client will request the
|
||||
func NewCredentialsClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) *credentials.Credentials {
|
||||
return credentials.NewCredentials(NewProviderClient(cfg, handlers, endpoint, options...))
|
||||
}
|
||||
|
||||
// IsExpired returns true if the credentials retrieved are expired, or not yet
|
||||
// retrieved.
|
||||
func (p *Provider) IsExpired() bool {
|
||||
if p.staticCreds {
|
||||
return false
|
||||
}
|
||||
return p.Expiry.IsExpired()
|
||||
}
|
||||
|
||||
// Retrieve will attempt to request the credentials from the endpoint the Provider
|
||||
// was configured for. And error will be returned if the retrieval fails.
|
||||
func (p *Provider) Retrieve() (credentials.Value, error) {
|
||||
resp, err := p.getCredentials()
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName},
|
||||
awserr.New("CredentialsEndpointError", "failed to load credentials", err)
|
||||
}
|
||||
|
||||
if resp.Expiration != nil {
|
||||
p.SetExpiration(*resp.Expiration, p.ExpiryWindow)
|
||||
} else {
|
||||
p.staticCreds = true
|
||||
}
|
||||
|
||||
return credentials.Value{
|
||||
AccessKeyID: resp.AccessKeyID,
|
||||
SecretAccessKey: resp.SecretAccessKey,
|
||||
SessionToken: resp.Token,
|
||||
ProviderName: ProviderName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type getCredentialsOutput struct {
|
||||
Expiration *time.Time
|
||||
AccessKeyID string
|
||||
SecretAccessKey string
|
||||
Token string
|
||||
}
|
||||
|
||||
type errorOutput struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (p *Provider) getCredentials() (*getCredentialsOutput, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetCredentials",
|
||||
HTTPMethod: "GET",
|
||||
}
|
||||
|
||||
out := &getCredentialsOutput{}
|
||||
req := p.Client.NewRequest(op, nil, out)
|
||||
req.HTTPRequest.Header.Set("Accept", "application/json")
|
||||
|
||||
return out, req.Send()
|
||||
}
|
||||
|
||||
func validateEndpointHandler(r *request.Request) {
|
||||
if len(r.ClientInfo.Endpoint) == 0 {
|
||||
r.Error = aws.ErrMissingEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalHandler(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
|
||||
out := r.Data.(*getCredentialsOutput)
|
||||
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil {
|
||||
r.Error = awserr.New("SerializationError",
|
||||
"failed to decode endpoint credentials",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalError(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
|
||||
var errOut errorOutput
|
||||
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&errOut); err != nil {
|
||||
r.Error = awserr.New("SerializationError",
|
||||
"failed to decode endpoint credentials",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
// Response body format is not consistent between metadata endpoints.
|
||||
// Grab the error message as a string and include that as the source error
|
||||
r.Error = awserr.New(errOut.Code, errOut.Message, nil)
|
||||
}
|
|
@ -30,13 +30,22 @@ func NewStaticCredentials(id, secret, token string) *Credentials {
|
|||
}})
|
||||
}
|
||||
|
||||
// NewStaticCredentialsFromCreds returns a pointer to a new Credentials object
|
||||
// wrapping the static credentials value provide. Same as NewStaticCredentials
|
||||
// but takes the creds Value instead of individual fields
|
||||
func NewStaticCredentialsFromCreds(creds Value) *Credentials {
|
||||
return NewCredentials(&StaticProvider{Value: creds})
|
||||
}
|
||||
|
||||
// Retrieve returns the credentials or error if the credentials are invalid.
|
||||
func (s *StaticProvider) Retrieve() (Value, error) {
|
||||
if s.AccessKeyID == "" || s.SecretAccessKey == "" {
|
||||
return Value{ProviderName: StaticProviderName}, ErrStaticCredentialsEmpty
|
||||
}
|
||||
|
||||
s.Value.ProviderName = StaticProviderName
|
||||
if len(s.Value.ProviderName) == 0 {
|
||||
s.Value.ProviderName = StaticProviderName
|
||||
}
|
||||
return s.Value, nil
|
||||
}
|
||||
|
||||
|
|
161
vendor/src/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
vendored
Normal file
161
vendor/src/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
// Package stscreds are credential Providers to retrieve STS AWS credentials.
|
||||
//
|
||||
// STS provides multiple ways to retrieve credentials which can be used when making
|
||||
// future AWS service API operation calls.
|
||||
package stscreds
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
|
||||
// ProviderName provides a name of AssumeRole provider
|
||||
const ProviderName = "AssumeRoleProvider"
|
||||
|
||||
// AssumeRoler represents the minimal subset of the STS client API used by this provider.
|
||||
type AssumeRoler interface {
|
||||
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
|
||||
}
|
||||
|
||||
// DefaultDuration is the default amount of time in minutes that the credentials
|
||||
// will be valid for.
|
||||
var DefaultDuration = time.Duration(15) * time.Minute
|
||||
|
||||
// AssumeRoleProvider retrieves temporary credentials from the STS service, and
|
||||
// keeps track of their expiration time. This provider must be used explicitly,
|
||||
// as it is not included in the credentials chain.
|
||||
type AssumeRoleProvider struct {
|
||||
credentials.Expiry
|
||||
|
||||
// STS client to make assume role request with.
|
||||
Client AssumeRoler
|
||||
|
||||
// Role to be assumed.
|
||||
RoleARN string
|
||||
|
||||
// Session name, if you wish to reuse the credentials elsewhere.
|
||||
RoleSessionName string
|
||||
|
||||
// Expiry duration of the STS credentials. Defaults to 15 minutes if not set.
|
||||
Duration time.Duration
|
||||
|
||||
// Optional ExternalID to pass along, defaults to nil if not set.
|
||||
ExternalID *string
|
||||
|
||||
// The policy plain text must be 2048 bytes or shorter. However, an internal
|
||||
// conversion compresses it into a packed binary format with a separate limit.
|
||||
// The PackedPolicySize response element indicates by percentage how close to
|
||||
// the upper size limit the policy is, with 100% equaling the maximum allowed
|
||||
// size.
|
||||
Policy *string
|
||||
|
||||
// The identification number of the MFA device that is associated with the user
|
||||
// who is making the AssumeRole call. Specify this value if the trust policy
|
||||
// of the role being assumed includes a condition that requires MFA authentication.
|
||||
// The value is either the serial number for a hardware device (such as GAHT12345678)
|
||||
// or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user).
|
||||
SerialNumber *string
|
||||
|
||||
// The value provided by the MFA device, if the trust policy of the role being
|
||||
// assumed requires MFA (that is, if the policy includes a condition that tests
|
||||
// for MFA). If the role being assumed requires MFA and if the TokenCode value
|
||||
// is missing or expired, the AssumeRole call returns an "access denied" error.
|
||||
TokenCode *string
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
// with expiring credentials do not cause request to fail unexpectedly
|
||||
// due to ExpiredTokenException exceptions.
|
||||
//
|
||||
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||
// 10 seconds before the credentials are actually expired.
|
||||
//
|
||||
// If ExpiryWindow is 0 or less it will be ignored.
|
||||
ExpiryWindow time.Duration
|
||||
}
|
||||
|
||||
// NewCredentials returns a pointer to a new Credentials object wrapping the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// Takes a Config provider to create the STS client. The ConfigProvider is
|
||||
// satisfied by the session.Session type.
|
||||
func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: sts.New(c),
|
||||
RoleARN: roleARN,
|
||||
Duration: DefaultDuration,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// Takes an AssumeRoler which can be satisfiede by the STS client.
|
||||
func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: svc,
|
||||
RoleARN: roleARN,
|
||||
Duration: DefaultDuration,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// Retrieve generates a new set of temporary credentials using STS.
|
||||
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
||||
|
||||
// Apply defaults where parameters are not set.
|
||||
if p.RoleSessionName == "" {
|
||||
// Try to work out a role name that will hopefully end up unique.
|
||||
p.RoleSessionName = fmt.Sprintf("%d", time.Now().UTC().UnixNano())
|
||||
}
|
||||
if p.Duration == 0 {
|
||||
// Expire as often as AWS permits.
|
||||
p.Duration = DefaultDuration
|
||||
}
|
||||
input := &sts.AssumeRoleInput{
|
||||
DurationSeconds: aws.Int64(int64(p.Duration / time.Second)),
|
||||
RoleArn: aws.String(p.RoleARN),
|
||||
RoleSessionName: aws.String(p.RoleSessionName),
|
||||
ExternalId: p.ExternalID,
|
||||
}
|
||||
if p.Policy != nil {
|
||||
input.Policy = p.Policy
|
||||
}
|
||||
if p.SerialNumber != nil && p.TokenCode != nil {
|
||||
input.SerialNumber = p.SerialNumber
|
||||
input.TokenCode = p.TokenCode
|
||||
}
|
||||
roleOutput, err := p.Client.AssumeRole(input)
|
||||
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName}, err
|
||||
}
|
||||
|
||||
// We will proactively generate new credentials before they expire.
|
||||
p.SetExpiration(*roleOutput.Credentials.Expiration, p.ExpiryWindow)
|
||||
|
||||
return credentials.Value{
|
||||
AccessKeyID: *roleOutput.Credentials.AccessKeyId,
|
||||
SecretAccessKey: *roleOutput.Credentials.SecretAccessKey,
|
||||
SessionToken: *roleOutput.Credentials.SessionToken,
|
||||
ProviderName: ProviderName,
|
||||
}, nil
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
package defaults
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
|
@ -70,6 +72,7 @@ func Handlers() request.Handlers {
|
|||
handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler)
|
||||
handlers.Build.AfterEachFn = request.HandlerListStopOnError
|
||||
handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.ValidateReqSigHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||
|
@ -83,16 +86,45 @@ func Handlers() request.Handlers {
|
|||
// is available if you need to reset the credentials of an
|
||||
// existing service client or session's Config.
|
||||
func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials {
|
||||
endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName, *cfg.Region, true)
|
||||
|
||||
return credentials.NewCredentials(&credentials.ChainProvider{
|
||||
VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
|
||||
Providers: []credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
&ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.NewClient(*cfg, handlers, endpoint, signingRegion),
|
||||
ExpiryWindow: 5 * time.Minute,
|
||||
},
|
||||
}})
|
||||
RemoteCredProvider(*cfg, handlers),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// RemoteCredProvider returns a credenitials provider for the default remote
|
||||
// endpoints such as EC2 or ECS Roles.
|
||||
func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||
ecsCredURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
|
||||
|
||||
if len(ecsCredURI) > 0 {
|
||||
return ecsCredProvider(cfg, handlers, ecsCredURI)
|
||||
}
|
||||
|
||||
return ec2RoleProvider(cfg, handlers)
|
||||
}
|
||||
|
||||
func ecsCredProvider(cfg aws.Config, handlers request.Handlers, uri string) credentials.Provider {
|
||||
const host = `169.254.170.2`
|
||||
|
||||
return endpointcreds.NewProviderClient(cfg, handlers,
|
||||
fmt.Sprintf("http://%s%s", host, uri),
|
||||
func(p *endpointcreds.Provider) {
|
||||
p.ExpiryWindow = 5 * time.Minute
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||
endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName,
|
||||
aws.StringValue(cfg.Region), true, false)
|
||||
|
||||
return &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.NewClient(cfg, handlers, endpoint, signingRegion),
|
||||
ExpiryWindow: 5 * time.Minute,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package ec2metadata
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -27,6 +28,27 @@ func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
|||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetUserData returns the userdata that was configured for the service. If
|
||||
// there is no user-data setup for the EC2 instance a "NotFoundError" error
|
||||
// code will be returned.
|
||||
func (c *EC2Metadata) GetUserData() (string, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetUserData",
|
||||
HTTPMethod: "GET",
|
||||
HTTPPath: path.Join("/", "user-data"),
|
||||
}
|
||||
|
||||
output := &metadataOutput{}
|
||||
req := c.NewRequest(op, nil, output)
|
||||
req.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
||||
if r.HTTPResponse.StatusCode == http.StatusNotFound {
|
||||
r.Error = awserr.New("NotFoundError", "user-data not found", r.Error)
|
||||
}
|
||||
})
|
||||
|
||||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetDynamicData uses the path provided to request information from the EC2
|
||||
// instance metadata service for dynamic data. The content will be returned
|
||||
// as a string, or error if the request failed.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build go1.5
|
||||
|
||||
package request
|
||||
|
||||
import (
|
||||
|
@ -9,20 +7,13 @@ import (
|
|||
)
|
||||
|
||||
func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request {
|
||||
req := &http.Request{
|
||||
URL: &url.URL{},
|
||||
Header: http.Header{},
|
||||
Close: r.Close,
|
||||
Body: body,
|
||||
Host: r.Host,
|
||||
Method: r.Method,
|
||||
Proto: r.Proto,
|
||||
ContentLength: r.ContentLength,
|
||||
// Cancel will be deprecated in 1.7 and will be replaced with Context
|
||||
Cancel: r.Cancel,
|
||||
}
|
||||
|
||||
req := new(http.Request)
|
||||
*req = *r
|
||||
req.URL = &url.URL{}
|
||||
*req.URL = *r.URL
|
||||
req.Body = body
|
||||
|
||||
req.Header = http.Header{}
|
||||
for k, v := range r.Header {
|
||||
for _, vv := range v {
|
||||
req.Header.Add(k, vv)
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
// +build !go1.5
|
||||
|
||||
package request
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request {
|
||||
req := &http.Request{
|
||||
URL: &url.URL{},
|
||||
Header: http.Header{},
|
||||
Close: r.Close,
|
||||
Body: body,
|
||||
Host: r.Host,
|
||||
Method: r.Method,
|
||||
Proto: r.Proto,
|
||||
ContentLength: r.ContentLength,
|
||||
}
|
||||
|
||||
*req.URL = *r.URL
|
||||
for k, v := range r.Header {
|
||||
for _, vv := range v {
|
||||
req.Header.Add(k, vv)
|
||||
}
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
|
@ -9,7 +9,7 @@ import (
|
|||
// with retrying requests
|
||||
type offsetReader struct {
|
||||
buf io.ReadSeeker
|
||||
lock sync.RWMutex
|
||||
lock sync.Mutex
|
||||
closed bool
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,8 @@ func newOffsetReader(buf io.ReadSeeker, offset int64) *offsetReader {
|
|||
return reader
|
||||
}
|
||||
|
||||
// Close is a thread-safe close. Uses the write lock.
|
||||
// Close will close the instance of the offset reader's access to
|
||||
// the underlying io.ReadSeeker.
|
||||
func (o *offsetReader) Close() error {
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
@ -29,10 +30,10 @@ func (o *offsetReader) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Read is a thread-safe read using a read lock.
|
||||
// Read is a thread-safe read of the underlying io.ReadSeeker
|
||||
func (o *offsetReader) Read(p []byte) (int, error) {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
||||
if o.closed {
|
||||
return 0, io.EOF
|
||||
|
@ -41,6 +42,14 @@ func (o *offsetReader) Read(p []byte) (int, error) {
|
|||
return o.buf.Read(p)
|
||||
}
|
||||
|
||||
// Seek is a thread-safe seeking operation.
|
||||
func (o *offsetReader) Seek(offset int64, whence int) (int64, error) {
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
||||
return o.buf.Seek(offset, whence)
|
||||
}
|
||||
|
||||
// CloseAndCopy will return a new offsetReader with a copy of the old buffer
|
||||
// and close the old buffer.
|
||||
func (o *offsetReader) CloseAndCopy(offset int64) *offsetReader {
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
@ -39,8 +38,15 @@ type Request struct {
|
|||
RetryDelay time.Duration
|
||||
NotHoist bool
|
||||
SignedHeaderVals http.Header
|
||||
LastSignedAt time.Time
|
||||
|
||||
built bool
|
||||
|
||||
// Need to persist an intermideant body betweend the input Body and HTTP
|
||||
// request body because the HTTP Client's transport can maintain a reference
|
||||
// to the HTTP request's body after the client has returned. This value is
|
||||
// safe to use concurrently and rewraps the input Body for each HTTP request.
|
||||
safeBody *offsetReader
|
||||
}
|
||||
|
||||
// An Operation is the service API operation to be made.
|
||||
|
@ -72,15 +78,11 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
|
|||
if method == "" {
|
||||
method = "POST"
|
||||
}
|
||||
p := operation.HTTPPath
|
||||
if p == "" {
|
||||
p = "/"
|
||||
}
|
||||
|
||||
httpReq, _ := http.NewRequest(method, "", nil)
|
||||
|
||||
var err error
|
||||
httpReq.URL, err = url.Parse(clientInfo.Endpoint + p)
|
||||
httpReq.URL, err = url.Parse(clientInfo.Endpoint + operation.HTTPPath)
|
||||
if err != nil {
|
||||
httpReq.URL = &url.URL{}
|
||||
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
|
||||
|
@ -138,8 +140,8 @@ func (r *Request) SetStringBody(s string) {
|
|||
|
||||
// SetReaderBody will set the request's body reader.
|
||||
func (r *Request) SetReaderBody(reader io.ReadSeeker) {
|
||||
r.HTTPRequest.Body = newOffsetReader(reader, 0)
|
||||
r.Body = reader
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
// Presign returns the request's signed URL. Error will be returned
|
||||
|
@ -208,7 +210,7 @@ func (r *Request) Build() error {
|
|||
return r.Error
|
||||
}
|
||||
|
||||
// Sign will sign the request retuning error if errors are encountered.
|
||||
// Sign will sign the request returning error if errors are encountered.
|
||||
//
|
||||
// Send will build the request prior to signing. All Sign Handlers will
|
||||
// be executed in the order they were set.
|
||||
|
@ -223,6 +225,24 @@ func (r *Request) Sign() error {
|
|||
return r.Error
|
||||
}
|
||||
|
||||
// ResetBody rewinds the request body backto its starting position, and
|
||||
// set's the HTTP Request body reference. When the body is read prior
|
||||
// to being sent in the HTTP request it will need to be rewound.
|
||||
func (r *Request) ResetBody() {
|
||||
if r.safeBody != nil {
|
||||
r.safeBody.Close()
|
||||
}
|
||||
|
||||
r.safeBody = newOffsetReader(r.Body, r.BodyStart)
|
||||
r.HTTPRequest.Body = r.safeBody
|
||||
}
|
||||
|
||||
// GetBody will return an io.ReadSeeker of the Request's underlying
|
||||
// input body with a concurrency safe wrapper.
|
||||
func (r *Request) GetBody() io.ReadSeeker {
|
||||
return r.safeBody
|
||||
}
|
||||
|
||||
// Send will send the request returning error if errors are encountered.
|
||||
//
|
||||
// Send will sign the request prior to sending. All Send Handlers will
|
||||
|
@ -234,6 +254,8 @@ func (r *Request) Sign() error {
|
|||
//
|
||||
// readLoop() and getConn(req *Request, cm connectMethod)
|
||||
// https://github.com/golang/go/blob/master/src/net/http/transport.go
|
||||
//
|
||||
// Send will not close the request.Request's body.
|
||||
func (r *Request) Send() error {
|
||||
for {
|
||||
if aws.BoolValue(r.Retryable) {
|
||||
|
@ -242,21 +264,15 @@ func (r *Request) Send() error {
|
|||
r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount))
|
||||
}
|
||||
|
||||
var body io.ReadCloser
|
||||
if reader, ok := r.HTTPRequest.Body.(*offsetReader); ok {
|
||||
body = reader.CloseAndCopy(r.BodyStart)
|
||||
} else {
|
||||
if r.Config.Logger != nil {
|
||||
r.Config.Logger.Log("Request body type has been overwritten. May cause race conditions")
|
||||
}
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
body = ioutil.NopCloser(r.Body)
|
||||
}
|
||||
// The previous http.Request will have a reference to the r.Body
|
||||
// and the HTTP Client's Transport may still be reading from
|
||||
// the request's body even though the Client's Do returned.
|
||||
r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, nil)
|
||||
r.ResetBody()
|
||||
|
||||
r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, body)
|
||||
// Closing response body to ensure that no response body is leaked
|
||||
// between retry attempts.
|
||||
if r.HTTPResponse != nil && r.HTTPResponse.Body != nil {
|
||||
// Closing response body. Since we are setting a new request to send off, this
|
||||
// response will get squashed and leaked.
|
||||
r.HTTPResponse.Body.Close()
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +300,6 @@ func (r *Request) Send() error {
|
|||
debugLogReqError(r, "Send Request", true, err)
|
||||
continue
|
||||
}
|
||||
|
||||
r.Handlers.UnmarshalMeta.Run(r)
|
||||
r.Handlers.ValidateResponse.Run(r)
|
||||
if r.Error != nil {
|
||||
|
|
223
vendor/src/github.com/aws/aws-sdk-go/aws/session/doc.go
vendored
Normal file
223
vendor/src/github.com/aws/aws-sdk-go/aws/session/doc.go
vendored
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
Package session provides configuration for the SDK's service clients.
|
||||
|
||||
Sessions can be shared across all service clients that share the same base
|
||||
configuration. The Session is built from the SDK's default configuration and
|
||||
request handlers.
|
||||
|
||||
Sessions should be cached when possible, because creating a new Session will
|
||||
load all configuration values from the environment, and config files each time
|
||||
the Session is created. Sharing the Session value across all of your service
|
||||
clients will ensure the configuration is loaded the fewest number of times possible.
|
||||
|
||||
Concurrency
|
||||
|
||||
Sessions are safe to use concurrently as long as the Session is not being
|
||||
modified. The SDK will not modify the Session once the Session has been created.
|
||||
Creating service clients concurrently from a shared Session is safe.
|
||||
|
||||
Sessions from Shared Config
|
||||
|
||||
Sessions can be created using the method above that will only load the
|
||||
additional config if the AWS_SDK_LOAD_CONFIG environment variable is set.
|
||||
Alternatively you can explicitly create a Session with shared config enabled.
|
||||
To do this you can use NewSessionWithOptions to configure how the Session will
|
||||
be created. Using the NewSessionWithOptions with SharedConfigState set to
|
||||
SharedConfigEnabled will create the session as if the AWS_SDK_LOAD_CONFIG
|
||||
environment variable was set.
|
||||
|
||||
Creating Sessions
|
||||
|
||||
When creating Sessions optional aws.Config values can be passed in that will
|
||||
override the default, or loaded config values the Session is being created
|
||||
with. This allows you to provide additional, or case based, configuration
|
||||
as needed.
|
||||
|
||||
By default NewSession will only load credentials from the shared credentials
|
||||
file (~/.aws/credentials). If the AWS_SDK_LOAD_CONFIG environment variable is
|
||||
set to a truthy value the Session will be created from the configuration
|
||||
values from the shared config (~/.aws/config) and shared credentials
|
||||
(~/.aws/credentials) files. See the section Sessions from Shared Config for
|
||||
more information.
|
||||
|
||||
Create a Session with the default config and request handlers. With credentials
|
||||
region, and profile loaded from the environment and shared config automatically.
|
||||
Requires the AWS_PROFILE to be set, or "default" is used.
|
||||
|
||||
// Create Session
|
||||
sess, err := session.NewSession()
|
||||
|
||||
// Create a Session with a custom region
|
||||
sess, err := session.NewSession(&aws.Config{Region: aws.String("us-east-1")})
|
||||
|
||||
// Create a S3 client instance from a session
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
// Handle Session creation error
|
||||
}
|
||||
svc := s3.New(sess)
|
||||
|
||||
Create Session With Option Overrides
|
||||
|
||||
In addition to NewSession, Sessions can be created using NewSessionWithOptions.
|
||||
This func allows you to control and override how the Session will be created
|
||||
through code instead of being driven by environment variables only.
|
||||
|
||||
Use NewSessionWithOptions when you want to provide the config profile, or
|
||||
override the shared config state (AWS_SDK_LOAD_CONFIG).
|
||||
|
||||
// Equivalent to session.NewSession()
|
||||
sess, err := session.NewSessionWithOptions(session.Options{})
|
||||
|
||||
// Specify profile to load for the session's config
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Profile: "profile_name",
|
||||
})
|
||||
|
||||
// Specify profile for config and region for requests
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: aws.Config{Region: aws.String("us-east-1")},
|
||||
Profile: "profile_name",
|
||||
})
|
||||
|
||||
// Force enable Shared Config support
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
SharedConfigState: SharedConfigEnable,
|
||||
})
|
||||
|
||||
Adding Handlers
|
||||
|
||||
You can add handlers to a session for processing HTTP requests. All service
|
||||
clients that use the session inherit the handlers. For example, the following
|
||||
handler logs every request and its payload made by a service client:
|
||||
|
||||
// Create a session, and add additional handlers for all service
|
||||
// clients created with the Session to inherit. Adds logging handler.
|
||||
sess, err := session.NewSession()
|
||||
sess.Handlers.Send.PushFront(func(r *request.Request) {
|
||||
// Log every request made and its payload
|
||||
logger.Println("Request: %s/%s, Payload: %s",
|
||||
r.ClientInfo.ServiceName, r.Operation, r.Params)
|
||||
})
|
||||
|
||||
Deprecated "New" function
|
||||
|
||||
The New session function has been deprecated because it does not provide good
|
||||
way to return errors that occur when loading the configuration files and values.
|
||||
Because of this, NewSession was created so errors can be retrieved when
|
||||
creating a session fails.
|
||||
|
||||
Shared Config Fields
|
||||
|
||||
By default the SDK will only load the shared credentials file's (~/.aws/credentials)
|
||||
credentials values, and all other config is provided by the environment variables,
|
||||
SDK defaults, and user provided aws.Config values.
|
||||
|
||||
If the AWS_SDK_LOAD_CONFIG environment variable is set, or SharedConfigEnable
|
||||
option is used to create the Session the full shared config values will be
|
||||
loaded. This includes credentials, region, and support for assume role. In
|
||||
addition the Session will load its configuration from both the shared config
|
||||
file (~/.aws/config) and shared credentials file (~/.aws/credentials). Both
|
||||
files have the same format.
|
||||
|
||||
If both config files are present the configuration from both files will be
|
||||
read. The Session will be created from configuration values from the shared
|
||||
credentials file (~/.aws/credentials) over those in the shared credentials
|
||||
file (~/.aws/config).
|
||||
|
||||
Credentials are the values the SDK should use for authenticating requests with
|
||||
AWS Services. They arfrom a configuration file will need to include both
|
||||
aws_access_key_id and aws_secret_access_key must be provided together in the
|
||||
same file to be considered valid. The values will be ignored if not a complete
|
||||
group. aws_session_token is an optional field that can be provided if both of
|
||||
the other two fields are also provided.
|
||||
|
||||
aws_access_key_id = AKID
|
||||
aws_secret_access_key = SECRET
|
||||
aws_session_token = TOKEN
|
||||
|
||||
Assume Role values allow you to configure the SDK to assume an IAM role using
|
||||
a set of credentials provided in a config file via the source_profile field.
|
||||
Both "role_arn" and "source_profile" are required. The SDK does not support
|
||||
assuming a role with MFA token Via the Session's constructor. You can use the
|
||||
stscreds.AssumeRoleProvider credentials provider to specify custom
|
||||
configuration and support for MFA.
|
||||
|
||||
role_arn = arn:aws:iam::<account_number>:role/<role_name>
|
||||
source_profile = profile_with_creds
|
||||
external_id = 1234
|
||||
mfa_serial = not supported!
|
||||
role_session_name = session_name
|
||||
|
||||
Region is the region the SDK should use for looking up AWS service endpoints
|
||||
and signing requests.
|
||||
|
||||
region = us-east-1
|
||||
|
||||
Environment Variables
|
||||
|
||||
When a Session is created several environment variables can be set to adjust
|
||||
how the SDK functions, and what configuration data it loads when creating
|
||||
Sessions. All environment values are optional, but some values like credentials
|
||||
require multiple of the values to set or the partial values will be ignored.
|
||||
All environment variable values are strings unless otherwise noted.
|
||||
|
||||
Environment configuration values. If set both Access Key ID and Secret Access
|
||||
Key must be provided. Session Token and optionally also be provided, but is
|
||||
not required.
|
||||
|
||||
# Access Key ID
|
||||
AWS_ACCESS_KEY_ID=AKID
|
||||
AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.
|
||||
|
||||
# Secret Access Key
|
||||
AWS_SECRET_ACCESS_KEY=SECRET
|
||||
AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.
|
||||
|
||||
# Session Token
|
||||
AWS_SESSION_TOKEN=TOKEN
|
||||
|
||||
Region value will instruct the SDK where to make service API requests to. If is
|
||||
not provided in the environment the region must be provided before a service
|
||||
client request is made.
|
||||
|
||||
AWS_REGION=us-east-1
|
||||
|
||||
# AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||
# and AWS_REGION is not also set.
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
|
||||
Profile name the SDK should load use when loading shared config from the
|
||||
configuration files. If not provided "default" will be used as the profile name.
|
||||
|
||||
AWS_PROFILE=my_profile
|
||||
|
||||
# AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||
# and AWS_PROFILE is not also set.
|
||||
AWS_DEFAULT_PROFILE=my_profile
|
||||
|
||||
SDK load config instructs the SDK to load the shared config in addition to
|
||||
shared credentials. This also expands the configuration loaded so the shared
|
||||
credentials will have parity with the shared config file. This also enables
|
||||
Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
|
||||
env values as well.
|
||||
|
||||
AWS_SDK_LOAD_CONFIG=1
|
||||
|
||||
Shared credentials file path can be set to instruct the SDK to use an alternative
|
||||
file for the shared credentials. If not set the file will be loaded from
|
||||
$HOME/.aws/credentials on Linux/Unix based systems, and
|
||||
%USERPROFILE%\.aws\credentials on Windows.
|
||||
|
||||
AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials
|
||||
|
||||
Shared config file path can be set to instruct the SDK to use an alternative
|
||||
file for the shared config. If not set the file will be loaded from
|
||||
$HOME/.aws/config on Linux/Unix based systems, and
|
||||
%USERPROFILE%\.aws\config on Windows.
|
||||
|
||||
AWS_CONFIG_FILE=$HOME/my_shared_config
|
||||
|
||||
|
||||
*/
|
||||
package session
|
188
vendor/src/github.com/aws/aws-sdk-go/aws/session/env_config.go
vendored
Normal file
188
vendor/src/github.com/aws/aws-sdk-go/aws/session/env_config.go
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
// envConfig is a collection of environment values the SDK will read
|
||||
// setup config from. All environment values are optional. But some values
|
||||
// such as credentials require multiple values to be complete or the values
|
||||
// will be ignored.
|
||||
type envConfig struct {
|
||||
// Environment configuration values. If set both Access Key ID and Secret Access
|
||||
// Key must be provided. Session Token and optionally also be provided, but is
|
||||
// not required.
|
||||
//
|
||||
// # Access Key ID
|
||||
// AWS_ACCESS_KEY_ID=AKID
|
||||
// AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.
|
||||
//
|
||||
// # Secret Access Key
|
||||
// AWS_SECRET_ACCESS_KEY=SECRET
|
||||
// AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.
|
||||
//
|
||||
// # Session Token
|
||||
// AWS_SESSION_TOKEN=TOKEN
|
||||
Creds credentials.Value
|
||||
|
||||
// Region value will instruct the SDK where to make service API requests to. If is
|
||||
// not provided in the environment the region must be provided before a service
|
||||
// client request is made.
|
||||
//
|
||||
// AWS_REGION=us-east-1
|
||||
//
|
||||
// # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||
// # and AWS_REGION is not also set.
|
||||
// AWS_DEFAULT_REGION=us-east-1
|
||||
Region string
|
||||
|
||||
// Profile name the SDK should load use when loading shared configuration from the
|
||||
// shared configuration files. If not provided "default" will be used as the
|
||||
// profile name.
|
||||
//
|
||||
// AWS_PROFILE=my_profile
|
||||
//
|
||||
// # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||
// # and AWS_PROFILE is not also set.
|
||||
// AWS_DEFAULT_PROFILE=my_profile
|
||||
Profile string
|
||||
|
||||
// SDK load config instructs the SDK to load the shared config in addition to
|
||||
// shared credentials. This also expands the configuration loaded from the shared
|
||||
// credentials to have parity with the shared config file. This also enables
|
||||
// Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
|
||||
// env values as well.
|
||||
//
|
||||
// AWS_SDK_LOAD_CONFIG=1
|
||||
EnableSharedConfig bool
|
||||
|
||||
// Shared credentials file path can be set to instruct the SDK to use an alternate
|
||||
// file for the shared credentials. If not set the file will be loaded from
|
||||
// $HOME/.aws/credentials on Linux/Unix based systems, and
|
||||
// %USERPROFILE%\.aws\credentials on Windows.
|
||||
//
|
||||
// AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials
|
||||
SharedCredentialsFile string
|
||||
|
||||
// Shared config file path can be set to instruct the SDK to use an alternate
|
||||
// file for the shared config. If not set the file will be loaded from
|
||||
// $HOME/.aws/config on Linux/Unix based systems, and
|
||||
// %USERPROFILE%\.aws\config on Windows.
|
||||
//
|
||||
// AWS_CONFIG_FILE=$HOME/my_shared_config
|
||||
SharedConfigFile string
|
||||
}
|
||||
|
||||
var (
|
||||
credAccessEnvKey = []string{
|
||||
"AWS_ACCESS_KEY_ID",
|
||||
"AWS_ACCESS_KEY",
|
||||
}
|
||||
credSecretEnvKey = []string{
|
||||
"AWS_SECRET_ACCESS_KEY",
|
||||
"AWS_SECRET_KEY",
|
||||
}
|
||||
credSessionEnvKey = []string{
|
||||
"AWS_SESSION_TOKEN",
|
||||
}
|
||||
|
||||
regionEnvKeys = []string{
|
||||
"AWS_REGION",
|
||||
"AWS_DEFAULT_REGION", // Only read if AWS_SDK_LOAD_CONFIG is also set
|
||||
}
|
||||
profileEnvKeys = []string{
|
||||
"AWS_PROFILE",
|
||||
"AWS_DEFAULT_PROFILE", // Only read if AWS_SDK_LOAD_CONFIG is also set
|
||||
}
|
||||
)
|
||||
|
||||
// loadEnvConfig retrieves the SDK's environment configuration.
|
||||
// See `envConfig` for the values that will be retrieved.
|
||||
//
|
||||
// If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value
|
||||
// the shared SDK config will be loaded in addition to the SDK's specific
|
||||
// configuration values.
|
||||
func loadEnvConfig() envConfig {
|
||||
enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG"))
|
||||
return envConfigLoad(enableSharedConfig)
|
||||
}
|
||||
|
||||
// loadEnvSharedConfig retrieves the SDK's environment configuration, and the
|
||||
// SDK shared config. See `envConfig` for the values that will be retrieved.
|
||||
//
|
||||
// Loads the shared configuration in addition to the SDK's specific configuration.
|
||||
// This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG`
|
||||
// environment variable is set.
|
||||
func loadSharedEnvConfig() envConfig {
|
||||
return envConfigLoad(true)
|
||||
}
|
||||
|
||||
func envConfigLoad(enableSharedConfig bool) envConfig {
|
||||
cfg := envConfig{}
|
||||
|
||||
cfg.EnableSharedConfig = enableSharedConfig
|
||||
|
||||
setFromEnvVal(&cfg.Creds.AccessKeyID, credAccessEnvKey)
|
||||
setFromEnvVal(&cfg.Creds.SecretAccessKey, credSecretEnvKey)
|
||||
setFromEnvVal(&cfg.Creds.SessionToken, credSessionEnvKey)
|
||||
|
||||
// Require logical grouping of credentials
|
||||
if len(cfg.Creds.AccessKeyID) == 0 || len(cfg.Creds.SecretAccessKey) == 0 {
|
||||
cfg.Creds = credentials.Value{}
|
||||
} else {
|
||||
cfg.Creds.ProviderName = "EnvConfigCredentials"
|
||||
}
|
||||
|
||||
regionKeys := regionEnvKeys
|
||||
profileKeys := profileEnvKeys
|
||||
if !cfg.EnableSharedConfig {
|
||||
regionKeys = regionKeys[:1]
|
||||
profileKeys = profileKeys[:1]
|
||||
}
|
||||
|
||||
setFromEnvVal(&cfg.Region, regionKeys)
|
||||
setFromEnvVal(&cfg.Profile, profileKeys)
|
||||
|
||||
cfg.SharedCredentialsFile = sharedCredentialsFilename()
|
||||
cfg.SharedConfigFile = sharedConfigFilename()
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func setFromEnvVal(dst *string, keys []string) {
|
||||
for _, k := range keys {
|
||||
if v := os.Getenv(k); len(v) > 0 {
|
||||
*dst = v
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sharedCredentialsFilename() string {
|
||||
if name := os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(name) > 0 {
|
||||
return name
|
||||
}
|
||||
|
||||
return filepath.Join(userHomeDir(), ".aws", "credentials")
|
||||
}
|
||||
|
||||
func sharedConfigFilename() string {
|
||||
if name := os.Getenv("AWS_CONFIG_FILE"); len(name) > 0 {
|
||||
return name
|
||||
}
|
||||
|
||||
return filepath.Join(userHomeDir(), ".aws", "config")
|
||||
}
|
||||
|
||||
func userHomeDir() string {
|
||||
homeDir := os.Getenv("HOME") // *nix
|
||||
if len(homeDir) == 0 { // windows
|
||||
homeDir = os.Getenv("USERPROFILE")
|
||||
}
|
||||
|
||||
return homeDir
|
||||
}
|
|
@ -1,17 +1,14 @@
|
|||
// Package session provides a way to create service clients with shared configuration
|
||||
// and handlers.
|
||||
//
|
||||
// Generally this package should be used instead of the `defaults` package.
|
||||
//
|
||||
// A session should be used to share configurations and request handlers between multiple
|
||||
// service clients. When service clients need specific configuration aws.Config can be
|
||||
// used to provide additional configuration directly to the service client.
|
||||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
|
@ -21,36 +18,204 @@ import (
|
|||
// store configurations and request handlers for those services.
|
||||
//
|
||||
// Sessions are safe to create service clients concurrently, but it is not safe
|
||||
// to mutate the session concurrently.
|
||||
// to mutate the Session concurrently.
|
||||
//
|
||||
// The Session satisfies the service client's client.ClientConfigProvider.
|
||||
type Session struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// New creates a new instance of the handlers merging in the provided Configs
|
||||
// on top of the SDK's default configurations. Once the session is created it
|
||||
// can be mutated to modify Configs or Handlers. The session is safe to be read
|
||||
// concurrently, but it should not be written to concurrently.
|
||||
// New creates a new instance of the handlers merging in the provided configs
|
||||
// on top of the SDK's default configurations. Once the Session is created it
|
||||
// can be mutated to modify the Config or Handlers. The Session is safe to be
|
||||
// read concurrently, but it should not be written to concurrently.
|
||||
//
|
||||
// Example:
|
||||
// // Create a session with the default config and request handlers.
|
||||
// sess := session.New()
|
||||
// If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New
|
||||
// method could now encounter an error when loading the configuration. When
|
||||
// The environment variable is set, and an error occurs, New will return a
|
||||
// session that will fail all requests reporting the error that occured while
|
||||
// loading the session. Use NewSession to get the error when creating the
|
||||
// session.
|
||||
//
|
||||
// // Create a session with a custom region
|
||||
// sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded, in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file.
|
||||
//
|
||||
// // Create a session, and add additional handlers for all service
|
||||
// // clients created with the session to inherit. Adds logging handler.
|
||||
// sess := session.New()
|
||||
// sess.Handlers.Send.PushFront(func(r *request.Request) {
|
||||
// // Log every request made and its payload
|
||||
// logger.Println("Request: %s/%s, Payload: %s", r.ClientInfo.ServiceName, r.Operation, r.Params)
|
||||
// Deprecated: Use NewSession functiions to create sessions instead. NewSession
|
||||
// has the same functionality as New except an error can be returned when the
|
||||
// func is called instead of waiting to receive an error until a request is made.
|
||||
func New(cfgs ...*aws.Config) *Session {
|
||||
// load initial config from environment
|
||||
envCfg := loadEnvConfig()
|
||||
|
||||
if envCfg.EnableSharedConfig {
|
||||
s, err := newSession(envCfg, cfgs...)
|
||||
if err != nil {
|
||||
// Old session.New expected all errors to be discovered when
|
||||
// a request is made, and would report the errors then. This
|
||||
// needs to be replicated if an error occurs while creating
|
||||
// the session.
|
||||
msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " +
|
||||
"Use session.NewSession to handle errors occuring during session creation."
|
||||
|
||||
// Session creation failed, need to report the error and prevent
|
||||
// any requests from succeeding.
|
||||
s = &Session{Config: defaults.Config()}
|
||||
s.Config.MergeIn(cfgs...)
|
||||
s.Config.Logger.Log("ERROR:", msg, "Error:", err)
|
||||
s.Handlers.Validate.PushBack(func(r *request.Request) {
|
||||
r.Error = err
|
||||
})
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
return oldNewSession(cfgs...)
|
||||
}
|
||||
|
||||
// NewSession returns a new Session created from SDK defaults, config files,
|
||||
// environment, and user provided config files. Once the Session is created
|
||||
// it can be mutated to modify the Config or Handlers. The Session is safe to
|
||||
// be read concurrently, but it should not be written to concurrently.
|
||||
//
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file. Enabling the Shared Config will also allow the Session
|
||||
// to be built with retrieving credentials with AssumeRole set in the config.
|
||||
//
|
||||
// See the NewSessionWithOptions func for information on how to override or
|
||||
// control through code how the Session will be created. Such as specifing the
|
||||
// config profile, and controlling if shared config is enabled or not.
|
||||
func NewSession(cfgs ...*aws.Config) (*Session, error) {
|
||||
envCfg := loadEnvConfig()
|
||||
|
||||
return newSession(envCfg, cfgs...)
|
||||
}
|
||||
|
||||
// SharedConfigState provides the ability to optionally override the state
|
||||
// of the session's creation based on the shared config being enabled or
|
||||
// disabled.
|
||||
type SharedConfigState int
|
||||
|
||||
const (
|
||||
// SharedConfigStateFromEnv does not override any state of the
|
||||
// AWS_SDK_LOAD_CONFIG env var. It is the default value of the
|
||||
// SharedConfigState type.
|
||||
SharedConfigStateFromEnv SharedConfigState = iota
|
||||
|
||||
// SharedConfigDisable overrides the AWS_SDK_LOAD_CONFIG env var value
|
||||
// and disables the shared config functionality.
|
||||
SharedConfigDisable
|
||||
|
||||
// SharedConfigEnable overrides the AWS_SDK_LOAD_CONFIG env var value
|
||||
// and enables the shared config functionality.
|
||||
SharedConfigEnable
|
||||
)
|
||||
|
||||
// Options provides the means to control how a Session is created and what
|
||||
// configuration values will be loaded.
|
||||
//
|
||||
type Options struct {
|
||||
// Provides config values for the SDK to use when creating service clients
|
||||
// and making API requests to services. Any value set in with this field
|
||||
// will override the associated value provided by the SDK defaults,
|
||||
// environment or config files where relevent.
|
||||
//
|
||||
// If not set, configuration values from from SDK defaults, environment,
|
||||
// config will be used.
|
||||
Config aws.Config
|
||||
|
||||
// Overrides the config profile the Session should be created from. If not
|
||||
// set the value of the environment variable will be loaded (AWS_PROFILE,
|
||||
// or AWS_DEFAULT_PROFILE if the Shared Config is enabled).
|
||||
//
|
||||
// If not set and environment variables are not set the "default"
|
||||
// (DefaultSharedConfigProfile) will be used as the profile to load the
|
||||
// session config from.
|
||||
Profile string
|
||||
|
||||
// Instructs how the Session will be created based on the AWS_SDK_LOAD_CONFIG
|
||||
// environment variable. By default a Session will be created using the
|
||||
// value provided by the AWS_SDK_LOAD_CONFIG environment variable.
|
||||
//
|
||||
// Setting this value to SharedConfigEnable or SharedConfigDisable
|
||||
// will allow you to override the AWS_SDK_LOAD_CONFIG environment variable
|
||||
// and enable or disable the shared config functionality.
|
||||
SharedConfigState SharedConfigState
|
||||
}
|
||||
|
||||
// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
|
||||
// environment, and user provided config files. This func uses the Options
|
||||
// values to configure how the Session is created.
|
||||
//
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file. Enabling the Shared Config will also allow the Session
|
||||
// to be built with retrieving credentials with AssumeRole set in the config.
|
||||
//
|
||||
// // Equivalent to session.New
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{})
|
||||
//
|
||||
// // Specify profile to load for the session's config
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// Profile: "profile_name",
|
||||
// })
|
||||
//
|
||||
// // Create a S3 client instance from a session
|
||||
// sess := session.New()
|
||||
// svc := s3.New(sess)
|
||||
func New(cfgs ...*aws.Config) *Session {
|
||||
// // Specify profile for config and region for requests
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// Config: aws.Config{Region: aws.String("us-east-1")},
|
||||
// Profile: "profile_name",
|
||||
// })
|
||||
//
|
||||
// // Force enable Shared Config support
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// SharedConfigState: SharedConfigEnable,
|
||||
// })
|
||||
func NewSessionWithOptions(opts Options) (*Session, error) {
|
||||
var envCfg envConfig
|
||||
if opts.SharedConfigState == SharedConfigEnable {
|
||||
envCfg = loadSharedEnvConfig()
|
||||
} else {
|
||||
envCfg = loadEnvConfig()
|
||||
}
|
||||
|
||||
if len(opts.Profile) > 0 {
|
||||
envCfg.Profile = opts.Profile
|
||||
}
|
||||
|
||||
switch opts.SharedConfigState {
|
||||
case SharedConfigDisable:
|
||||
envCfg.EnableSharedConfig = false
|
||||
case SharedConfigEnable:
|
||||
envCfg.EnableSharedConfig = true
|
||||
}
|
||||
|
||||
return newSession(envCfg, &opts.Config)
|
||||
}
|
||||
|
||||
// Must is a helper function to ensure the Session is valid and there was no
|
||||
// error when calling a NewSession function.
|
||||
//
|
||||
// This helper is intended to be used in variable initialization to load the
|
||||
// Session and configuration at startup. Such as:
|
||||
//
|
||||
// var sess = session.Must(session.NewSession())
|
||||
func Must(sess *Session, err error) *Session {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return sess
|
||||
}
|
||||
|
||||
func oldNewSession(cfgs ...*aws.Config) *Session {
|
||||
cfg := defaults.Config()
|
||||
handlers := defaults.Handlers()
|
||||
|
||||
|
@ -72,6 +237,115 @@ func New(cfgs ...*aws.Config) *Session {
|
|||
return s
|
||||
}
|
||||
|
||||
func newSession(envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
||||
cfg := defaults.Config()
|
||||
handlers := defaults.Handlers()
|
||||
|
||||
// Get a merged version of the user provided config to determine if
|
||||
// credentials were.
|
||||
userCfg := &aws.Config{}
|
||||
userCfg.MergeIn(cfgs...)
|
||||
|
||||
// Order config files will be loaded in with later files overwriting
|
||||
// previous config file values.
|
||||
cfgFiles := []string{envCfg.SharedConfigFile, envCfg.SharedCredentialsFile}
|
||||
if !envCfg.EnableSharedConfig {
|
||||
// The shared config file (~/.aws/config) is only loaded if instructed
|
||||
// to load via the envConfig.EnableSharedConfig (AWS_SDK_LOAD_CONFIG).
|
||||
cfgFiles = cfgFiles[1:]
|
||||
}
|
||||
|
||||
// Load additional config from file(s)
|
||||
sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers)
|
||||
|
||||
s := &Session{
|
||||
Config: cfg,
|
||||
Handlers: handlers,
|
||||
}
|
||||
|
||||
initHandlers(s)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers) {
|
||||
// Merge in user provided configuration
|
||||
cfg.MergeIn(userCfg)
|
||||
|
||||
// Region if not already set by user
|
||||
if len(aws.StringValue(cfg.Region)) == 0 {
|
||||
if len(envCfg.Region) > 0 {
|
||||
cfg.WithRegion(envCfg.Region)
|
||||
} else if envCfg.EnableSharedConfig && len(sharedCfg.Region) > 0 {
|
||||
cfg.WithRegion(sharedCfg.Region)
|
||||
}
|
||||
}
|
||||
|
||||
// Configure credentials if not already set
|
||||
if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
|
||||
if len(envCfg.Creds.AccessKeyID) > 0 {
|
||||
cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||
envCfg.Creds,
|
||||
)
|
||||
} else if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.RoleARN) > 0 && sharedCfg.AssumeRoleSource != nil {
|
||||
cfgCp := *cfg
|
||||
cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||
sharedCfg.AssumeRoleSource.Creds,
|
||||
)
|
||||
cfg.Credentials = stscreds.NewCredentials(
|
||||
&Session{
|
||||
Config: &cfgCp,
|
||||
Handlers: handlers.Copy(),
|
||||
},
|
||||
sharedCfg.AssumeRole.RoleARN,
|
||||
func(opt *stscreds.AssumeRoleProvider) {
|
||||
opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName
|
||||
|
||||
if len(sharedCfg.AssumeRole.ExternalID) > 0 {
|
||||
opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID)
|
||||
}
|
||||
|
||||
// MFA not supported
|
||||
},
|
||||
)
|
||||
} else if len(sharedCfg.Creds.AccessKeyID) > 0 {
|
||||
cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||
sharedCfg.Creds,
|
||||
)
|
||||
} else {
|
||||
// Fallback to default credentials provider, include mock errors
|
||||
// for the credential chain so user can identify why credentials
|
||||
// failed to be retrieved.
|
||||
cfg.Credentials = credentials.NewCredentials(&credentials.ChainProvider{
|
||||
VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
|
||||
Providers: []credentials.Provider{
|
||||
&credProviderError{Err: awserr.New("EnvAccessKeyNotFound", "failed to find credentials in the environment.", nil)},
|
||||
&credProviderError{Err: awserr.New("SharedCredsLoad", fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil)},
|
||||
defaults.RemoteCredProvider(*cfg, handlers),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type credProviderError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
var emptyCreds = credentials.Value{}
|
||||
|
||||
func (c credProviderError) Retrieve() (credentials.Value, error) {
|
||||
return credentials.Value{}, c.Err
|
||||
}
|
||||
func (c credProviderError) IsExpired() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func initHandlers(s *Session) {
|
||||
// Add the Validate parameter handler if it is not disabled.
|
||||
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
|
||||
|
@ -80,12 +354,11 @@ func initHandlers(s *Session) {
|
|||
}
|
||||
}
|
||||
|
||||
// Copy creates and returns a copy of the current session, coping the config
|
||||
// Copy creates and returns a copy of the current Session, coping the config
|
||||
// and handlers. If any additional configs are provided they will be merged
|
||||
// on top of the session's copied config.
|
||||
// on top of the Session's copied config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a copy of the current session, configured for the us-west-2 region.
|
||||
// // Create a copy of the current Session, configured for the us-west-2 region.
|
||||
// sess.Copy(&aws.Config{Region: aws.String("us-west-2")})
|
||||
func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
||||
newSession := &Session{
|
||||
|
@ -101,15 +374,15 @@ func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
|||
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
||||
// configure the service client instances. Passing the Session to the service
|
||||
// client's constructor (New) will use this method to configure the client.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.New()
|
||||
// s3.New(sess)
|
||||
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
|
||||
s = s.Copy(cfgs...)
|
||||
endpoint, signingRegion := endpoints.NormalizeEndpoint(
|
||||
aws.StringValue(s.Config.Endpoint), serviceName,
|
||||
aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL))
|
||||
aws.StringValue(s.Config.Endpoint),
|
||||
serviceName,
|
||||
aws.StringValue(s.Config.Region),
|
||||
aws.BoolValue(s.Config.DisableSSL),
|
||||
aws.BoolValue(s.Config.UseDualStack),
|
||||
)
|
||||
|
||||
return client.Config{
|
||||
Config: s.Config,
|
||||
|
|
295
vendor/src/github.com/aws/aws-sdk-go/aws/session/shared_config.go
vendored
Normal file
295
vendor/src/github.com/aws/aws-sdk-go/aws/session/shared_config.go
vendored
Normal file
|
@ -0,0 +1,295 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/go-ini/ini"
|
||||
)
|
||||
|
||||
const (
|
||||
// Static Credentials group
|
||||
accessKeyIDKey = `aws_access_key_id` // group required
|
||||
secretAccessKey = `aws_secret_access_key` // group required
|
||||
sessionTokenKey = `aws_session_token` // optional
|
||||
|
||||
// Assume Role Credentials group
|
||||
roleArnKey = `role_arn` // group required
|
||||
sourceProfileKey = `source_profile` // group required
|
||||
externalIDKey = `external_id` // optional
|
||||
mfaSerialKey = `mfa_serial` // optional
|
||||
roleSessionNameKey = `role_session_name` // optional
|
||||
|
||||
// Additional Config fields
|
||||
regionKey = `region`
|
||||
|
||||
// DefaultSharedConfigProfile is the default profile to be used when
|
||||
// loading configuration from the config files if another profile name
|
||||
// is not provided.
|
||||
DefaultSharedConfigProfile = `default`
|
||||
)
|
||||
|
||||
type assumeRoleConfig struct {
|
||||
RoleARN string
|
||||
SourceProfile string
|
||||
ExternalID string
|
||||
MFASerial string
|
||||
RoleSessionName string
|
||||
}
|
||||
|
||||
// sharedConfig represents the configuration fields of the SDK config files.
|
||||
type sharedConfig struct {
|
||||
// Credentials values from the config file. Both aws_access_key_id
|
||||
// and aws_secret_access_key must be provided together in the same file
|
||||
// to be considered valid. The values will be ignored if not a complete group.
|
||||
// aws_session_token is an optional field that can be provided if both of the
|
||||
// other two fields are also provided.
|
||||
//
|
||||
// aws_access_key_id
|
||||
// aws_secret_access_key
|
||||
// aws_session_token
|
||||
Creds credentials.Value
|
||||
|
||||
AssumeRole assumeRoleConfig
|
||||
AssumeRoleSource *sharedConfig
|
||||
|
||||
// Region is the region the SDK should use for looking up AWS service endpoints
|
||||
// and signing requests.
|
||||
//
|
||||
// region
|
||||
Region string
|
||||
}
|
||||
|
||||
type sharedConfigFile struct {
|
||||
Filename string
|
||||
IniData *ini.File
|
||||
}
|
||||
|
||||
// loadSharedConfig retrieves the configuration from the list of files
|
||||
// using the profile provided. The order the files are listed will determine
|
||||
// precedence. Values in subsequent files will overwrite values defined in
|
||||
// earlier files.
|
||||
//
|
||||
// For example, given two files A and B. Both define credentials. If the order
|
||||
// of the files are A then B, B's credential values will be used instead of A's.
|
||||
//
|
||||
// See sharedConfig.setFromFile for information how the config files
|
||||
// will be loaded.
|
||||
func loadSharedConfig(profile string, filenames []string) (sharedConfig, error) {
|
||||
if len(profile) == 0 {
|
||||
profile = DefaultSharedConfigProfile
|
||||
}
|
||||
|
||||
files, err := loadSharedConfigIniFiles(filenames)
|
||||
if err != nil {
|
||||
return sharedConfig{}, err
|
||||
}
|
||||
|
||||
cfg := sharedConfig{}
|
||||
if err = cfg.setFromIniFiles(profile, files); err != nil {
|
||||
return sharedConfig{}, err
|
||||
}
|
||||
|
||||
if len(cfg.AssumeRole.SourceProfile) > 0 {
|
||||
if err := cfg.setAssumeRoleSource(profile, files); err != nil {
|
||||
return sharedConfig{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func loadSharedConfigIniFiles(filenames []string) ([]sharedConfigFile, error) {
|
||||
files := make([]sharedConfigFile, 0, len(filenames))
|
||||
|
||||
for _, filename := range filenames {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
// Skip files which can't be opened and read for whatever reason
|
||||
continue
|
||||
}
|
||||
|
||||
f, err := ini.Load(b)
|
||||
if err != nil {
|
||||
return nil, SharedConfigLoadError{Filename: filename}
|
||||
}
|
||||
|
||||
files = append(files, sharedConfigFile{
|
||||
Filename: filename, IniData: f,
|
||||
})
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (cfg *sharedConfig) setAssumeRoleSource(origProfile string, files []sharedConfigFile) error {
|
||||
var assumeRoleSrc sharedConfig
|
||||
|
||||
// Multiple level assume role chains are not support
|
||||
if cfg.AssumeRole.SourceProfile == origProfile {
|
||||
assumeRoleSrc = *cfg
|
||||
assumeRoleSrc.AssumeRole = assumeRoleConfig{}
|
||||
} else {
|
||||
err := assumeRoleSrc.setFromIniFiles(cfg.AssumeRole.SourceProfile, files)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(assumeRoleSrc.Creds.AccessKeyID) == 0 {
|
||||
return SharedConfigAssumeRoleError{RoleARN: cfg.AssumeRole.RoleARN}
|
||||
}
|
||||
|
||||
cfg.AssumeRoleSource = &assumeRoleSrc
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *sharedConfig) setFromIniFiles(profile string, files []sharedConfigFile) error {
|
||||
// Trim files from the list that don't exist.
|
||||
for _, f := range files {
|
||||
if err := cfg.setFromIniFile(profile, f); err != nil {
|
||||
if _, ok := err.(SharedConfigProfileNotExistsError); ok {
|
||||
// Ignore proviles missings
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setFromFile loads the configuration from the file using
|
||||
// the profile provided. A sharedConfig pointer type value is used so that
|
||||
// multiple config file loadings can be chained.
|
||||
//
|
||||
// Only loads complete logically grouped values, and will not set fields in cfg
|
||||
// for incomplete grouped values in the config. Such as credentials. For example
|
||||
// if a config file only includes aws_access_key_id but no aws_secret_access_key
|
||||
// the aws_access_key_id will be ignored.
|
||||
func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile) error {
|
||||
section, err := file.IniData.GetSection(profile)
|
||||
if err != nil {
|
||||
// Fallback to to alternate profile name: profile <name>
|
||||
section, err = file.IniData.GetSection(fmt.Sprintf("profile %s", profile))
|
||||
if err != nil {
|
||||
return SharedConfigProfileNotExistsError{Profile: profile, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
// Shared Credentials
|
||||
akid := section.Key(accessKeyIDKey).String()
|
||||
secret := section.Key(secretAccessKey).String()
|
||||
if len(akid) > 0 && len(secret) > 0 {
|
||||
cfg.Creds = credentials.Value{
|
||||
AccessKeyID: akid,
|
||||
SecretAccessKey: secret,
|
||||
SessionToken: section.Key(sessionTokenKey).String(),
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", file.Filename),
|
||||
}
|
||||
}
|
||||
|
||||
// Assume Role
|
||||
roleArn := section.Key(roleArnKey).String()
|
||||
srcProfile := section.Key(sourceProfileKey).String()
|
||||
if len(roleArn) > 0 && len(srcProfile) > 0 {
|
||||
cfg.AssumeRole = assumeRoleConfig{
|
||||
RoleARN: roleArn,
|
||||
SourceProfile: srcProfile,
|
||||
ExternalID: section.Key(externalIDKey).String(),
|
||||
MFASerial: section.Key(mfaSerialKey).String(),
|
||||
RoleSessionName: section.Key(roleSessionNameKey).String(),
|
||||
}
|
||||
}
|
||||
|
||||
// Region
|
||||
if v := section.Key(regionKey).String(); len(v) > 0 {
|
||||
cfg.Region = v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SharedConfigLoadError is an error for the shared config file failed to load.
|
||||
type SharedConfigLoadError struct {
|
||||
Filename string
|
||||
Err error
|
||||
}
|
||||
|
||||
// Code is the short id of the error.
|
||||
func (e SharedConfigLoadError) Code() string {
|
||||
return "SharedConfigLoadError"
|
||||
}
|
||||
|
||||
// Message is the description of the error
|
||||
func (e SharedConfigLoadError) Message() string {
|
||||
return fmt.Sprintf("failed to load config file, %s", e.Filename)
|
||||
}
|
||||
|
||||
// OrigErr is the underlying error that caused the failure.
|
||||
func (e SharedConfigLoadError) OrigErr() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (e SharedConfigLoadError) Error() string {
|
||||
return awserr.SprintError(e.Code(), e.Message(), "", e.Err)
|
||||
}
|
||||
|
||||
// SharedConfigProfileNotExistsError is an error for the shared config when
|
||||
// the profile was not find in the config file.
|
||||
type SharedConfigProfileNotExistsError struct {
|
||||
Profile string
|
||||
Err error
|
||||
}
|
||||
|
||||
// Code is the short id of the error.
|
||||
func (e SharedConfigProfileNotExistsError) Code() string {
|
||||
return "SharedConfigProfileNotExistsError"
|
||||
}
|
||||
|
||||
// Message is the description of the error
|
||||
func (e SharedConfigProfileNotExistsError) Message() string {
|
||||
return fmt.Sprintf("failed to get profile, %s", e.Profile)
|
||||
}
|
||||
|
||||
// OrigErr is the underlying error that caused the failure.
|
||||
func (e SharedConfigProfileNotExistsError) OrigErr() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (e SharedConfigProfileNotExistsError) Error() string {
|
||||
return awserr.SprintError(e.Code(), e.Message(), "", e.Err)
|
||||
}
|
||||
|
||||
// SharedConfigAssumeRoleError is an error for the shared config when the
|
||||
// profile contains assume role information, but that information is invalid
|
||||
// or not complete.
|
||||
type SharedConfigAssumeRoleError struct {
|
||||
RoleARN string
|
||||
}
|
||||
|
||||
// Code is the short id of the error.
|
||||
func (e SharedConfigAssumeRoleError) Code() string {
|
||||
return "SharedConfigAssumeRoleError"
|
||||
}
|
||||
|
||||
// Message is the description of the error
|
||||
func (e SharedConfigAssumeRoleError) Message() string {
|
||||
return fmt.Sprintf("failed to load assume role for %s, source profile has no shared credentials",
|
||||
e.RoleARN)
|
||||
}
|
||||
|
||||
// OrigErr is the underlying error that caused the failure.
|
||||
func (e SharedConfigAssumeRoleError) OrigErr() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (e SharedConfigAssumeRoleError) Error() string {
|
||||
return awserr.SprintError(e.Code(), e.Message(), "", nil)
|
||||
}
|
24
vendor/src/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path.go
vendored
Normal file
24
vendor/src/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path.go
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
// +build go1.5
|
||||
|
||||
package v4
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getURIPath(u *url.URL) string {
|
||||
var uri string
|
||||
|
||||
if len(u.Opaque) > 0 {
|
||||
uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/")
|
||||
} else {
|
||||
uri = u.EscapedPath()
|
||||
}
|
||||
|
||||
if len(uri) == 0 {
|
||||
uri = "/"
|
||||
}
|
||||
|
||||
return uri
|
||||
}
|
24
vendor/src/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path_1_4.go
vendored
Normal file
24
vendor/src/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path_1_4.go
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
// +build !go1.5
|
||||
|
||||
package v4
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getURIPath(u *url.URL) string {
|
||||
var uri string
|
||||
|
||||
if len(u.Opaque) > 0 {
|
||||
uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/")
|
||||
} else {
|
||||
uri = u.Path
|
||||
}
|
||||
|
||||
if len(uri) == 0 {
|
||||
uri = "/"
|
||||
}
|
||||
|
||||
return uri
|
||||
}
|
713
vendor/src/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go
vendored
Normal file
713
vendor/src/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go
vendored
Normal file
|
@ -0,0 +1,713 @@
|
|||
// Package v4 implements signing for AWS V4 signer
|
||||
//
|
||||
// Provides request signing for request that need to be signed with
|
||||
// AWS V4 Signatures.
|
||||
//
|
||||
// Standalone Signer
|
||||
//
|
||||
// Generally using the signer outside of the SDK should not require any additional
|
||||
// logic when using Go v1.5 or higher. The signer does this by taking advantage
|
||||
// of the URL.EscapedPath method. If your request URI requires additional escaping
|
||||
// you many need to use the URL.Opaque to define what the raw URI should be sent
|
||||
// to the service as.
|
||||
//
|
||||
// The signer will first check the URL.Opaque field, and use its value if set.
|
||||
// The signer does require the URL.Opaque field to be set in the form of:
|
||||
//
|
||||
// "//<hostname>/<path>"
|
||||
//
|
||||
// // e.g.
|
||||
// "//example.com/some/path"
|
||||
//
|
||||
// The leading "//" and hostname are required or the URL.Opaque escaping will
|
||||
// not work correctly.
|
||||
//
|
||||
// If URL.Opaque is not set the signer will fallback to the URL.EscapedPath()
|
||||
// method and using the returned value. If you're using Go v1.4 you must set
|
||||
// URL.Opaque if the URI path needs escaping. If URL.Opaque is not set with
|
||||
// Go v1.5 the signer will fallback to URL.Path.
|
||||
//
|
||||
// AWS v4 signature validation requires that the canonical string's URI path
|
||||
// element must be the URI escaped form of the HTTP request's path.
|
||||
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
//
|
||||
// The Go HTTP client will perform escaping automatically on the request. Some
|
||||
// of these escaping may cause signature validation errors because the HTTP
|
||||
// request differs from the URI path or query that the signature was generated.
|
||||
// https://golang.org/pkg/net/url/#URL.EscapedPath
|
||||
//
|
||||
// Because of this, it is recommended that when using the signer outside of the
|
||||
// SDK that explicitly escaping the request prior to being signed is preferable,
|
||||
// and will help prevent signature validation errors. This can be done by setting
|
||||
// the URL.Opaque or URL.RawPath. The SDK will use URL.Opaque first and then
|
||||
// call URL.EscapedPath() if Opaque is not set.
|
||||
//
|
||||
// Test `TestStandaloneSign` provides a complete example of using the signer
|
||||
// outside of the SDK and pre-escaping the URI path.
|
||||
package v4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
authHeaderPrefix = "AWS4-HMAC-SHA256"
|
||||
timeFormat = "20060102T150405Z"
|
||||
shortTimeFormat = "20060102"
|
||||
|
||||
// emptyStringSHA256 is a SHA256 of an empty string
|
||||
emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
|
||||
)
|
||||
|
||||
var ignoredHeaders = rules{
|
||||
blacklist{
|
||||
mapRule{
|
||||
"Authorization": struct{}{},
|
||||
"User-Agent": struct{}{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// requiredSignedHeaders is a whitelist for build canonical headers.
|
||||
var requiredSignedHeaders = rules{
|
||||
whitelist{
|
||||
mapRule{
|
||||
"Cache-Control": struct{}{},
|
||||
"Content-Disposition": struct{}{},
|
||||
"Content-Encoding": struct{}{},
|
||||
"Content-Language": struct{}{},
|
||||
"Content-Md5": struct{}{},
|
||||
"Content-Type": struct{}{},
|
||||
"Expires": struct{}{},
|
||||
"If-Match": struct{}{},
|
||||
"If-Modified-Since": struct{}{},
|
||||
"If-None-Match": struct{}{},
|
||||
"If-Unmodified-Since": struct{}{},
|
||||
"Range": struct{}{},
|
||||
"X-Amz-Acl": struct{}{},
|
||||
"X-Amz-Copy-Source": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Match": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Modified-Since": struct{}{},
|
||||
"X-Amz-Copy-Source-If-None-Match": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Unmodified-Since": struct{}{},
|
||||
"X-Amz-Copy-Source-Range": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
|
||||
"X-Amz-Grant-Full-control": struct{}{},
|
||||
"X-Amz-Grant-Read": struct{}{},
|
||||
"X-Amz-Grant-Read-Acp": struct{}{},
|
||||
"X-Amz-Grant-Write": struct{}{},
|
||||
"X-Amz-Grant-Write-Acp": struct{}{},
|
||||
"X-Amz-Metadata-Directive": struct{}{},
|
||||
"X-Amz-Mfa": struct{}{},
|
||||
"X-Amz-Request-Payer": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Algorithm": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Key": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
|
||||
"X-Amz-Storage-Class": struct{}{},
|
||||
"X-Amz-Website-Redirect-Location": struct{}{},
|
||||
},
|
||||
},
|
||||
patterns{"X-Amz-Meta-"},
|
||||
}
|
||||
|
||||
// allowedHoisting is a whitelist for build query headers. The boolean value
|
||||
// represents whether or not it is a pattern.
|
||||
var allowedQueryHoisting = inclusiveRules{
|
||||
blacklist{requiredSignedHeaders},
|
||||
patterns{"X-Amz-"},
|
||||
}
|
||||
|
||||
// Signer applies AWS v4 signing to given request. Use this to sign requests
|
||||
// that need to be signed with AWS V4 Signatures.
|
||||
type Signer struct {
|
||||
// The authentication credentials the request will be signed against.
|
||||
// This value must be set to sign requests.
|
||||
Credentials *credentials.Credentials
|
||||
|
||||
// Sets the log level the signer should use when reporting information to
|
||||
// the logger. If the logger is nil nothing will be logged. See
|
||||
// aws.LogLevelType for more information on available logging levels
|
||||
//
|
||||
// By default nothing will be logged.
|
||||
Debug aws.LogLevelType
|
||||
|
||||
// The logger loging information will be written to. If there the logger
|
||||
// is nil, nothing will be logged.
|
||||
Logger aws.Logger
|
||||
|
||||
// Disables the Signer's moving HTTP header key/value pairs from the HTTP
|
||||
// request header to the request's query string. This is most commonly used
|
||||
// with pre-signed requests preventing headers from being added to the
|
||||
// request's query string.
|
||||
DisableHeaderHoisting bool
|
||||
|
||||
// Disables the automatic escaping of the URI path of the request for the
|
||||
// siganture's canonical string's path. For services that do not need additional
|
||||
// escaping then use this to disable the signer escaping the path.
|
||||
//
|
||||
// S3 is an example of a service that does not need additional escaping.
|
||||
//
|
||||
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
DisableURIPathEscaping bool
|
||||
|
||||
// currentTimeFn returns the time value which represents the current time.
|
||||
// This value should only be used for testing. If it is nil the default
|
||||
// time.Now will be used.
|
||||
currentTimeFn func() time.Time
|
||||
}
|
||||
|
||||
// NewSigner returns a Signer pointer configured with the credentials and optional
|
||||
// option values provided. If not options are provided the Signer will use its
|
||||
// default configuration.
|
||||
func NewSigner(credentials *credentials.Credentials, options ...func(*Signer)) *Signer {
|
||||
v4 := &Signer{
|
||||
Credentials: credentials,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(v4)
|
||||
}
|
||||
|
||||
return v4
|
||||
}
|
||||
|
||||
type signingCtx struct {
|
||||
ServiceName string
|
||||
Region string
|
||||
Request *http.Request
|
||||
Body io.ReadSeeker
|
||||
Query url.Values
|
||||
Time time.Time
|
||||
ExpireTime time.Duration
|
||||
SignedHeaderVals http.Header
|
||||
|
||||
DisableURIPathEscaping bool
|
||||
|
||||
credValues credentials.Value
|
||||
isPresign bool
|
||||
formattedTime string
|
||||
formattedShortTime string
|
||||
|
||||
bodyDigest string
|
||||
signedHeaders string
|
||||
canonicalHeaders string
|
||||
canonicalString string
|
||||
credentialString string
|
||||
stringToSign string
|
||||
signature string
|
||||
authorization string
|
||||
}
|
||||
|
||||
// Sign signs AWS v4 requests with the provided body, service name, region the
|
||||
// request is made to, and time the request is signed at. The signTime allows
|
||||
// you to specify that a request is signed for the future, and cannot be
|
||||
// used until then.
|
||||
//
|
||||
// Returns a list of HTTP headers that were included in the signature or an
|
||||
// error if signing the request failed. Generally for signed requests this value
|
||||
// is not needed as the full request context will be captured by the http.Request
|
||||
// value. It is included for reference though.
|
||||
//
|
||||
// Sign will set the request's Body to be the `body` parameter passed in. If
|
||||
// the body is not already an io.ReadCloser, it will be wrapped within one. If
|
||||
// a `nil` body parameter passed to Sign, the request's Body field will be
|
||||
// also set to nil. Its important to note that this functionality will not
|
||||
// change the request's ContentLength of the request.
|
||||
//
|
||||
// Sign differs from Presign in that it will sign the request using HTTP
|
||||
// header values. This type of signing is intended for http.Request values that
|
||||
// will not be shared, or are shared in a way the header values on the request
|
||||
// will not be lost.
|
||||
//
|
||||
// The requests body is an io.ReadSeeker so the SHA256 of the body can be
|
||||
// generated. To bypass the signer computing the hash you can set the
|
||||
// "X-Amz-Content-Sha256" header with a precomputed value. The signer will
|
||||
// only compute the hash if the request header value is empty.
|
||||
func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region string, signTime time.Time) (http.Header, error) {
|
||||
return v4.signWithBody(r, body, service, region, 0, signTime)
|
||||
}
|
||||
|
||||
// Presign signs AWS v4 requests with the provided body, service name, region
|
||||
// the request is made to, and time the request is signed at. The signTime
|
||||
// allows you to specify that a request is signed for the future, and cannot
|
||||
// be used until then.
|
||||
//
|
||||
// Returns a list of HTTP headers that were included in the signature or an
|
||||
// error if signing the request failed. For presigned requests these headers
|
||||
// and their values must be included on the HTTP request when it is made. This
|
||||
// is helpful to know what header values need to be shared with the party the
|
||||
// presigned request will be distributed to.
|
||||
//
|
||||
// Presign differs from Sign in that it will sign the request using query string
|
||||
// instead of header values. This allows you to share the Presigned Request's
|
||||
// URL with third parties, or distribute it throughout your system with minimal
|
||||
// dependencies.
|
||||
//
|
||||
// Presign also takes an exp value which is the duration the
|
||||
// signed request will be valid after the signing time. This is allows you to
|
||||
// set when the request will expire.
|
||||
//
|
||||
// The requests body is an io.ReadSeeker so the SHA256 of the body can be
|
||||
// generated. To bypass the signer computing the hash you can set the
|
||||
// "X-Amz-Content-Sha256" header with a precomputed value. The signer will
|
||||
// only compute the hash if the request header value is empty.
|
||||
//
|
||||
// Presigning a S3 request will not compute the body's SHA256 hash by default.
|
||||
// This is done due to the general use case for S3 presigned URLs is to share
|
||||
// PUT/GET capabilities. If you would like to include the body's SHA256 in the
|
||||
// presigned request's signature you can set the "X-Amz-Content-Sha256"
|
||||
// HTTP header and that will be included in the request's signature.
|
||||
func (v4 Signer) Presign(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) {
|
||||
return v4.signWithBody(r, body, service, region, exp, signTime)
|
||||
}
|
||||
|
||||
func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) {
|
||||
currentTimeFn := v4.currentTimeFn
|
||||
if currentTimeFn == nil {
|
||||
currentTimeFn = time.Now
|
||||
}
|
||||
|
||||
ctx := &signingCtx{
|
||||
Request: r,
|
||||
Body: body,
|
||||
Query: r.URL.Query(),
|
||||
Time: signTime,
|
||||
ExpireTime: exp,
|
||||
isPresign: exp != 0,
|
||||
ServiceName: service,
|
||||
Region: region,
|
||||
DisableURIPathEscaping: v4.DisableURIPathEscaping,
|
||||
}
|
||||
|
||||
if ctx.isRequestSigned() {
|
||||
ctx.Time = currentTimeFn()
|
||||
ctx.handlePresignRemoval()
|
||||
}
|
||||
|
||||
var err error
|
||||
ctx.credValues, err = v4.Credentials.Get()
|
||||
if err != nil {
|
||||
return http.Header{}, err
|
||||
}
|
||||
|
||||
ctx.assignAmzQueryValues()
|
||||
ctx.build(v4.DisableHeaderHoisting)
|
||||
|
||||
// If the request is not presigned the body should be attached to it. This
|
||||
// prevents the confusion of wanting to send a signed request without
|
||||
// the body the request was signed for attached.
|
||||
if !ctx.isPresign {
|
||||
var reader io.ReadCloser
|
||||
if body != nil {
|
||||
var ok bool
|
||||
if reader, ok = body.(io.ReadCloser); !ok {
|
||||
reader = ioutil.NopCloser(body)
|
||||
}
|
||||
}
|
||||
r.Body = reader
|
||||
}
|
||||
|
||||
if v4.Debug.Matches(aws.LogDebugWithSigning) {
|
||||
v4.logSigningInfo(ctx)
|
||||
}
|
||||
|
||||
return ctx.SignedHeaderVals, nil
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) handlePresignRemoval() {
|
||||
if !ctx.isPresign {
|
||||
return
|
||||
}
|
||||
|
||||
// The credentials have expired for this request. The current signing
|
||||
// is invalid, and needs to be request because the request will fail.
|
||||
ctx.removePresign()
|
||||
|
||||
// Update the request's query string to ensure the values stays in
|
||||
// sync in the case retrieving the new credentials fails.
|
||||
ctx.Request.URL.RawQuery = ctx.Query.Encode()
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) assignAmzQueryValues() {
|
||||
if ctx.isPresign {
|
||||
ctx.Query.Set("X-Amz-Algorithm", authHeaderPrefix)
|
||||
if ctx.credValues.SessionToken != "" {
|
||||
ctx.Query.Set("X-Amz-Security-Token", ctx.credValues.SessionToken)
|
||||
} else {
|
||||
ctx.Query.Del("X-Amz-Security-Token")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.credValues.SessionToken != "" {
|
||||
ctx.Request.Header.Set("X-Amz-Security-Token", ctx.credValues.SessionToken)
|
||||
}
|
||||
}
|
||||
|
||||
// SignRequestHandler is a named request handler the SDK will use to sign
|
||||
// service client request with using the V4 signature.
|
||||
var SignRequestHandler = request.NamedHandler{
|
||||
Name: "v4.SignRequestHandler", Fn: SignSDKRequest,
|
||||
}
|
||||
|
||||
// SignSDKRequest signs an AWS request with the V4 signature. This
|
||||
// request handler is bested used only with the SDK's built in service client's
|
||||
// API operation requests.
|
||||
//
|
||||
// This function should not be used on its on its own, but in conjunction with
|
||||
// an AWS service client's API operation call. To sign a standalone request
|
||||
// not created by a service client's API operation method use the "Sign" or
|
||||
// "Presign" functions of the "Signer" type.
|
||||
//
|
||||
// If the credentials of the request's config are set to
|
||||
// credentials.AnonymousCredentials the request will not be signed.
|
||||
func SignSDKRequest(req *request.Request) {
|
||||
signSDKRequestWithCurrTime(req, time.Now)
|
||||
}
|
||||
func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time) {
|
||||
// If the request does not need to be signed ignore the signing of the
|
||||
// request if the AnonymousCredentials object is used.
|
||||
if req.Config.Credentials == credentials.AnonymousCredentials {
|
||||
return
|
||||
}
|
||||
|
||||
region := req.ClientInfo.SigningRegion
|
||||
if region == "" {
|
||||
region = aws.StringValue(req.Config.Region)
|
||||
}
|
||||
|
||||
name := req.ClientInfo.SigningName
|
||||
if name == "" {
|
||||
name = req.ClientInfo.ServiceName
|
||||
}
|
||||
|
||||
v4 := NewSigner(req.Config.Credentials, func(v4 *Signer) {
|
||||
v4.Debug = req.Config.LogLevel.Value()
|
||||
v4.Logger = req.Config.Logger
|
||||
v4.DisableHeaderHoisting = req.NotHoist
|
||||
v4.currentTimeFn = curTimeFn
|
||||
if name == "s3" {
|
||||
// S3 service should not have any escaping applied
|
||||
v4.DisableURIPathEscaping = true
|
||||
}
|
||||
})
|
||||
|
||||
signingTime := req.Time
|
||||
if !req.LastSignedAt.IsZero() {
|
||||
signingTime = req.LastSignedAt
|
||||
}
|
||||
|
||||
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(),
|
||||
name, region, req.ExpireTime, signingTime,
|
||||
)
|
||||
if err != nil {
|
||||
req.Error = err
|
||||
req.SignedHeaderVals = nil
|
||||
return
|
||||
}
|
||||
|
||||
req.SignedHeaderVals = signedHeaders
|
||||
req.LastSignedAt = curTimeFn()
|
||||
}
|
||||
|
||||
const logSignInfoMsg = `DEBUG: Request Signature:
|
||||
---[ CANONICAL STRING ]-----------------------------
|
||||
%s
|
||||
---[ STRING TO SIGN ]--------------------------------
|
||||
%s%s
|
||||
-----------------------------------------------------`
|
||||
const logSignedURLMsg = `
|
||||
---[ SIGNED URL ]------------------------------------
|
||||
%s`
|
||||
|
||||
func (v4 *Signer) logSigningInfo(ctx *signingCtx) {
|
||||
signedURLMsg := ""
|
||||
if ctx.isPresign {
|
||||
signedURLMsg = fmt.Sprintf(logSignedURLMsg, ctx.Request.URL.String())
|
||||
}
|
||||
msg := fmt.Sprintf(logSignInfoMsg, ctx.canonicalString, ctx.stringToSign, signedURLMsg)
|
||||
v4.Logger.Log(msg)
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) build(disableHeaderHoisting bool) {
|
||||
ctx.buildTime() // no depends
|
||||
ctx.buildCredentialString() // no depends
|
||||
|
||||
unsignedHeaders := ctx.Request.Header
|
||||
if ctx.isPresign {
|
||||
if !disableHeaderHoisting {
|
||||
urlValues := url.Values{}
|
||||
urlValues, unsignedHeaders = buildQuery(allowedQueryHoisting, unsignedHeaders) // no depends
|
||||
for k := range urlValues {
|
||||
ctx.Query[k] = urlValues[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.buildBodyDigest()
|
||||
ctx.buildCanonicalHeaders(ignoredHeaders, unsignedHeaders)
|
||||
ctx.buildCanonicalString() // depends on canon headers / signed headers
|
||||
ctx.buildStringToSign() // depends on canon string
|
||||
ctx.buildSignature() // depends on string to sign
|
||||
|
||||
if ctx.isPresign {
|
||||
ctx.Request.URL.RawQuery += "&X-Amz-Signature=" + ctx.signature
|
||||
} else {
|
||||
parts := []string{
|
||||
authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString,
|
||||
"SignedHeaders=" + ctx.signedHeaders,
|
||||
"Signature=" + ctx.signature,
|
||||
}
|
||||
ctx.Request.Header.Set("Authorization", strings.Join(parts, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildTime() {
|
||||
ctx.formattedTime = ctx.Time.UTC().Format(timeFormat)
|
||||
ctx.formattedShortTime = ctx.Time.UTC().Format(shortTimeFormat)
|
||||
|
||||
if ctx.isPresign {
|
||||
duration := int64(ctx.ExpireTime / time.Second)
|
||||
ctx.Query.Set("X-Amz-Date", ctx.formattedTime)
|
||||
ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10))
|
||||
} else {
|
||||
ctx.Request.Header.Set("X-Amz-Date", ctx.formattedTime)
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildCredentialString() {
|
||||
ctx.credentialString = strings.Join([]string{
|
||||
ctx.formattedShortTime,
|
||||
ctx.Region,
|
||||
ctx.ServiceName,
|
||||
"aws4_request",
|
||||
}, "/")
|
||||
|
||||
if ctx.isPresign {
|
||||
ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString)
|
||||
}
|
||||
}
|
||||
|
||||
func buildQuery(r rule, header http.Header) (url.Values, http.Header) {
|
||||
query := url.Values{}
|
||||
unsignedHeaders := http.Header{}
|
||||
for k, h := range header {
|
||||
if r.IsValid(k) {
|
||||
query[k] = h
|
||||
} else {
|
||||
unsignedHeaders[k] = h
|
||||
}
|
||||
}
|
||||
|
||||
return query, unsignedHeaders
|
||||
}
|
||||
func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) {
|
||||
var headers []string
|
||||
headers = append(headers, "host")
|
||||
for k, v := range header {
|
||||
canonicalKey := http.CanonicalHeaderKey(k)
|
||||
if !r.IsValid(canonicalKey) {
|
||||
continue // ignored header
|
||||
}
|
||||
if ctx.SignedHeaderVals == nil {
|
||||
ctx.SignedHeaderVals = make(http.Header)
|
||||
}
|
||||
|
||||
lowerCaseKey := strings.ToLower(k)
|
||||
if _, ok := ctx.SignedHeaderVals[lowerCaseKey]; ok {
|
||||
// include additional values
|
||||
ctx.SignedHeaderVals[lowerCaseKey] = append(ctx.SignedHeaderVals[lowerCaseKey], v...)
|
||||
continue
|
||||
}
|
||||
|
||||
headers = append(headers, lowerCaseKey)
|
||||
ctx.SignedHeaderVals[lowerCaseKey] = v
|
||||
}
|
||||
sort.Strings(headers)
|
||||
|
||||
ctx.signedHeaders = strings.Join(headers, ";")
|
||||
|
||||
if ctx.isPresign {
|
||||
ctx.Query.Set("X-Amz-SignedHeaders", ctx.signedHeaders)
|
||||
}
|
||||
|
||||
headerValues := make([]string, len(headers))
|
||||
for i, k := range headers {
|
||||
if k == "host" {
|
||||
headerValues[i] = "host:" + ctx.Request.URL.Host
|
||||
} else {
|
||||
headerValues[i] = k + ":" +
|
||||
strings.Join(ctx.SignedHeaderVals[k], ",")
|
||||
}
|
||||
}
|
||||
|
||||
ctx.canonicalHeaders = strings.Join(stripExcessSpaces(headerValues), "\n")
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildCanonicalString() {
|
||||
ctx.Request.URL.RawQuery = strings.Replace(ctx.Query.Encode(), "+", "%20", -1)
|
||||
|
||||
uri := getURIPath(ctx.Request.URL)
|
||||
|
||||
if !ctx.DisableURIPathEscaping {
|
||||
uri = rest.EscapePath(uri, false)
|
||||
}
|
||||
|
||||
ctx.canonicalString = strings.Join([]string{
|
||||
ctx.Request.Method,
|
||||
uri,
|
||||
ctx.Request.URL.RawQuery,
|
||||
ctx.canonicalHeaders + "\n",
|
||||
ctx.signedHeaders,
|
||||
ctx.bodyDigest,
|
||||
}, "\n")
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildStringToSign() {
|
||||
ctx.stringToSign = strings.Join([]string{
|
||||
authHeaderPrefix,
|
||||
ctx.formattedTime,
|
||||
ctx.credentialString,
|
||||
hex.EncodeToString(makeSha256([]byte(ctx.canonicalString))),
|
||||
}, "\n")
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildSignature() {
|
||||
secret := ctx.credValues.SecretAccessKey
|
||||
date := makeHmac([]byte("AWS4"+secret), []byte(ctx.formattedShortTime))
|
||||
region := makeHmac(date, []byte(ctx.Region))
|
||||
service := makeHmac(region, []byte(ctx.ServiceName))
|
||||
credentials := makeHmac(service, []byte("aws4_request"))
|
||||
signature := makeHmac(credentials, []byte(ctx.stringToSign))
|
||||
ctx.signature = hex.EncodeToString(signature)
|
||||
}
|
||||
|
||||
func (ctx *signingCtx) buildBodyDigest() {
|
||||
hash := ctx.Request.Header.Get("X-Amz-Content-Sha256")
|
||||
if hash == "" {
|
||||
if ctx.isPresign && ctx.ServiceName == "s3" {
|
||||
hash = "UNSIGNED-PAYLOAD"
|
||||
} else if ctx.Body == nil {
|
||||
hash = emptyStringSHA256
|
||||
} else {
|
||||
hash = hex.EncodeToString(makeSha256Reader(ctx.Body))
|
||||
}
|
||||
if ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" {
|
||||
ctx.Request.Header.Set("X-Amz-Content-Sha256", hash)
|
||||
}
|
||||
}
|
||||
ctx.bodyDigest = hash
|
||||
}
|
||||
|
||||
// isRequestSigned returns if the request is currently signed or presigned
|
||||
func (ctx *signingCtx) isRequestSigned() bool {
|
||||
if ctx.isPresign && ctx.Query.Get("X-Amz-Signature") != "" {
|
||||
return true
|
||||
}
|
||||
if ctx.Request.Header.Get("Authorization") != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// unsign removes signing flags for both signed and presigned requests.
|
||||
func (ctx *signingCtx) removePresign() {
|
||||
ctx.Query.Del("X-Amz-Algorithm")
|
||||
ctx.Query.Del("X-Amz-Signature")
|
||||
ctx.Query.Del("X-Amz-Security-Token")
|
||||
ctx.Query.Del("X-Amz-Date")
|
||||
ctx.Query.Del("X-Amz-Expires")
|
||||
ctx.Query.Del("X-Amz-Credential")
|
||||
ctx.Query.Del("X-Amz-SignedHeaders")
|
||||
}
|
||||
|
||||
func makeHmac(key []byte, data []byte) []byte {
|
||||
hash := hmac.New(sha256.New, key)
|
||||
hash.Write(data)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
func makeSha256(data []byte) []byte {
|
||||
hash := sha256.New()
|
||||
hash.Write(data)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
func makeSha256Reader(reader io.ReadSeeker) []byte {
|
||||
hash := sha256.New()
|
||||
start, _ := reader.Seek(0, 1)
|
||||
defer reader.Seek(start, 0)
|
||||
|
||||
io.Copy(hash, reader)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
const doubleSpaces = " "
|
||||
|
||||
var doubleSpaceBytes = []byte(doubleSpaces)
|
||||
|
||||
func stripExcessSpaces(headerVals []string) []string {
|
||||
vals := make([]string, len(headerVals))
|
||||
for i, str := range headerVals {
|
||||
// Trim leading and trailing spaces
|
||||
trimmed := strings.TrimSpace(str)
|
||||
|
||||
idx := strings.Index(trimmed, doubleSpaces)
|
||||
var buf []byte
|
||||
for idx > -1 {
|
||||
// Multiple adjacent spaces found
|
||||
if buf == nil {
|
||||
// first time create the buffer
|
||||
buf = []byte(trimmed)
|
||||
}
|
||||
|
||||
stripToIdx := -1
|
||||
for j := idx + 1; j < len(buf); j++ {
|
||||
if buf[j] != ' ' {
|
||||
buf = append(buf[:idx+1], buf[j:]...)
|
||||
stripToIdx = j
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if stripToIdx >= 0 {
|
||||
idx = bytes.Index(buf[stripToIdx:], doubleSpaceBytes)
|
||||
if idx >= 0 {
|
||||
idx += stripToIdx
|
||||
}
|
||||
} else {
|
||||
idx = -1
|
||||
}
|
||||
}
|
||||
|
||||
if buf != nil {
|
||||
vals[i] = string(buf)
|
||||
} else {
|
||||
vals[i] = trimmed
|
||||
}
|
||||
}
|
||||
return vals
|
||||
}
|
|
@ -5,4 +5,4 @@ package aws
|
|||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "1.1.30"
|
||||
const SDKVersion = "1.4.22"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Package endpoints validates regional endpoints for services.
|
||||
package endpoints
|
||||
|
||||
//go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
|
||||
//go:generate go run -tags codegen ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
|
||||
//go:generate gofmt -s -w endpoints_map.go
|
||||
|
||||
import (
|
||||
|
@ -14,9 +14,9 @@ import (
|
|||
// normalized endpoint and signing region. If the endpoint is not an empty string
|
||||
// the service name and region will be used to look up the service's API endpoint.
|
||||
// If the endpoint is provided the scheme will be added if it is not present.
|
||||
func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL bool) (normEndpoint, signingRegion string) {
|
||||
func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL, useDualStack bool) (normEndpoint, signingRegion string) {
|
||||
if endpoint == "" {
|
||||
return EndpointForRegion(serviceName, region, disableSSL)
|
||||
return EndpointForRegion(serviceName, region, disableSSL, useDualStack)
|
||||
}
|
||||
|
||||
return AddScheme(endpoint, disableSSL), ""
|
||||
|
@ -24,12 +24,17 @@ func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL bool) (n
|
|||
|
||||
// EndpointForRegion returns an endpoint and its signing region for a service and region.
|
||||
// if the service and region pair are not found endpoint and signingRegion will be empty.
|
||||
func EndpointForRegion(svcName, region string, disableSSL bool) (endpoint, signingRegion string) {
|
||||
func EndpointForRegion(svcName, region string, disableSSL, useDualStack bool) (endpoint, signingRegion string) {
|
||||
dualStackField := ""
|
||||
if useDualStack {
|
||||
dualStackField = "/dualstack"
|
||||
}
|
||||
|
||||
derivedKeys := []string{
|
||||
region + "/" + svcName,
|
||||
region + "/*",
|
||||
"*/" + svcName,
|
||||
"*/*",
|
||||
region + "/" + svcName + dualStackField,
|
||||
region + "/*" + dualStackField,
|
||||
"*/" + svcName + dualStackField,
|
||||
"*/*" + dualStackField,
|
||||
}
|
||||
|
||||
for _, key := range derivedKeys {
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
"us-gov-west-1/ec2metadata": {
|
||||
"endpoint": "http://169.254.169.254/latest"
|
||||
},
|
||||
"*/budgets": {
|
||||
"endpoint": "budgets.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/cloudfront": {
|
||||
"endpoint": "cloudfront.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
|
@ -65,6 +69,9 @@
|
|||
"*/s3": {
|
||||
"endpoint": "s3-{region}.amazonaws.com"
|
||||
},
|
||||
"*/s3/dualstack": {
|
||||
"endpoint": "s3.dualstack.{region}.amazonaws.com"
|
||||
},
|
||||
"us-east-1/s3": {
|
||||
"endpoint": "s3.amazonaws.com"
|
||||
},
|
||||
|
|
|
@ -18,6 +18,10 @@ var endpointsMap = endpointStruct{
|
|||
"*/*": {
|
||||
Endpoint: "{service}.{region}.amazonaws.com",
|
||||
},
|
||||
"*/budgets": {
|
||||
Endpoint: "budgets.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/cloudfront": {
|
||||
Endpoint: "cloudfront.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
|
@ -48,6 +52,9 @@ var endpointsMap = endpointStruct{
|
|||
"*/s3": {
|
||||
Endpoint: "s3-{region}.amazonaws.com",
|
||||
},
|
||||
"*/s3/dualstack": {
|
||||
Endpoint: "s3.dualstack.{region}.amazonaws.com",
|
||||
},
|
||||
"*/sts": {
|
||||
Endpoint: "sts.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Package jsonutil provides JSON serialisation of AWS requests and responses.
|
||||
// Package jsonutil provides JSON serialization of AWS requests and responses.
|
||||
package jsonutil
|
||||
|
||||
import (
|
||||
|
@ -160,7 +160,7 @@ func (sv sortedValues) Less(i, j int) bool { return sv[i].String() < sv[j].Strin
|
|||
func buildMap(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
|
||||
buf.WriteString("{")
|
||||
|
||||
var sv sortedValues = value.MapKeys()
|
||||
sv := sortedValues(value.MapKeys())
|
||||
sort.Sort(sv)
|
||||
|
||||
for i, k := range sv {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// Package jsonrpc provides JSON RPC utilities for serialisation of AWS
|
||||
// Package jsonrpc provides JSON RPC utilities for serialization of AWS
|
||||
// requests and responses.
|
||||
package jsonrpc
|
||||
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
36
vendor/src/github.com/aws/aws-sdk-go/private/protocol/query/build.go
vendored
Normal file
36
vendor/src/github.com/aws/aws-sdk-go/private/protocol/query/build.go
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Package query provides serialization of AWS query requests, and responses.
|
||||
package query
|
||||
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query/queryutil"
|
||||
)
|
||||
|
||||
// BuildHandler is a named request handler for building query protocol requests
|
||||
var BuildHandler = request.NamedHandler{Name: "awssdk.query.Build", Fn: Build}
|
||||
|
||||
// Build builds a request for an AWS Query service.
|
||||
func Build(r *request.Request) {
|
||||
body := url.Values{
|
||||
"Action": {r.Operation.Name},
|
||||
"Version": {r.ClientInfo.APIVersion},
|
||||
}
|
||||
if err := queryutil.Parse(body, r.Params, false); err != nil {
|
||||
r.Error = awserr.New("SerializationError", "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()
|
||||
}
|
||||
}
|
230
vendor/src/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go
vendored
Normal file
230
vendor/src/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go
vendored
Normal file
|
@ -0,0 +1,230 @@
|
|||
package queryutil
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/private/protocol"
|
||||
)
|
||||
|
||||
// Parse parses an object i and fills a url.Values object. The isEC2 flag
|
||||
// indicates if this is the EC2 Query sub-protocol.
|
||||
func Parse(body url.Values, i interface{}, isEC2 bool) error {
|
||||
q := queryParser{isEC2: isEC2}
|
||||
return q.parseValue(body, reflect.ValueOf(i), "", "")
|
||||
}
|
||||
|
||||
func elemOf(value reflect.Value) reflect.Value {
|
||||
for value.Kind() == reflect.Ptr {
|
||||
value = value.Elem()
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
type queryParser struct {
|
||||
isEC2 bool
|
||||
}
|
||||
|
||||
func (q *queryParser) parseValue(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
|
||||
value = elemOf(value)
|
||||
|
||||
// no need to handle zero values
|
||||
if !value.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
t := tag.Get("type")
|
||||
if t == "" {
|
||||
switch value.Kind() {
|
||||
case reflect.Struct:
|
||||
t = "structure"
|
||||
case reflect.Slice:
|
||||
t = "list"
|
||||
case reflect.Map:
|
||||
t = "map"
|
||||
}
|
||||
}
|
||||
|
||||
switch t {
|
||||
case "structure":
|
||||
return q.parseStruct(v, value, prefix)
|
||||
case "list":
|
||||
return q.parseList(v, value, prefix, tag)
|
||||
case "map":
|
||||
return q.parseMap(v, value, prefix, tag)
|
||||
default:
|
||||
return q.parseScalar(v, value, prefix, tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix string) error {
|
||||
if !value.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
t := value.Type()
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
elemValue := elemOf(value.Field(i))
|
||||
field := t.Field(i)
|
||||
|
||||
if field.PkgPath != "" {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
|
||||
if protocol.CanSetIdempotencyToken(value.Field(i), field) {
|
||||
token := protocol.GetIdempotencyToken()
|
||||
elemValue = reflect.ValueOf(token)
|
||||
}
|
||||
|
||||
var name string
|
||||
if q.isEC2 {
|
||||
name = field.Tag.Get("queryName")
|
||||
}
|
||||
if name == "" {
|
||||
if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
|
||||
name = field.Tag.Get("locationNameList")
|
||||
} else if locName := field.Tag.Get("locationName"); locName != "" {
|
||||
name = locName
|
||||
}
|
||||
if name != "" && q.isEC2 {
|
||||
name = strings.ToUpper(name[0:1]) + name[1:]
|
||||
}
|
||||
}
|
||||
if name == "" {
|
||||
name = field.Name
|
||||
}
|
||||
|
||||
if prefix != "" {
|
||||
name = prefix + "." + name
|
||||
}
|
||||
|
||||
if err := q.parseValue(v, elemValue, name, field.Tag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
|
||||
// If it's empty, generate an empty value
|
||||
if !value.IsNil() && value.Len() == 0 {
|
||||
v.Set(prefix, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
// check for unflattened list member
|
||||
if !q.isEC2 && tag.Get("flattened") == "" {
|
||||
prefix += ".member"
|
||||
}
|
||||
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
slicePrefix := prefix
|
||||
if slicePrefix == "" {
|
||||
slicePrefix = strconv.Itoa(i + 1)
|
||||
} else {
|
||||
slicePrefix = slicePrefix + "." + strconv.Itoa(i+1)
|
||||
}
|
||||
if err := q.parseValue(v, value.Index(i), slicePrefix, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *queryParser) parseMap(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
|
||||
// If it's empty, generate an empty value
|
||||
if !value.IsNil() && value.Len() == 0 {
|
||||
v.Set(prefix, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
// check for unflattened list member
|
||||
if !q.isEC2 && tag.Get("flattened") == "" {
|
||||
prefix += ".entry"
|
||||
}
|
||||
|
||||
// sort keys for improved serialization consistency.
|
||||
// this is not strictly necessary for protocol support.
|
||||
mapKeyValues := value.MapKeys()
|
||||
mapKeys := map[string]reflect.Value{}
|
||||
mapKeyNames := make([]string, len(mapKeyValues))
|
||||
for i, mapKey := range mapKeyValues {
|
||||
name := mapKey.String()
|
||||
mapKeys[name] = mapKey
|
||||
mapKeyNames[i] = name
|
||||
}
|
||||
sort.Strings(mapKeyNames)
|
||||
|
||||
for i, mapKeyName := range mapKeyNames {
|
||||
mapKey := mapKeys[mapKeyName]
|
||||
mapValue := value.MapIndex(mapKey)
|
||||
|
||||
kname := tag.Get("locationNameKey")
|
||||
if kname == "" {
|
||||
kname = "key"
|
||||
}
|
||||
vname := tag.Get("locationNameValue")
|
||||
if vname == "" {
|
||||
vname = "value"
|
||||
}
|
||||
|
||||
// serialize key
|
||||
var keyName string
|
||||
if prefix == "" {
|
||||
keyName = strconv.Itoa(i+1) + "." + kname
|
||||
} else {
|
||||
keyName = prefix + "." + strconv.Itoa(i+1) + "." + kname
|
||||
}
|
||||
|
||||
if err := q.parseValue(v, mapKey, keyName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// serialize value
|
||||
var valueName string
|
||||
if prefix == "" {
|
||||
valueName = strconv.Itoa(i+1) + "." + vname
|
||||
} else {
|
||||
valueName = prefix + "." + strconv.Itoa(i+1) + "." + vname
|
||||
}
|
||||
|
||||
if err := q.parseValue(v, mapValue, valueName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *queryParser) parseScalar(v url.Values, r reflect.Value, name string, tag reflect.StructTag) error {
|
||||
switch value := r.Interface().(type) {
|
||||
case string:
|
||||
v.Set(name, value)
|
||||
case []byte:
|
||||
if !r.IsNil() {
|
||||
v.Set(name, base64.StdEncoding.EncodeToString(value))
|
||||
}
|
||||
case bool:
|
||||
v.Set(name, strconv.FormatBool(value))
|
||||
case int64:
|
||||
v.Set(name, strconv.FormatInt(value, 10))
|
||||
case int:
|
||||
v.Set(name, strconv.Itoa(value))
|
||||
case float64:
|
||||
v.Set(name, strconv.FormatFloat(value, 'f', -1, 64))
|
||||
case float32:
|
||||
v.Set(name, strconv.FormatFloat(float64(value), 'f', -1, 32))
|
||||
case time.Time:
|
||||
const ISO8601UTC = "2006-01-02T15:04:05Z"
|
||||
v.Set(name, value.UTC().Format(ISO8601UTC))
|
||||
default:
|
||||
return fmt.Errorf("unsupported value for param %s: %v (%s)", name, r.Interface(), r.Type().Name())
|
||||
}
|
||||
return nil
|
||||
}
|
35
vendor/src/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal.go
vendored
Normal file
35
vendor/src/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal.go
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package query
|
||||
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
|
||||
)
|
||||
|
||||
// UnmarshalHandler is a named request handler for unmarshaling query protocol requests
|
||||
var UnmarshalHandler = request.NamedHandler{Name: "awssdk.query.Unmarshal", Fn: Unmarshal}
|
||||
|
||||
// UnmarshalMetaHandler is a named request handler for unmarshaling query protocol request metadata
|
||||
var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalMeta", Fn: UnmarshalMeta}
|
||||
|
||||
// Unmarshal unmarshals a response for an AWS Query service.
|
||||
func Unmarshal(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
if r.DataFilled() {
|
||||
decoder := xml.NewDecoder(r.HTTPResponse.Body)
|
||||
err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result")
|
||||
if err != nil {
|
||||
r.Error = awserr.New("SerializationError", "failed decoding Query response", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalMeta unmarshals header response values for an AWS Query service.
|
||||
func UnmarshalMeta(r *request.Request) {
|
||||
r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid")
|
||||
}
|
66
vendor/src/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_error.go
vendored
Normal file
66
vendor/src/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_error.go
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
package query
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
type xmlErrorResponse struct {
|
||||
XMLName xml.Name `xml:"ErrorResponse"`
|
||||
Code string `xml:"Error>Code"`
|
||||
Message string `xml:"Error>Message"`
|
||||
RequestID string `xml:"RequestId"`
|
||||
}
|
||||
|
||||
type xmlServiceUnavailableResponse struct {
|
||||
XMLName xml.Name `xml:"ServiceUnavailableException"`
|
||||
}
|
||||
|
||||
// UnmarshalErrorHandler is a name request handler to unmarshal request errors
|
||||
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalError", Fn: UnmarshalError}
|
||||
|
||||
// UnmarshalError unmarshals an error response for an AWS Query service.
|
||||
func UnmarshalError(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
|
||||
bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.New("SerializationError", "failed to read from query HTTP response body", err)
|
||||
return
|
||||
}
|
||||
|
||||
// First check for specific error
|
||||
resp := xmlErrorResponse{}
|
||||
decodeErr := xml.Unmarshal(bodyBytes, &resp)
|
||||
if decodeErr == nil {
|
||||
reqID := resp.RequestID
|
||||
if reqID == "" {
|
||||
reqID = r.RequestID
|
||||
}
|
||||
r.Error = awserr.NewRequestFailure(
|
||||
awserr.New(resp.Code, resp.Message, nil),
|
||||
r.HTTPResponse.StatusCode,
|
||||
reqID,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for unhandled error
|
||||
servUnavailResp := xmlServiceUnavailableResponse{}
|
||||
unavailErr := xml.Unmarshal(bodyBytes, &servUnavailResp)
|
||||
if unavailErr == nil {
|
||||
r.Error = awserr.NewRequestFailure(
|
||||
awserr.New("ServiceUnavailableException", "service is unavailable", nil),
|
||||
r.HTTPResponse.StatusCode,
|
||||
r.RequestID,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Failed to retrieve any error message from the response body
|
||||
r.Error = awserr.New("SerializationError",
|
||||
"failed to decode query XML error response", decodeErr)
|
||||
}
|
293
vendor/src/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/build.go
vendored
Normal file
293
vendor/src/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/build.go
vendored
Normal file
|
@ -0,0 +1,293 @@
|
|||
// Package xmlutil provides XML serialization of AWS requests and responses.
|
||||
package xmlutil
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/private/protocol"
|
||||
)
|
||||
|
||||
// BuildXML will serialize params into an xml.Encoder.
|
||||
// Error will be returned if the serialization of any of the params or nested values fails.
|
||||
func BuildXML(params interface{}, e *xml.Encoder) error {
|
||||
b := xmlBuilder{encoder: e, namespaces: map[string]string{}}
|
||||
root := NewXMLElement(xml.Name{})
|
||||
if err := b.buildValue(reflect.ValueOf(params), root, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, c := range root.Children {
|
||||
for _, v := range c {
|
||||
return StructToXML(e, v, false)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the reflection element of a value, if it is a pointer.
|
||||
func elemOf(value reflect.Value) reflect.Value {
|
||||
for value.Kind() == reflect.Ptr {
|
||||
value = value.Elem()
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// A xmlBuilder serializes values from Go code to XML
|
||||
type xmlBuilder struct {
|
||||
encoder *xml.Encoder
|
||||
namespaces map[string]string
|
||||
}
|
||||
|
||||
// buildValue generic XMLNode builder for any type. Will build value for their specific type
|
||||
// struct, list, map, scalar.
|
||||
//
|
||||
// Also takes a "type" tag value to set what type a value should be converted to XMLNode as. If
|
||||
// type is not provided reflect will be used to determine the value's type.
|
||||
func (b *xmlBuilder) buildValue(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||
value = elemOf(value)
|
||||
if !value.IsValid() { // no need to handle zero values
|
||||
return nil
|
||||
} else if tag.Get("location") != "" { // don't handle non-body location values
|
||||
return nil
|
||||
}
|
||||
|
||||
t := tag.Get("type")
|
||||
if t == "" {
|
||||
switch value.Kind() {
|
||||
case reflect.Struct:
|
||||
t = "structure"
|
||||
case reflect.Slice:
|
||||
t = "list"
|
||||
case reflect.Map:
|
||||
t = "map"
|
||||
}
|
||||
}
|
||||
|
||||
switch t {
|
||||
case "structure":
|
||||
if field, ok := value.Type().FieldByName("_"); ok {
|
||||
tag = tag + reflect.StructTag(" ") + field.Tag
|
||||
}
|
||||
return b.buildStruct(value, current, tag)
|
||||
case "list":
|
||||
return b.buildList(value, current, tag)
|
||||
case "map":
|
||||
return b.buildMap(value, current, tag)
|
||||
default:
|
||||
return b.buildScalar(value, current, tag)
|
||||
}
|
||||
}
|
||||
|
||||
// buildStruct adds a struct and its fields to the current XMLNode. All fields any any nested
|
||||
// types are converted to XMLNodes also.
|
||||
func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||
if !value.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
fieldAdded := false
|
||||
|
||||
// unwrap payloads
|
||||
if payload := tag.Get("payload"); payload != "" {
|
||||
field, _ := value.Type().FieldByName(payload)
|
||||
tag = field.Tag
|
||||
value = elemOf(value.FieldByName(payload))
|
||||
|
||||
if !value.IsValid() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
child := NewXMLElement(xml.Name{Local: tag.Get("locationName")})
|
||||
|
||||
// there is an xmlNamespace associated with this struct
|
||||
if prefix, uri := tag.Get("xmlPrefix"), tag.Get("xmlURI"); uri != "" {
|
||||
ns := xml.Attr{
|
||||
Name: xml.Name{Local: "xmlns"},
|
||||
Value: uri,
|
||||
}
|
||||
if prefix != "" {
|
||||
b.namespaces[prefix] = uri // register the namespace
|
||||
ns.Name.Local = "xmlns:" + prefix
|
||||
}
|
||||
|
||||
child.Attr = append(child.Attr, ns)
|
||||
}
|
||||
|
||||
t := value.Type()
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
member := elemOf(value.Field(i))
|
||||
field := t.Field(i)
|
||||
|
||||
if field.PkgPath != "" {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
|
||||
mTag := field.Tag
|
||||
if mTag.Get("location") != "" { // skip non-body members
|
||||
continue
|
||||
}
|
||||
|
||||
if protocol.CanSetIdempotencyToken(value.Field(i), field) {
|
||||
token := protocol.GetIdempotencyToken()
|
||||
member = reflect.ValueOf(token)
|
||||
}
|
||||
|
||||
memberName := mTag.Get("locationName")
|
||||
if memberName == "" {
|
||||
memberName = field.Name
|
||||
mTag = reflect.StructTag(string(mTag) + ` locationName:"` + memberName + `"`)
|
||||
}
|
||||
if err := b.buildValue(member, child, mTag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fieldAdded = true
|
||||
}
|
||||
|
||||
if fieldAdded { // only append this child if we have one ore more valid members
|
||||
current.AddChild(child)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildList adds the value's list items to the current XMLNode as children nodes. All
|
||||
// nested values in the list are converted to XMLNodes also.
|
||||
func (b *xmlBuilder) buildList(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||
if value.IsNil() { // don't build omitted lists
|
||||
return nil
|
||||
}
|
||||
|
||||
// check for unflattened list member
|
||||
flattened := tag.Get("flattened") != ""
|
||||
|
||||
xname := xml.Name{Local: tag.Get("locationName")}
|
||||
if flattened {
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
child := NewXMLElement(xname)
|
||||
current.AddChild(child)
|
||||
if err := b.buildValue(value.Index(i), child, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
list := NewXMLElement(xname)
|
||||
current.AddChild(list)
|
||||
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
iname := tag.Get("locationNameList")
|
||||
if iname == "" {
|
||||
iname = "member"
|
||||
}
|
||||
|
||||
child := NewXMLElement(xml.Name{Local: iname})
|
||||
list.AddChild(child)
|
||||
if err := b.buildValue(value.Index(i), child, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildMap adds the value's key/value pairs to the current XMLNode as children nodes. All
|
||||
// nested values in the map are converted to XMLNodes also.
|
||||
//
|
||||
// Error will be returned if it is unable to build the map's values into XMLNodes
|
||||
func (b *xmlBuilder) buildMap(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||
if value.IsNil() { // don't build omitted maps
|
||||
return nil
|
||||
}
|
||||
|
||||
maproot := NewXMLElement(xml.Name{Local: tag.Get("locationName")})
|
||||
current.AddChild(maproot)
|
||||
current = maproot
|
||||
|
||||
kname, vname := "key", "value"
|
||||
if n := tag.Get("locationNameKey"); n != "" {
|
||||
kname = n
|
||||
}
|
||||
if n := tag.Get("locationNameValue"); n != "" {
|
||||
vname = n
|
||||
}
|
||||
|
||||
// sorting is not required for compliance, but it makes testing easier
|
||||
keys := make([]string, value.Len())
|
||||
for i, k := range value.MapKeys() {
|
||||
keys[i] = k.String()
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
v := value.MapIndex(reflect.ValueOf(k))
|
||||
|
||||
mapcur := current
|
||||
if tag.Get("flattened") == "" { // add "entry" tag to non-flat maps
|
||||
child := NewXMLElement(xml.Name{Local: "entry"})
|
||||
mapcur.AddChild(child)
|
||||
mapcur = child
|
||||
}
|
||||
|
||||
kchild := NewXMLElement(xml.Name{Local: kname})
|
||||
kchild.Text = k
|
||||
vchild := NewXMLElement(xml.Name{Local: vname})
|
||||
mapcur.AddChild(kchild)
|
||||
mapcur.AddChild(vchild)
|
||||
|
||||
if err := b.buildValue(v, vchild, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildScalar will convert the value into a string and append it as a attribute or child
|
||||
// of the current XMLNode.
|
||||
//
|
||||
// The value will be added as an attribute if tag contains a "xmlAttribute" attribute value.
|
||||
//
|
||||
// Error will be returned if the value type is unsupported.
|
||||
func (b *xmlBuilder) buildScalar(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||
var str string
|
||||
switch converted := value.Interface().(type) {
|
||||
case string:
|
||||
str = converted
|
||||
case []byte:
|
||||
if !value.IsNil() {
|
||||
str = base64.StdEncoding.EncodeToString(converted)
|
||||
}
|
||||
case bool:
|
||||
str = strconv.FormatBool(converted)
|
||||
case int64:
|
||||
str = strconv.FormatInt(converted, 10)
|
||||
case int:
|
||||
str = strconv.Itoa(converted)
|
||||
case float64:
|
||||
str = strconv.FormatFloat(converted, 'f', -1, 64)
|
||||
case float32:
|
||||
str = strconv.FormatFloat(float64(converted), 'f', -1, 32)
|
||||
case time.Time:
|
||||
const ISO8601UTC = "2006-01-02T15:04:05Z"
|
||||
str = converted.UTC().Format(ISO8601UTC)
|
||||
default:
|
||||
return fmt.Errorf("unsupported value for param %s: %v (%s)",
|
||||
tag.Get("locationName"), value.Interface(), value.Type().Name())
|
||||
}
|
||||
|
||||
xname := xml.Name{Local: tag.Get("locationName")}
|
||||
if tag.Get("xmlAttribute") != "" { // put into current node's attribute list
|
||||
attr := xml.Attr{Name: xname, Value: str}
|
||||
current.Attr = append(current.Attr, attr)
|
||||
} else { // regular text node
|
||||
current.AddChild(&XMLNode{Name: xname, Text: str})
|
||||
}
|
||||
return nil
|
||||
}
|
260
vendor/src/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go
vendored
Normal file
260
vendor/src/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go
vendored
Normal file
|
@ -0,0 +1,260 @@
|
|||
package xmlutil
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UnmarshalXML deserializes an xml.Decoder into the container v. V
|
||||
// needs to match the shape of the XML expected to be decoded.
|
||||
// If the shape doesn't match unmarshaling will fail.
|
||||
func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
|
||||
n, _ := XMLToStruct(d, nil)
|
||||
if n.Children != nil {
|
||||
for _, root := range n.Children {
|
||||
for _, c := range root {
|
||||
if wrappedChild, ok := c.Children[wrapper]; ok {
|
||||
c = wrappedChild[0] // pull out wrapped element
|
||||
}
|
||||
|
||||
err := parse(reflect.ValueOf(v), c, "")
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
|
||||
// will be used to determine the type from r.
|
||||
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||
rtype := r.Type()
|
||||
if rtype.Kind() == reflect.Ptr {
|
||||
rtype = rtype.Elem() // check kind of actual element type
|
||||
}
|
||||
|
||||
t := tag.Get("type")
|
||||
if t == "" {
|
||||
switch rtype.Kind() {
|
||||
case reflect.Struct:
|
||||
t = "structure"
|
||||
case reflect.Slice:
|
||||
t = "list"
|
||||
case reflect.Map:
|
||||
t = "map"
|
||||
}
|
||||
}
|
||||
|
||||
switch t {
|
||||
case "structure":
|
||||
if field, ok := rtype.FieldByName("_"); ok {
|
||||
tag = field.Tag
|
||||
}
|
||||
return parseStruct(r, node, tag)
|
||||
case "list":
|
||||
return parseList(r, node, tag)
|
||||
case "map":
|
||||
return parseMap(r, node, tag)
|
||||
default:
|
||||
return parseScalar(r, node, tag)
|
||||
}
|
||||
}
|
||||
|
||||
// parseStruct deserializes a structure and its fields from an XMLNode. Any nested
|
||||
// types in the structure will also be deserialized.
|
||||
func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||
t := r.Type()
|
||||
if r.Kind() == reflect.Ptr {
|
||||
if r.IsNil() { // create the structure if it's nil
|
||||
s := reflect.New(r.Type().Elem())
|
||||
r.Set(s)
|
||||
r = s
|
||||
}
|
||||
|
||||
r = r.Elem()
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
// unwrap any payloads
|
||||
if payload := tag.Get("payload"); payload != "" {
|
||||
field, _ := t.FieldByName(payload)
|
||||
return parseStruct(r.FieldByName(payload), node, field.Tag)
|
||||
}
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
if c := field.Name[0:1]; strings.ToLower(c) == c {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
|
||||
// figure out what this field is called
|
||||
name := field.Name
|
||||
if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
|
||||
name = field.Tag.Get("locationNameList")
|
||||
} else if locName := field.Tag.Get("locationName"); locName != "" {
|
||||
name = locName
|
||||
}
|
||||
|
||||
// try to find the field by name in elements
|
||||
elems := node.Children[name]
|
||||
|
||||
if elems == nil { // try to find the field in attributes
|
||||
for _, a := range node.Attr {
|
||||
if name == a.Name.Local {
|
||||
// turn this into a text node for de-serializing
|
||||
elems = []*XMLNode{{Text: a.Value}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
member := r.FieldByName(field.Name)
|
||||
for _, elem := range elems {
|
||||
err := parse(member, elem, field.Tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseList deserializes a list of values from an XML node. Each list entry
|
||||
// will also be deserialized.
|
||||
func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||
t := r.Type()
|
||||
|
||||
if tag.Get("flattened") == "" { // look at all item entries
|
||||
mname := "member"
|
||||
if name := tag.Get("locationNameList"); name != "" {
|
||||
mname = name
|
||||
}
|
||||
|
||||
if Children, ok := node.Children[mname]; ok {
|
||||
if r.IsNil() {
|
||||
r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
|
||||
}
|
||||
|
||||
for i, c := range Children {
|
||||
err := parse(r.Index(i), c, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // flattened list means this is a single element
|
||||
if r.IsNil() {
|
||||
r.Set(reflect.MakeSlice(t, 0, 0))
|
||||
}
|
||||
|
||||
childR := reflect.Zero(t.Elem())
|
||||
r.Set(reflect.Append(r, childR))
|
||||
err := parse(r.Index(r.Len()-1), node, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
|
||||
// will also be deserialized as map entries.
|
||||
func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||
if r.IsNil() {
|
||||
r.Set(reflect.MakeMap(r.Type()))
|
||||
}
|
||||
|
||||
if tag.Get("flattened") == "" { // look at all child entries
|
||||
for _, entry := range node.Children["entry"] {
|
||||
parseMapEntry(r, entry, tag)
|
||||
}
|
||||
} else { // this element is itself an entry
|
||||
parseMapEntry(r, node, tag)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseMapEntry deserializes a map entry from a XML node.
|
||||
func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||
kname, vname := "key", "value"
|
||||
if n := tag.Get("locationNameKey"); n != "" {
|
||||
kname = n
|
||||
}
|
||||
if n := tag.Get("locationNameValue"); n != "" {
|
||||
vname = n
|
||||
}
|
||||
|
||||
keys, ok := node.Children[kname]
|
||||
values := node.Children[vname]
|
||||
if ok {
|
||||
for i, key := range keys {
|
||||
keyR := reflect.ValueOf(key.Text)
|
||||
value := values[i]
|
||||
valueR := reflect.New(r.Type().Elem()).Elem()
|
||||
|
||||
parse(valueR, value, "")
|
||||
r.SetMapIndex(keyR, valueR)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseScaller deserializes an XMLNode value into a concrete type based on the
|
||||
// interface type of r.
|
||||
//
|
||||
// Error is returned if the deserialization fails due to invalid type conversion,
|
||||
// or unsupported interface type.
|
||||
func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||
switch r.Interface().(type) {
|
||||
case *string:
|
||||
r.Set(reflect.ValueOf(&node.Text))
|
||||
return nil
|
||||
case []byte:
|
||||
b, err := base64.StdEncoding.DecodeString(node.Text)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Set(reflect.ValueOf(b))
|
||||
case *bool:
|
||||
v, err := strconv.ParseBool(node.Text)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Set(reflect.ValueOf(&v))
|
||||
case *int64:
|
||||
v, err := strconv.ParseInt(node.Text, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Set(reflect.ValueOf(&v))
|
||||
case *float64:
|
||||
v, err := strconv.ParseFloat(node.Text, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Set(reflect.ValueOf(&v))
|
||||
case *time.Time:
|
||||
const ISO8601UTC = "2006-01-02T15:04:05Z"
|
||||
t, err := time.Parse(ISO8601UTC, node.Text)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Set(reflect.ValueOf(&t))
|
||||
default:
|
||||
return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
105
vendor/src/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go
vendored
Normal file
105
vendor/src/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
package xmlutil
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// A XMLNode contains the values to be encoded or decoded.
|
||||
type XMLNode struct {
|
||||
Name xml.Name `json:",omitempty"`
|
||||
Children map[string][]*XMLNode `json:",omitempty"`
|
||||
Text string `json:",omitempty"`
|
||||
Attr []xml.Attr `json:",omitempty"`
|
||||
}
|
||||
|
||||
// NewXMLElement returns a pointer to a new XMLNode initialized to default values.
|
||||
func NewXMLElement(name xml.Name) *XMLNode {
|
||||
return &XMLNode{
|
||||
Name: name,
|
||||
Children: map[string][]*XMLNode{},
|
||||
Attr: []xml.Attr{},
|
||||
}
|
||||
}
|
||||
|
||||
// AddChild adds child to the XMLNode.
|
||||
func (n *XMLNode) AddChild(child *XMLNode) {
|
||||
if _, ok := n.Children[child.Name.Local]; !ok {
|
||||
n.Children[child.Name.Local] = []*XMLNode{}
|
||||
}
|
||||
n.Children[child.Name.Local] = append(n.Children[child.Name.Local], child)
|
||||
}
|
||||
|
||||
// XMLToStruct converts a xml.Decoder stream to XMLNode with nested values.
|
||||
func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) {
|
||||
out := &XMLNode{}
|
||||
for {
|
||||
tok, err := d.Token()
|
||||
if tok == nil || err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
switch typed := tok.(type) {
|
||||
case xml.CharData:
|
||||
out.Text = string(typed.Copy())
|
||||
case xml.StartElement:
|
||||
el := typed.Copy()
|
||||
out.Attr = el.Attr
|
||||
if out.Children == nil {
|
||||
out.Children = map[string][]*XMLNode{}
|
||||
}
|
||||
|
||||
name := typed.Name.Local
|
||||
slice := out.Children[name]
|
||||
if slice == nil {
|
||||
slice = []*XMLNode{}
|
||||
}
|
||||
node, e := XMLToStruct(d, &el)
|
||||
if e != nil {
|
||||
return out, e
|
||||
}
|
||||
node.Name = typed.Name
|
||||
slice = append(slice, node)
|
||||
out.Children[name] = slice
|
||||
case xml.EndElement:
|
||||
if s != nil && s.Name.Local == typed.Name.Local { // matching end token
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// StructToXML writes an XMLNode to a xml.Encoder as tokens.
|
||||
func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error {
|
||||
e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr})
|
||||
|
||||
if node.Text != "" {
|
||||
e.EncodeToken(xml.CharData([]byte(node.Text)))
|
||||
} else if sorted {
|
||||
sortedNames := []string{}
|
||||
for k := range node.Children {
|
||||
sortedNames = append(sortedNames, k)
|
||||
}
|
||||
sort.Strings(sortedNames)
|
||||
|
||||
for _, k := range sortedNames {
|
||||
for _, v := range node.Children[k] {
|
||||
StructToXML(e, v, sorted)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, c := range node.Children {
|
||||
for _, v := range c {
|
||||
StructToXML(e, v, sorted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e.EncodeToken(xml.EndElement{Name: node.Name})
|
||||
return e.Flush()
|
||||
}
|
|
@ -1,465 +0,0 @@
|
|||
// Package v4 implements signing for AWS V4 signer
|
||||
package v4
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
authHeaderPrefix = "AWS4-HMAC-SHA256"
|
||||
timeFormat = "20060102T150405Z"
|
||||
shortTimeFormat = "20060102"
|
||||
)
|
||||
|
||||
var ignoredHeaders = rules{
|
||||
blacklist{
|
||||
mapRule{
|
||||
"Authorization": struct{}{},
|
||||
"User-Agent": struct{}{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// requiredSignedHeaders is a whitelist for build canonical headers.
|
||||
var requiredSignedHeaders = rules{
|
||||
whitelist{
|
||||
mapRule{
|
||||
"Cache-Control": struct{}{},
|
||||
"Content-Disposition": struct{}{},
|
||||
"Content-Encoding": struct{}{},
|
||||
"Content-Language": struct{}{},
|
||||
"Content-Md5": struct{}{},
|
||||
"Content-Type": struct{}{},
|
||||
"Expires": struct{}{},
|
||||
"If-Match": struct{}{},
|
||||
"If-Modified-Since": struct{}{},
|
||||
"If-None-Match": struct{}{},
|
||||
"If-Unmodified-Since": struct{}{},
|
||||
"Range": struct{}{},
|
||||
"X-Amz-Acl": struct{}{},
|
||||
"X-Amz-Copy-Source": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Match": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Modified-Since": struct{}{},
|
||||
"X-Amz-Copy-Source-If-None-Match": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Unmodified-Since": struct{}{},
|
||||
"X-Amz-Copy-Source-Range": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
|
||||
"X-Amz-Grant-Full-control": struct{}{},
|
||||
"X-Amz-Grant-Read": struct{}{},
|
||||
"X-Amz-Grant-Read-Acp": struct{}{},
|
||||
"X-Amz-Grant-Write": struct{}{},
|
||||
"X-Amz-Grant-Write-Acp": struct{}{},
|
||||
"X-Amz-Metadata-Directive": struct{}{},
|
||||
"X-Amz-Mfa": struct{}{},
|
||||
"X-Amz-Request-Payer": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Algorithm": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Key": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
|
||||
"X-Amz-Storage-Class": struct{}{},
|
||||
"X-Amz-Website-Redirect-Location": struct{}{},
|
||||
},
|
||||
},
|
||||
patterns{"X-Amz-Meta-"},
|
||||
}
|
||||
|
||||
// allowedHoisting is a whitelist for build query headers. The boolean value
|
||||
// represents whether or not it is a pattern.
|
||||
var allowedQueryHoisting = inclusiveRules{
|
||||
blacklist{requiredSignedHeaders},
|
||||
patterns{"X-Amz-"},
|
||||
}
|
||||
|
||||
type signer struct {
|
||||
Request *http.Request
|
||||
Time time.Time
|
||||
ExpireTime time.Duration
|
||||
ServiceName string
|
||||
Region string
|
||||
CredValues credentials.Value
|
||||
Credentials *credentials.Credentials
|
||||
Query url.Values
|
||||
Body io.ReadSeeker
|
||||
Debug aws.LogLevelType
|
||||
Logger aws.Logger
|
||||
|
||||
isPresign bool
|
||||
formattedTime string
|
||||
formattedShortTime string
|
||||
|
||||
signedHeaders string
|
||||
canonicalHeaders string
|
||||
canonicalString string
|
||||
credentialString string
|
||||
stringToSign string
|
||||
signature string
|
||||
authorization string
|
||||
notHoist bool
|
||||
signedHeaderVals http.Header
|
||||
}
|
||||
|
||||
// Sign requests with signature version 4.
|
||||
//
|
||||
// Will sign the requests with the service config's Credentials object
|
||||
// Signing is skipped if the credentials is the credentials.AnonymousCredentials
|
||||
// object.
|
||||
func Sign(req *request.Request) {
|
||||
// If the request does not need to be signed ignore the signing of the
|
||||
// request if the AnonymousCredentials object is used.
|
||||
if req.Config.Credentials == credentials.AnonymousCredentials {
|
||||
return
|
||||
}
|
||||
|
||||
region := req.ClientInfo.SigningRegion
|
||||
if region == "" {
|
||||
region = aws.StringValue(req.Config.Region)
|
||||
}
|
||||
|
||||
name := req.ClientInfo.SigningName
|
||||
if name == "" {
|
||||
name = req.ClientInfo.ServiceName
|
||||
}
|
||||
|
||||
s := signer{
|
||||
Request: req.HTTPRequest,
|
||||
Time: req.Time,
|
||||
ExpireTime: req.ExpireTime,
|
||||
Query: req.HTTPRequest.URL.Query(),
|
||||
Body: req.Body,
|
||||
ServiceName: name,
|
||||
Region: region,
|
||||
Credentials: req.Config.Credentials,
|
||||
Debug: req.Config.LogLevel.Value(),
|
||||
Logger: req.Config.Logger,
|
||||
notHoist: req.NotHoist,
|
||||
}
|
||||
|
||||
req.Error = s.sign()
|
||||
req.Time = s.Time
|
||||
req.SignedHeaderVals = s.signedHeaderVals
|
||||
}
|
||||
|
||||
func (v4 *signer) sign() error {
|
||||
if v4.ExpireTime != 0 {
|
||||
v4.isPresign = true
|
||||
}
|
||||
|
||||
if v4.isRequestSigned() {
|
||||
if !v4.Credentials.IsExpired() && time.Now().Before(v4.Time.Add(10*time.Minute)) {
|
||||
// If the request is already signed, and the credentials have not
|
||||
// expired, and the request is not too old ignore the signing request.
|
||||
return nil
|
||||
}
|
||||
v4.Time = time.Now()
|
||||
|
||||
// The credentials have expired for this request. The current signing
|
||||
// is invalid, and needs to be request because the request will fail.
|
||||
if v4.isPresign {
|
||||
v4.removePresign()
|
||||
// Update the request's query string to ensure the values stays in
|
||||
// sync in the case retrieving the new credentials fails.
|
||||
v4.Request.URL.RawQuery = v4.Query.Encode()
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
v4.CredValues, err = v4.Credentials.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v4.isPresign {
|
||||
v4.Query.Set("X-Amz-Algorithm", authHeaderPrefix)
|
||||
if v4.CredValues.SessionToken != "" {
|
||||
v4.Query.Set("X-Amz-Security-Token", v4.CredValues.SessionToken)
|
||||
} else {
|
||||
v4.Query.Del("X-Amz-Security-Token")
|
||||
}
|
||||
} else if v4.CredValues.SessionToken != "" {
|
||||
v4.Request.Header.Set("X-Amz-Security-Token", v4.CredValues.SessionToken)
|
||||
}
|
||||
|
||||
v4.build()
|
||||
|
||||
if v4.Debug.Matches(aws.LogDebugWithSigning) {
|
||||
v4.logSigningInfo()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const logSignInfoMsg = `DEBUG: Request Signiture:
|
||||
---[ CANONICAL STRING ]-----------------------------
|
||||
%s
|
||||
---[ STRING TO SIGN ]--------------------------------
|
||||
%s%s
|
||||
-----------------------------------------------------`
|
||||
const logSignedURLMsg = `
|
||||
---[ SIGNED URL ]------------------------------------
|
||||
%s`
|
||||
|
||||
func (v4 *signer) logSigningInfo() {
|
||||
signedURLMsg := ""
|
||||
if v4.isPresign {
|
||||
signedURLMsg = fmt.Sprintf(logSignedURLMsg, v4.Request.URL.String())
|
||||
}
|
||||
msg := fmt.Sprintf(logSignInfoMsg, v4.canonicalString, v4.stringToSign, signedURLMsg)
|
||||
v4.Logger.Log(msg)
|
||||
}
|
||||
|
||||
func (v4 *signer) build() {
|
||||
|
||||
v4.buildTime() // no depends
|
||||
v4.buildCredentialString() // no depends
|
||||
|
||||
unsignedHeaders := v4.Request.Header
|
||||
if v4.isPresign {
|
||||
if !v4.notHoist {
|
||||
urlValues := url.Values{}
|
||||
urlValues, unsignedHeaders = buildQuery(allowedQueryHoisting, unsignedHeaders) // no depends
|
||||
for k := range urlValues {
|
||||
v4.Query[k] = urlValues[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v4.buildCanonicalHeaders(ignoredHeaders, unsignedHeaders)
|
||||
v4.buildCanonicalString() // depends on canon headers / signed headers
|
||||
v4.buildStringToSign() // depends on canon string
|
||||
v4.buildSignature() // depends on string to sign
|
||||
|
||||
if v4.isPresign {
|
||||
v4.Request.URL.RawQuery += "&X-Amz-Signature=" + v4.signature
|
||||
} else {
|
||||
parts := []string{
|
||||
authHeaderPrefix + " Credential=" + v4.CredValues.AccessKeyID + "/" + v4.credentialString,
|
||||
"SignedHeaders=" + v4.signedHeaders,
|
||||
"Signature=" + v4.signature,
|
||||
}
|
||||
v4.Request.Header.Set("Authorization", strings.Join(parts, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
func (v4 *signer) buildTime() {
|
||||
v4.formattedTime = v4.Time.UTC().Format(timeFormat)
|
||||
v4.formattedShortTime = v4.Time.UTC().Format(shortTimeFormat)
|
||||
|
||||
if v4.isPresign {
|
||||
duration := int64(v4.ExpireTime / time.Second)
|
||||
v4.Query.Set("X-Amz-Date", v4.formattedTime)
|
||||
v4.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10))
|
||||
} else {
|
||||
v4.Request.Header.Set("X-Amz-Date", v4.formattedTime)
|
||||
}
|
||||
}
|
||||
|
||||
func (v4 *signer) buildCredentialString() {
|
||||
v4.credentialString = strings.Join([]string{
|
||||
v4.formattedShortTime,
|
||||
v4.Region,
|
||||
v4.ServiceName,
|
||||
"aws4_request",
|
||||
}, "/")
|
||||
|
||||
if v4.isPresign {
|
||||
v4.Query.Set("X-Amz-Credential", v4.CredValues.AccessKeyID+"/"+v4.credentialString)
|
||||
}
|
||||
}
|
||||
|
||||
func buildQuery(r rule, header http.Header) (url.Values, http.Header) {
|
||||
query := url.Values{}
|
||||
unsignedHeaders := http.Header{}
|
||||
for k, h := range header {
|
||||
if r.IsValid(k) {
|
||||
query[k] = h
|
||||
} else {
|
||||
unsignedHeaders[k] = h
|
||||
}
|
||||
}
|
||||
|
||||
return query, unsignedHeaders
|
||||
}
|
||||
func (v4 *signer) buildCanonicalHeaders(r rule, header http.Header) {
|
||||
var headers []string
|
||||
headers = append(headers, "host")
|
||||
for k, v := range header {
|
||||
canonicalKey := http.CanonicalHeaderKey(k)
|
||||
if !r.IsValid(canonicalKey) {
|
||||
continue // ignored header
|
||||
}
|
||||
if v4.signedHeaderVals == nil {
|
||||
v4.signedHeaderVals = make(http.Header)
|
||||
}
|
||||
|
||||
lowerCaseKey := strings.ToLower(k)
|
||||
if _, ok := v4.signedHeaderVals[lowerCaseKey]; ok {
|
||||
// include additional values
|
||||
v4.signedHeaderVals[lowerCaseKey] = append(v4.signedHeaderVals[lowerCaseKey], v...)
|
||||
continue
|
||||
}
|
||||
|
||||
headers = append(headers, lowerCaseKey)
|
||||
v4.signedHeaderVals[lowerCaseKey] = v
|
||||
}
|
||||
sort.Strings(headers)
|
||||
|
||||
v4.signedHeaders = strings.Join(headers, ";")
|
||||
|
||||
if v4.isPresign {
|
||||
v4.Query.Set("X-Amz-SignedHeaders", v4.signedHeaders)
|
||||
}
|
||||
|
||||
headerValues := make([]string, len(headers))
|
||||
for i, k := range headers {
|
||||
if k == "host" {
|
||||
headerValues[i] = "host:" + v4.Request.URL.Host
|
||||
} else {
|
||||
headerValues[i] = k + ":" +
|
||||
strings.Join(v4.signedHeaderVals[k], ",")
|
||||
}
|
||||
}
|
||||
|
||||
v4.canonicalHeaders = strings.Join(stripExcessSpaces(headerValues), "\n")
|
||||
}
|
||||
|
||||
func (v4 *signer) buildCanonicalString() {
|
||||
v4.Request.URL.RawQuery = strings.Replace(v4.Query.Encode(), "+", "%20", -1)
|
||||
uri := v4.Request.URL.Opaque
|
||||
if uri != "" {
|
||||
uri = "/" + strings.Join(strings.Split(uri, "/")[3:], "/")
|
||||
} else {
|
||||
uri = v4.Request.URL.Path
|
||||
}
|
||||
if uri == "" {
|
||||
uri = "/"
|
||||
}
|
||||
|
||||
if v4.ServiceName != "s3" {
|
||||
uri = rest.EscapePath(uri, false)
|
||||
}
|
||||
|
||||
v4.canonicalString = strings.Join([]string{
|
||||
v4.Request.Method,
|
||||
uri,
|
||||
v4.Request.URL.RawQuery,
|
||||
v4.canonicalHeaders + "\n",
|
||||
v4.signedHeaders,
|
||||
v4.bodyDigest(),
|
||||
}, "\n")
|
||||
}
|
||||
|
||||
func (v4 *signer) buildStringToSign() {
|
||||
v4.stringToSign = strings.Join([]string{
|
||||
authHeaderPrefix,
|
||||
v4.formattedTime,
|
||||
v4.credentialString,
|
||||
hex.EncodeToString(makeSha256([]byte(v4.canonicalString))),
|
||||
}, "\n")
|
||||
}
|
||||
|
||||
func (v4 *signer) buildSignature() {
|
||||
secret := v4.CredValues.SecretAccessKey
|
||||
date := makeHmac([]byte("AWS4"+secret), []byte(v4.formattedShortTime))
|
||||
region := makeHmac(date, []byte(v4.Region))
|
||||
service := makeHmac(region, []byte(v4.ServiceName))
|
||||
credentials := makeHmac(service, []byte("aws4_request"))
|
||||
signature := makeHmac(credentials, []byte(v4.stringToSign))
|
||||
v4.signature = hex.EncodeToString(signature)
|
||||
}
|
||||
|
||||
func (v4 *signer) bodyDigest() string {
|
||||
hash := v4.Request.Header.Get("X-Amz-Content-Sha256")
|
||||
if hash == "" {
|
||||
if v4.isPresign && v4.ServiceName == "s3" {
|
||||
hash = "UNSIGNED-PAYLOAD"
|
||||
} else if v4.Body == nil {
|
||||
hash = hex.EncodeToString(makeSha256([]byte{}))
|
||||
} else {
|
||||
hash = hex.EncodeToString(makeSha256Reader(v4.Body))
|
||||
}
|
||||
v4.Request.Header.Add("X-Amz-Content-Sha256", hash)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// isRequestSigned returns if the request is currently signed or presigned
|
||||
func (v4 *signer) isRequestSigned() bool {
|
||||
if v4.isPresign && v4.Query.Get("X-Amz-Signature") != "" {
|
||||
return true
|
||||
}
|
||||
if v4.Request.Header.Get("Authorization") != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// unsign removes signing flags for both signed and presigned requests.
|
||||
func (v4 *signer) removePresign() {
|
||||
v4.Query.Del("X-Amz-Algorithm")
|
||||
v4.Query.Del("X-Amz-Signature")
|
||||
v4.Query.Del("X-Amz-Security-Token")
|
||||
v4.Query.Del("X-Amz-Date")
|
||||
v4.Query.Del("X-Amz-Expires")
|
||||
v4.Query.Del("X-Amz-Credential")
|
||||
v4.Query.Del("X-Amz-SignedHeaders")
|
||||
}
|
||||
|
||||
func makeHmac(key []byte, data []byte) []byte {
|
||||
hash := hmac.New(sha256.New, key)
|
||||
hash.Write(data)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
func makeSha256(data []byte) []byte {
|
||||
hash := sha256.New()
|
||||
hash.Write(data)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
func makeSha256Reader(reader io.ReadSeeker) []byte {
|
||||
hash := sha256.New()
|
||||
start, _ := reader.Seek(0, 1)
|
||||
defer reader.Seek(start, 0)
|
||||
|
||||
io.Copy(hash, reader)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
func stripExcessSpaces(headerVals []string) []string {
|
||||
vals := make([]string, len(headerVals))
|
||||
for i, str := range headerVals {
|
||||
stripped := ""
|
||||
found := false
|
||||
str = strings.TrimSpace(str)
|
||||
for _, c := range str {
|
||||
if !found && c == ' ' {
|
||||
stripped += string(c)
|
||||
found = true
|
||||
} else if c != ' ' {
|
||||
stripped += string(c)
|
||||
found = false
|
||||
}
|
||||
}
|
||||
vals[i] = stripped
|
||||
}
|
||||
return vals
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -7,8 +7,8 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
|
||||
"github.com/aws/aws-sdk-go/private/signer/v4"
|
||||
)
|
||||
|
||||
// You can use Amazon CloudWatch Logs to monitor, store, and access your log
|
||||
|
@ -19,27 +19,28 @@ import (
|
|||
//
|
||||
// You can use CloudWatch Logs to:
|
||||
//
|
||||
// Monitor Logs from Amazon EC2 Instances in Real-time: You can use CloudWatch
|
||||
// Logs to monitor applications and systems using log data. For example, CloudWatch
|
||||
// Logs can track the number of errors that occur in your application logs and
|
||||
// send you a notification whenever the rate of errors exceeds a threshold you
|
||||
// specify. CloudWatch Logs uses your log data for monitoring; so, no code changes
|
||||
// are required. For example, you can monitor application logs for specific
|
||||
// literal terms (such as "NullReferenceException") or count the number of occurrences
|
||||
// of a literal term at a particular position in log data (such as "404" status
|
||||
// codes in an Apache access log). When the term you are searching for is found,
|
||||
// CloudWatch Logs reports the data to a Amazon CloudWatch metric that you specify.
|
||||
// * Monitor Logs from Amazon EC2 Instances in Real-time: You can use CloudWatch
|
||||
// Logs to monitor applications and systems using log data. For example,
|
||||
// CloudWatch Logs can track the number of errors that occur in your application
|
||||
// logs and send you a notification whenever the rate of errors exceeds a
|
||||
// threshold you specify. CloudWatch Logs uses your log data for monitoring;
|
||||
// so, no code changes are required. For example, you can monitor application
|
||||
// logs for specific literal terms (such as "NullReferenceException") or
|
||||
// count the number of occurrences of a literal term at a particular position
|
||||
// in log data (such as "404" status codes in an Apache access log). When
|
||||
// the term you are searching for is found, CloudWatch Logs reports the data
|
||||
// to a Amazon CloudWatch metric that you specify.
|
||||
//
|
||||
// Monitor Amazon CloudTrail Logged Events: You can create alarms in Amazon
|
||||
// CloudWatch and receive notifications of particular API activity as captured
|
||||
// by CloudTrail and use the notification to perform troubleshooting.
|
||||
// * Monitor Amazon CloudTrail Logged Events: You can create alarms in Amazon
|
||||
// CloudWatch and receive notifications of particular API activity as captured
|
||||
// by CloudTrail and use the notification to perform troubleshooting.
|
||||
//
|
||||
// Archive Log Data: You can use CloudWatch Logs to store your log data in
|
||||
// highly durable storage. You can change the log retention setting so that
|
||||
// any log events older than this setting are automatically deleted. The CloudWatch
|
||||
// Logs agent makes it easy to quickly send both rotated and non-rotated log
|
||||
// data off of a host and into the log service. You can then access the raw
|
||||
// log data when you need it.
|
||||
// * Archive Log Data: You can use CloudWatch Logs to store your log data
|
||||
// in highly durable storage. You can change the log retention setting so
|
||||
// that any log events older than this setting are automatically deleted.
|
||||
// The CloudWatch Logs agent makes it easy to quickly send both rotated and
|
||||
// non-rotated log data off of a host and into the log service. You can then
|
||||
// access the raw log data when you need it.
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type CloudWatchLogs struct {
|
||||
|
@ -88,7 +89,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
|||
}
|
||||
|
||||
// Handlers
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
|
||||
svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler)
|
||||
svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler)
|
||||
svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler)
|
||||
|
|
1894
vendor/src/github.com/aws/aws-sdk-go/service/sts/api.go
vendored
Normal file
1894
vendor/src/github.com/aws/aws-sdk-go/service/sts/api.go
vendored
Normal file
File diff suppressed because it is too large
Load diff
12
vendor/src/github.com/aws/aws-sdk-go/service/sts/customizations.go
vendored
Normal file
12
vendor/src/github.com/aws/aws-sdk-go/service/sts/customizations.go
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
package sts
|
||||
|
||||
import "github.com/aws/aws-sdk-go/aws/request"
|
||||
|
||||
func init() {
|
||||
initRequest = func(r *request.Request) {
|
||||
switch r.Operation.Name {
|
||||
case opAssumeRoleWithSAML, opAssumeRoleWithWebIdentity:
|
||||
r.Handlers.Sign.Clear() // these operations are unsigned
|
||||
}
|
||||
}
|
||||
}
|
130
vendor/src/github.com/aws/aws-sdk-go/service/sts/service.go
vendored
Normal file
130
vendor/src/github.com/aws/aws-sdk-go/service/sts/service.go
vendored
Normal file
|
@ -0,0 +1,130 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package sts
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query"
|
||||
)
|
||||
|
||||
// The AWS Security Token Service (STS) is a web service that enables you to
|
||||
// request temporary, limited-privilege credentials for AWS Identity and Access
|
||||
// Management (IAM) users or for users that you authenticate (federated users).
|
||||
// This guide provides descriptions of the STS API. For more detailed information
|
||||
// about using this service, go to Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html).
|
||||
//
|
||||
// As an alternative to using the API, you can use one of the AWS SDKs, which
|
||||
// consist of libraries and sample code for various programming languages and
|
||||
// platforms (Java, Ruby, .NET, iOS, Android, etc.). The SDKs provide a convenient
|
||||
// way to create programmatic access to STS. For example, the SDKs take care
|
||||
// of cryptographically signing requests, managing errors, and retrying requests
|
||||
// automatically. For information about the AWS SDKs, including how to download
|
||||
// and install them, see the Tools for Amazon Web Services page (http://aws.amazon.com/tools/).
|
||||
//
|
||||
// For information about setting up signatures and authorization through the
|
||||
// API, go to Signing AWS API Requests (http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html)
|
||||
// in the AWS General Reference. For general information about the Query API,
|
||||
// go to Making Query Requests (http://docs.aws.amazon.com/IAM/latest/UserGuide/IAM_UsingQueryAPI.html)
|
||||
// in Using IAM. For information about using security tokens with other AWS
|
||||
// products, go to AWS Services That Work with IAM (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html)
|
||||
// in the IAM User Guide.
|
||||
//
|
||||
// If you're new to AWS and need additional technical information about a specific
|
||||
// AWS product, you can find the product's technical documentation at http://aws.amazon.com/documentation/
|
||||
// (http://aws.amazon.com/documentation/).
|
||||
//
|
||||
// Endpoints
|
||||
//
|
||||
// The AWS Security Token Service (STS) has a default endpoint of https://sts.amazonaws.com
|
||||
// that maps to the US East (N. Virginia) region. Additional regions are available
|
||||
// and are activated by default. For more information, see Activating and Deactivating
|
||||
// AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||
// in the IAM User Guide.
|
||||
//
|
||||
// For information about STS endpoints, see Regions and Endpoints (http://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region)
|
||||
// in the AWS General Reference.
|
||||
//
|
||||
// Recording API requests
|
||||
//
|
||||
// STS supports AWS CloudTrail, which is a service that records AWS calls for
|
||||
// your AWS account and delivers log files to an Amazon S3 bucket. By using
|
||||
// information collected by CloudTrail, you can determine what requests were
|
||||
// successfully made to STS, who made the request, when it was made, and so
|
||||
// on. To learn more about CloudTrail, including how to turn it on and find
|
||||
// your log files, see the AWS CloudTrail User Guide (http://docs.aws.amazon.com/awscloudtrail/latest/userguide/what_is_cloud_trail_top_level.html).
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type STS struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// Used for custom client initialization logic
|
||||
var initClient func(*client.Client)
|
||||
|
||||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "sts"
|
||||
|
||||
// New creates a new instance of the STS client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a STS client from just a session.
|
||||
// svc := sts.New(mySession)
|
||||
//
|
||||
// // Create a STS client with additional configuration
|
||||
// svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *STS {
|
||||
svc := &STS{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2011-06-15",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
// Handlers
|
||||
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
|
||||
svc.Handlers.Build.PushBackNamed(query.BuildHandler)
|
||||
svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler)
|
||||
svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler)
|
||||
svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler)
|
||||
|
||||
// Run custom client initialization if present
|
||||
if initClient != nil {
|
||||
initClient(svc.Client)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a STS operation and runs any
|
||||
// custom request initialization.
|
||||
func (c *STS) newRequest(op *request.Operation, params, data interface{}) *request.Request {
|
||||
req := c.NewRequest(op, params, data)
|
||||
|
||||
// Run custom request initialization if present
|
||||
if initRequest != nil {
|
||||
initRequest(req)
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
Loading…
Add table
Reference in a new issue