diff options
author | vitalyisaev <vitalyisaev@ydb.tech> | 2023-12-12 21:55:07 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@ydb.tech> | 2023-12-12 22:25:10 +0300 |
commit | 4967f99474a4040ba150eb04995de06342252718 (patch) | |
tree | c9c118836513a8fab6e9fcfb25be5d404338bca7 /vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds | |
parent | 2ce9cccb9b0bdd4cd7a3491dc5cbf8687cda51de (diff) | |
download | ydb-4967f99474a4040ba150eb04995de06342252718.tar.gz |
YQ Connector: prepare code base for S3 integration
1. Кодовая база Коннектора переписана с помощью Go дженериков так, чтобы добавление нового источника данных (в частности S3 + csv) максимально переиспользовало имеющийся код (чтобы сохранялась логика нарезания на блоки данных, учёт трафика и пр.)
2. API Connector расширено для работы с S3, но ещё пока не протестировано.
Diffstat (limited to 'vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds')
10 files changed, 833 insertions, 0 deletions
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/gotest/ya.make b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/gotest/ya.make new file mode 100644 index 0000000000..47591ee12d --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/gotest/ya.make @@ -0,0 +1,5 @@ +GO_TEST_FOR(vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds) + +LICENSE(Apache-2.0) + +END() diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client.go new file mode 100644 index 0000000000..60b8298f86 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client.go @@ -0,0 +1,148 @@ +package client + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/aws/retry" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go" + smithymiddleware "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// ServiceID is the client identifer +const ServiceID = "endpoint-credentials" + +// HTTPClient is a client for sending HTTP requests +type HTTPClient interface { + Do(*http.Request) (*http.Response, error) +} + +// Options is the endpoint client configurable options +type Options struct { + // The endpoint to retrieve credentials from + Endpoint string + + // The HTTP client to invoke API calls with. Defaults to client's default HTTP + // implementation if nil. + HTTPClient HTTPClient + + // Retryer guides how HTTP requests should be retried in case of recoverable + // failures. When nil the API client will use a default retryer. + Retryer aws.Retryer + + // Set of options to modify how the credentials operation is invoked. + APIOptions []func(*smithymiddleware.Stack) error +} + +// Copy creates a copy of the API options. +func (o Options) Copy() Options { + to := o + to.APIOptions = make([]func(*smithymiddleware.Stack) error, len(o.APIOptions)) + copy(to.APIOptions, o.APIOptions) + return to +} + +// Client is an client for retrieving AWS credentials from an endpoint +type Client struct { + options Options +} + +// New constructs a new Client from the given options +func New(options Options, optFns ...func(*Options)) *Client { + options = options.Copy() + + if options.HTTPClient == nil { + options.HTTPClient = awshttp.NewBuildableClient() + } + + if options.Retryer == nil { + options.Retryer = retry.NewStandard() + } + + for _, fn := range optFns { + fn(&options) + } + + client := &Client{ + options: options, + } + + return client +} + +// GetCredentialsInput is the input to send with the endpoint service to receive credentials. +type GetCredentialsInput struct { + AuthorizationToken string +} + +// GetCredentials retrieves credentials from credential endpoint +func (c *Client) GetCredentials(ctx context.Context, params *GetCredentialsInput, optFns ...func(*Options)) (*GetCredentialsOutput, error) { + stack := smithymiddleware.NewStack("GetCredentials", smithyhttp.NewStackRequest) + options := c.options.Copy() + for _, fn := range optFns { + fn(&options) + } + + stack.Serialize.Add(&serializeOpGetCredential{}, smithymiddleware.After) + stack.Build.Add(&buildEndpoint{Endpoint: options.Endpoint}, smithymiddleware.After) + stack.Deserialize.Add(&deserializeOpGetCredential{}, smithymiddleware.After) + retry.AddRetryMiddlewares(stack, retry.AddRetryMiddlewaresOptions{Retryer: options.Retryer}) + middleware.AddSDKAgentKey(middleware.FeatureMetadata, ServiceID) + smithyhttp.AddErrorCloseResponseBodyMiddleware(stack) + smithyhttp.AddCloseResponseBodyMiddleware(stack) + + for _, fn := range options.APIOptions { + if err := fn(stack); err != nil { + return nil, err + } + } + + handler := smithymiddleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack) + result, _, err := handler.Handle(ctx, params) + if err != nil { + return nil, err + } + + return result.(*GetCredentialsOutput), err +} + +// GetCredentialsOutput is the response from the credential endpoint +type GetCredentialsOutput struct { + Expiration *time.Time + AccessKeyID string + SecretAccessKey string + Token string +} + +// EndpointError is an error returned from the endpoint service +type EndpointError struct { + Code string `json:"code"` + Message string `json:"message"` + Fault smithy.ErrorFault `json:"-"` +} + +// Error is the error mesage string +func (e *EndpointError) Error() string { + return fmt.Sprintf("%s: %s", e.Code, e.Message) +} + +// ErrorCode is the error code returned by the endpoint +func (e *EndpointError) ErrorCode() string { + return e.Code +} + +// ErrorMessage is the error message returned by the endpoint +func (e *EndpointError) ErrorMessage() string { + return e.Message +} + +// ErrorFault indicates error fault classification +func (e *EndpointError) ErrorFault() smithy.ErrorFault { + return e.Fault +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client_test.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client_test.go new file mode 100644 index 0000000000..ac7e37524b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client_test.go @@ -0,0 +1,228 @@ +package client + +import ( + "bytes" + "context" + "errors" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/aws/smithy-go" + smithytesting "github.com/aws/smithy-go/testing" +) + +func TestClient_GetCredentials(t *testing.T) { + cases := map[string]struct { + Token string + RelativeURI string + ResponseCode int + ResponseBody []byte + ExpectResult *GetCredentialsOutput + ExpectErr bool + ValidateRequest func(*testing.T, *http.Request) + ValidateError func(*testing.T, error) bool + }{ + "success static": { + ResponseCode: 200, + ResponseBody: []byte(` { + "AccessKeyId" : "FooKey", + "SecretAccessKey" : "FooSecret" + }`), + ExpectResult: &GetCredentialsOutput{ + AccessKeyID: "FooKey", + SecretAccessKey: "FooSecret", + }, + }, + "success with authorization token": { + Token: "MySecretAuthToken", + ResponseCode: 200, + ResponseBody: []byte(` { + "AccessKeyId" : "FooKey", + "SecretAccessKey" : "FooSecret" + }`), + ExpectResult: &GetCredentialsOutput{ + AccessKeyID: "FooKey", + SecretAccessKey: "FooSecret", + }, + }, + "success refreshable": { + Token: "MySecretAuthToken", + ResponseCode: 200, + ResponseBody: []byte(`{ + "AccessKeyId": "FooKey", + "SecretAccessKey": "FooSecret", + "Token": "FooToken", + "Expiration": "2016-02-25T06:03:31Z" +}`), + ExpectResult: &GetCredentialsOutput{ + AccessKeyID: "FooKey", + SecretAccessKey: "FooSecret", + Token: "FooToken", + Expiration: func() *time.Time { + t := time.Date(2016, 2, 25, 6, 3, 31, 0, time.UTC) + return &t + }(), + }, + }, + "success with additional URI components": { + RelativeURI: "/path/to/thing?someKey=someValue", + ResponseCode: 200, + ResponseBody: []byte(` { + "AccessKeyId" : "FooKey", + "SecretAccessKey" : "FooSecret" + }`), + ValidateRequest: func(t *testing.T, r *http.Request) { + t.Helper() + if e, a := "/path/to/thing", r.URL.Path; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "someValue", r.URL.Query().Get("someKey"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + }, + ExpectResult: &GetCredentialsOutput{ + AccessKeyID: "FooKey", + SecretAccessKey: "FooSecret", + }, + }, + "json error response client fault": { + ResponseCode: 403, + ResponseBody: []byte(`{ + "code": "Unauthorized", + "message": "not authorized for endpoint" +}`), + ExpectErr: true, + ValidateError: func(t *testing.T, err error) (ok bool) { + t.Helper() + var apiError smithy.APIError + if errors.As(err, &apiError) { + if e, a := "Unauthorized", apiError.ErrorCode(); e != a { + t.Errorf("expect %v, got %v", e, a) + ok = false + } + if e, a := "not authorized for endpoint", apiError.ErrorMessage(); e != a { + t.Errorf("expect %v, got %v", e, a) + ok = false + } + if e, a := smithy.FaultClient, apiError.ErrorFault(); e != a { + t.Errorf("expect %v, got %v", e, a) + ok = false + } + } else { + t.Errorf("expect %T error type, got %T: %v", apiError, err, err) + ok = false + } + return ok + }, + }, + "json error response server fault": { + ResponseCode: 500, + ResponseBody: []byte(`{ + "code": "InternalError", + "message": "an error occurred" +}`), + ExpectErr: true, + ValidateError: func(t *testing.T, err error) (ok bool) { + t.Helper() + var apiError smithy.APIError + if errors.As(err, &apiError) { + if e, a := "InternalError", apiError.ErrorCode(); e != a { + t.Errorf("expect %v, got %v", e, a) + ok = false + } + if e, a := "an error occurred", apiError.ErrorMessage(); e != a { + t.Errorf("expect %v, got %v", e, a) + ok = false + } + if e, a := smithy.FaultServer, apiError.ErrorFault(); e != a { + t.Errorf("expect %v, got %v", e, a) + ok = false + } + } else { + t.Errorf("expect %T error type, got %T: %v", apiError, err, err) + ok = false + } + return ok + }, + }, + "non-json error response": { + ResponseCode: 500, + ResponseBody: []byte(`<html><body>unexpected message format</body></html>`), + ExpectErr: true, + ValidateError: func(t *testing.T, err error) (ok bool) { + t.Helper() + if e, a := "failed to decode error message", err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v, got %v", e, a) + ok = false + } + return ok + }, + }, + } + + for name, tt := range cases { + t.Run(name, func(t *testing.T) { + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read r body, %v", err) + } + + actualReq.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes())) + + w.WriteHeader(tt.ResponseCode) + w.Write(tt.ResponseBody) + })) + defer server.Close() + + client := New(Options{Endpoint: server.URL + tt.RelativeURI}) + + result, err := client.GetCredentials(context.Background(), &GetCredentialsInput{AuthorizationToken: tt.Token}) + if (err != nil) != tt.ExpectErr { + t.Fatalf("got error %v, but ExpectErr=%v", err, tt.ExpectErr) + } + if err != nil && tt.ValidateError != nil { + if !tt.ValidateError(t, err) { + return + } + } + + if e, a := "application/json", actualReq.Header.Get("Accept"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + + if len(tt.Token) > 0 { + if e, a := tt.Token, actualReq.Header.Get("Authorization"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + } + + if tt.ValidateRequest != nil { + tt.ValidateRequest(t, actualReq) + } + + if err = smithytesting.CompareValues(tt.ExpectResult, result); err != nil { + t.Errorf("expect value match:\n%v", err) + } + }) + } +} + +func TestClient_GetCredentials_NoEndpoint(t *testing.T) { + client := New(Options{}) + + _, err := client.GetCredentials(context.Background(), &GetCredentialsInput{}) + if err == nil { + t.Fatalf("expect error got none") + } + if e, a := "endpoint not provided", err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v, got %v", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/gotest/ya.make b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/gotest/ya.make new file mode 100644 index 0000000000..00dc081f11 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/gotest/ya.make @@ -0,0 +1,5 @@ +GO_TEST_FOR(vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client) + +LICENSE(Apache-2.0) + +END() diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/middleware.go new file mode 100644 index 0000000000..40747a53c1 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/middleware.go @@ -0,0 +1,120 @@ +package client + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + + "github.com/aws/smithy-go" + smithymiddleware "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +type buildEndpoint struct { + Endpoint string +} + +func (b *buildEndpoint) ID() string { + return "BuildEndpoint" +} + +func (b *buildEndpoint) HandleBuild(ctx context.Context, in smithymiddleware.BuildInput, next smithymiddleware.BuildHandler) ( + out smithymiddleware.BuildOutput, metadata smithymiddleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport, %T", in.Request) + } + + if len(b.Endpoint) == 0 { + return out, metadata, fmt.Errorf("endpoint not provided") + } + + parsed, err := url.Parse(b.Endpoint) + if err != nil { + return out, metadata, fmt.Errorf("failed to parse endpoint, %w", err) + } + + request.URL = parsed + + return next.HandleBuild(ctx, in) +} + +type serializeOpGetCredential struct{} + +func (s *serializeOpGetCredential) ID() string { + return "OperationSerializer" +} + +func (s *serializeOpGetCredential) HandleSerialize(ctx context.Context, in smithymiddleware.SerializeInput, next smithymiddleware.SerializeHandler) ( + out smithymiddleware.SerializeOutput, metadata smithymiddleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type, %T", in.Request) + } + + params, ok := in.Parameters.(*GetCredentialsInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters, %T", in.Parameters) + } + + const acceptHeader = "Accept" + request.Header[acceptHeader] = append(request.Header[acceptHeader][:0], "application/json") + + if len(params.AuthorizationToken) > 0 { + const authHeader = "Authorization" + request.Header[authHeader] = append(request.Header[authHeader][:0], params.AuthorizationToken) + } + + return next.HandleSerialize(ctx, in) +} + +type deserializeOpGetCredential struct{} + +func (d *deserializeOpGetCredential) ID() string { + return "OperationDeserializer" +} + +func (d *deserializeOpGetCredential) HandleDeserialize(ctx context.Context, in smithymiddleware.DeserializeInput, next smithymiddleware.DeserializeHandler) ( + out smithymiddleware.DeserializeOutput, metadata smithymiddleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, deserializeError(response) + } + + var shape *GetCredentialsOutput + if err = json.NewDecoder(response.Body).Decode(&shape); err != nil { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("failed to deserialize json response, %w", err)} + } + + out.Result = shape + return out, metadata, err +} + +func deserializeError(response *smithyhttp.Response) error { + var errShape *EndpointError + err := json.NewDecoder(response.Body).Decode(&errShape) + if err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to decode error message, %w", err)} + } + + if response.StatusCode >= 500 { + errShape.Fault = smithy.FaultServer + } else { + errShape.Fault = smithy.FaultClient + } + + return errShape +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/ya.make b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/ya.make new file mode 100644 index 0000000000..19cb81ab0b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/ya.make @@ -0,0 +1,16 @@ +GO_LIBRARY() + +LICENSE(Apache-2.0) + +SRCS( + client.go + middleware.go +) + +GO_TEST_SRCS(client_test.go) + +END() + +RECURSE( + gotest +) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/ya.make b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/ya.make new file mode 100644 index 0000000000..54d997a3b4 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/ya.make @@ -0,0 +1,3 @@ +RECURSE( + client +) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go new file mode 100644 index 0000000000..adc7fc6b00 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go @@ -0,0 +1,136 @@ +// 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 ( + "context" + "fmt" + "net/http" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client" + "github.com/aws/smithy-go/middleware" +) + +// ProviderName is the name of the credentials provider. +const ProviderName = `CredentialsEndpointProvider` + +type getCredentialsAPIClient interface { + GetCredentials(context.Context, *client.GetCredentialsInput, ...func(*client.Options)) (*client.GetCredentialsOutput, error) +} + +// Provider satisfies the aws.CredentialsProvider interface, and is a client to +// retrieve credentials from an arbitrary endpoint. +type Provider struct { + // The 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 + // EndpointResolver. + client getCredentialsAPIClient + + options Options +} + +// HTTPClient is a client for sending HTTP requests +type HTTPClient interface { + Do(*http.Request) (*http.Response, error) +} + +// Options is structure of configurable options for Provider +type Options struct { + // Endpoint to retrieve credentials from. Required + Endpoint string + + // HTTPClient to handle sending HTTP requests to the target endpoint. + HTTPClient HTTPClient + + // Set of options to modify how the credentials operation is invoked. + APIOptions []func(*middleware.Stack) error + + // The Retryer to be used for determining whether a failed requested should be retried + Retryer aws.Retryer + + // Optional authorization token value if set will be used as the value of + // the Authorization header of the endpoint credential request. + AuthorizationToken string +} + +// New returns a credentials Provider for retrieving AWS credentials +// from arbitrary endpoint. +func New(endpoint string, optFns ...func(*Options)) *Provider { + o := Options{ + Endpoint: endpoint, + } + + for _, fn := range optFns { + fn(&o) + } + + p := &Provider{ + client: client.New(client.Options{ + HTTPClient: o.HTTPClient, + Endpoint: o.Endpoint, + APIOptions: o.APIOptions, + Retryer: o.Retryer, + }), + options: o, + } + + return p +} + +// 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(ctx context.Context) (aws.Credentials, error) { + resp, err := p.getCredentials(ctx) + if err != nil { + return aws.Credentials{}, fmt.Errorf("failed to load credentials, %w", err) + } + + creds := aws.Credentials{ + AccessKeyID: resp.AccessKeyID, + SecretAccessKey: resp.SecretAccessKey, + SessionToken: resp.Token, + Source: ProviderName, + } + + if resp.Expiration != nil { + creds.CanExpire = true + creds.Expires = *resp.Expiration + } + + return creds, nil +} + +func (p *Provider) getCredentials(ctx context.Context) (*client.GetCredentialsOutput, error) { + return p.client.GetCredentials(ctx, &client.GetCredentialsInput{AuthorizationToken: p.options.AuthorizationToken}) +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider_test.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider_test.go new file mode 100644 index 0000000000..15a539518a --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider_test.go @@ -0,0 +1,156 @@ +package endpointcreds_test + +import ( + "bytes" + "context" + "errors" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/credentials/endpointcreds" + "github.com/aws/aws-sdk-go-v2/internal/sdk" + "github.com/aws/smithy-go" +) + +type mockClient func(*http.Request) (*http.Response, error) + +func (m mockClient) Do(r *http.Request) (*http.Response, error) { + return m(r) +} + +func TestRetrieveRefreshableCredentials(t *testing.T) { + orig := sdk.NowTime + defer func() { sdk.NowTime = orig }() + + p := endpointcreds.New("http://127.0.0.1", func(o *endpointcreds.Options) { + o.HTTPClient = mockClient(func(r *http.Request) (*http.Response, error) { + expTime := time.Now().UTC().Add(1 * time.Hour).Format("2006-01-02T15:04:05Z") + + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewReader([]byte(fmt.Sprintf(`{ + "AccessKeyID": "AKID", + "SecretAccessKey": "SECRET", + "Token": "TOKEN", + "Expiration": "%s" +}`, expTime)))), + }, nil + }) + }) + creds, err := p.Retrieve(context.Background()) + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if e, a := "AKID", creds.AccessKeyID; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "SECRET", creds.SecretAccessKey; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "TOKEN", creds.SessionToken; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if creds.Expired() { + t.Errorf("expect not expired") + } + + sdk.NowTime = func() time.Time { + return time.Now().Add(2 * time.Hour) + } + if !creds.Expired() { + t.Errorf("expect to be expired") + } +} + +func TestRetrieveStaticCredentials(t *testing.T) { + orig := sdk.NowTime + defer func() { sdk.NowTime = orig }() + + p := endpointcreds.New("http://127.0.0.1", func(o *endpointcreds.Options) { + o.HTTPClient = mockClient(func(r *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewReader([]byte(`{ + "AccessKeyID": "AKID", + "SecretAccessKey": "SECRET" +}`))), + }, nil + }) + }) + creds, err := p.Retrieve(context.Background()) + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if e, a := "AKID", creds.AccessKeyID; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "SECRET", creds.SecretAccessKey; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if v := creds.SessionToken; len(v) != 0 { + t.Errorf("expect empty, got %v", v) + } + + sdk.NowTime = func() time.Time { + return time.Date(3000, 12, 16, 1, 30, 37, 0, time.UTC) + } + + if creds.Expired() { + t.Errorf("expect not to be expired") + } +} + +func TestFailedRetrieveCredentials(t *testing.T) { + p := endpointcreds.New("http://127.0.0.1", func(o *endpointcreds.Options) { + o.HTTPClient = mockClient(func(r *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: 400, + Body: ioutil.NopCloser(bytes.NewReader([]byte(`{ + "code": "Error", + "message": "Message" +}`))), + }, nil + }) + }) + creds, err := p.Retrieve(context.Background()) + + if err == nil { + t.Fatalf("expect error, got none") + } + + if e, a := "failed to load credentials", err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v, got %v", e, a) + } + + var apiError smithy.APIError + if !errors.As(err, &apiError) { + t.Fatalf("expect %T error, got %v", apiError, err) + } + if e, a := "Error", apiError.ErrorCode(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "Message", apiError.ErrorMessage(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + + if v := creds.AccessKeyID; len(v) != 0 { + t.Errorf("expect empty, got %v", v) + } + if v := creds.SecretAccessKey; len(v) != 0 { + t.Errorf("expect empty, got %v", v) + } + if v := creds.SessionToken; len(v) != 0 { + t.Errorf("expect empty, got %v", v) + } + if creds.Expired() { + t.Errorf("expect empty creds not to be expired") + } +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/ya.make b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/ya.make new file mode 100644 index 0000000000..f56107148a --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/ya.make @@ -0,0 +1,16 @@ +GO_LIBRARY() + +LICENSE(Apache-2.0) + +SRCS( + provider.go +) + +GO_XTEST_SRCS(provider_test.go) + +END() + +RECURSE( + gotest + internal +) |