Skip to content
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,20 @@ functions:
binary: "bash"
include_expansions_in_env: [KMS_TLS_TESTCASE]
args: [*task-runner, evg-test-kms]
run-custom-aws-credentials-test:
- command: subprocess.exec
params:
binary: "bash"
env:
GO_BUILD_TAGS: cse
include_expansions_in_env: [AUTH, SSL, MONGODB_URI, TOPOLOGY, MONGO_GO_DRIVER_COMPRESSOR]
args: [*task-runner, setup-test]
- command: subprocess.exec
type: test
retry_on_failure: true
params:
binary: "bash"
args: [*task-runner, evg-test-custom-aws-credentials]
run-kmip-tests:
- command: subprocess.exec
params:
Expand Down Expand Up @@ -1438,6 +1452,16 @@ tasks:
TOPOLOGY: "server"
AUTH: "noauth"
SSL: "nossl"
- name: "test-custom-aws-credentials"
tags: ["kms-test"]
commands:
- func: bootstrap-mongo-orchestration
vars:
TOPOLOGY: "server"
AUTH: "noauth"
SSL: "nossl"
- func: start-cse-servers
- func: run-custom-aws-credentials-test
- name: "test-kms-kmip"
tags: ["kms-kmip"]
commands:
Expand Down
2 changes: 2 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ tasks:
- go test -exec "env PKG_CONFIG_PATH=${PKG_CONFIG_PATH} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} DYLD_LIBRARY_PATH=${MACOS_LIBRARY_PATH}" ${BUILD_TAGS} -v -timeout {{.TEST_TIMEOUT}}s ./internal/integration -run TestClientSideEncryptionProse/kms_tls_options_test >> test.suite
evg-test-kms:
- go test -exec "env PKG_CONFIG_PATH=${PKG_CONFIG_PATH} LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" ${BUILD_TAGS} -v -timeout {{.TEST_TIMEOUT}}s ./internal/integration -run TestClientSideEncryptionProse/kms_tls_tests >> test.suite
evg-test-custom-aws-credentials:
- go test -exec "env PKG_CONFIG_PATH=${PKG_CONFIG_PATH} LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" ${BUILD_TAGS} -v -timeout {{.TEST_TIMEOUT}}s ./internal/integration -run TestCustomAwsCredentialsProse >> test.suite
evg-test-retry-kms-requests:
- go test -exec "env PKG_CONFIG_PATH=${PKG_CONFIG_PATH} LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" ${BUILD_TAGS} -v -timeout {{.TEST_TIMEOUT}}s ./internal/integration -run TestClientSideEncryptionProse/kms_retry_tests >> test.suite
evg-test-load-balancers:
Expand Down
20 changes: 20 additions & 0 deletions ext/awsauth/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

// This package allows credential providers and signers in v2 AWS SDK to be
// supplied to the MongoDB Go Driver for use with the MONGODB-AWS authentication
// mechanism.
//

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[docs] We should add context about avoiding the AWS SDK depenency in the main driver:

Suggested change
//
//
// This package is a separate module to avoid adding the AWS SDK as a dependency
// of the main driver. Users who don't need AWS authentication won't need to
// import the AWS SDK.
//

// NewCredentialsProvider() adapts an AWS CredentialsProvider to be used in:
//
// ClientOptions
// ClinetEncryptionOptions

Copilot AI Jan 17, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: "ClinetEncryptionOptions" should be "ClientEncryptionOptions".

Suggested change
// ClinetEncryptionOptions
// ClientEncryptionOptions

Copilot uses AI. Check for mistakes.
// AutoEncryptionOptions
//
// NewSigner() adapts an AWS HTTPSigner to be used in:
//
// ClientOptions
package awsauth
21 changes: 21 additions & 0 deletions ext/awsauth/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module go.mongodb.org/mongo-driver/v2/awsauth

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're planning to tag the initial module release with v0.1, so the module name should not include "v2", but should include the "ext" dir.

Suggested change
module go.mongodb.org/mongo-driver/v2/awsauth
module go.mongodb.org/mongo-driver/ext/awsauth


go 1.23

require (
github.com/aws/aws-sdk-go-v2 v1.40.1
go.mongodb.org/mongo-driver/v2 v2.0.0-beta2
)

require (
github.com/aws/smithy-go v1.24.0 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/klauspost/compress v1.17.6 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.2.0 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/text v0.22.0 // indirect
)
52 changes: 52 additions & 0 deletions ext/awsauth/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
github.com/aws/aws-sdk-go-v2 v1.40.1 h1:difXb4maDZkRH0x//Qkwcfpdg1XQVXEAEs2DdXldFFc=
github.com/aws/aws-sdk-go-v2 v1.40.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver/v2 v2.0.0-beta2 h1:PRtbRKwblE8ZfI8qOhofcjn9y8CmKZI7trS5vDMeJX0=
go.mongodb.org/mongo-driver/v2 v2.0.0-beta2/go.mod h1:UGLb3ZgEzaY0cCbJpH9UFt9B6gEXiTPzsnJS38nBeoU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
76 changes: 76 additions & 0 deletions ext/awsauth/mongoaws.go

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Rename file to awsauth.go.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

package awsauth

import (
"context"
"crypto/sha256"
"encoding/hex"
"net/http"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"

"go.mongodb.org/mongo-driver/v2/mongo/options"
)

const (
// emptyStringSHA256 is a SHA256 of an empty string
emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
)

var _ options.AWSCredentialsProvider = (*CredentialsProvider)(nil)

// CredentialsProvider is an implementation of options.AWSCredentialsProvider in

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] This documentation is kind of missleading. CredentialsProvider is just a thin wrapper around aws.CredentialsProvider and doesn't directly provide "caching and concurrency safe credentials retrieval".

// CredentialsProvider adapts an AWS SDK v2 CredentialsProvider to the
// options.AWSCredentialsProvider interface used by the MongoDB Go Driver.

// MongoDB Go driver. It provides caching and concurrency safe credentials retrieval
// via the provider's retrieve method.
type CredentialsProvider struct {
Comment thread
prestonvasquez marked this conversation as resolved.
Outdated
provider aws.CredentialsProvider
}

// NewCredentialsProvider returns a CredentialsProvider that wraps AWS
// CredentialsProvider. Provider is expected to not be nil.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provider is expected to not be nil

[question] Should we just validate this to prevent misuse?

func NewCredentialsProvider(provider aws.CredentialsProvider) *CredentialsProvider {
return &CredentialsProvider{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[question] Does this need to return a pointer references? Whatever we decide, can we make NewSigner symmetric?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making the NewSigner() align with the NewCredentialsProvider(). Will also return an error to indicate the nil interface.

provider: provider,
}
}

// Retrieve returns the credentials.
func (p *CredentialsProvider) Retrieve(ctx context.Context) (options.AWSCredentials, error) {
creds, err := p.provider.Retrieve(ctx)
return options.AWSCredentials(creds), err
}

var _ options.AWSSigner = (*Signer)(nil)

// Signer is an implementation of options.AWSSigner in MongoDB Go driver.
type Signer struct {
signer v4.HTTPSigner
}

// NewSigner creates a new Signer from the provided AWS HTTPSigner.
func NewSigner(httpSigner v4.HTTPSigner) Signer {
return Signer{
signer: httpSigner,
}
}

// Sign signs AWS v4 requests.
func (s Signer) Sign(

@prestonvasquez prestonvasquez Jan 26, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[docs] We should note that this method hashes the payload if it's not empty.

// The payload parameter should be the raw request body. This method computes
// the SHA256 hash of the payload before signing. If payload is empty, the
// precomputed hash of an empty string is used.

ctx context.Context, creds options.AWSCredentials, r *http.Request,
payload, service, region string, signingTime time.Time) error {
if len(payload) == 0 {
payload = emptyStringSHA256
} else {
hash := sha256.Sum256([]byte(payload))
payload = hex.EncodeToString(hash[:])
}
r.Header.Set("X-Amz-Security-Token", creds.SessionToken)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[question] Do we need to guard this against empty creds.SessionToken?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The guard is in aws_conv.go. IMO, the methods in this file should only be a shin layer that adapts the AWS SDK to the go driver interface. Therefore, we shouldn't include a lot of go driver logic here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT we don't unset X-Amz-Security-Token in aws_conv.go. We just use it to set another header. I think we should avoid sending an empty value, in case that has some connotation we aren't aware of.

return s.signer.SignHTTP(ctx, aws.Credentials(creds), r, payload, service, region, signingTime)
}
45 changes: 45 additions & 0 deletions ext/awsauth/mongoaws_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

package awsauth

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testable examples should always be in a *_test package. That has two benefits:

  1. The example code has to import the package under test (e.g. awstest here), so it looks more like the code a customer would write.
  2. Testable example functions are rendered as full code files, including imports and a main block, in the docs site.
Suggested change
package awsauth
package awsauth_test


import (
"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)

func ExampleNewCredentialsProvider() {
awsCredentialProvider := NewCredentialsProvider(aws.NewConfig().Credentials)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[docs] Users would typically load credentials using LoadDefaultConfig, can we update examples to do that?

cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    panic(err)
}
awsCredentialProvider := NewCredentialsProvider(cfg.Credentials)

credential := options.Credential{
AuthMechanism: "MONGODB-AWS",
AWSCredentialsProvider: awsCredentialProvider,
}
client, err := mongo.Connect(
options.Client().SetAuth(credential))
if err != nil {
panic(err)
}
_ = client
}

func ExampleNewSigner() {
awsCredentialProvider := NewCredentialsProvider(aws.NewConfig().Credentials)
awsSigner := NewSigner(v4.NewSigner())
_ = awsSigner
credential := options.Credential{
AuthMechanism: "MONGODB-AWS",
AWSCredentialsProvider: awsCredentialProvider,
AWSSigner: awsSigner,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned asking customers to specify both AWSCredentialsProvider and AWSSigner is going to create confusion. There's currently no observable behavior difference and no guidance on why a customer should specify it. Also, having to initialize and specify both a cred provider and a signer separately requires customers to write more code that could be avoided if the interfaces were combined.

We should either:

  1. Combine the AWSCredentialsProvider and AWSSigner interfaces and update the docs to say that we're planning to require customers to use awsauth for signing in Go Driver v3.
  2. Remove the AWSSigner interface and the awsauth.Signer type.

I prefer option 2 because it seems to be a better overall customer experience. While it would be nice to eventually remove the AWS v4 signing logic from the Go Driver, it doesn't seem worth a more confusing API.

}
client, err := mongo.Connect(
options.Client().SetAuth(credential))
if err != nil {
panic(err)
}
_ = client
}
1 change: 1 addition & 0 deletions go.work
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ use (
./internal/cmd/faas/awslambda/mongodb
./internal/test/compilecheck
./internal/test/goleak
./ext/awsauth
)
37 changes: 10 additions & 27 deletions internal/aws/credentials/chain_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,20 @@
package credentials

import (
"context"
"errors"

"go.mongodb.org/mongo-driver/v2/internal/aws/awserr"
)

// A ChainProvider will search for a provider which returns credentials
// and cache that provider until Retrieve is called again.
//
// The ChainProvider provides a way of chaining multiple providers together
// which will pick the first available using priority order of the Providers
// in the list.
//
// If none of the Providers retrieve valid credentials Value, ChainProvider's
// Retrieve() will return the error ErrNoValidProvidersFoundInChain.
//
// If a Provider is found which returns valid credentials Value ChainProvider
// will cache that Provider for all calls to IsExpired(), until Retrieve is
// called again.
// Retrieve() will return an error.
type ChainProvider struct {
Providers []Provider
curr Provider
}

// NewChainCredentials returns a pointer to a new Credentials object
Expand All @@ -42,31 +37,19 @@ func NewChainCredentials(providers []Provider) *Credentials {

// Retrieve returns the credentials value or error if no provider returned
// without error.
//
// If a provider is found it will be cached and any calls to IsExpired()
// will return the expired state of the cached provider.
func (c *ChainProvider) Retrieve() (Value, error) {
func (c *ChainProvider) Retrieve(ctx context.Context) (Value, error) {
var errs = make([]error, 0, len(c.Providers))
for _, p := range c.Providers {
creds, err := p.Retrieve()
creds, err := p.Retrieve(ctx)
if err == nil {
c.curr = p
return creds, nil
if !creds.Expired() && creds.HasKeys() {
return creds, nil
}
err = errors.New("credentials are invalid")
}
errs = append(errs, err)
}
c.curr = nil

var err = awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs)
return Value{}, err
}

// IsExpired will returned the expired state of the currently cached provider
// if there is one. If there is no current provider, true will be returned.
func (c *ChainProvider) IsExpired() bool {
if c.curr != nil {
return c.curr.IsExpired()
}

return true
}
Loading
Loading