Skip to content

Commit

Permalink
Merge branch 'main' into ui/VAULT-17315-hds-adoption-replace-Modal
Browse files Browse the repository at this point in the history
  • Loading branch information
hellobontempo authored Oct 6, 2023
2 parents 4a18861 + 92fcfda commit 584f79b
Show file tree
Hide file tree
Showing 42 changed files with 1,609 additions and 242 deletions.
2 changes: 1 addition & 1 deletion builtin/credential/aws/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,7 @@ func buildCallerIdentityLoginData(request *http.Request, roleName string) (map[s
"iam_request_url": base64.StdEncoding.EncodeToString([]byte(request.URL.String())),
"iam_request_headers": base64.StdEncoding.EncodeToString(headersJson),
"iam_request_body": base64.StdEncoding.EncodeToString(requestBody),
"request_role": roleName,
"role": roleName,
}, nil
}

Expand Down
30 changes: 15 additions & 15 deletions builtin/credential/aws/path_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ func (b *backend) pathLoginIamGetRoleNameCallerIdAndEntity(ctx context.Context,

config, err := b.lockedClientConfigEntry(ctx, req.Storage)
if err != nil {
return "", nil, nil, logical.ErrorResponse("error getting configuration"), nil
return "", nil, nil, nil, fmt.Errorf("error getting configuration: %w", err)
}

endpoint := "https://sts.amazonaws.com"
Expand All @@ -319,23 +319,23 @@ func (b *backend) pathLoginIamGetRoleNameCallerIdAndEntity(ctx context.Context,
if config.MaxRetries >= 0 {
maxRetries = config.MaxRetries
}
}

// Extract and use a regional STS endpoint
// based on the region set in the Authorization header.
if config.UseSTSRegionFromClient {
clientSpecifiedRegion, err := awsRegionFromHeader(headers.Get("Authorization"))
if err != nil {
return "", nil, nil, logical.ErrorResponse("region missing from Authorization header"), nil
}
// Extract and use a regional STS endpoint
// based on the region set in the Authorization header.
if config.UseSTSRegionFromClient {
clientSpecifiedRegion, err := awsRegionFromHeader(headers.Get("Authorization"))
if err != nil {
return "", nil, nil, logical.ErrorResponse("region missing from Authorization header"), nil
}

url, err := stsRegionalEndpoint(clientSpecifiedRegion)
if err != nil {
return "", nil, nil, logical.ErrorResponse(err.Error()), nil
}
url, err := stsRegionalEndpoint(clientSpecifiedRegion)
if err != nil {
return "", nil, nil, logical.ErrorResponse(err.Error()), nil
}

b.Logger().Debug("use_sts_region_from_client set; using region specified from header", "region", clientSpecifiedRegion)
endpoint = url
b.Logger().Debug("use_sts_region_from_client set; using region specified from header", "region", clientSpecifiedRegion)
endpoint = url
}
}

b.Logger().Debug("submitting caller identity request", "endpoint", endpoint)
Expand Down
50 changes: 50 additions & 0 deletions builtin/credential/aws/path_login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,56 @@ func TestBackend_validateVaultPostRequestValues(t *testing.T) {
}
}

// TestBackend_pathLogin_NoClientConfig covers logging in via IAM auth when the
// client config does not exist. This is a regression test to cover potential
// panics when referencing the potentially-nil config in the login handler. For
// details see https://github.com/hashicorp/vault/issues/23361.
func TestBackend_pathLogin_NoClientConfig(t *testing.T) {
storage := new(logical.InmemStorage)
config := logical.TestBackendConfig()
config.StorageView = storage
b, err := Backend(config)
if err != nil {
t.Fatal(err)
}

err = b.Setup(context.Background(), config)
if err != nil {
t.Fatal(err)
}

// Intentionally left out the client configuration

roleEntry := &awsRoleEntry{
RoleID: "foo",
Version: currentRoleStorageVersion,
AuthType: iamAuthType,
}
err = b.setRole(context.Background(), storage, testValidRoleName, roleEntry)
if err != nil {
t.Fatal(err)
}

loginData, err := defaultLoginData()
if err != nil {
t.Fatal(err)
}
loginRequest := &logical.Request{
Operation: logical.UpdateOperation,
Path: "login",
Storage: storage,
Data: loginData,
Connection: &logical.Connection{},
}
resp, err := b.HandleRequest(context.Background(), loginRequest)
if err != nil {
t.Fatalf("expected nil error, got: %v", err)
}
if !resp.IsError() {
t.Fatalf("expected error response, got: %+v", resp)
}
}

// TestBackend_pathLogin_IAMHeaders tests login with iam_request_headers,
// supporting both base64 encoded string and JSON headers
func TestBackend_pathLogin_IAMHeaders(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions changelog/23140.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
core: emit logs when user(s) are locked out and when all lockouts have been cleared
```
3 changes: 3 additions & 0 deletions changelog/23534.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
config/listener: allow per-listener configuration settings to redact sensitive parts of response to unauthenticated endpoints.
```
3 changes: 3 additions & 0 deletions changelog/23555.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
auth/aws: Fixes a panic that can occur in IAM-based login when a [client config](https://developer.hashicorp.com/vault/api-docs/auth/aws#configure-client) does not exist.
```
10 changes: 3 additions & 7 deletions command/agentproxyshared/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func tokenRevocationValidation(t *testing.T, sampleSpace map[string]string, expe
t.Helper()
for val, valType := range sampleSpace {
index, err := leaseCache.db.Get(valType, val)
if err != nil {
if err != nil && err != cachememdb.ErrCacheItemNotFound {
t.Fatal(err)
}
if expected[val] == "" && index != nil {
Expand Down Expand Up @@ -1098,12 +1098,8 @@ func testCachingCacheClearCommon(t *testing.T, clearType string) {

// Verify the entry is cleared
idx, err = leaseCache.db.Get(cachememdb.IndexNameLease, gotLeaseID)
if err != nil {
t.Fatal(err)
}

if idx != nil {
t.Fatalf("expected entry to be nil, got: %v", idx)
if err != cachememdb.ErrCacheItemNotFound {
t.Fatal("expected entry to be nil, got", err)
}
}

Expand Down
5 changes: 5 additions & 0 deletions command/agentproxyshared/cache/cacheboltdb/bolt.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ const (
// StaticSecretType - Bucket/type for static secrets
StaticSecretType = "static-secret"

// TokenCapabilitiesType - Bucket/type for the token capabilities that
// are used to govern access to static secrets. These will be updated
// periodically to ensure that access to the cached secret remains.
TokenCapabilitiesType = "token-capabilities"

// LeaseType - v2 Bucket/type for auth AND secret leases.
//
// This bucket stores keys in the same order they were created using
Expand Down
75 changes: 69 additions & 6 deletions command/agentproxyshared/cache/cachememdb/cache_memdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ import (
)

const (
tableNameIndexer = "indexer"
tableNameIndexer = "indexer"
tableNameCapabilitiesIndexer = "capabilities-indexer"
)

// ErrCacheItemNotFound is returned on Get and GetCapabilitiesIndex calls
// when the entry is not found in the cache.
var ErrCacheItemNotFound = errors.New("cache item not found")

// CacheMemDB is the underlying cache database for storing indexes.
type CacheMemDB struct {
db *atomic.Value
Expand Down Expand Up @@ -120,6 +125,20 @@ func newDB() (*memdb.MemDB, error) {
},
},
},
tableNameCapabilitiesIndexer: {
Name: tableNameCapabilitiesIndexer,
Indexes: map[string]*memdb.IndexSchema{
// This index enables fetching the cached item based on the
// identifier of the index.
CapabilitiesIndexNameID: {
Name: CapabilitiesIndexNameID,
Unique: true,
Indexer: &memdb.StringFieldIndex{
Field: "ID",
},
},
},
},
},
}

Expand All @@ -131,6 +150,7 @@ func newDB() (*memdb.MemDB, error) {
}

// Get returns the index based on the indexer and the index values provided.
// If the capabilities index isn't present, it will return nil, ErrCacheItemNotFound
func (c *CacheMemDB) Get(indexName string, indexValues ...interface{}) (*Index, error) {
if !validIndexName(indexName) {
return nil, fmt.Errorf("invalid index name %q", indexName)
Expand All @@ -144,7 +164,7 @@ func (c *CacheMemDB) Get(indexName string, indexValues ...interface{}) (*Index,
}

if raw == nil {
return nil, nil
return nil, ErrCacheItemNotFound
}

index, ok := raw.(*Index)
Expand Down Expand Up @@ -173,6 +193,50 @@ func (c *CacheMemDB) Set(index *Index) error {
return nil
}

// GetCapabilitiesIndex returns the CapabilitiesIndex from the cache.
// If the capabilities index isn't present, it will return nil, ErrCacheItemNotFound
func (c *CacheMemDB) GetCapabilitiesIndex(indexName string, indexValues ...interface{}) (*CapabilitiesIndex, error) {
if !validCapabilitiesIndexName(indexName) {
return nil, fmt.Errorf("invalid index name %q", indexName)
}

txn := c.db.Load().(*memdb.MemDB).Txn(false)

raw, err := txn.First(tableNameCapabilitiesIndexer, indexName, indexValues...)
if err != nil {
return nil, err
}

if raw == nil {
return nil, ErrCacheItemNotFound
}

index, ok := raw.(*CapabilitiesIndex)
if !ok {
return nil, errors.New("unable to parse capabilities index value from the cache")
}

return index, nil
}

// SetCapabilitiesIndex stores the CapabilitiesIndex index into the cache.
func (c *CacheMemDB) SetCapabilitiesIndex(index *CapabilitiesIndex) error {
if index == nil {
return errors.New("nil capabilities index provided")
}

txn := c.db.Load().(*memdb.MemDB).Txn(true)
defer txn.Abort()

if err := txn.Insert(tableNameCapabilitiesIndexer, index); err != nil {
return fmt.Errorf("unable to insert index into cache: %v", err)
}

txn.Commit()

return nil
}

// GetByPrefix returns all the cached indexes based on the index name and the
// value prefix.
func (c *CacheMemDB) GetByPrefix(indexName string, indexValues ...interface{}) ([]*Index, error) {
Expand Down Expand Up @@ -210,14 +274,13 @@ func (c *CacheMemDB) GetByPrefix(indexName string, indexValues ...interface{}) (
// Evict removes an index from the cache based on index name and value.
func (c *CacheMemDB) Evict(indexName string, indexValues ...interface{}) error {
index, err := c.Get(indexName, indexValues...)
if err == ErrCacheItemNotFound {
return nil
}
if err != nil {
return fmt.Errorf("unable to fetch index on cache deletion: %v", err)
}

if index == nil {
return nil
}

txn := c.db.Load().(*memdb.MemDB).Txn(true)
defer txn.Abort()

Expand Down
24 changes: 12 additions & 12 deletions command/agentproxyshared/cache/cachememdb/cache_memdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ func TestCacheMemDB_Get(t *testing.T) {

// Test on empty cache
index, err := cache.Get(IndexNameID, "foo")
if err != nil {
t.Fatal(err)
if err != ErrCacheItemNotFound {
t.Fatal("expected cache item to be not found", err)
}
if index != nil {
t.Fatalf("expected nil index, got: %v", index)
Expand All @@ -56,6 +56,7 @@ func TestCacheMemDB_Get(t *testing.T) {
TokenAccessor: "test_accessor",
Lease: "test_lease",
Response: []byte("hello world"),
Tokens: map[string]struct{}{},
}

if err := cache.Set(in); err != nil {
Expand Down Expand Up @@ -97,7 +98,7 @@ func TestCacheMemDB_Get(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
out, err := cache.Get(tc.indexName, tc.indexValues...)
if err != nil {
if err != nil && err != ErrCacheItemNotFound {
t.Fatal(err)
}
if diff := deep.Equal(in, out); diff != nil {
Expand Down Expand Up @@ -169,22 +170,22 @@ func TestCacheMemDB_GetByPrefix(t *testing.T) {
}{
{
"by_request_path",
"request_path",
IndexNameRequestPath,
[]interface{}{"test_ns/", "/v1/request/path"},
},
{
"by_lease",
"lease",
IndexNameLease,
[]interface{}{"path/to/test_lease"},
},
{
"by_token_parent",
"token_parent",
IndexNameTokenParent,
[]interface{}{"test_token_parent"},
},
{
"by_lease_token",
"lease_token",
IndexNameLeaseToken,
[]interface{}{"test_lease_token"},
},
}
Expand Down Expand Up @@ -348,10 +349,9 @@ func TestCacheMemDB_Evict(t *testing.T) {

// Verify that the cache doesn't contain the entry any more
index, err := cache.Get(tc.indexName, tc.indexValues...)
if (err != nil) != tc.wantErr {
t.Fatal(err)
if err != ErrCacheItemNotFound && !tc.wantErr {
t.Fatal("expected cache item to be not found", err)
}

if index != nil {
t.Fatalf("expected nil entry, got = %#v", index)
}
Expand Down Expand Up @@ -386,8 +386,8 @@ func TestCacheMemDB_Flush(t *testing.T) {

// Check the cache doesn't contain inserted index
out, err := cache.Get(IndexNameID, "test_id")
if err != nil {
t.Fatal(err)
if err != ErrCacheItemNotFound {
t.Fatal("expected cache item to be not found", err)
}
if out != nil {
t.Fatalf("expected cache to be empty, got = %v", out)
Expand Down
Loading

0 comments on commit 584f79b

Please sign in to comment.