mirror of https://github.com/hashicorp/boundary
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
12 KiB
390 lines
12 KiB
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package oss_test
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
"github.com/hashicorp/boundary/internal/db/common"
|
|
"github.com/hashicorp/boundary/internal/db/schema/migration"
|
|
"github.com/hashicorp/boundary/internal/db/schema/migrations/oss"
|
|
"github.com/hashicorp/boundary/internal/db/schema/migrations/oss/internal/hook46001"
|
|
"github.com/hashicorp/boundary/testing/dbtest"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestMigrationHook46001(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
dialect := dbtest.Postgres
|
|
|
|
c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1))
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() {
|
|
require.NoError(t, c())
|
|
})
|
|
d, err := common.SqlOpen(dialect, u)
|
|
require.NoError(t, err)
|
|
|
|
// get a connection
|
|
dbType, err := db.StringToDbType(dialect)
|
|
require.NoError(t, err)
|
|
conn, err := db.Open(ctx, dbType, u)
|
|
require.NoError(t, err)
|
|
rw := db.New(conn)
|
|
|
|
// The reason why we are starting at 43001 is because one of the security vulnerabilities was a
|
|
// bad trigger on table target_host_set that was suppose to validate scope_id integrity between
|
|
// the target & host set. In migration 44002, this trigger is fixed.
|
|
oss.ApplyMigration(t, ctx, d, 43001)
|
|
|
|
// Insert test data into the database.
|
|
populateScopes(t, rw)
|
|
populateKMS(t, rw)
|
|
|
|
// Belongs to PRJA___65001
|
|
populateTarget(t, rw)
|
|
|
|
// Valid associations to target
|
|
populateStaticCredential(t, rw, "PRJA___65001")
|
|
populateCredentialLibrary(t, rw, "PRJA___65001")
|
|
populateHostSet(t, rw, "PRJA___65001")
|
|
|
|
// Illegal associations to target
|
|
populateStaticCredential(t, rw, "PRJB___65001")
|
|
populateCredentialLibrary(t, rw, "PRJB___65001")
|
|
populateHostSet(t, rw, "PRJB___65001")
|
|
|
|
// Apply migrations 4400x, 4500x
|
|
migrationIds := []int{44001, 44002, 44003, 44004, 45001, 45002, 45003}
|
|
for _, migrationId := range migrationIds {
|
|
oss.ApplyMigration(t, ctx, d, migrationId)
|
|
}
|
|
|
|
tx, err := d.BeginTx(ctx, nil)
|
|
require.NoError(t, err)
|
|
|
|
// Run hook check
|
|
checkReport, err := hook46001.FindIllegalAssociations(ctx, tx)
|
|
require.NoError(t, err)
|
|
|
|
// Run hook repair
|
|
repairReport, err := hook46001.RepairIllegalAssociations(ctx, tx)
|
|
require.NoError(t, err)
|
|
|
|
err = tx.Commit()
|
|
require.NoError(t, err)
|
|
|
|
// Hook validations
|
|
validateCheckFunc(t, checkReport)
|
|
validateRepairFunc(t, rw, repairReport)
|
|
}
|
|
|
|
func populateScopes(t *testing.T, rw *db.Db) {
|
|
t.Helper()
|
|
require := require.New(t)
|
|
ctx := context.Background()
|
|
|
|
var (
|
|
err error
|
|
query string
|
|
)
|
|
query = `
|
|
insert into iam_scope
|
|
(parent_id, type, public_id, name)
|
|
values
|
|
('global', 'org', 'o_test___65001', 'Testing Invalid Target Associations')`
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = `
|
|
insert into iam_scope
|
|
(parent_id, type, public_id, name)
|
|
values
|
|
('o_test___65001', 'project', 'p_PRJA___65001', 'testing 65001 Project A'),
|
|
('o_test___65001', 'project', 'p_PRJB___65001', 'testing 65001 Project B')`
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
}
|
|
|
|
func populateKMS(t *testing.T, rw *db.Db) {
|
|
t.Helper()
|
|
require := require.New(t)
|
|
ctx := context.Background()
|
|
|
|
var (
|
|
err error
|
|
query string
|
|
)
|
|
|
|
query = `
|
|
insert into kms_root_key
|
|
(private_id, scope_id)
|
|
values
|
|
('krk________65001', 'o_test___65001')`
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = `
|
|
insert into kms_root_key_version
|
|
(private_id, root_key_id, key)
|
|
values
|
|
('krkv________65001', 'krk________65001', '________65001'::bytea)`
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = `
|
|
insert into kms_data_key
|
|
(private_id, root_key_id, purpose)
|
|
values
|
|
('kdk________65001', 'krk________65001', 'database')`
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = `
|
|
insert into kms_data_key_version
|
|
(private_id, data_key_id, root_key_version_id, key)
|
|
values
|
|
('kdkv_PRJA___65001', 'kdk________65001', 'krkv________65001', '________65001'::bytea),
|
|
('kdkv_PRJB___65001', 'kdk________65001', 'krkv________65001', '________65001'::bytea)`
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
}
|
|
|
|
func populateTarget(t *testing.T, rw *db.Db) {
|
|
t.Helper()
|
|
require := require.New(t)
|
|
ctx := context.Background()
|
|
|
|
var (
|
|
err error
|
|
query string
|
|
)
|
|
query = `
|
|
insert into target_tcp
|
|
(scope_id, public_id, name)
|
|
values
|
|
('p_PRJA___65001', 'ttcp_PRJA___65001', 'Test Target Project A')`
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
}
|
|
|
|
func populateStaticCredential(t *testing.T, rw *db.Db, projectId string) {
|
|
t.Helper()
|
|
require := require.New(t)
|
|
ctx := context.Background()
|
|
|
|
var (
|
|
err error
|
|
query string
|
|
)
|
|
query = fmt.Sprintf(`
|
|
insert into credential_static_store
|
|
(scope_id, public_id, name, description)
|
|
values
|
|
('p_%[1]s', 'csst_%[1]s', '%[1]s', 'None')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into credential_static_username_password_credential
|
|
(store_id, public_id, name, description, username, password_encrypted, password_hmac, key_id)
|
|
values
|
|
('csst_%[1]s', 'credup_%[1]s', 'test %[1]s static credential', 'None', 'admin', 'encrypted_password', 'hmac-value', 'kdkv_%[1]s')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into target_static_credential
|
|
(target_id, credential_static_id, credential_purpose)
|
|
values
|
|
('ttcp_PRJA___65001', 'credup_%s', 'brokered')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
}
|
|
|
|
func populateCredentialLibrary(t *testing.T, rw *db.Db, projectId string) {
|
|
t.Helper()
|
|
require := require.New(t)
|
|
ctx := context.Background()
|
|
|
|
var (
|
|
err error
|
|
query string
|
|
)
|
|
query = fmt.Sprintf(`
|
|
insert into credential_vault_store
|
|
(scope_id, public_id, name, description, vault_address, namespace)
|
|
values
|
|
('p_%[1]s', 'csvlt_%[1]s', 'test credentail library', 'None', 'https://vault.widget', 'default')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into credential_vault_token
|
|
(store_id, key_id, status, token_hmac, token, last_renewal_time, expiration_time)
|
|
values
|
|
('csvlt_%[1]s', 'kdkv_%[1]s', 'current', '%[1]s-hmac-value', 'token-value', now(), now() + interval '1 hour')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into credential_vault_library
|
|
(store_id, public_id, name, description, vault_path, http_method, credential_type)
|
|
values
|
|
('csvlt_%[1]s', 'clvlt_%[1]s', 'test credential', 'None', '/secrets/kv/one', 'GET', 'username_password')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into target_credential_library
|
|
(target_id, credential_library_id, credential_purpose)
|
|
values
|
|
('ttcp_PRJA___65001', 'clvlt_%s', 'brokered')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
}
|
|
|
|
func populateHostSet(t *testing.T, rw *db.Db, projectId string) {
|
|
t.Helper()
|
|
require := require.New(t)
|
|
ctx := context.Background()
|
|
|
|
var (
|
|
err error
|
|
query string
|
|
)
|
|
query = fmt.Sprintf(`
|
|
insert into static_host_catalog
|
|
(scope_id, public_id, name)
|
|
values
|
|
('p_%[1]s', 'hcst_%[1]s', '%[1]s HostCatalog')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into static_host
|
|
(catalog_id, public_id, address)
|
|
values
|
|
('hcst_%[1]s', 'hst_%[1]s', '%[1]s Host')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into static_host_set
|
|
(catalog_id, public_id, name)
|
|
values
|
|
('hcst_%[1]s', 'hsst_%[1]s', '%[1]s HostSet')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into static_host_set_member
|
|
( host_id, set_id, catalog_id)
|
|
values
|
|
('hst_%[1]s', 'hsst_%[1]s', 'hcst_%[1]s')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
|
|
query = fmt.Sprintf(`
|
|
insert into target_host_set
|
|
(target_id, host_set_id)
|
|
values
|
|
('ttcp_PRJA___65001', 'hsst_%s')`, projectId)
|
|
_, err = rw.Exec(ctx, query, nil)
|
|
require.NoError(err)
|
|
}
|
|
|
|
func validateCheckFunc(t *testing.T, checkReport migration.Problems) {
|
|
t.Helper()
|
|
require := require.New(t)
|
|
require.ElementsMatch(checkReport, migration.Problems{
|
|
"Target ttcp_PRJA___65001 in project p_PRJA___65001 in org o_test___65001 has an illegal association to credential library clvlt_PRJB___65001 in credential store csvlt_PRJB___65001 in project p_PRJB___65001 in org o_test___65001",
|
|
"Target ttcp_PRJA___65001 in project p_PRJA___65001 in org o_test___65001 has an illegal association to host set hsst_PRJB___65001 in host catalog hcst_PRJB___65001 in project p_PRJB___65001 in org o_test___65001",
|
|
"Target ttcp_PRJA___65001 in project p_PRJA___65001 in org o_test___65001 has an illegal association to static credential credup_PRJB___65001 in credential store csst_PRJB___65001 in project p_PRJB___65001 in org o_test___65001",
|
|
})
|
|
}
|
|
|
|
func validateRepairFunc(t *testing.T, rw *db.Db, repairReport migration.Repairs) {
|
|
t.Helper()
|
|
require := require.New(t)
|
|
ctx := context.Background()
|
|
|
|
require.ElementsMatch(repairReport, migration.Repairs{
|
|
"Removed illegal association from target ttcp_PRJA___65001 in project p_PRJA___65001 in org o_test___65001 to credential library clvlt_PRJB___65001 in credential store csvlt_PRJB___65001 in project p_PRJB___65001 in org o_test___65001",
|
|
"Removed illegal association from target ttcp_PRJA___65001 in project p_PRJA___65001 in org o_test___65001 to host set hsst_PRJB___65001 in host catalog hcst_PRJB___65001 in project p_PRJB___65001 in org o_test___65001",
|
|
"Removed illegal association from target ttcp_PRJA___65001 in project p_PRJA___65001 in org o_test___65001 to static credential credup_PRJB___65001 in credential store csst_PRJB___65001 in project p_PRJB___65001 in org o_test___65001",
|
|
})
|
|
|
|
var (
|
|
err error
|
|
query string
|
|
rows *sql.Rows
|
|
)
|
|
type targetAssociation struct {
|
|
targetId string
|
|
resourceId string
|
|
}
|
|
query = `
|
|
with
|
|
ths (target_id, host_set_id) as (
|
|
select ths.target_id, ths.host_set_id
|
|
from target_host_set as ths
|
|
where ths.target_id = 'ttcp_PRJA___65001'
|
|
),
|
|
tsc (target_id, credential_static_id) as (
|
|
select tsc.target_id, tsc.credential_static_id
|
|
from target_static_credential as tsc
|
|
where tsc.target_id = 'ttcp_PRJA___65001'
|
|
),
|
|
tcl (target_id, credential_library_id) as (
|
|
select tcl.target_id, tcl.credential_library_id
|
|
from target_credential_library as tcl
|
|
where tcl.target_id = 'ttcp_PRJA___65001'
|
|
),
|
|
resources (target_id, resource_id) as (
|
|
select target_id, host_set_id as resource_id
|
|
from ths
|
|
union
|
|
select target_id, credential_static_id as resource_id
|
|
from tsc
|
|
union
|
|
select target_id, credential_library_id as resource_id
|
|
from tcl
|
|
)
|
|
select * from resources;`
|
|
rows, err = rw.Query(ctx, query, nil)
|
|
require.NoError(err)
|
|
associations := []targetAssociation{}
|
|
for rows.Next() {
|
|
var targetId, resourceId string
|
|
if err := rows.Scan(&targetId, &resourceId); err != nil {
|
|
require.NoError(err)
|
|
}
|
|
associations = append(associations, targetAssociation{
|
|
targetId: targetId,
|
|
resourceId: resourceId,
|
|
})
|
|
}
|
|
require.NoError(rows.Err())
|
|
require.Equal([]targetAssociation{
|
|
{
|
|
targetId: "ttcp_PRJA___65001",
|
|
resourceId: "clvlt_PRJA___65001",
|
|
},
|
|
{
|
|
targetId: "ttcp_PRJA___65001",
|
|
resourceId: "hsst_PRJA___65001",
|
|
},
|
|
{
|
|
targetId: "ttcp_PRJA___65001",
|
|
resourceId: "credup_PRJA___65001",
|
|
},
|
|
}, associations)
|
|
}
|