aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds
diff options
context:
space:
mode:
authorvitalyisaev <vitalyisaev@ydb.tech>2023-12-12 21:55:07 +0300
committervitalyisaev <vitalyisaev@ydb.tech>2023-12-12 22:25:10 +0300
commit4967f99474a4040ba150eb04995de06342252718 (patch)
treec9c118836513a8fab6e9fcfb25be5d404338bca7 /vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds
parent2ce9cccb9b0bdd4cd7a3491dc5cbf8687cda51de (diff)
downloadydb-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/ssocreds')
-rw-r--r--vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/doc.go81
-rw-r--r--vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/gotest/ya.make5
-rw-r--r--vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go233
-rw-r--r--vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go152
-rw-r--r--vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider_test.go195
-rw-r--r--vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_token_provider.go147
-rw-r--r--vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/ya.make24
7 files changed, 837 insertions, 0 deletions
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/doc.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/doc.go
new file mode 100644
index 0000000000..ece1e65f73
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/doc.go
@@ -0,0 +1,81 @@
+// Package ssocreds provides a credential provider for retrieving temporary AWS
+// credentials using an SSO access token.
+//
+// IMPORTANT: The provider in this package does not initiate or perform the AWS
+// SSO login flow. The SDK provider expects that you have already performed the
+// SSO login flow using AWS CLI using the "aws sso login" command, or by some
+// other mechanism. The provider must find a valid non-expired access token for
+// the AWS SSO user portal URL in ~/.aws/sso/cache. If a cached token is not
+// found, it is expired, or the file is malformed an error will be returned.
+//
+// # Loading AWS SSO credentials with the AWS shared configuration file
+//
+// You can use configure AWS SSO credentials from the AWS shared configuration file by
+// specifying the required keys in the profile and referencing an sso-session:
+//
+// sso_session
+// sso_account_id
+// sso_role_name
+//
+// For example, the following defines a profile "devsso" and specifies the AWS
+// SSO parameters that defines the target account, role, sign-on portal, and
+// the region where the user portal is located. Note: all SSO arguments must be
+// provided, or an error will be returned.
+//
+// [profile devsso]
+// sso_session = dev-session
+// sso_role_name = SSOReadOnlyRole
+// sso_account_id = 123456789012
+//
+// [sso-session dev-session]
+// sso_start_url = https://my-sso-portal.awsapps.com/start
+// sso_region = us-east-1
+// sso_registration_scopes = sso:account:access
+//
+// Using the config module, you can load the AWS SDK shared configuration, and
+// specify that this profile be used to retrieve credentials. For example:
+//
+// config, err := config.LoadDefaultConfig(context.TODO(), config.WithSharedConfigProfile("devsso"))
+// if err != nil {
+// return err
+// }
+//
+// # Programmatically loading AWS SSO credentials directly
+//
+// You can programmatically construct the AWS SSO Provider in your application,
+// and provide the necessary information to load and retrieve temporary
+// credentials using an access token from ~/.aws/sso/cache.
+//
+// ssoClient := sso.NewFromConfig(cfg)
+// ssoOidcClient := ssooidc.NewFromConfig(cfg)
+// tokenPath, err := ssocreds.StandardCachedTokenFilepath("dev-session")
+// if err != nil {
+// return err
+// }
+//
+// var provider aws.CredentialsProvider
+// provider = ssocreds.New(ssoClient, "123456789012", "SSOReadOnlyRole", "https://my-sso-portal.awsapps.com/start", func(options *ssocreds.Options) {
+// options.SSOTokenProvider = ssocreds.NewSSOTokenProvider(ssoOidcClient, tokenPath)
+// })
+//
+// // Wrap the provider with aws.CredentialsCache to cache the credentials until their expire time
+// provider = aws.NewCredentialsCache(provider)
+//
+// credentials, err := provider.Retrieve(context.TODO())
+// if err != nil {
+// return err
+// }
+//
+// It is important that you wrap the Provider with aws.CredentialsCache if you
+// are programmatically constructing the provider directly. This prevents your
+// application from accessing the cached access token and requesting new
+// credentials each time the credentials are used.
+//
+// # Additional Resources
+//
+// Configuring the AWS CLI to use AWS Single Sign-On:
+// https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
+//
+// AWS Single Sign-On User Guide:
+// https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html
+package ssocreds
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/gotest/ya.make b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/gotest/ya.make
new file mode 100644
index 0000000000..7b149b0df0
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/gotest/ya.make
@@ -0,0 +1,5 @@
+GO_TEST_FOR(vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds)
+
+LICENSE(Apache-2.0)
+
+END()
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go
new file mode 100644
index 0000000000..3b97e6dd40
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go
@@ -0,0 +1,233 @@
+package ssocreds
+
+import (
+ "crypto/sha1"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/aws/aws-sdk-go-v2/internal/sdk"
+ "github.com/aws/aws-sdk-go-v2/internal/shareddefaults"
+)
+
+var osUserHomeDur = shareddefaults.UserHomeDir
+
+// StandardCachedTokenFilepath returns the filepath for the cached SSO token file, or
+// error if unable get derive the path. Key that will be used to compute a SHA1
+// value that is hex encoded.
+//
+// Derives the filepath using the Key as:
+//
+// ~/.aws/sso/cache/<sha1-hex-encoded-key>.json
+func StandardCachedTokenFilepath(key string) (string, error) {
+ homeDir := osUserHomeDur()
+ if len(homeDir) == 0 {
+ return "", fmt.Errorf("unable to get USER's home directory for cached token")
+ }
+ hash := sha1.New()
+ if _, err := hash.Write([]byte(key)); err != nil {
+ return "", fmt.Errorf("unable to compute cached token filepath key SHA1 hash, %w", err)
+ }
+
+ cacheFilename := strings.ToLower(hex.EncodeToString(hash.Sum(nil))) + ".json"
+
+ return filepath.Join(homeDir, ".aws", "sso", "cache", cacheFilename), nil
+}
+
+type tokenKnownFields struct {
+ AccessToken string `json:"accessToken,omitempty"`
+ ExpiresAt *rfc3339 `json:"expiresAt,omitempty"`
+
+ RefreshToken string `json:"refreshToken,omitempty"`
+ ClientID string `json:"clientId,omitempty"`
+ ClientSecret string `json:"clientSecret,omitempty"`
+}
+
+type token struct {
+ tokenKnownFields
+ UnknownFields map[string]interface{} `json:"-"`
+}
+
+func (t token) MarshalJSON() ([]byte, error) {
+ fields := map[string]interface{}{}
+
+ setTokenFieldString(fields, "accessToken", t.AccessToken)
+ setTokenFieldRFC3339(fields, "expiresAt", t.ExpiresAt)
+
+ setTokenFieldString(fields, "refreshToken", t.RefreshToken)
+ setTokenFieldString(fields, "clientId", t.ClientID)
+ setTokenFieldString(fields, "clientSecret", t.ClientSecret)
+
+ for k, v := range t.UnknownFields {
+ if _, ok := fields[k]; ok {
+ return nil, fmt.Errorf("unknown token field %v, duplicates known field", k)
+ }
+ fields[k] = v
+ }
+
+ return json.Marshal(fields)
+}
+
+func setTokenFieldString(fields map[string]interface{}, key, value string) {
+ if value == "" {
+ return
+ }
+ fields[key] = value
+}
+func setTokenFieldRFC3339(fields map[string]interface{}, key string, value *rfc3339) {
+ if value == nil {
+ return
+ }
+ fields[key] = value
+}
+
+func (t *token) UnmarshalJSON(b []byte) error {
+ var fields map[string]interface{}
+ if err := json.Unmarshal(b, &fields); err != nil {
+ return nil
+ }
+
+ t.UnknownFields = map[string]interface{}{}
+
+ for k, v := range fields {
+ var err error
+ switch k {
+ case "accessToken":
+ err = getTokenFieldString(v, &t.AccessToken)
+ case "expiresAt":
+ err = getTokenFieldRFC3339(v, &t.ExpiresAt)
+ case "refreshToken":
+ err = getTokenFieldString(v, &t.RefreshToken)
+ case "clientId":
+ err = getTokenFieldString(v, &t.ClientID)
+ case "clientSecret":
+ err = getTokenFieldString(v, &t.ClientSecret)
+ default:
+ t.UnknownFields[k] = v
+ }
+
+ if err != nil {
+ return fmt.Errorf("field %q, %w", k, err)
+ }
+ }
+
+ return nil
+}
+
+func getTokenFieldString(v interface{}, value *string) error {
+ var ok bool
+ *value, ok = v.(string)
+ if !ok {
+ return fmt.Errorf("expect value to be string, got %T", v)
+ }
+ return nil
+}
+
+func getTokenFieldRFC3339(v interface{}, value **rfc3339) error {
+ var stringValue string
+ if err := getTokenFieldString(v, &stringValue); err != nil {
+ return err
+ }
+
+ timeValue, err := parseRFC3339(stringValue)
+ if err != nil {
+ return err
+ }
+
+ *value = &timeValue
+ return nil
+}
+
+func loadCachedToken(filename string) (token, error) {
+ fileBytes, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return token{}, fmt.Errorf("failed to read cached SSO token file, %w", err)
+ }
+
+ var t token
+ if err := json.Unmarshal(fileBytes, &t); err != nil {
+ return token{}, fmt.Errorf("failed to parse cached SSO token file, %w", err)
+ }
+
+ if len(t.AccessToken) == 0 || t.ExpiresAt == nil || time.Time(*t.ExpiresAt).IsZero() {
+ return token{}, fmt.Errorf(
+ "cached SSO token must contain accessToken and expiresAt fields")
+ }
+
+ return t, nil
+}
+
+func storeCachedToken(filename string, t token, fileMode os.FileMode) (err error) {
+ tmpFilename := filename + ".tmp-" + strconv.FormatInt(sdk.NowTime().UnixNano(), 10)
+ if err := writeCacheFile(tmpFilename, fileMode, t); err != nil {
+ return err
+ }
+
+ if err := os.Rename(tmpFilename, filename); err != nil {
+ return fmt.Errorf("failed to replace old cached SSO token file, %w", err)
+ }
+
+ return nil
+}
+
+func writeCacheFile(filename string, fileMode os.FileMode, t token) (err error) {
+ var f *os.File
+ f, err = os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_RDWR, fileMode)
+ if err != nil {
+ return fmt.Errorf("failed to create cached SSO token file %w", err)
+ }
+
+ defer func() {
+ closeErr := f.Close()
+ if err == nil && closeErr != nil {
+ err = fmt.Errorf("failed to close cached SSO token file, %w", closeErr)
+ }
+ }()
+
+ encoder := json.NewEncoder(f)
+
+ if err = encoder.Encode(t); err != nil {
+ return fmt.Errorf("failed to serialize cached SSO token, %w", err)
+ }
+
+ return nil
+}
+
+type rfc3339 time.Time
+
+func parseRFC3339(v string) (rfc3339, error) {
+ parsed, err := time.Parse(time.RFC3339, v)
+ if err != nil {
+ return rfc3339{}, fmt.Errorf("expected RFC3339 timestamp: %w", err)
+ }
+
+ return rfc3339(parsed), nil
+}
+
+func (r *rfc3339) UnmarshalJSON(bytes []byte) (err error) {
+ var value string
+
+ // Use JSON unmarshal to unescape the quoted value making use of JSON's
+ // unquoting rules.
+ if err = json.Unmarshal(bytes, &value); err != nil {
+ return err
+ }
+
+ *r, err = parseRFC3339(value)
+
+ return nil
+}
+
+func (r *rfc3339) MarshalJSON() ([]byte, error) {
+ value := time.Time(*r).Format(time.RFC3339)
+
+ // Use JSON unmarshal to unescape the quoted value making use of JSON's
+ // quoting rules.
+ return json.Marshal(value)
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go
new file mode 100644
index 0000000000..b3cf7853e7
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go
@@ -0,0 +1,152 @@
+package ssocreds
+
+import (
+ "context"
+ "time"
+
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/internal/sdk"
+ "github.com/aws/aws-sdk-go-v2/service/sso"
+)
+
+// ProviderName is the name of the provider used to specify the source of
+// credentials.
+const ProviderName = "SSOProvider"
+
+// GetRoleCredentialsAPIClient is a API client that implements the
+// GetRoleCredentials operation.
+type GetRoleCredentialsAPIClient interface {
+ GetRoleCredentials(context.Context, *sso.GetRoleCredentialsInput, ...func(*sso.Options)) (
+ *sso.GetRoleCredentialsOutput, error,
+ )
+}
+
+// Options is the Provider options structure.
+type Options struct {
+ // The Client which is configured for the AWS Region where the AWS SSO user
+ // portal is located.
+ Client GetRoleCredentialsAPIClient
+
+ // The AWS account that is assigned to the user.
+ AccountID string
+
+ // The role name that is assigned to the user.
+ RoleName string
+
+ // The URL that points to the organization's AWS Single Sign-On (AWS SSO)
+ // user portal.
+ StartURL string
+
+ // The filepath the cached token will be retrieved from. If unset Provider will
+ // use the startURL to determine the filepath at.
+ //
+ // ~/.aws/sso/cache/<sha1-hex-encoded-startURL>.json
+ //
+ // If custom cached token filepath is used, the Provider's startUrl
+ // parameter will be ignored.
+ CachedTokenFilepath string
+
+ // Used by the SSOCredentialProvider if a token configuration
+ // profile is used in the shared config
+ SSOTokenProvider *SSOTokenProvider
+}
+
+// Provider is an AWS credential provider that retrieves temporary AWS
+// credentials by exchanging an SSO login token.
+type Provider struct {
+ options Options
+
+ cachedTokenFilepath string
+}
+
+// New returns a new AWS Single Sign-On (AWS SSO) credential provider. The
+// provided client is expected to be configured for the AWS Region where the
+// AWS SSO user portal is located.
+func New(client GetRoleCredentialsAPIClient, accountID, roleName, startURL string, optFns ...func(options *Options)) *Provider {
+ options := Options{
+ Client: client,
+ AccountID: accountID,
+ RoleName: roleName,
+ StartURL: startURL,
+ }
+
+ for _, fn := range optFns {
+ fn(&options)
+ }
+
+ return &Provider{
+ options: options,
+ cachedTokenFilepath: options.CachedTokenFilepath,
+ }
+}
+
+// Retrieve retrieves temporary AWS credentials from the configured Amazon
+// Single Sign-On (AWS SSO) user portal by exchanging the accessToken present
+// in ~/.aws/sso/cache. However, if a token provider configuration exists
+// in the shared config, then we ought to use the token provider rather then
+// direct access on the cached token.
+func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) {
+ var accessToken *string
+ if p.options.SSOTokenProvider != nil {
+ token, err := p.options.SSOTokenProvider.RetrieveBearerToken(ctx)
+ if err != nil {
+ return aws.Credentials{}, err
+ }
+ accessToken = &token.Value
+ } else {
+ if p.cachedTokenFilepath == "" {
+ cachedTokenFilepath, err := StandardCachedTokenFilepath(p.options.StartURL)
+ if err != nil {
+ return aws.Credentials{}, &InvalidTokenError{Err: err}
+ }
+ p.cachedTokenFilepath = cachedTokenFilepath
+ }
+
+ tokenFile, err := loadCachedToken(p.cachedTokenFilepath)
+ if err != nil {
+ return aws.Credentials{}, &InvalidTokenError{Err: err}
+ }
+
+ if tokenFile.ExpiresAt == nil || sdk.NowTime().After(time.Time(*tokenFile.ExpiresAt)) {
+ return aws.Credentials{}, &InvalidTokenError{}
+ }
+ accessToken = &tokenFile.AccessToken
+ }
+
+ output, err := p.options.Client.GetRoleCredentials(ctx, &sso.GetRoleCredentialsInput{
+ AccessToken: accessToken,
+ AccountId: &p.options.AccountID,
+ RoleName: &p.options.RoleName,
+ })
+ if err != nil {
+ return aws.Credentials{}, err
+ }
+
+ return aws.Credentials{
+ AccessKeyID: aws.ToString(output.RoleCredentials.AccessKeyId),
+ SecretAccessKey: aws.ToString(output.RoleCredentials.SecretAccessKey),
+ SessionToken: aws.ToString(output.RoleCredentials.SessionToken),
+ CanExpire: true,
+ Expires: time.Unix(0, output.RoleCredentials.Expiration*int64(time.Millisecond)).UTC(),
+ Source: ProviderName,
+ }, nil
+}
+
+// InvalidTokenError is the error type that is returned if loaded token has
+// expired or is otherwise invalid. To refresh the SSO session run AWS SSO
+// login with the corresponding profile.
+type InvalidTokenError struct {
+ Err error
+}
+
+func (i *InvalidTokenError) Unwrap() error {
+ return i.Err
+}
+
+func (i *InvalidTokenError) Error() string {
+ const msg = "the SSO session has expired or is invalid"
+ if i.Err == nil {
+ return msg
+ }
+ return msg + ": " + i.Err.Error()
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider_test.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider_test.go
new file mode 100644
index 0000000000..c9006ea63c
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider_test.go
@@ -0,0 +1,195 @@
+package ssocreds
+
+import (
+ "context"
+ "fmt"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/internal/sdk"
+ "github.com/aws/aws-sdk-go-v2/service/sso"
+ "github.com/aws/aws-sdk-go-v2/service/sso/types"
+ "github.com/google/go-cmp/cmp"
+)
+
+type mockClient struct {
+ t *testing.T
+
+ Output *sso.GetRoleCredentialsOutput
+ Err error
+
+ ExpectedAccountID string
+ ExpectedAccessToken string
+ ExpectedRoleName string
+
+ Response func(mockClient) (*sso.GetRoleCredentialsOutput, error)
+}
+
+func (m mockClient) GetRoleCredentials(ctx context.Context, params *sso.GetRoleCredentialsInput, optFns ...func(options *sso.Options)) (out *sso.GetRoleCredentialsOutput, err error) {
+ m.t.Helper()
+
+ if len(m.ExpectedAccountID) > 0 {
+ if diff := cmp.Diff(m.ExpectedAccountID, aws.ToString(params.AccountId)); len(diff) > 0 {
+ m.t.Error(diff)
+ }
+ }
+
+ if len(m.ExpectedAccessToken) > 0 {
+ if diff := cmp.Diff(m.ExpectedAccessToken, aws.ToString(params.AccessToken)); len(diff) > 0 {
+ m.t.Error(diff)
+ }
+ }
+
+ if len(m.ExpectedRoleName) > 0 {
+ if diff := cmp.Diff(m.ExpectedRoleName, aws.ToString(params.RoleName)); len(diff) > 0 {
+ m.t.Error(diff)
+ }
+ }
+
+ if m.Response == nil {
+ return out, err
+ }
+ return m.Response(m)
+}
+
+func TestProvider(t *testing.T) {
+ origHomeDir := osUserHomeDur
+ defer func() {
+ osUserHomeDur = origHomeDir
+ }()
+
+ osUserHomeDur = func() string {
+ return "testdata"
+ }
+
+ restoreTime := sdk.TestingUseReferenceTime(time.Date(2021, 01, 19, 19, 50, 0, 0, time.UTC))
+ defer restoreTime()
+
+ cases := map[string]struct {
+ Client mockClient
+ AccountID string
+ Region string
+ RoleName string
+ StartURL string
+ Options []func(*Options)
+
+ ExpectedErr string
+ ExpectedCredentials aws.Credentials
+ }{
+ "missing required parameter values": {
+ StartURL: "https://invalid-required",
+ ExpectedErr: "cached SSO token must contain accessToken and expiresAt fields",
+ },
+ "valid required parameter values": {
+ Client: mockClient{
+ ExpectedAccountID: "012345678901",
+ ExpectedRoleName: "TestRole",
+ ExpectedAccessToken: "dGhpcyBpcyBub3QgYSByZWFsIHZhbHVl",
+ Response: func(mock mockClient) (*sso.GetRoleCredentialsOutput, error) {
+ return &sso.GetRoleCredentialsOutput{
+ RoleCredentials: &types.RoleCredentials{
+ AccessKeyId: aws.String("AccessKey"),
+ SecretAccessKey: aws.String("SecretKey"),
+ SessionToken: aws.String("SessionToken"),
+ Expiration: 1611177743123,
+ },
+ }, nil
+ },
+ },
+ AccountID: "012345678901",
+ Region: "us-west-2",
+ RoleName: "TestRole",
+ StartURL: "https://valid-required-only",
+ ExpectedCredentials: aws.Credentials{
+ AccessKeyID: "AccessKey",
+ SecretAccessKey: "SecretKey",
+ SessionToken: "SessionToken",
+ CanExpire: true,
+ Expires: time.Date(2021, 01, 20, 21, 22, 23, 0.123e9, time.UTC),
+ Source: ProviderName,
+ },
+ },
+ "custom cached token file": {
+ Client: mockClient{
+ ExpectedAccountID: "012345678901",
+ ExpectedRoleName: "TestRole",
+ ExpectedAccessToken: "dGhpcyBpcyBub3QgYSByZWFsIHZhbHVl",
+ Response: func(mock mockClient) (*sso.GetRoleCredentialsOutput, error) {
+ return &sso.GetRoleCredentialsOutput{
+ RoleCredentials: &types.RoleCredentials{
+ AccessKeyId: aws.String("AccessKey"),
+ SecretAccessKey: aws.String("SecretKey"),
+ SessionToken: aws.String("SessionToken"),
+ Expiration: 1611177743123,
+ },
+ }, nil
+ },
+ },
+ Options: []func(*Options){
+ func(o *Options) {
+ o.CachedTokenFilepath = filepath.Join("testdata", "valid_token.json")
+ },
+ },
+ AccountID: "012345678901",
+ Region: "us-west-2",
+ RoleName: "TestRole",
+ StartURL: "ignored value",
+ ExpectedCredentials: aws.Credentials{
+ AccessKeyID: "AccessKey",
+ SecretAccessKey: "SecretKey",
+ SessionToken: "SessionToken",
+ CanExpire: true,
+ Expires: time.Date(2021, 01, 20, 21, 22, 23, 0.123e9, time.UTC),
+ Source: ProviderName,
+ },
+ },
+ "expired access token": {
+ StartURL: "https://expired",
+ ExpectedErr: "SSO session has expired or is invalid",
+ },
+ "api error": {
+ Client: mockClient{
+ ExpectedAccountID: "012345678901",
+ ExpectedRoleName: "TestRole",
+ ExpectedAccessToken: "dGhpcyBpcyBub3QgYSByZWFsIHZhbHVl",
+ Response: func(mock mockClient) (*sso.GetRoleCredentialsOutput, error) {
+ return nil, fmt.Errorf("api error")
+ },
+ },
+ AccountID: "012345678901",
+ Region: "us-west-2",
+ RoleName: "TestRole",
+ StartURL: "https://valid-required-only",
+ ExpectedErr: "api error",
+ },
+ }
+
+ for name, tt := range cases {
+ t.Run(name, func(t *testing.T) {
+ tt.Client.t = t
+
+ provider := New(tt.Client, tt.AccountID, tt.RoleName, tt.StartURL, tt.Options...)
+
+ credentials, err := provider.Retrieve(context.Background())
+ if tt.ExpectedErr != "" {
+ if err == nil {
+ t.Fatalf("expect %v error, got none", tt.ExpectedErr)
+ }
+ if e, a := tt.ExpectedErr, err.Error(); !strings.Contains(a, e) {
+ t.Fatalf("expect %v error, got %v", e, a)
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("expect no error, got %v", err)
+ }
+
+ if diff := cmp.Diff(tt.ExpectedCredentials, credentials); len(diff) > 0 {
+ t.Errorf(diff)
+ }
+ })
+ }
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_token_provider.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_token_provider.go
new file mode 100644
index 0000000000..7f4fc54677
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_token_provider.go
@@ -0,0 +1,147 @@
+package ssocreds
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/internal/sdk"
+ "github.com/aws/aws-sdk-go-v2/service/ssooidc"
+ "github.com/aws/smithy-go/auth/bearer"
+)
+
+// CreateTokenAPIClient provides the interface for the SSOTokenProvider's API
+// client for calling CreateToken operation to refresh the SSO token.
+type CreateTokenAPIClient interface {
+ CreateToken(context.Context, *ssooidc.CreateTokenInput, ...func(*ssooidc.Options)) (
+ *ssooidc.CreateTokenOutput, error,
+ )
+}
+
+// SSOTokenProviderOptions provides the options for configuring the
+// SSOTokenProvider.
+type SSOTokenProviderOptions struct {
+ // Client that can be overridden
+ Client CreateTokenAPIClient
+
+ // The set of API Client options to be applied when invoking the
+ // CreateToken operation.
+ ClientOptions []func(*ssooidc.Options)
+
+ // The path the file containing the cached SSO token will be read from.
+ // Initialized the NewSSOTokenProvider's cachedTokenFilepath parameter.
+ CachedTokenFilepath string
+}
+
+// SSOTokenProvider provides an utility for refreshing SSO AccessTokens for
+// Bearer Authentication. The SSOTokenProvider can only be used to refresh
+// already cached SSO Tokens. This utility cannot perform the initial SSO
+// create token.
+//
+// The SSOTokenProvider is not safe to use concurrently. It must be wrapped in
+// a utility such as smithy-go's auth/bearer#TokenCache. The SDK's
+// config.LoadDefaultConfig will automatically wrap the SSOTokenProvider with
+// the smithy-go TokenCache, if the external configuration loaded configured
+// for an SSO session.
+//
+// The initial SSO create token should be preformed with the AWS CLI before the
+// Go application using the SSOTokenProvider will need to retrieve the SSO
+// token. If the AWS CLI has not created the token cache file, this provider
+// will return an error when attempting to retrieve the cached token.
+//
+// This provider will attempt to refresh the cached SSO token periodically if
+// needed when RetrieveBearerToken is called.
+//
+// A utility such as the AWS CLI must be used to initially create the SSO
+// session and cached token file.
+// https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
+type SSOTokenProvider struct {
+ options SSOTokenProviderOptions
+}
+
+var _ bearer.TokenProvider = (*SSOTokenProvider)(nil)
+
+// NewSSOTokenProvider returns an initialized SSOTokenProvider that will
+// periodically refresh the SSO token cached stored in the cachedTokenFilepath.
+// The cachedTokenFilepath file's content will be rewritten by the token
+// provider when the token is refreshed.
+//
+// The client must be configured for the AWS region the SSO token was created for.
+func NewSSOTokenProvider(client CreateTokenAPIClient, cachedTokenFilepath string, optFns ...func(o *SSOTokenProviderOptions)) *SSOTokenProvider {
+ options := SSOTokenProviderOptions{
+ Client: client,
+ CachedTokenFilepath: cachedTokenFilepath,
+ }
+ for _, fn := range optFns {
+ fn(&options)
+ }
+
+ provider := &SSOTokenProvider{
+ options: options,
+ }
+
+ return provider
+}
+
+// RetrieveBearerToken returns the SSO token stored in the cachedTokenFilepath
+// the SSOTokenProvider was created with. If the token has expired
+// RetrieveBearerToken will attempt to refresh it. If the token cannot be
+// refreshed or is not present an error will be returned.
+//
+// A utility such as the AWS CLI must be used to initially create the SSO
+// session and cached token file. https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
+func (p SSOTokenProvider) RetrieveBearerToken(ctx context.Context) (bearer.Token, error) {
+ cachedToken, err := loadCachedToken(p.options.CachedTokenFilepath)
+ if err != nil {
+ return bearer.Token{}, err
+ }
+
+ if cachedToken.ExpiresAt != nil && sdk.NowTime().After(time.Time(*cachedToken.ExpiresAt)) {
+ cachedToken, err = p.refreshToken(ctx, cachedToken)
+ if err != nil {
+ return bearer.Token{}, fmt.Errorf("refresh cached SSO token failed, %w", err)
+ }
+ }
+
+ expiresAt := aws.ToTime((*time.Time)(cachedToken.ExpiresAt))
+ return bearer.Token{
+ Value: cachedToken.AccessToken,
+ CanExpire: !expiresAt.IsZero(),
+ Expires: expiresAt,
+ }, nil
+}
+
+func (p SSOTokenProvider) refreshToken(ctx context.Context, cachedToken token) (token, error) {
+ if cachedToken.ClientSecret == "" || cachedToken.ClientID == "" || cachedToken.RefreshToken == "" {
+ return token{}, fmt.Errorf("cached SSO token is expired, or not present, and cannot be refreshed")
+ }
+
+ createResult, err := p.options.Client.CreateToken(ctx, &ssooidc.CreateTokenInput{
+ ClientId: &cachedToken.ClientID,
+ ClientSecret: &cachedToken.ClientSecret,
+ RefreshToken: &cachedToken.RefreshToken,
+ GrantType: aws.String("refresh_token"),
+ }, p.options.ClientOptions...)
+ if err != nil {
+ return token{}, fmt.Errorf("unable to refresh SSO token, %w", err)
+ }
+
+ expiresAt := sdk.NowTime().Add(time.Duration(createResult.ExpiresIn) * time.Second)
+
+ cachedToken.AccessToken = aws.ToString(createResult.AccessToken)
+ cachedToken.ExpiresAt = (*rfc3339)(&expiresAt)
+ cachedToken.RefreshToken = aws.ToString(createResult.RefreshToken)
+
+ fileInfo, err := os.Stat(p.options.CachedTokenFilepath)
+ if err != nil {
+ return token{}, fmt.Errorf("failed to stat cached SSO token file %w", err)
+ }
+
+ if err = storeCachedToken(p.options.CachedTokenFilepath, cachedToken, fileInfo.Mode()); err != nil {
+ return token{}, fmt.Errorf("unable to cache refreshed SSO token, %w", err)
+ }
+
+ return cachedToken, nil
+}
diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/ya.make b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/ya.make
new file mode 100644
index 0000000000..4d3de6c163
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/ya.make
@@ -0,0 +1,24 @@
+GO_LIBRARY()
+
+LICENSE(Apache-2.0)
+
+GO_SKIP_TESTS(TestProvider)
+
+SRCS(
+ doc.go
+ sso_cached_token.go
+ sso_credentials_provider.go
+ sso_token_provider.go
+)
+
+GO_TEST_SRCS(
+ # sso_cached_token_test.go
+ sso_credentials_provider_test.go
+ # sso_token_provider_test.go
+)
+
+END()
+
+RECURSE(
+ gotest
+)