Files
threshold/internal/db/schema/migrations/oss/postgres_57_01_test.go
T
Johan Brandhorst-Satzkorn eb113b5c9e fix(db): Reorder migrations (#2688)
Migration numbers need to be consistent between version upgrades.
The migrations for the key lifecycle management were merged
into v0.11.1 as number 56, but are currently 58 in main.
This reorders them down to 56, fixing an issue when
migrating from 0.11.1 to main.
2022-12-08 13:40:14 -05:00

296 lines
9.3 KiB
Go

package oss_test
import (
"context"
"crypto/rand"
"testing"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/common"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/testing/dbtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMigrations_DeleteOrphanedAccounts(t *testing.T) {
const (
priorMigration = 56001
currentMigration = 57001
)
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)
// migration to the prior migration (before the one we want to test)
m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err := m.CurrentState(ctx)
require.NoError(t, err)
want := &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: priorMigration,
DatabaseSchemaVersion: priorMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// Get a connection
dbType, err := db.StringToDbType(dialect)
require.NoError(t, err)
conn, err := db.Open(ctx, dbType, u)
require.NoError(t, err)
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
err = kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader))
require.NoError(t, err)
// Create the user we will associate accounts with
iamRepo := iam.TestRepo(t, conn, wrapper)
usr, err := iam.NewUser(scope.Global.String())
require.NoError(t, err)
usr.PublicId = "u_1234567890"
num, err := rw.Exec(ctx, `
insert into iam_user
(public_id, scope_id)
values
(?, ?)
`, []any{usr.PublicId, scope.Global.String()})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Create the accounts we will delete and assert their behavior
pwAm1, err := password.NewAuthMethod(scope.Global.String())
require.NoError(t, err)
pwAm1.PublicId = "ampw_1234567890"
_, err = rw.DoTx(ctx, 0, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error {
_, err := w.Exec(ctx, `
insert into auth_password_argon2_conf
(private_id, password_method_id)
values
(?, ?)
`, []any{"arg2conf_1234567890", pwAm1.PublicId})
if err != nil {
return err
}
_, err = w.Exec(ctx, `
insert into auth_password_method
(public_id, password_conf_id, scope_id)
values
(?, ?, ?)
`, []any{pwAm1.PublicId, "arg2conf_1234567890", pwAm1.ScopeId})
return err
})
require.NoError(t, err)
pwAcct1, err := password.NewAccount(pwAm1.GetPublicId(), password.WithLoginName("account1"), password.WithPassword("password"))
require.NoError(t, err)
pwAcct1.PublicId = "acctpw_1234567890"
num, err = rw.Exec(ctx, `
insert into auth_password_account
(public_id, auth_method_id, scope_id, login_name)
values
(?, ?, ?, ?)
`, []any{pwAcct1.PublicId, pwAm1.PublicId, pwAm1.ScopeId, pwAcct1.LoginName})
require.NoError(t, err)
assert.Equal(t, 1, num)
pwAm2, err := password.NewAuthMethod(scope.Global.String())
require.NoError(t, err)
pwAm2.PublicId = "ampw_0123456789"
_, err = rw.DoTx(ctx, 0, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error {
_, err := w.Exec(ctx, `
insert into auth_password_argon2_conf
(private_id, password_method_id)
values
(?, ?)
`, []any{"arg2conf_0123456789", pwAm2.PublicId})
if err != nil {
return err
}
_, err = w.Exec(ctx, `
insert into auth_password_method
(public_id, password_conf_id, scope_id)
values
(?, ?, ?)
`, []any{pwAm2.PublicId, "arg2conf_0123456789", pwAm2.ScopeId})
return err
})
pwAcct2, err := password.NewAccount(pwAm2.GetPublicId(), password.WithLoginName("account2"), password.WithPassword("password"))
require.NoError(t, err)
pwAcct2.PublicId = "acctpw_0123456789"
num, err = rw.Exec(ctx, `
insert into auth_password_account
(public_id, auth_method_id, scope_id, login_name)
values
(?, ?, ?, ?)
`, []any{pwAcct2.PublicId, pwAm2.PublicId, pwAm2.ScopeId, pwAcct2.LoginName})
require.NoError(t, err)
assert.Equal(t, 1, num)
databaseWrapper, err := kmsCache.GetWrapper(context.Background(), scope.Global.String(), kms.KeyPurposeDatabase)
oidcAm1 := oidc.TestAuthMethod(t, conn, databaseWrapper, scope.Global.String(), oidc.InactiveState, "alice_rp1",
"my-dogs-name", oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice1.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api1.com")[0]))
oidcAm1.PublicId = "amoidc_1234567890"
num, err = rw.Exec(ctx, `
insert into auth_oidc_method
(public_id, scope_id, state, key_id)
values
(?, ?, ?, ?)
`, []any{oidcAm1.PublicId, oidcAm1.ScopeId, oidcAm1.OperationalState, oidcAm1.KeyId})
require.NoError(t, err)
assert.Equal(t, 1, num)
oidcAcct1, err := oidc.NewAccount(ctx, oidcAm1.GetPublicId(), "oidcAcct1")
require.NoError(t, err)
oidcAcct1.PublicId = "acctoidc_0123456789"
num, err = rw.Exec(ctx, `
insert into auth_oidc_account
(public_id, auth_method_id, scope_id, issuer, subject)
values
(?, ?, ?, ?, ?)
`, []any{oidcAcct1.PublicId, oidcAm1.PublicId, oidcAm1.ScopeId, oidcAm1.Issuer, oidcAcct1.Subject})
require.NoError(t, err)
assert.Equal(t, 1, num)
oidcAm2 := oidc.TestAuthMethod(t, conn, databaseWrapper, scope.Global.String(), oidc.InactiveState, "alice_rp2",
"my-dogs-name", oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice2.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api2.com")[0]))
oidcAm2.PublicId = "amoidc_0123456789"
num, err = rw.Exec(ctx, `
insert into auth_oidc_method
(public_id, scope_id, state, key_id)
values
(?, ?, ?, ?)
`, []any{oidcAm2.PublicId, oidcAm2.ScopeId, oidcAm2.OperationalState, oidcAm2.KeyId})
require.NoError(t, err)
assert.Equal(t, 1, num)
oidcAcct2, err := oidc.NewAccount(ctx, oidcAm2.GetPublicId(), "oidcAcct2")
require.NoError(t, err)
oidcAcct2.PublicId = "acctoidc_1234567890"
num, err = rw.Exec(ctx, `
insert into auth_oidc_account
(public_id, auth_method_id, scope_id, issuer, subject)
values
(?, ?, ?, ?, ?)
`, []any{oidcAcct2.PublicId, oidcAm2.PublicId, oidcAm2.ScopeId, oidcAm2.Issuer, oidcAcct2.Subject})
require.NoError(t, err)
assert.Equal(t, 1, num)
num, err = rw.Exec(ctx, `
update auth_account set
iam_user_id=?
where
public_id in (?, ?, ?, ?)
`, []any{
usr.PublicId,
pwAcct1.PublicId, pwAcct2.PublicId, oidcAcct1.PublicId, oidcAcct2.PublicId,
})
require.NoError(t, err)
assert.Equal(t, 4, num)
usr, accts, err := iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.ElementsMatch(t, []string{
pwAcct1.GetPublicId(), pwAcct2.GetPublicId(),
oidcAcct1.GetPublicId(), oidcAcct2.GetPublicId(),
}, accts)
num, err = rw.Exec(ctx, `
delete from auth_password_account
where
public_id=?
`, []any{pwAcct1.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
num, err = rw.Exec(ctx, `
delete from auth_oidc_account
where
public_id=?
`, []any{oidcAcct1.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
// pwAcct1 is still listed as an account for this user! oh no!
_, accts, err = iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.ElementsMatch(t, []string{
pwAcct1.GetPublicId(), pwAcct2.GetPublicId(),
oidcAcct1.GetPublicId(), oidcAcct2.GetPublicId(),
}, accts)
// now we're ready for the migration we want to test.
m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err = m.CurrentState(ctx)
require.NoError(t, err)
want = &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: currentMigration,
DatabaseSchemaVersion: currentMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// pwAcct1 is no longer listed as an account for this user. Phew!
_, accts, err = iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.ElementsMatch(t, []string{pwAcct2.GetPublicId(), oidcAcct2.GetPublicId()}, accts)
num, err = rw.Exec(ctx, `
delete from auth_password_account
where
public_id=?
`, []any{pwAcct2.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
_, accts, err = iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.ElementsMatch(t, []string{oidcAcct2.GetPublicId()}, accts)
num, err = rw.Exec(ctx, `
delete from auth_oidc_account
where
public_id=?
`, []any{oidcAcct2.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Deleting the account now removes the association with the user
_, accts, err = iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.Empty(t, accts)
}