2554 lines
79 KiB
Go
2554 lines
79 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package vault
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"github.com/hashicorp/boundary/globals"
|
|
"github.com/hashicorp/boundary/internal/credential"
|
|
"github.com/hashicorp/boundary/internal/credential/vault/store"
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
dbassert "github.com/hashicorp/boundary/internal/db/assert"
|
|
"github.com/hashicorp/boundary/internal/db/timestamp"
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
"github.com/hashicorp/boundary/internal/iam"
|
|
"github.com/hashicorp/boundary/internal/kms"
|
|
"github.com/hashicorp/boundary/internal/oplog"
|
|
"github.com/hashicorp/boundary/internal/scheduler"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
)
|
|
|
|
func TestRepository_CreateCredentialLibrary(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
|
|
tests := []struct {
|
|
name string
|
|
in *CredentialLibrary
|
|
opts []Option
|
|
want *CredentialLibrary
|
|
wantErr errors.Code
|
|
}{
|
|
{
|
|
name: "nil-CredentialLibrary",
|
|
wantErr: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "nil-embedded-CredentialLibrary",
|
|
in: &CredentialLibrary{},
|
|
wantErr: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "invalid-no-store-id",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{},
|
|
},
|
|
wantErr: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "invalid-public-id-set",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
PublicId: "abcd_OOOOOOOOOO",
|
|
},
|
|
},
|
|
wantErr: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "invalid-no-vault-path",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
},
|
|
},
|
|
wantErr: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "valid-no-options",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-with-name",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
Name: "test-name-repo",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
Name: "test-name-repo",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-with-description",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
Description: "test-description-repo",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
Description: "test-description-repo",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-POST-method",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "POST",
|
|
Description: "test-description-repo",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "POST",
|
|
Description: "test-description-repo",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-POST-http-body",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "POST",
|
|
Description: "test-description-repo",
|
|
VaultPath: "/some/path",
|
|
HttpRequestBody: []byte(`{"common_name":"boundary.com"}`),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "POST",
|
|
Description: "test-description-repo",
|
|
VaultPath: "/some/path",
|
|
HttpRequestBody: []byte(`{"common_name":"boundary.com"}`),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-username-password-credential-type",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "unknown-mapping-override-type",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: unknownMapper(1),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
wantErr: errors.VaultInvalidMappingOverride,
|
|
},
|
|
{
|
|
name: "invalid-mapping-override-type",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(WithOverrideUsernameAttribute("test")),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
wantErr: errors.VaultInvalidMappingOverride,
|
|
},
|
|
{
|
|
name: "valid-username-password-credential-type-with-username-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-username-password-credential-type-with-password-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-username-password-credential-type-with-username-and-password-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-password-credential-type",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "unknown-password-mapping-override-type",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: unknownMapper(1),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
wantErr: errors.VaultInvalidMappingOverride,
|
|
},
|
|
{
|
|
name: "invalid-password-mapping-override-type",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(WithOverrideUsernameAttribute("test")),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
wantErr: errors.VaultInvalidMappingOverride,
|
|
},
|
|
{
|
|
name: "valid-password-credential-type-with-password-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewPasswordOverride(
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewPasswordOverride(
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "unknown-ssh-private-key-mapping-override-type",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: unknownMapper(1),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
wantErr: errors.VaultInvalidMappingOverride,
|
|
},
|
|
{
|
|
name: "invalid-ssh-private-key-mapping-override-type",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(WithOverrideUsernameAttribute("test")),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
wantErr: errors.VaultInvalidMappingOverride,
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type-with-username-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type-with-private-key-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type-with-passphrase-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyPassphraseAttribute("passtest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyPassphraseAttribute("passtest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-keyt-credential-type-with-all-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
WithOverridePrivateKeyAttribute("pktest"),
|
|
WithOverridePrivateKeyPassphraseAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
WithOverridePrivateKeyAttribute("pktest"),
|
|
WithOverridePrivateKeyPassphraseAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
require.NoError(err)
|
|
require.NotNil(repo)
|
|
got, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), tt.in, tt.opts...)
|
|
if tt.wantErr != 0 {
|
|
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
|
|
assert.Nil(got)
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Empty(tt.in.PublicId)
|
|
require.NotNil(got)
|
|
assertPublicId(t, globals.VaultCredentialLibraryPrefix, got.GetPublicId())
|
|
assert.NotSame(tt.in, got)
|
|
assert.Equal(tt.want.Name, got.Name)
|
|
assert.Equal(tt.want.Description, got.Description)
|
|
assert.Equal(tt.want.CredentialType(), got.CredentialType())
|
|
assert.Equal(got.CreateTime, got.UpdateTime)
|
|
|
|
assert.NoError(db.TestVerifyOplog(t, rw, got.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)))
|
|
|
|
if tt.in.MappingOverride != nil {
|
|
require.NotNil(got.MappingOverride)
|
|
assert.IsType(tt.want.MappingOverride, got.MappingOverride)
|
|
switch w := tt.want.MappingOverride.(type) {
|
|
case *UsernamePasswordOverride:
|
|
g, ok := got.MappingOverride.(*UsernamePasswordOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.UsernameAttribute, g.UsernameAttribute)
|
|
assert.Equal(w.PasswordAttribute, g.PasswordAttribute)
|
|
|
|
// verify it was persisted in the database
|
|
override := allocUsernamePasswordOverride()
|
|
assert.NoError(rw.LookupWhere(ctx, &override, "library_id = ?", []any{got.GetPublicId()}))
|
|
|
|
case *PasswordOverride:
|
|
g, ok := got.MappingOverride.(*PasswordOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.PasswordAttribute, g.PasswordAttribute)
|
|
|
|
// verify it was persisted in the database
|
|
override := allocPasswordOverride()
|
|
assert.NoError(rw.LookupWhere(ctx, &override, "library_id = ?", []any{got.GetPublicId()}))
|
|
|
|
case *SshPrivateKeyOverride:
|
|
g, ok := got.MappingOverride.(*SshPrivateKeyOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.UsernameAttribute, g.UsernameAttribute)
|
|
assert.Equal(w.PrivateKeyAttribute, g.PrivateKeyAttribute)
|
|
assert.Equal(w.PrivateKeyPassphraseAttribute, g.PrivateKeyPassphraseAttribute)
|
|
|
|
// verify it was persisted in the database
|
|
override := allocSshPrivateKeyOverride()
|
|
assert.NoError(rw.LookupWhere(ctx, &override, "library_id = ?", []any{got.GetPublicId()}))
|
|
|
|
default:
|
|
assert.Fail("Unknown mapping override")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("invalid-duplicate-names", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
require.NoError(err)
|
|
require.NotNil(repo)
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
in := &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
}
|
|
|
|
got, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), in)
|
|
require.NoError(err)
|
|
require.NotNil(got)
|
|
assertPublicId(t, globals.VaultCredentialLibraryPrefix, got.GetPublicId())
|
|
assert.NotSame(in, got)
|
|
assert.Equal(in.Name, got.Name)
|
|
assert.Equal(in.Description, got.Description)
|
|
assert.Equal(got.CreateTime, got.UpdateTime)
|
|
|
|
got2, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), in)
|
|
assert.Truef(errors.Match(errors.T(errors.NotUnique), err), "want err: %q got: %q", errors.NotUnique, err)
|
|
assert.Nil(got2)
|
|
})
|
|
|
|
t.Run("valid-duplicate-names-diff-stores", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
require.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
css := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2)
|
|
|
|
csA, csB := css[0], css[1]
|
|
|
|
in := &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
}
|
|
in2 := in.clone()
|
|
|
|
in.StoreId = csA.GetPublicId()
|
|
got, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), in)
|
|
require.NoError(err)
|
|
require.NotNil(got)
|
|
assertPublicId(t, globals.VaultCredentialLibraryPrefix, got.GetPublicId())
|
|
assert.NotSame(in, got)
|
|
assert.Equal(in.Name, got.Name)
|
|
assert.Equal(in.Description, got.Description)
|
|
assert.Equal(got.CreateTime, got.UpdateTime)
|
|
|
|
in2.StoreId = csB.GetPublicId()
|
|
got2, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), in2)
|
|
require.NoError(err)
|
|
require.NotNil(got2)
|
|
assertPublicId(t, globals.VaultCredentialLibraryPrefix, got2.GetPublicId())
|
|
assert.NotSame(in2, got2)
|
|
assert.Equal(in2.Name, got2.Name)
|
|
assert.Equal(in2.Description, got2.Description)
|
|
assert.Equal(got2.CreateTime, got2.UpdateTime)
|
|
})
|
|
}
|
|
|
|
func TestRepository_UpdateCredentialLibrary(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
|
|
changeHttpRequestBody := func(b []byte) func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.HttpRequestBody = b
|
|
return l
|
|
}
|
|
}
|
|
|
|
changeHttpMethod := func(m Method) func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.HttpMethod = string(m)
|
|
return l
|
|
}
|
|
}
|
|
|
|
makeHttpMethodEmptyString := func() func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.HttpMethod = ""
|
|
return l
|
|
}
|
|
}
|
|
|
|
changeVaultPath := func(p string) func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.VaultPath = p
|
|
return l
|
|
}
|
|
}
|
|
|
|
changeName := func(n string) func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.Name = n
|
|
return l
|
|
}
|
|
}
|
|
|
|
changeDescription := func(d string) func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.Description = d
|
|
return l
|
|
}
|
|
}
|
|
|
|
changeCredentialType := func(t globals.CredentialType) func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.CredentialLibrary.CredentialType = string(t)
|
|
return l
|
|
}
|
|
}
|
|
|
|
changeMappingOverride := func(m MappingOverride) func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.MappingOverride = m
|
|
return l
|
|
}
|
|
}
|
|
|
|
makeNil := func() func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
makeEmbeddedNil := func() func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
return &CredentialLibrary{}
|
|
}
|
|
}
|
|
|
|
deletePublicId := func() func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.PublicId = ""
|
|
return l
|
|
}
|
|
}
|
|
|
|
nonExistentPublicId := func() func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
l.PublicId = "abcd_OOOOOOOOOO"
|
|
return l
|
|
}
|
|
}
|
|
|
|
combine := func(fns ...func(l *CredentialLibrary) *CredentialLibrary) func(*CredentialLibrary) *CredentialLibrary {
|
|
return func(l *CredentialLibrary) *CredentialLibrary {
|
|
for _, fn := range fns {
|
|
l = fn(l)
|
|
}
|
|
return l
|
|
}
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
orig *CredentialLibrary
|
|
chgFn func(*CredentialLibrary) *CredentialLibrary
|
|
masks []string
|
|
want *CredentialLibrary
|
|
wantCount int
|
|
wantErr errors.Code
|
|
}{
|
|
{
|
|
name: "nil-credential-library",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
chgFn: makeNil(),
|
|
masks: []string{nameField, descriptionField},
|
|
wantErr: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "nil-embedded-credential-library",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
chgFn: makeEmbeddedNil(),
|
|
masks: []string{nameField, descriptionField},
|
|
wantErr: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "no-public-id",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
chgFn: deletePublicId(),
|
|
masks: []string{nameField, descriptionField},
|
|
wantErr: errors.InvalidPublicId,
|
|
},
|
|
{
|
|
name: "updating-non-existent-credential-library",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
},
|
|
chgFn: combine(nonExistentPublicId(), changeName("test-update-name-repo")),
|
|
masks: []string{nameField},
|
|
wantErr: errors.RecordNotFound,
|
|
},
|
|
{
|
|
name: "empty-field-mask",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
},
|
|
chgFn: changeName("test-update-name-repo"),
|
|
wantErr: errors.EmptyFieldMask,
|
|
},
|
|
{
|
|
name: "read-only-fields-in-field-mask",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
},
|
|
chgFn: changeName("test-update-name-repo"),
|
|
masks: []string{"PublicId", "CreateTime", "UpdateTime", "StoreId"},
|
|
wantErr: errors.InvalidFieldMask,
|
|
},
|
|
{
|
|
name: "unknown-field-in-field-mask",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
},
|
|
chgFn: changeName("test-update-name-repo"),
|
|
masks: []string{"Bilbo"},
|
|
wantErr: errors.InvalidFieldMask,
|
|
},
|
|
{
|
|
name: "change-name",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
},
|
|
chgFn: changeName("test-update-name-repo"),
|
|
masks: []string{nameField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-update-name-repo",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "change-description",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Description: "test-description-repo",
|
|
},
|
|
},
|
|
chgFn: changeDescription("test-update-description-repo"),
|
|
masks: []string{descriptionField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Description: "test-update-description-repo",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "change-name-and-description",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
Description: "test-description-repo",
|
|
},
|
|
},
|
|
chgFn: combine(changeDescription("test-update-description-repo"), changeName("test-update-name-repo")),
|
|
masks: []string{nameField, descriptionField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-update-name-repo",
|
|
Description: "test-update-description-repo",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "delete-name",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
Description: "test-description-repo",
|
|
},
|
|
},
|
|
masks: []string{nameField},
|
|
chgFn: combine(changeDescription("test-update-description-repo"), changeName("")),
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Description: "test-description-repo",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "delete-description",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
Description: "test-description-repo",
|
|
},
|
|
},
|
|
masks: []string{descriptionField},
|
|
chgFn: combine(changeDescription(""), changeName("test-update-name-repo")),
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "do-not-delete-name",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
Description: "test-description-repo",
|
|
},
|
|
},
|
|
masks: []string{descriptionField},
|
|
chgFn: combine(changeDescription("test-update-description-repo"), changeName("")),
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
Description: "test-update-description-repo",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "do-not-delete-description",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
Description: "test-description-repo",
|
|
},
|
|
},
|
|
masks: []string{nameField},
|
|
chgFn: combine(changeDescription(""), changeName("test-update-name-repo")),
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-update-name-repo",
|
|
Description: "test-description-repo",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "change-vault-path",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(WithOverrideUsernameAttribute("orig-username")),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/old/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeVaultPath("/new/path"),
|
|
masks: []string{vaultPathField},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(WithOverrideUsernameAttribute("orig-username")),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/new/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "delete-vault-path",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
chgFn: changeVaultPath(""),
|
|
masks: []string{vaultPathField},
|
|
wantErr: errors.NotNull,
|
|
},
|
|
{
|
|
name: "change-http-method",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
chgFn: changeHttpMethod(MethodPost),
|
|
masks: []string{httpMethodField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "delete-http-method",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
chgFn: makeHttpMethodEmptyString(),
|
|
masks: []string{httpMethodField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "add-http-request-body",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
chgFn: changeHttpRequestBody([]byte("new request body")),
|
|
masks: []string{httpRequestBodyField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
HttpRequestBody: []byte("new request body"),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "delete-http-request-body",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
HttpRequestBody: []byte("request body"),
|
|
},
|
|
},
|
|
chgFn: changeHttpRequestBody(nil),
|
|
masks: []string{httpRequestBodyField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "change-http-request-body",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
HttpRequestBody: []byte("old request body"),
|
|
},
|
|
},
|
|
chgFn: changeHttpRequestBody([]byte("new request body")),
|
|
masks: []string{httpRequestBodyField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
HttpRequestBody: []byte("new request body"),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "change-method-to-GET-leave-request-body",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
HttpRequestBody: []byte("old request body"),
|
|
},
|
|
},
|
|
chgFn: changeHttpMethod(MethodGet),
|
|
masks: []string{httpMethodField},
|
|
wantErr: errors.CheckConstraint,
|
|
},
|
|
{
|
|
name: "change-method-to-POST-add-request-body",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
chgFn: combine(changeHttpRequestBody([]byte("new request body")), changeHttpMethod(MethodPost)),
|
|
masks: []string{httpRequestBodyField, httpMethodField},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "POST",
|
|
VaultPath: "/some/path",
|
|
HttpRequestBody: []byte("new request body"),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "read-only-credential-type-in-field-mask",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeCredentialType(globals.UnspecifiedCredentialType),
|
|
masks: []string{"PublicId", "CreateTime", "UpdateTime", "StoreId", "CredentialType"},
|
|
wantErr: errors.InvalidFieldMask,
|
|
},
|
|
{
|
|
name: "username-password-attributes-change-username-attribute",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
WithOverridePasswordAttribute("orig-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "username-password-attributes-change-password-attribute",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
WithOverridePasswordAttribute("orig-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewUsernamePasswordOverride(
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "username-password-attributes-change-username-and-password-attributes",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
WithOverridePasswordAttribute("orig-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "no-mapping-override-change-username-and-password-attributes",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "username-password-attributes-delete-mapping-override",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
WithOverridePasswordAttribute("orig-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(nil),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "set-mapping-override-on-unspecified-credential-type",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
wantErr: errors.VaultInvalidMappingOverride,
|
|
},
|
|
{
|
|
name: "password-attribute-change-password-attribute",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewPasswordOverride(
|
|
WithOverridePasswordAttribute("orig-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-password-repo",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewPasswordOverride(
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewPasswordOverride(
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-password-repo",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "no-mapping-override-change-password-attributes",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-password-repo",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewPasswordOverride(
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewPasswordOverride(
|
|
WithOverridePasswordAttribute("changed-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-password-repo",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "password-attributes-delete-mapping-override",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewPasswordOverride(
|
|
WithOverridePasswordAttribute("orig-password"),
|
|
WithOverridePrivateKeyAttribute("orig-private-key"),
|
|
WithOverridePrivateKeyPassphraseAttribute("orig-passphrase"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-password-repo",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(nil),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-password-repo",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "ssh-private-key-attributes-change-username-attribute",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "ssh-private-key-attributes-change-private-key-attribute",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyAttribute("orig-private-key"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyAttribute("changed-private-key"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyAttribute("changed-private-key"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "ssh-private-key-attributes-change-passphrase-attribute",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyPassphraseAttribute("orig-passphrase"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyPassphraseAttribute("changed-passphrase"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyPassphraseAttribute("changed-passphrase"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "ssh-private-key-attributes-change-all-attributes",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
WithOverridePrivateKeyAttribute("orig-private-key"),
|
|
WithOverridePrivateKeyPassphraseAttribute("orig-passphrase"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePrivateKeyAttribute("changed-private-key"),
|
|
WithOverridePrivateKeyPassphraseAttribute("changed-passphrase"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePrivateKeyAttribute("changed-private-key"),
|
|
WithOverridePrivateKeyPassphraseAttribute("changed-passphrase"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "no-mapping-override-change-all-attributes",
|
|
orig: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(
|
|
NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePrivateKeyAttribute("changed-private-key"),
|
|
WithOverridePrivateKeyPassphraseAttribute("changed-passphrase"),
|
|
),
|
|
),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("changed-username"),
|
|
WithOverridePrivateKeyAttribute("changed-private-key"),
|
|
WithOverridePrivateKeyPassphraseAttribute("changed-passphrase"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "ssh-private-key-attributes-delete-mapping-override",
|
|
orig: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
WithOverridePrivateKeyAttribute("orig-private-key"),
|
|
WithOverridePrivateKeyPassphraseAttribute("orig-passphrase"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
chgFn: changeMappingOverride(nil),
|
|
masks: []string{"MappingOverride"},
|
|
want: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-ssh-private-key-repo",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
|
|
tt.orig.StoreId = cs.GetPublicId()
|
|
orig, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), tt.orig)
|
|
assert.NoError(err)
|
|
require.NotNil(orig)
|
|
|
|
if tt.chgFn != nil {
|
|
orig = tt.chgFn(orig)
|
|
}
|
|
got, gotCount, err := repo.UpdateCredentialLibrary(ctx, prj.GetPublicId(), orig, 1, tt.masks)
|
|
if tt.wantErr != 0 {
|
|
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
|
|
assert.Equal(tt.wantCount, gotCount, "row count")
|
|
assert.Nil(got)
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Empty(tt.orig.PublicId)
|
|
require.NotNil(got)
|
|
assertPublicId(t, globals.VaultCredentialLibraryPrefix, got.GetPublicId())
|
|
assert.Equal(tt.wantCount, gotCount, "row count")
|
|
assert.NotSame(tt.orig, got)
|
|
assert.Equal(tt.orig.StoreId, got.StoreId)
|
|
underlyingDB, err := conn.SqlDB(ctx)
|
|
require.NoError(err)
|
|
dbassert := dbassert.New(t, underlyingDB)
|
|
|
|
switch tt.want.Name {
|
|
case "":
|
|
dbassert.IsNull(got, "name")
|
|
default:
|
|
assert.Equal(tt.want.Name, got.Name)
|
|
}
|
|
|
|
switch tt.want.Description {
|
|
case "":
|
|
dbassert.IsNull(got, "description")
|
|
default:
|
|
assert.Equal(tt.want.Description, got.Description)
|
|
}
|
|
|
|
if tt.wantCount > 0 {
|
|
assert.NoError(db.TestVerifyOplog(t, rw, got.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second)))
|
|
}
|
|
|
|
switch w := tt.want.MappingOverride.(type) {
|
|
case nil:
|
|
assert.Nil(got.MappingOverride)
|
|
case *UsernamePasswordOverride:
|
|
g, ok := got.MappingOverride.(*UsernamePasswordOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.UsernameAttribute, g.UsernameAttribute)
|
|
assert.Equal(w.PasswordAttribute, g.PasswordAttribute)
|
|
case *PasswordOverride:
|
|
g, ok := got.MappingOverride.(*PasswordOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.PasswordAttribute, g.PasswordAttribute)
|
|
case *SshPrivateKeyOverride:
|
|
g, ok := got.MappingOverride.(*SshPrivateKeyOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.UsernameAttribute, g.UsernameAttribute)
|
|
assert.Equal(w.PrivateKeyAttribute, g.PrivateKeyAttribute)
|
|
assert.Equal(w.PrivateKeyPassphraseAttribute, g.PrivateKeyPassphraseAttribute)
|
|
default:
|
|
assert.Fail("Unknown mapping override")
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("invalid-duplicate-names", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
name := "test-dup-name"
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
libs := TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), globals.UnspecifiedCredentialType, 2)
|
|
|
|
lA, lB := libs[0], libs[1]
|
|
|
|
lA.Name = name
|
|
got1, gotCount1, err := repo.UpdateCredentialLibrary(ctx, prj.GetPublicId(), lA, 1, []string{"name"})
|
|
assert.NoError(err)
|
|
require.NotNil(got1)
|
|
assert.Equal(name, got1.Name)
|
|
assert.Equal(1, gotCount1, "row count")
|
|
assert.NoError(db.TestVerifyOplog(t, rw, lA.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second)))
|
|
|
|
lB.Name = name
|
|
got2, gotCount2, err := repo.UpdateCredentialLibrary(ctx, prj.GetPublicId(), lB, 1, []string{"name"})
|
|
assert.Truef(errors.Match(errors.T(errors.NotUnique), err), "want err code: %v got err: %v", errors.NotUnique, err)
|
|
assert.Nil(got2)
|
|
assert.Equal(db.NoRowsAffected, gotCount2, "row count")
|
|
err = db.TestVerifyOplog(t, rw, lB.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
|
|
assert.Error(err)
|
|
assert.True(errors.IsNotFoundError(err))
|
|
})
|
|
|
|
t.Run("valid-duplicate-names-diff-CredentialStores", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
css := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2)
|
|
|
|
csA, csB := css[0], css[1]
|
|
|
|
in := &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
}
|
|
in2 := in.clone()
|
|
|
|
in.StoreId = csA.GetPublicId()
|
|
got, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), in)
|
|
assert.NoError(err)
|
|
require.NotNil(got)
|
|
assertPublicId(t, globals.VaultCredentialLibraryPrefix, got.GetPublicId())
|
|
assert.NotSame(in, got)
|
|
assert.Equal(in.Name, got.Name)
|
|
assert.Equal(in.Description, got.Description)
|
|
|
|
in2.StoreId = csB.GetPublicId()
|
|
in2.Name = "first-name"
|
|
got2, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), in2)
|
|
assert.NoError(err)
|
|
require.NotNil(got2)
|
|
got2.Name = got.Name
|
|
got3, gotCount3, err := repo.UpdateCredentialLibrary(ctx, prj.GetPublicId(), got2, 1, []string{"name"})
|
|
assert.NoError(err)
|
|
require.NotNil(got3)
|
|
assert.NotSame(got2, got3)
|
|
assert.Equal(got.Name, got3.Name)
|
|
assert.Equal(got2.Description, got3.Description)
|
|
assert.Equal(1, gotCount3, "row count")
|
|
assert.NoError(db.TestVerifyOplog(t, rw, got2.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second)))
|
|
})
|
|
|
|
t.Run("valid-update-with-expired-store-token", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
css := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)
|
|
cs := css[0]
|
|
|
|
in := &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
},
|
|
}
|
|
|
|
in.StoreId = cs.GetPublicId()
|
|
got, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), in)
|
|
assert.NoError(err)
|
|
require.NotNil(got)
|
|
|
|
// Expire the credential store Vault token
|
|
rows, err := rw.Exec(context.Background(),
|
|
"update credential_vault_token set status = ? where token_hmac = ?",
|
|
[]any{ExpiredToken, cs.Token().TokenHmac})
|
|
require.NoError(err)
|
|
require.Equal(1, rows)
|
|
|
|
got.Name = "new-name"
|
|
updated, gotCount, err := repo.UpdateCredentialLibrary(ctx, prj.GetPublicId(), got, 1, []string{"name"})
|
|
assert.NoError(err)
|
|
require.NotNil(updated)
|
|
assert.Equal("new-name", updated.Name)
|
|
assert.Equal(1, gotCount)
|
|
})
|
|
|
|
t.Run("change-project-id", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
css := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2)
|
|
|
|
csA, csB := css[0], css[1]
|
|
|
|
lA := TestCredentialLibraries(t, conn, wrapper, csA.GetPublicId(), globals.UnspecifiedCredentialType, 1)[0]
|
|
lB := TestCredentialLibraries(t, conn, wrapper, csB.GetPublicId(), globals.UnspecifiedCredentialType, 1)[0]
|
|
|
|
assert.NotEqual(lA.StoreId, lB.StoreId)
|
|
orig := lA.clone()
|
|
|
|
lA.StoreId = lB.StoreId
|
|
assert.Equal(lA.StoreId, lB.StoreId)
|
|
|
|
got1, gotCount1, err := repo.UpdateCredentialLibrary(ctx, prj.GetPublicId(), lA, 1, []string{"name"})
|
|
|
|
assert.NoError(err)
|
|
require.NotNil(got1)
|
|
assert.Equal(orig.StoreId, got1.StoreId)
|
|
assert.Equal(1, gotCount1, "row count")
|
|
assert.NoError(db.TestVerifyOplog(t, rw, lA.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second)))
|
|
})
|
|
}
|
|
|
|
func TestRepository_LookupCredentialLibrary(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
|
|
{
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
css := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2)
|
|
|
|
cs := css[0]
|
|
csWithExpiredToken := css[1]
|
|
rows, err := rw.Exec(context.Background(),
|
|
"update credential_vault_token set status = ? where token_hmac = ?",
|
|
[]any{ExpiredToken, csWithExpiredToken.Token().TokenHmac})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, rows)
|
|
|
|
tests := []struct {
|
|
name string
|
|
in *CredentialLibrary
|
|
}{
|
|
{
|
|
name: "valid-no-options",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "valid-with-expired-cred-store-token",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: csWithExpiredToken.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-username-password-credential-type",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-username-password-credential-type-with-username-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-username-password-credential-type-with-password-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-username-password-credential-type-with-username-and-password-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-password-credential-type",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-password-credential-type-with-password-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewPasswordOverride(
|
|
WithOverridePasswordAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.PasswordCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type",
|
|
in: &CredentialLibrary{
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type-with-username-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type-with-private-key-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type-with-passphrase-override",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverridePrivateKeyPassphraseAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "valid-ssh-private-key-credential-type-with-all-overrides",
|
|
in: &CredentialLibrary{
|
|
MappingOverride: NewSshPrivateKeyOverride(
|
|
WithOverrideUsernameAttribute("utest"),
|
|
WithOverridePrivateKeyAttribute("pktest"),
|
|
WithOverridePrivateKeyPassphraseAttribute("ptest"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// setup
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
orig, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), tt.in)
|
|
assert.NoError(err)
|
|
require.NotEmpty(orig)
|
|
// test
|
|
got, err := repo.LookupCredentialLibrary(ctx, orig.GetPublicId())
|
|
assert.NoError(err)
|
|
require.NotEmpty(got)
|
|
assert.Equal(orig.Name, got.Name)
|
|
assert.Equal(orig.Description, got.Description)
|
|
assert.Equal(orig.CredentialType(), got.CredentialType())
|
|
if tt.in.MappingOverride != nil {
|
|
require.NotNil(got.MappingOverride)
|
|
assert.IsType(orig.MappingOverride, got.MappingOverride)
|
|
switch w := orig.MappingOverride.(type) {
|
|
case *UsernamePasswordOverride:
|
|
g, ok := got.MappingOverride.(*UsernamePasswordOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.UsernameAttribute, g.UsernameAttribute)
|
|
assert.Equal(w.PasswordAttribute, g.PasswordAttribute)
|
|
case *PasswordOverride:
|
|
g, ok := got.MappingOverride.(*PasswordOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.PasswordAttribute, g.PasswordAttribute)
|
|
case *SshPrivateKeyOverride:
|
|
g, ok := got.MappingOverride.(*SshPrivateKeyOverride)
|
|
require.True(ok)
|
|
assert.Equal(w.UsernameAttribute, g.UsernameAttribute)
|
|
assert.Equal(w.PrivateKeyAttribute, g.PrivateKeyAttribute)
|
|
assert.Equal(w.PrivateKeyPassphraseAttribute, g.PrivateKeyPassphraseAttribute)
|
|
default:
|
|
assert.Fail("Unknown mapping override")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
t.Run("empty-public-id", func(t *testing.T) {
|
|
// setup
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
// test
|
|
got, err := repo.LookupCredentialLibrary(ctx, "")
|
|
wantErr := errors.InvalidParameter
|
|
assert.Truef(errors.Match(errors.T(wantErr), err), "want err: %q got: %q", wantErr, err)
|
|
assert.Nil(got)
|
|
})
|
|
|
|
t.Run("not-found", func(t *testing.T) {
|
|
// setup
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
badId, err := newCredentialLibraryId(ctx)
|
|
assert.NoError(err)
|
|
require.NotNil(badId)
|
|
// test
|
|
got, err := repo.LookupCredentialLibrary(ctx, badId)
|
|
assert.NoError(err)
|
|
assert.Empty(got)
|
|
})
|
|
}
|
|
|
|
func TestRepository_DeleteCredentialLibrary(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
|
|
{
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
l := TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), globals.UnspecifiedCredentialType, 1)[0]
|
|
|
|
badId, err := newCredentialLibraryId(ctx)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, badId)
|
|
|
|
tests := []struct {
|
|
name string
|
|
in string
|
|
want int
|
|
wantErr errors.Code
|
|
}{
|
|
{
|
|
name: "found",
|
|
in: l.GetPublicId(),
|
|
want: 1,
|
|
},
|
|
{
|
|
name: "not-found",
|
|
in: badId,
|
|
},
|
|
{
|
|
name: "empty-public-id",
|
|
in: "",
|
|
wantErr: errors.InvalidParameter,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
got, err := repo.DeleteCredentialLibrary(ctx, prj.GetPublicId(), tt.in)
|
|
if tt.wantErr != 0 {
|
|
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
|
|
return
|
|
}
|
|
assert.NoError(err)
|
|
assert.Equal(tt.want, got, "row count")
|
|
})
|
|
}
|
|
}
|
|
|
|
t.Run("library-with-mapping-overrides", func(t *testing.T) {
|
|
// setup
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
lib := &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
WithOverridePasswordAttribute("orig-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
}
|
|
|
|
orig, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), lib)
|
|
assert.NoError(err)
|
|
require.NotNil(orig)
|
|
|
|
// test
|
|
got, err := repo.DeleteCredentialLibrary(ctx, prj.GetPublicId(), orig.GetPublicId())
|
|
assert.NoError(err)
|
|
assert.Equal(1, got)
|
|
})
|
|
}
|
|
|
|
func TestRepository_ListCredentialLibraries(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
|
|
t.Run("CredentialStore-with-a-library", func(t *testing.T) {
|
|
// setup
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2)[0]
|
|
lib := &CredentialLibrary{
|
|
MappingOverride: NewUsernamePasswordOverride(
|
|
WithOverrideUsernameAttribute("orig-username"),
|
|
WithOverridePasswordAttribute("orig-password"),
|
|
),
|
|
CredentialLibrary: &store.CredentialLibrary{
|
|
StoreId: cs.GetPublicId(),
|
|
HttpMethod: "GET",
|
|
VaultPath: "/some/path",
|
|
Name: "test-name-repo",
|
|
CredentialType: string(globals.UsernamePasswordCredentialType),
|
|
},
|
|
}
|
|
|
|
orig, err := repo.CreateCredentialLibrary(ctx, prj.GetPublicId(), lib)
|
|
assert.NoError(err)
|
|
require.NotNil(orig)
|
|
|
|
// test
|
|
got, ttime, err := repo.ListLibraries(ctx, cs.GetPublicId())
|
|
assert.NoError(err)
|
|
require.Len(got, 1)
|
|
// Transaction timestamp should be within ~10 seconds of now
|
|
assert.True(time.Now().Before(ttime.Add(10 * time.Second)))
|
|
assert.True(time.Now().After(ttime.Add(-10 * time.Second)))
|
|
require.Empty(cmp.Diff(
|
|
orig,
|
|
got[0],
|
|
cmpopts.IgnoreUnexported(
|
|
CredentialLibrary{},
|
|
store.CredentialLibrary{},
|
|
timestamp.Timestamp{},
|
|
timestamppb.Timestamp{},
|
|
),
|
|
cmpopts.IgnoreFields(
|
|
CredentialLibrary{},
|
|
"MappingOverride",
|
|
),
|
|
))
|
|
})
|
|
|
|
t.Run("with-no-credential-store-id", func(t *testing.T) {
|
|
// setup
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
// test
|
|
_, _, err = repo.ListLibraries(ctx, "")
|
|
wantErr := errors.InvalidParameter
|
|
assert.Truef(errors.Match(errors.T(wantErr), err), "want err: %q got: %q", wantErr, err)
|
|
})
|
|
|
|
t.Run("CredentialStore-with-no-libraries", func(t *testing.T) {
|
|
// setup
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
// test
|
|
got, ttime, err := repo.ListLibraries(ctx, cs.GetPublicId())
|
|
assert.NoError(err)
|
|
assert.Empty(got)
|
|
// Transaction timestamp should be within ~10 seconds of now
|
|
assert.True(time.Now().Before(ttime.Add(10 * time.Second)))
|
|
assert.True(time.Now().After(ttime.Add(-10 * time.Second)))
|
|
})
|
|
}
|
|
|
|
func TestRepository_ListCredentialLibraries_Limits(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
cs := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
const count = 10
|
|
libs := TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), globals.UnspecifiedCredentialType, count)
|
|
|
|
tests := []struct {
|
|
name string
|
|
repoOpts []Option
|
|
listOpts []credential.Option
|
|
wantLen int
|
|
}{
|
|
{
|
|
name: "with-no-limits",
|
|
wantLen: count,
|
|
},
|
|
{
|
|
name: "with-repo-limit",
|
|
repoOpts: []Option{WithLimit(3)},
|
|
wantLen: 3,
|
|
},
|
|
{
|
|
name: "with-list-limit",
|
|
listOpts: []credential.Option{credential.WithLimit(3)},
|
|
wantLen: 3,
|
|
},
|
|
{
|
|
name: "with-repo-smaller-than-list-limit",
|
|
repoOpts: []Option{WithLimit(2)},
|
|
listOpts: []credential.Option{credential.WithLimit(6)},
|
|
wantLen: 6,
|
|
},
|
|
{
|
|
name: "with-repo-larger-than-list-limit",
|
|
repoOpts: []Option{WithLimit(6)},
|
|
listOpts: []credential.Option{credential.WithLimit(2)},
|
|
wantLen: 2,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche, tt.repoOpts...)
|
|
assert.NoError(err)
|
|
require.NotNil(repo)
|
|
got, ttime, err := repo.ListLibraries(ctx, libs[0].StoreId, tt.listOpts...)
|
|
require.NoError(err)
|
|
assert.Len(got, tt.wantLen)
|
|
// Transaction timestamp should be within ~10 seconds of now
|
|
assert.True(time.Now().Before(ttime.Add(10 * time.Second)))
|
|
assert.True(time.Now().After(ttime.Add(-10 * time.Second)))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRepository_ListCredentialLibraries_Pagination(t *testing.T) {
|
|
t.Parallel()
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
css := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 3)
|
|
|
|
for _, cs := range css[:2] { // Leave the third store empty
|
|
TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), globals.UnspecifiedCredentialType, 5)
|
|
}
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
require.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
for _, cs := range css[:2] {
|
|
page1, ttime, err := repo.ListLibraries(ctx, cs.GetPublicId(), credential.WithLimit(2))
|
|
require.NoError(err)
|
|
require.Len(page1, 2)
|
|
// Transaction timestamp should be within ~10 seconds of now
|
|
assert.True(time.Now().Before(ttime.Add(10 * time.Second)))
|
|
assert.True(time.Now().After(ttime.Add(-10 * time.Second)))
|
|
page2, ttime, err := repo.ListLibraries(ctx, cs.GetPublicId(), credential.WithLimit(2), credential.WithStartPageAfterItem(page1[1]))
|
|
require.NoError(err)
|
|
require.Len(page2, 2)
|
|
assert.True(time.Now().Before(ttime.Add(10 * time.Second)))
|
|
assert.True(time.Now().After(ttime.Add(-10 * time.Second)))
|
|
for _, item := range page1 {
|
|
assert.NotEqual(item.GetPublicId(), page2[0].GetPublicId())
|
|
assert.NotEqual(item.GetPublicId(), page2[1].GetPublicId())
|
|
}
|
|
page3, ttime, err := repo.ListLibraries(ctx, cs.GetPublicId(), credential.WithLimit(2), credential.WithStartPageAfterItem(page2[1]))
|
|
require.NoError(err)
|
|
require.Len(page3, 1)
|
|
assert.True(time.Now().Before(ttime.Add(10 * time.Second)))
|
|
assert.True(time.Now().After(ttime.Add(-10 * time.Second)))
|
|
for _, item := range append(page1, page2...) {
|
|
assert.NotEqual(item.GetPublicId(), page3[0].GetPublicId())
|
|
}
|
|
page4, ttime, err := repo.ListLibraries(ctx, cs.GetPublicId(), credential.WithLimit(2), credential.WithStartPageAfterItem(page3[0]))
|
|
require.NoError(err)
|
|
require.Empty(page4)
|
|
assert.True(time.Now().Before(ttime.Add(10 * time.Second)))
|
|
assert.True(time.Now().After(ttime.Add(-10 * time.Second)))
|
|
}
|
|
|
|
emptyPage, ttime, err := repo.ListLibraries(ctx, css[2].GetPublicId(), credential.WithLimit(2))
|
|
require.NoError(err)
|
|
assert.True(time.Now().Before(ttime.Add(10 * time.Second)))
|
|
assert.True(time.Now().After(ttime.Add(-10 * time.Second)))
|
|
require.Empty(emptyPage)
|
|
}
|
|
|
|
func TestRepository_ListDeletedLibraryIds(t *testing.T) {
|
|
t.Parallel()
|
|
require := require.New(t)
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
store := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
libs := TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), globals.UnspecifiedCredentialType, 2)
|
|
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
require.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
// Expect no entries at the start
|
|
deletedIds, ttime, err := repo.ListDeletedLibraryIds(ctx, time.Now().AddDate(-1, 0, 0))
|
|
require.NoError(err)
|
|
require.Empty(deletedIds)
|
|
// Transaction timestamp should be within ~10 seconds of now
|
|
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
|
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
|
|
|
// Delete a vault library
|
|
_, err = repo.DeleteCredentialLibrary(ctx, prj.GetPublicId(), libs[0].GetPublicId())
|
|
require.NoError(err)
|
|
|
|
// Expect a single entry
|
|
deletedIds, ttime, err = repo.ListDeletedLibraryIds(ctx, time.Now().AddDate(-1, 0, 0))
|
|
require.NoError(err)
|
|
require.Equal([]string{libs[0].GetPublicId()}, deletedIds)
|
|
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
|
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
|
|
|
// Try again with the time set to now, expect no entries
|
|
deletedIds, ttime, err = repo.ListDeletedLibraryIds(ctx, time.Now())
|
|
require.NoError(err)
|
|
require.Empty(deletedIds)
|
|
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
|
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
|
}
|
|
|
|
func TestRepository_EstimatedLibraryCount(t *testing.T) {
|
|
t.Parallel()
|
|
assert, require := assert.New(t), require.New(t)
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
sqlDb, err := conn.SqlDB(ctx)
|
|
require.NoError(err)
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
sche := scheduler.TestScheduler(t, conn, wrapper)
|
|
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
store := TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
|
|
|
|
repo, err := NewRepository(ctx, rw, rw, kms, sche)
|
|
require.NoError(err)
|
|
require.NotNil(repo)
|
|
|
|
// Check total entries at start, expect 0
|
|
numItems, err := repo.EstimatedLibraryCount(ctx)
|
|
require.NoError(err)
|
|
assert.Equal(0, numItems)
|
|
|
|
// Create some libraries
|
|
libs := TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), globals.UnspecifiedCredentialType, 2)
|
|
// Run analyze to update postgres meta tables
|
|
_, err = sqlDb.ExecContext(ctx, "analyze")
|
|
require.NoError(err)
|
|
|
|
numItems, err = repo.EstimatedLibraryCount(ctx)
|
|
require.NoError(err)
|
|
assert.Equal(2, numItems)
|
|
|
|
// Delete a library
|
|
_, err = repo.DeleteCredentialLibrary(ctx, prj.GetPublicId(), libs[0].GetPublicId())
|
|
require.NoError(err)
|
|
_, err = sqlDb.ExecContext(ctx, "analyze")
|
|
require.NoError(err)
|
|
|
|
numItems, err = repo.EstimatedLibraryCount(ctx)
|
|
require.NoError(err)
|
|
assert.Equal(1, numItems)
|
|
}
|