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.
pull/2627/head
Johan Brandhorst-Satzkorn 3 years ago committed by GitHub
parent 70a1302cd9
commit eb113b5c9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -18,7 +18,7 @@ create domain wt_scope_id as text
check(
length(trim(value)) > 10 or value = 'global'
);
-- Comment fixed in 57/01_fix_comments.up.sql
-- Comment fixed in 58/01_fix_comments.up.sql
comment on domain wt_scope_id is
'"global" or random ID generated with github.com/hashicorp/go-secure-stdlib/base62';
@ -26,7 +26,7 @@ create domain wt_user_id as text not null
check(
length(trim(value)) > 10 or value = 'u_anon' or value = 'u_auth' or value = 'u_recovery'
);
-- Comment fixed in 57/01_fix_comments.up.sql
-- Comment fixed in 58/01_fix_comments.up.sql
comment on domain wt_scope_id is
'"u_anon", "u_auth", or random ID generated with github.com/hashicorp/go-secure-stdlib/base62';
@ -34,7 +34,7 @@ create domain wt_role_id as text not null
check(
length(trim(value)) > 10
);
-- Comment fixed in 57/01_fix_comments.up.sql
-- Comment fixed in 58/01_fix_comments.up.sql
comment on domain wt_scope_id is
'Random ID generated with github.com/hashicorp/go-secure-stdlib/base62';

@ -57,7 +57,7 @@ begin;
comment on function update_last_access_time() is
'function used in before update triggers to properly set last_access_time columns';
-- this trigger is deleted in 58/05_mutable_ciphertext_columns.up.sql
-- this trigger is deleted in 56/05_mutable_ciphertext_columns.up.sql
create or replace function immutable_auth_token_columns() returns trigger
as $$
begin

@ -190,7 +190,7 @@ begin;
create trigger default_create_time_column before insert on credential_vault_token
for each row execute procedure default_create_time();
-- this trigger is updated in 58/05_mutable_ciphertext_columns.up.sql
-- this trigger is updated in 56/05_mutable_ciphertext_columns.up.sql
create trigger immutable_columns before update on credential_vault_token
for each row execute procedure immutable_columns('token_hmac', 'token', 'store_id','create_time');

@ -2,7 +2,7 @@ begin;
-- The 'comment on function' statements below are not for the functions in the
-- file. They incorrectly override the comments for functions declared in
-- 7/01_functions.up.sql. Fixes are contained in 57/01_fix_comments.up.sql.
-- 7/01_functions.up.sql. Fixes are contained in 58/01_fix_comments.up.sql.
create function wt_sub_seconds(sec integer, ts timestamp with time zone) returns timestamp with time zone
as $$

@ -158,7 +158,7 @@ create table auth_oidc_account (
constraint auth_oidc_account_auth_method_id_public_id_uq
unique(auth_method_id, public_id)
);
-- Comment fixed in 57/01_fix_comments.up.sql
-- Comment fixed in 58/01_fix_comments.up.sql
comment on table auth_oidc_method is
'auth_oidc_account entries are subtypes of auth_account and represent an oidc account.';

@ -22,7 +22,7 @@ begin;
'session_credential is a table where each row contains a credential to be used by '
'by a worker when a connection is established for the session_id.';
-- this trigger is updated in 58/05_mutable_ciphertext_columns.up.sql
-- this trigger is updated in 56/05_mutable_ciphertext_columns.up.sql
create trigger immutable_columns before update on session_credential
for each row execute procedure immutable_columns('session_id', 'credential', 'key_id');

@ -101,7 +101,7 @@ create table kms_data_key_version (
constraint kms_data_key_version_data_key_id_version_uq
unique(data_key_id, version)
);
-- Comment fixed in 57/01_fix_comments.up.sql
-- Comment fixed in 58/01_fix_comments.up.sql
comment on table kms_data_key is
'kms_data_key_version contains versions of a kms_data_key (dek aka data keys)';

@ -72,7 +72,7 @@ create table worker_auth_ca_certificate(
comment on table worker_auth_ca_certificate is
'worker_auth_ca_certificate is a table where each row represents a root certificate for used for worker authentication.';
-- this trigger is updated in 58/05_mutable_ciphertext_columns.up.sql
-- this trigger is updated in 56/05_mutable_ciphertext_columns.up.sql
create trigger immutable_columns before update on worker_auth_ca_certificate
for each row execute procedure immutable_columns('serial_number', 'certificate', 'not_valid_before', 'not_valid_after', 'public_key', 'private_key', 'key_id', 'state', 'issuing_ca');
@ -102,7 +102,7 @@ create table worker_auth_authorized(
comment on table worker_auth_authorized is
'worker_auth_authorized is a table where each row represents key and cert data associated with an authorized worker.';
-- this trigger is updated in 58/05_mutable_ciphertext_columns.up.sql
-- this trigger is updated in 56/05_mutable_ciphertext_columns.up.sql
create trigger immutable_columns before update on worker_auth_authorized
for each row execute procedure immutable_columns('worker_key_identifier', 'worker_id', 'worker_signing_pub_key', 'worker_encryption_pub_key', 'controller_encryption_priv_key', 'key_id', 'nonce');

@ -13,7 +13,7 @@ begin;
add constraint session_credential_session_id_credential_sha256_uq
unique(session_id, credential_sha256);
-- this trigger is updated in 58/05_mutable_ciphertext_columns.up.sql
-- this trigger is updated in 56/05_mutable_ciphertext_columns.up.sql
drop trigger immutable_columns on session_credential;
create trigger immutable_columns before update on session_credential
for each row execute procedure immutable_columns('session_id', 'credential', 'key_id', 'credential_sha256');

@ -212,7 +212,7 @@ begin;
'No encrypted data is returned. This view can be used to retrieve data which will be returned external to boundary.';
-- Replaces view from 41/01_worker_filter_vault_cred_store.up.sql
-- Recreated in 58/02_add_data_key_foreign_key_references.up.sql
-- Recreated in 56/02_add_data_key_foreign_key_references.up.sql
create view credential_vault_credential_private as
select credential.public_id as public_id,
credential.library_id as library_id,

@ -71,7 +71,7 @@ begin;
-- update views
drop view host_plugin_catalog_with_secret;
-- Recreated in 58/02_add_data_key_foreign_key_references.up.sql
-- Recreated in 56/02_add_data_key_foreign_key_references.up.sql
create view host_plugin_catalog_with_secret as
select
hc.public_id,

@ -12,7 +12,7 @@ begin;
;
-- Replaces trigger from 01/50_session.up.sql
-- Replaced in 58/02_add_data_key_foreign_key_references
-- Replaced in 56/02_add_data_key_foreign_key_references
create or replace function cancel_session_with_null_fk() returns trigger
as $$
begin
@ -60,7 +60,7 @@ begin;
$$ language plpgsql;
-- Replaces view from 34/04_views.up.sql
-- Replaced in 58/06_add_session_private_key_column
-- Replaced in 56/06_add_session_private_key_column
drop view session_list;
create view session_list as
select

@ -24,7 +24,7 @@ create table worker_auth_server_led_activation_token(
comment on table worker_auth_server_led_activation_token is
'worker_auth_server_led_activation_token is a table where each row represents an activation token for a worker. Only one activation token is allowed per worker.';
-- this trigger is updated in 58/05_mutable_ciphertext_columns.up.sql
-- this trigger is updated in 56/05_mutable_ciphertext_columns.up.sql
create trigger immutable_columns before update on worker_auth_server_led_activation_token
for each row execute procedure immutable_columns('worker_id', 'token_id', 'creation_time_encrypted');

@ -6,7 +6,7 @@ begin;
drop view credential_vault_library_private;
drop view credential_vault_store_private;
-- Recreated in 58/02_add_data_key_foreign_key_references.up.sql
-- Recreated in 56/02_add_data_key_foreign_key_references.up.sql
create view credential_vault_token_renewal_revocation as
with
tokens as (
@ -78,7 +78,7 @@ begin;
'If the Vault token has expired this view will return an empty token_hmac and a token_status of ''expired'' '
'No encrypted data is returned. This view can be used to retrieve data which will be returned external to boundary.';
-- Recreated in 58/02_add_data_key_foreign_key_references.up.sql
-- Recreated in 56/02_add_data_key_foreign_key_references.up.sql
create view credential_vault_store_client as
select store.public_id as public_id,
store.project_id as project_id,
@ -107,7 +107,7 @@ begin;
'The view returns the current token for the store, if the Vault token has expired this view will return an empty token_hmac and a token_status of ''expired'' '
'Each row may contain encrypted data. This view should not be used to retrieve data which will be returned external to boundary.';
-- Recreated in 58/02_add_data_key_foreign_key_references.up.sql
-- Recreated in 56/02_add_data_key_foreign_key_references.up.sql
create view credential_vault_library_issue_credentials as
with
password_override (library_id, username_attribute, password_attribute) as (

@ -93,7 +93,7 @@ alter table worker_auth_authorized
;
drop trigger immutable_columns on worker_auth_authorized;
-- this trigger is updated in 58/05_mutable_ciphertext_columns.up.sql
-- this trigger is updated in 56/05_mutable_ciphertext_columns.up.sql
create trigger immutable_columns before update on worker_auth_authorized
for each row execute function immutable_columns('worker_key_identifier', 'worker_id', 'worker_signing_pub_key',
'worker_encryption_pub_key', 'controller_encryption_priv_key', 'key_id', 'nonce', 'create_time');

@ -85,7 +85,7 @@ select public_id,
'tcp' as type
from target_tcp;
-- Replaces view from 58/06_add_session_private_key_column.up.sql
-- Replaces view from 56/06_add_session_private_key_column.up.sql
drop view session_list;
create view session_list as
select
@ -134,4 +134,4 @@ create trigger immutable_columns before update on session
for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit',
'create_time', 'endpoint', 'worker_filter', 'egress_worker_filter', 'ingress_worker_filter');
commit;
commit;

@ -42,7 +42,7 @@ drop view oidc_auth_method_with_value_obj;
-- value is part of the primary key and unique. This view will make things like
-- recursive listing of oidc auth methods fairly straightforward to implement
-- for the oidc repo. The view also includes an is_primary_auth_method bool
-- Recreated in 58/02_add_data_key_foreign_key_references.up.sql
-- Recreated in 56/02_add_data_key_foreign_key_references.up.sql
create view oidc_auth_method_with_value_obj as
select
case when s.primary_auth_method_id is not null then

@ -1,7 +1,7 @@
begin;
-- Comments for the functions below were incorrectly overridden in
-- 12/01_timestamp_sub_funcs.up.sql but fixed in 57/01_fix_comments.up.sql.
-- 12/01_timestamp_sub_funcs.up.sql but fixed in 58/01_fix_comments.up.sql.
create function wt_add_seconds(sec integer, ts timestamp with time zone) returns timestamp with time zone
as $$

@ -2,26 +2,23 @@ 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/authtoken"
"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) {
func TestMigrations_NewForeignKeys(t *testing.T) {
const (
priorMigration = 55001
currentMigration = 56001
priorMigration = 56001
currentMigration = 56002
)
t.Parallel()
@ -65,182 +62,19 @@ func TestMigrations_DeleteOrphanedAccounts(t *testing.T) {
conn, err := db.Open(ctx, dbType, u)
require.NoError(t, err)
// Create project
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))
err = kmsCache.CreateKeys(ctx, scope.Global.String())
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
// Create a password account
pwam := password.TestAuthMethod(t, conn, "global")
password.TestAccount(t, conn, pwam.PublicId, "user", password.WithPassword("password"))
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)
// Create an auth token
tok := authtoken.TestAuthToken(t, conn, kmsCache, "global")
_ = tok
// now we're ready for the migration we want to test.
m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
@ -265,31 +99,5 @@ where
}
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)
// As long as there were no errors, the migration succeeded.
}

@ -0,0 +1,295 @@
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)
}

@ -1,103 +0,0 @@
package oss_test
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
"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/kms"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/testing/dbtest"
"github.com/stretchr/testify/require"
)
func TestMigrations_NewForeignKeys(t *testing.T) {
const (
priorMigration = 58001
currentMigration = 58002
)
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)
// Create project
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
err = kmsCache.CreateKeys(ctx, scope.Global.String())
require.NoError(t, err)
// Create a password account
pwam := password.TestAuthMethod(t, conn, "global")
password.TestAccount(t, conn, pwam.PublicId, "user", password.WithPassword("password"))
// Create an auth token
tok := authtoken.TestAuthToken(t, conn, kmsCache, "global")
_ = tok
// 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)
// As long as there were no errors, the migration succeeded.
}
Loading…
Cancel
Save