From c5535699e014e7c69b95096c07e1b2a9347dae79 Mon Sep 17 00:00:00 2001 From: April-May <18632637+AprilMay0@users.noreply.github.com> Date: Thu, 22 May 2025 19:10:06 +0100 Subject: [PATCH] feat(db): Add username_password_domain credential entities Co-Authored-By: Andrew Gaffney --- .../postgres/49/01_vault_credentials.up.sql | 1 + ...1_credential_vault_ssh_cert_library.up.sql | 1 + .../71/14_recording_static_credential.up.sql | 1 + ...d_certs_additional_valid_principals.up.sql | 1 + ...username_password_domain_credential.up.sql | 230 ++++++++++++++++++ .../02_username_password_domain_vault.up.sql | 216 ++++++++++++++++ .../db/sqltest/initdb.d/01_colors_persona.sql | 12 +- .../sqltest/initdb.d/03_widgets_persona.sql | 73 +++++- ...ential_vault_library_issue_credentials.sql | 6 +- ..._username_password_domain_mapping_ovrd.sql | 75 ++++++ .../tests/history/static_credentials.sql | 7 +- .../sqltest/tests/pagination/credential.sql | 3 +- .../recording_static_credentials.sql | 21 +- 13 files changed, 627 insertions(+), 20 deletions(-) create mode 100644 internal/db/schema/migrations/oss/postgres/99901/01_credential_static_username_password_domain_credential.up.sql create mode 100644 internal/db/schema/migrations/oss/postgres/99901/02_username_password_domain_vault.up.sql create mode 100644 internal/db/sqltest/tests/credential/vault/credential_vault_library_username_password_domain_mapping_ovrd.sql diff --git a/internal/db/schema/migrations/oss/postgres/49/01_vault_credentials.up.sql b/internal/db/schema/migrations/oss/postgres/49/01_vault_credentials.up.sql index f7ac54c48..a2ec8dd29 100644 --- a/internal/db/schema/migrations/oss/postgres/49/01_vault_credentials.up.sql +++ b/internal/db/schema/migrations/oss/postgres/49/01_vault_credentials.up.sql @@ -168,6 +168,7 @@ begin; 'This view should only be used when issuing credentials from a Vault credential library. Each row may contain encrypted data. ' 'This view should not be used to retrieve data which will be returned external to boundary.'; + -- Replaced in 99901/02_username_password_domain_vault.up.sql create view credential_vault_library_list_lookup as with password_override (library_id, username_attribute, password_attribute) as ( diff --git a/internal/db/schema/migrations/oss/postgres/63/01_credential_vault_ssh_cert_library.up.sql b/internal/db/schema/migrations/oss/postgres/63/01_credential_vault_ssh_cert_library.up.sql index d41f9a11f..b1dd23a0d 100644 --- a/internal/db/schema/migrations/oss/postgres/63/01_credential_vault_ssh_cert_library.up.sql +++ b/internal/db/schema/migrations/oss/postgres/63/01_credential_vault_ssh_cert_library.up.sql @@ -9,6 +9,7 @@ begin; -- Add new constraint that only allows known types -- This replaces the constraint defined in 39/01_static_ssh_private_key_creds_up + -- This constraint is replaced in 99901/01_credential_static_username_password_domain_credential.up.sql alter table credential_type_enm add constraint only_predefined_credential_types_allowed check ( diff --git a/internal/db/schema/migrations/oss/postgres/71/14_recording_static_credential.up.sql b/internal/db/schema/migrations/oss/postgres/71/14_recording_static_credential.up.sql index 50bcc0b03..a9dbcb82c 100644 --- a/internal/db/schema/migrations/oss/postgres/71/14_recording_static_credential.up.sql +++ b/internal/db/schema/migrations/oss/postgres/71/14_recording_static_credential.up.sql @@ -32,6 +32,7 @@ begin; 'along with the values of those entities at the time of the recording. ' 'These values are also stored in the BSR file.'; + -- This function is updated in 99901/01_credential_static_username_password_domain_credential.up.sql create function insert_recording_static_credentials() returns trigger as $$ begin diff --git a/internal/db/schema/migrations/oss/postgres/78/01_ssh_signed_certs_additional_valid_principals.up.sql b/internal/db/schema/migrations/oss/postgres/78/01_ssh_signed_certs_additional_valid_principals.up.sql index 12507b861..ae9fd9d80 100644 --- a/internal/db/schema/migrations/oss/postgres/78/01_ssh_signed_certs_additional_valid_principals.up.sql +++ b/internal/db/schema/migrations/oss/postgres/78/01_ssh_signed_certs_additional_valid_principals.up.sql @@ -6,6 +6,7 @@ begin; alter table credential_vault_ssh_cert_library add column additional_valid_principals text null; -- Replaces view from 63/02_add_ssh_cert_to_vault_cred_library_view.up.sql + -- This view is replaced in 99901/02_username_password_domain_vault.up.sql drop view credential_vault_library_issue_credentials; create view credential_vault_library_issue_credentials as with diff --git a/internal/db/schema/migrations/oss/postgres/99901/01_credential_static_username_password_domain_credential.up.sql b/internal/db/schema/migrations/oss/postgres/99901/01_credential_static_username_password_domain_credential.up.sql new file mode 100644 index 000000000..d22c1f8b7 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/99901/01_credential_static_username_password_domain_credential.up.sql @@ -0,0 +1,230 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: BUSL-1.1 + +begin; + + create table credential_static_username_password_domain_credential( + public_id wt_public_id primary key, + store_id wt_public_id not null + constraint credential_static_store_fkey + references credential_static_store (public_id) + on delete cascade + on update cascade, + project_id wt_public_id not null, + name wt_name, + description wt_description, + create_time wt_timestamp, + update_time wt_timestamp, + version wt_version, + username text not null + constraint username_must_not_be_empty + check(length(trim(username)) > 0), + domain text not null + constraint domain_must_not_be_empty + check (length(domain) > 0), + password_encrypted bytea not null + constraint password_encrypted_must_not_be_empty + check(length(password_encrypted) > 0), + password_hmac bytea not null + constraint password_hmac_must_not_be_empty + check(length(password_hmac) > 0), + key_id text not null + constraint kms_data_key_version_fkey + references kms_data_key_version (private_id) + on delete restrict + on update cascade, + constraint credential_static_fkey + foreign key (project_id, store_id,public_id) + references credential_static (project_id, store_id,public_id) + on delete cascade + on update cascade, + -- The constraint names below do not follow our naming conventions + -- because they would be too long. The max length for identifiers + -- in PostgreSQL is 63 characters. + -- https://www.postgresql.org/docs/current/limits.html + constraint credential_static_user_password_domain_cred_store_id_name_uq + unique(store_id, name), + constraint credential_static_user_password_domain_store_id_public_id_uq + unique(store_id, public_id) + ); + comment on table credential_static_username_password_domain_credential is + 'credential_static_username_password_domain_credential table where each row is a resource that represents a static username password domain credential. ' + 'It is a credential_static subtype and an aggregate root.'; + + create trigger update_version_column after update on credential_static_username_password_domain_credential + for each row execute procedure update_version_column(); + + create trigger update_time_column before update on credential_static_username_password_domain_credential + for each row execute procedure update_time_column(); + + create trigger update_credential_static_table_update_time before update on credential_static_username_password_domain_credential + for each row execute procedure update_credential_static_table_update_time(); + + create trigger default_create_time_column before insert on credential_static_username_password_domain_credential + for each row execute procedure default_create_time(); + + create trigger immutable_columns before update on credential_static_username_password_domain_credential + for each row execute procedure immutable_columns('public_id', 'store_id', 'create_time', 'project_id'); + + create trigger insert_credential_static_subtype before insert on credential_static_username_password_domain_credential + for each row execute procedure insert_credential_static_subtype(); + + create trigger delete_credential_static_subtype after delete on credential_static_username_password_domain_credential + for each row execute procedure delete_credential_static_subtype(); + + + create table credential_static_username_password_domain_credential_hst ( + public_id wt_public_id not null, + name wt_name, + description wt_description, + project_id wt_public_id not null, + store_id wt_public_id not null, + username text not null, + domain text not null + constraint domain_must_not_be_empty + check (length(domain) > 0), + password_hmac bytea not null, + history_id wt_url_safe_id default wt_url_safe_id() primary key + constraint credential_static_history_base_fkey + references credential_static_history_base (history_id) + on delete cascade + on update cascade, + valid_range tstzrange not null default tstzrange(current_timestamp, null), + constraint credential_static_user_pass_domain_cred_hst_valid_range_excl + exclude using gist (public_id with =, valid_range with &&) + -- The name of this constraint does not follow our naming conventions for + -- constraints because it would be to long. + ); + comment on table credential_static_username_password_domain_credential_hst is + 'credential_static_username_password_domain_credential_hst is a history table where each row contains the values from a row ' + 'in the credential_static_username_password_domain_credential table during the time range in the valid_range column.'; + + create trigger insert_credential_static_history_subtype before insert on credential_static_username_password_domain_credential_hst + for each row execute function insert_credential_static_history_subtype(); + + create trigger delete_credential_static_history_subtype after delete on credential_static_username_password_domain_credential_hst + for each row execute function delete_credential_static_history_subtype(); + + create trigger hst_on_insert after insert on credential_static_username_password_domain_credential + for each row execute function hst_on_insert(); + + create trigger hst_on_update after update on credential_static_username_password_domain_credential + for each row execute function hst_on_update(); + + create trigger hst_on_delete after delete on credential_static_username_password_domain_credential + for each row execute function hst_on_delete(); + + + create table credential_static_username_password_domain_credential_deleted ( + public_id wt_public_id not null + constraint credential_static_user_pass_domain_cred_deleted_pkey primary key, -- named to avoid exceeding 63 characters + delete_time wt_timestamp not null + ); + comment on table credential_static_username_password_domain_credential_deleted is + 'credential_static_username_password_domain_credential_deleted holds the ID and delete_time ' + 'of every deleted static username password domain credential. ' + 'It is automatically trimmed of records older than 30 days by a job.'; + + create trigger insert_deleted_id after delete on credential_static_username_password_domain_credential + for each row execute function insert_deleted_id('credential_static_username_password_domain_credential_deleted'); + + create index credential_static_username_password_domain_delete_time_idx on credential_static_username_password_domain_credential_deleted (delete_time); + + + create view credential_static_username_password_domain_credential_hst_agg as + select + rsc.recording_id, + supdc.public_id, + supdc.name, + supdc.description, + supdc.username, + supdc.domain, + supdc.password_hmac, + css.public_id as store_public_id, + css.project_id as store_project_id, + css.name as store_name, + css.description as store_description, + string_agg(distinct rsc.credential_purpose, '|') as purposes + from + credential_static_username_password_domain_credential_hst as supdc + left join recording_static_credential as rsc on supdc.history_id = rsc.credential_static_hst_id + join credential_static_store_hst as css on rsc.credential_static_store_hst_id = css.history_id + group by supdc.history_id, rsc.recording_id, css.history_id; + comment on view credential_static_username_password_domain_credential_hst_agg is + 'credential_static_username_password_domain_credential_hst_aggregate contains the username password credential history data along with its store and purpose data.'; + + + -- This constraint replaces the previous constraint created in 63/01_credential_vault_ssh_cert_library.up.sql + alter table credential_type_enm + drop constraint only_predefined_credential_types_allowed; + + alter table credential_type_enm + add constraint only_predefined_credential_types_allowed + check ( + name in ( + 'unspecified', + 'username_password', + 'ssh_private_key', + 'ssh_certificate', + 'username_password_domain' + ) + ); + + insert into credential_type_enm (name) + values ('username_password_domain'); + + +-- This function replaces the previous function created in 71/14_recording_static_credential.up.sql +create or replace function insert_recording_static_credentials() returns trigger + as $$ + begin + with + session_recording(session_id, recording_id) as ( + select session_id, public_id + from recording_session + where session_id = new.session_id + ), + session_static_creds(cred_id, purpose, recording_id) as ( + select credential_static_id, credential_purpose, recording_id + from session_credential_static + join session_recording using (session_id) + ), + static_cred_history(public_id, store_id, cred_hst_id, valid_range) as ( + select public_id, store_id, history_id, valid_range + from credential_static_json_credential_hst + union + select public_id, store_id, history_id, valid_range + from credential_static_ssh_private_key_credential_hst + union + select public_id, store_id, history_id, valid_range + from credential_static_username_password_credential_hst + union + select public_id, store_id, history_id, valid_range + from credential_static_username_password_domain_credential_hst + ), + final(recording_id, cred_id, store_id, cred_hst_id, store_hst_id, cred_purpose) as ( + select ssc.recording_id, sc.public_id, sc.store_id, sc.cred_hst_id, store_hst.history_id, ssc.purpose + from static_cred_history as sc + join credential_static_store_hst as store_hst on sc.store_id = store_hst.public_id + and store_hst.valid_range @> current_timestamp + join session_static_creds as ssc on sc.public_id = ssc.cred_id + where sc.public_id in (select cred_id from session_static_creds) + and sc.valid_range @> current_timestamp + ) + insert into recording_static_credential + (recording_id, credential_static_store_hst_id, credential_static_hst_id, credential_purpose) + select recording_id, store_hst_id, cred_hst_id, cred_purpose + from final; + + return new; + end; + $$ language plpgsql; + comment on function insert_recording_static_credentials is + 'insert_recording_static_credentials is an after insert trigger for the recording_session table.'; + + + insert into oplog_ticket (name, version) + values ('credential_static_username_password_domain_credential', 1); + + +commit; diff --git a/internal/db/schema/migrations/oss/postgres/99901/02_username_password_domain_vault.up.sql b/internal/db/schema/migrations/oss/postgres/99901/02_username_password_domain_vault.up.sql new file mode 100644 index 000000000..91720c6d2 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/99901/02_username_password_domain_vault.up.sql @@ -0,0 +1,216 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: BUSL-1.1 + +begin; + + create table credential_vault_library_username_password_domain_mapping_ovrd ( + library_id wt_public_id primary key + constraint credential_vault_library_fkey + references credential_vault_library (public_id) + on delete cascade + on update cascade + constraint credential_vault_library_mapping_override_fkey + references credential_vault_library_mapping_override (library_id) + on delete cascade + on update cascade, + username_attribute wt_sentinel + default wt_to_sentinel('no override') + not null, + password_attribute wt_sentinel + default wt_to_sentinel('no override') + not null, + domain_attribute wt_sentinel + default wt_to_sentinel('no override') + not null + + ); + comment on table credential_vault_library_username_password_domain_mapping_ovrd is + 'credential_vault_library_username_password_domain_mapping_ovrd is a table ' + 'where each row represents a mapping that overrides the default mapping ' + 'from a generic vault secret to a user password domain credential type ' + 'for a vault credential library.'; + + create trigger insert_credential_vault_library_mapping_override_subtype before insert on credential_vault_library_username_password_domain_mapping_ovrd + for each row execute procedure insert_credential_vault_library_mapping_override_subtype(); + + create trigger delete_credential_vault_library_mapping_override_subtype after delete on credential_vault_library_username_password_domain_mapping_ovrd + for each row execute procedure delete_credential_vault_library_mapping_override_subtype(); + + +-- Replaces view from 78/01_ssh_signed_certs_additional_valid_principals.up.sql + drop view credential_vault_library_issue_credentials; + create view credential_vault_library_issue_credentials as + with + password_override (library_id, username_attribute, password_attribute) as ( + select library_id, + nullif(username_attribute, wt_to_sentinel('no override')), + nullif(password_attribute, wt_to_sentinel('no override')) + from credential_vault_library_username_password_mapping_override + ), + ssh_private_key_override (library_id, username_attribute, private_key_attribute, private_key_passphrase_attribute) as ( + select library_id, + nullif(username_attribute, wt_to_sentinel('no override')), + nullif(private_key_attribute, wt_to_sentinel('no override')), + nullif(private_key_passphrase_attribute, wt_to_sentinel('no override')) + from credential_vault_library_ssh_private_key_mapping_override + ), + password_domain_override (library_id, username_attribute, password_attribute, domain_attribute) as ( + select library_id, + nullif(username_attribute, wt_to_sentinel('no override')), + nullif(password_attribute, wt_to_sentinel('no override')), + nullif(domain_attribute, wt_to_sentinel('no override')) + from credential_vault_library_username_password_domain_mapping_ovrd + ) + select library.public_id as public_id, + library.store_id as store_id, + library.name as name, + library.description as description, + library.create_time as create_time, + library.update_time as update_time, + library.version as version, + library.vault_path as vault_path, + library.http_method as http_method, + library.http_request_body as http_request_body, + library.credential_type as credential_type, + null as key_type, + null as key_bits, + null as username, + null as ttl, + null as key_id, + null as critical_options, + null as extensions, + store.project_id as project_id, + store.vault_address as vault_address, + store.namespace as namespace, + store.ca_cert as ca_cert, + store.tls_server_name as tls_server_name, + store.tls_skip_verify as tls_skip_verify, + store.worker_filter as worker_filter, + store.ct_token as ct_token, -- encrypted + store.token_hmac as token_hmac, + store.token_status as token_status, + store.token_key_id as token_key_id, + store.client_cert as client_cert, + store.ct_client_key as ct_client_key, -- encrypted + store.client_key_id as client_key_id, + coalesce(upasso.username_attribute, sshpk.username_attribute, pd.username_attribute) + as username_attribute, + coalesce(upasso.password_attribute, pd.password_attribute) + as password_attribute, + pd.domain_attribute as domain_attribute, + sshpk.private_key_attribute as private_key_attribute, + sshpk.private_key_passphrase_attribute as private_key_passphrase_attribute, + 'generic' as cred_lib_type, -- used to switch on + null as additional_valid_principals + from credential_vault_library library + join credential_vault_store_client store + on library.store_id = store.public_id + left join password_override upasso + on library.public_id = upasso.library_id + left join ssh_private_key_override sshpk + on library.public_id = sshpk.library_id + left join password_domain_override pd + on library.public_id = pd.library_id + union + select library.public_id as public_id, + library.store_id as store_id, + library.name as name, + library.description as description, + library.create_time as create_time, + library.update_time as update_time, + library.version as version, + library.vault_path as vault_path, + null as http_method, + null as http_request_body, + library.credential_type as credential_type, + library.key_type as key_type, + library.key_bits as key_bits, + library.username as username, + library.ttl as ttl, + library.key_id as key_id, + library.critical_options as critical_options, + library.extensions as extensions, + store.project_id as project_id, + store.vault_address as vault_address, + store.namespace as namespace, + store.ca_cert as ca_cert, + store.tls_server_name as tls_server_name, + store.tls_skip_verify as tls_skip_verify, + store.worker_filter as worker_filter, + store.ct_token as ct_token, -- encrypted + store.token_hmac as token_hmac, + store.token_status as token_status, + store.token_key_id as token_key_id, + store.client_cert as client_cert, + store.ct_client_key as ct_client_key, -- encrypted + store.client_key_id as client_key_id, + null as username_attribute, + null as password_attribute, + null as domain_attribute, + null as private_key_attribute, + null as private_key_passphrase_attribute, + 'ssh-signed-cert' as cred_lib_type, -- used to switch on + additional_valid_principals as additional_valid_principals + from credential_vault_ssh_cert_library library + join credential_vault_store_client store + on library.store_id = store.public_id; + comment on view credential_vault_library_issue_credentials is + 'credential_vault_library_issue_credentials is a view where each row contains a credential library and the credential library''s data needed to connect to Vault. ' + 'This view should only be used when issuing credentials from a Vault credential library. Each row may contain encrypted data. ' + 'This view should not be used to retrieve data which will be returned external to boundary.'; + + +-- Replaces view created in 49/01_vault_credentials.up.sql + drop view credential_vault_library_list_lookup; + create view credential_vault_library_list_lookup as + with + password_override (library_id, username_attribute, password_attribute) as ( + select library_id, + nullif(username_attribute, wt_to_sentinel('no override')), + nullif(password_attribute, wt_to_sentinel('no override')) + from credential_vault_library_username_password_mapping_override + ), + ssh_private_key_override (library_id, username_attribute, private_key_attribute, private_key_passphrase_attribute) as ( + select library_id, + nullif(username_attribute, wt_to_sentinel('no override')), + nullif(private_key_attribute, wt_to_sentinel('no override')), + nullif(private_key_passphrase_attribute, wt_to_sentinel('no override')) + from credential_vault_library_ssh_private_key_mapping_override + ), + password_domain_override (library_id, username_attribute, password_attribute, domain_attribute) as ( + select library_id, + nullif(username_attribute, wt_to_sentinel('no override')), + nullif(password_attribute, wt_to_sentinel('no override')), + nullif(domain_attribute, wt_to_sentinel('no override')) + from credential_vault_library_username_password_domain_mapping_ovrd + ) + select library.public_id as public_id, + library.store_id as store_id, + library.name as name, + library.description as description, + library.create_time as create_time, + library.update_time as update_time, + library.version as version, + library.vault_path as vault_path, + library.http_method as http_method, + library.http_request_body as http_request_body, + library.credential_type as credential_type, + coalesce(upasso.username_attribute, sshpk.username_attribute, pd.username_attribute) + as username_attribute, + coalesce(upasso.password_attribute, pd.password_attribute) + as password_attribute, + sshpk.private_key_attribute as private_key_attribute, + sshpk.private_key_passphrase_attribute as private_key_passphrase_attribute, + pd.domain_attribute as domain_attribute + from credential_vault_library library + left join password_override upasso + on library.public_id = upasso.library_id + left join ssh_private_key_override sshpk + on library.public_id = sshpk.library_id + left join password_domain_override pd + on library.public_id = pd.library_id; + comment on view credential_vault_library_list_lookup is + 'credential_vault_library_list_lookup is a view where each row contains a credential library and any of library''s credential mapping overrides. ' + 'No encrypted data is returned. This view can be used to retrieve data which will be returned external to boundary.'; + +commit; \ No newline at end of file diff --git a/internal/db/sqltest/initdb.d/01_colors_persona.sql b/internal/db/sqltest/initdb.d/01_colors_persona.sql index ad99bfad2..ce6a8040a 100644 --- a/internal/db/sqltest/initdb.d/01_colors_persona.sql +++ b/internal/db/sqltest/initdb.d/01_colors_persona.sql @@ -501,6 +501,13 @@ begin; ('kdkv__colors', 'p____rcolors', 'css__rcolors', 'csu__rcolors', 'Red username password cred', 'ruser', 'rpasswd-enc'::bytea, 'rpasswd-hmac'::bytea), ('kdkv__colors', 'p____gcolors', 'css__gcolors', 'csu__gcolors', 'Green username password cred', 'guser', 'gpasswd-enc'::bytea, 'gpasswd-hmac'::bytea); + insert into credential_static_username_password_domain_credential + (key_id, project_id, store_id, public_id, name, username, password_encrypted, password_hmac, domain) + values + ('kdkv__colors', 'p____bcolors', 'css__bcolors', 'csud_bcolors', 'Blue username password cred', 'buser', 'bpasswd-enc'::bytea, 'bpasswd-hmac'::bytea, 'blue.domain'), + ('kdkv__colors', 'p____rcolors', 'css__rcolors', 'csud_rcolors', 'Red username password cred', 'ruser', 'rpasswd-enc'::bytea, 'rpasswd-hmac'::bytea, 'red.domain'), + ('kdkv__colors', 'p____gcolors', 'css__gcolors', 'csud_gcolors', 'Green username password cred', 'guser', 'gpasswd-enc'::bytea, 'gpasswd-hmac'::bytea, 'green.domain'); + insert into credential_static_ssh_private_key_credential (key_id, project_id, store_id, public_id, name, username, private_key_encrypted, private_key_hmac) values @@ -515,7 +522,9 @@ begin; ('p____bcolors', 'tssh______cb', 'csj__bcolors', 'injected_application'), ('p____gcolors', 'tssh______cg', 'csj__gcolors', 'brokered'), ('p____gcolors', 'tssh______cg', 'csu__gcolors', 'brokered'), - ('p____gcolors', 'tssh______cg', 'cspk_gcolors', 'injected_application'); + ('p____gcolors', 'tssh______cg', 'cspk_gcolors', 'injected_application'), + ('p____gcolors', 'tssh______cg', 'csud_gcolors', 'brokered'); + ; insert into target_credential_library (project_id, target_id, credential_library_id, credential_purpose) @@ -560,6 +569,7 @@ begin; ('s1______cora', 'csj__gcolors', 'brokered'), -- tssh______cg ('s1______cora', 'csu__gcolors', 'brokered'), -- tssh______cg ('s1______cora', 'cspk_gcolors', 'injected_application'), -- tssh______cg + ('s1______cora', 'csud_gcolors', 'brokered'), -- tssh______cg ('s2______cora', 'csj__gcolors', 'brokered'), -- tssh______cg ('s2______cora', 'cspk_gcolors', 'injected_application'); -- tssh______cg diff --git a/internal/db/sqltest/initdb.d/03_widgets_persona.sql b/internal/db/sqltest/initdb.d/03_widgets_persona.sql index c7e63dc59..01b63839d 100644 --- a/internal/db/sqltest/initdb.d/03_widgets_persona.sql +++ b/internal/db/sqltest/initdb.d/03_widgets_persona.sql @@ -391,18 +391,27 @@ begin; insert into credential_vault_library (store_id, public_id, name, description, vault_path, http_method, credential_type) values - ('vs_______wvs', 'vl______wvl1', 'widget vault library', 'None', '/secrets', 'GET', 'unspecified'), - ('vs_______wvs', 'vl______wvl2', 'widget vault ssh', 'None', '/secrets/ssh/admin', 'GET', 'unspecified'), - ('vs_______wvs', 'vl______wvl3', 'widget vault kv one', 'None', '/secrets/kv/one', 'GET', 'username_password'), - ('vs_______wvs', 'vl______wvl4', 'widget vault kv two', 'None', '/secrets/kv/two', 'GET', 'username_password'), - ('vs_______wvs', 'vl______wvl5', 'widget vault kv three', 'None', '/secrets/kv/three', 'GET', 'username_password'), - ('vs_______wvs', 'vl______wvl6', 'widget vault kv four', 'None', '/secrets/kv/four', 'GET', 'username_password'), - ('vs_______wvs', 'vl______wvl7', 'widget vault kv five', 'None', '/secrets/kv/five', 'GET', 'username_password'), - ('vs_______wvs', 'vl______wvl8', 'widget vault kv six', 'None', '/secrets/kv/six', 'GET', 'ssh_private_key'), - ('vs_______wvs', 'vl______wvl9', 'widget vault kv seven', 'None', '/secrets/kv/seven', 'GET', 'ssh_private_key'), - ('vs_______wvs', 'vl______wvl10', 'widget vault kv eight', 'None', '/secrets/kv/eight', 'GET', 'ssh_private_key'), - ('vs_______wvs', 'vl______wvl11', 'widget vault kv nine', 'None', '/secrets/kv/nine', 'GET', 'ssh_private_key'), - ('vs_______wvs', 'vl______wvl12', 'widget vault kv ten', 'None', '/secrets/kv/n', 'GET', 'ssh_private_key'); + ('vs_______wvs', 'vl______wvl1', 'widget vault library', 'None', '/secrets', 'GET', 'unspecified'), + ('vs_______wvs', 'vl______wvl2', 'widget vault ssh', 'None', '/secrets/ssh/admin', 'GET', 'unspecified'), + ('vs_______wvs', 'vl______wvl3', 'widget vault kv one', 'None', '/secrets/kv/one', 'GET', 'username_password'), + ('vs_______wvs', 'vl______wvl4', 'widget vault kv two', 'None', '/secrets/kv/two', 'GET', 'username_password'), + ('vs_______wvs', 'vl______wvl5', 'widget vault kv three', 'None', '/secrets/kv/three', 'GET', 'username_password'), + ('vs_______wvs', 'vl______wvl6', 'widget vault kv four', 'None', '/secrets/kv/four', 'GET', 'username_password'), + ('vs_______wvs', 'vl______wvl7', 'widget vault kv five', 'None', '/secrets/kv/five', 'GET', 'username_password'), + ('vs_______wvs', 'vl______wvl8', 'widget vault kv six', 'None', '/secrets/kv/six', 'GET', 'ssh_private_key'), + ('vs_______wvs', 'vl______wvl9', 'widget vault kv seven', 'None', '/secrets/kv/seven', 'GET', 'ssh_private_key'), + ('vs_______wvs', 'vl______wvl10', 'widget vault kv eight', 'None', '/secrets/kv/eight', 'GET', 'ssh_private_key'), + ('vs_______wvs', 'vl______wvl11', 'widget vault kv nine', 'None', '/secrets/kv/nine', 'GET', 'ssh_private_key'), + ('vs_______wvs', 'vl______wvl12', 'widget vault kv ten', 'None', '/secrets/kv/n', 'GET', 'ssh_private_key'), + ('vs_______wvs', 'vl______wvl13', 'widget vault kv eleven', 'None', '/secrets/kv/eleven', 'GET', 'username_password_domain'), + ('vs_______wvs', 'vl______wvl14', 'widget vault kv twelve', 'None', '/secrets/kv/twelve', 'GET', 'username_password_domain'), + ('vs_______wvs', 'vl______wvl15', 'widget vault kv thirteen', 'None', '/secrets/kv/thirteen', 'GET', 'username_password_domain'), + ('vs_______wvs', 'vl______wvl16', 'widget vault kv fourteen', 'None', '/secrets/kv/fourteen', 'GET', 'username_password_domain'), + ('vs_______wvs', 'vl______wvl17', 'widget vault kv fifteen', 'None', '/secrets/kv/fifteen', 'GET', 'username_password_domain'), + ('vs_______wvs', 'vl______wvl18', 'widget vault kv sixteen', 'None', '/secrets/kv/sixteen', 'GET', 'username_password_domain'), + ('vs_______wvs', 'vl______wvl19', 'widget vault kv seventeen', 'None', '/secrets/kv/seventeen', 'GET', 'username_password_domain'), + ('vs_______wvs', 'vl______wvl20', 'widget vault kv eighteen', 'None', '/secrets/kv/eighteen', 'GET', 'username_password_domain'), + ('vs_______wvs', 'vl______wvl21', 'widget vault kv nineteen', 'None', '/secrets/kv/nineteen', 'GET', 'username_password_domain'); insert into credential_vault_library_username_password_mapping_override (library_id) @@ -444,6 +453,46 @@ begin; values ('vl______wvl12', 'my_username', 'my_private_key', 'my_passphrase'); + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id) + values + ('vl______wvl13'); + + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id, username_attribute, password_attribute, domain_attribute) + values + ('vl______wvl14', 'my_username', 'my_password', 'my_domain'); + + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id, username_attribute, domain_attribute) + values + ('vl______wvl15', 'my_username', 'my_domain'); + + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id, password_attribute, domain_attribute) + values + ('vl______wvl16', 'my_password', 'my_domain'); + + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id, username_attribute, password_attribute) + values + ('vl______wvl17', 'my_username', 'my_password'); + + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id, username_attribute) + values + ('vl______wvl18', 'my_username'); + + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id, password_attribute) + values + ('vl______wvl19', 'my_password'); + + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id, domain_attribute) + values + ('vl______wvl20', 'my_domain'); + insert into credential_vault_ssh_cert_library (store_id, public_id, name, description, vault_path, username, key_type, key_bits) values diff --git a/internal/db/sqltest/tests/credential/vault/credential_vault_library_issue_credentials.sql b/internal/db/sqltest/tests/credential/vault/credential_vault_library_issue_credentials.sql index f914f1772..5248a335c 100644 --- a/internal/db/sqltest/tests/credential/vault/credential_vault_library_issue_credentials.sql +++ b/internal/db/sqltest/tests/credential/vault/credential_vault_library_issue_credentials.sql @@ -5,7 +5,7 @@ begin; - select plan(8); + select plan(9); select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets', 'credentials'); -- validate the setup data @@ -20,6 +20,10 @@ begin; from credential_vault_library_username_password_mapping_override where library_id in ('vl______wvl4', 'vl______wvl5', 'vl______wvl6', 'vl______wvl7'); + select is(count(*), 8::bigint) + from credential_vault_library_username_password_domain_mapping_ovrd + where library_id in ('vl______wvl13', 'vl______wvl14', 'vl______wvl15', 'vl______wvl16', 'vl______wvl17', 'vl______wvl18', 'vl______wvl19', 'vl______wvl20'); + select is(count(*), 8::bigint) from credential_vault_library_mapping_override where library_id in ('vl______wvl4', 'vl______wvl5', 'vl______wvl6', 'vl______wvl7', 'vl______wvl9', 'vl______wvl10', 'vl______wvl11', 'vl______wvl12'); diff --git a/internal/db/sqltest/tests/credential/vault/credential_vault_library_username_password_domain_mapping_ovrd.sql b/internal/db/sqltest/tests/credential/vault/credential_vault_library_username_password_domain_mapping_ovrd.sql new file mode 100644 index 000000000..343adf0bc --- /dev/null +++ b/internal/db/sqltest/tests/credential/vault/credential_vault_library_username_password_domain_mapping_ovrd.sql @@ -0,0 +1,75 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: BUSL-1.1 + +-- credential_vault_library_username_password_domain_mapping_ovrd tests: +-- the following triggers +-- insert_credential_vault_library_mapping_override_subtype +-- delete_credential_vault_library_mapping_override_subtype +-- and the following view +-- credential_vault_library_list_lookup + +begin; + + select plan(11); + select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets', 'credentials'); + + + select is(count(*), 8::bigint) + from credential_vault_library_username_password_domain_mapping_ovrd + where library_id in ('vl______wvl13', 'vl______wvl14', 'vl______wvl15', 'vl______wvl16', 'vl______wvl17', 'vl______wvl18', 'vl______wvl19', 'vl______wvl20'); + + select is(count(*), 8::bigint) + from credential_vault_library_mapping_override + where library_id in ('vl______wvl13', 'vl______wvl14', 'vl______wvl15', 'vl______wvl16', 'vl______wvl17', 'vl______wvl18', 'vl______wvl19', 'vl______wvl20'); + + prepare select_libraries as + select public_id::text, credential_type::text, username_attribute::text, password_attribute::text, domain_attribute::text + from credential_vault_library_list_lookup + where public_id in ('vl______wvl2', 'vl______wvl21', 'vl______wvl13', 'vl______wvl14', 'vl______wvl15', 'vl______wvl16', 'vl______wvl17', 'vl______wvl18', 'vl______wvl19', 'vl______wvl20') + order by public_id; + + select results_eq( + 'select_libraries', + $$VALUES + ('vl______wvl13', 'username_password_domain', null, null, null), + ('vl______wvl14', 'username_password_domain', 'my_username','my_password', 'my_domain'), + ('vl______wvl15', 'username_password_domain', 'my_username', null, 'my_domain'), + ('vl______wvl16', 'username_password_domain', null, 'my_password', 'my_domain'), + ('vl______wvl17', 'username_password_domain', 'my_username','my_password', null), + ('vl______wvl18', 'username_password_domain', 'my_username', null, null), + ('vl______wvl19', 'username_password_domain', null, 'my_password', null), + ('vl______wvl2', 'unspecified', null, null, null), + ('vl______wvl20', 'username_password_domain', null, null, 'my_domain'), + ('vl______wvl21', 'username_password_domain', null, null, null)$$ + ); + + + -- validate insert triggers + select is(count(*), 0::bigint) from credential_vault_library_username_password_domain_mapping_ovrd where library_id = 'vl______wvl21'; + select is(count(*), 0::bigint) from credential_vault_library_mapping_override where library_id = 'vl______wvl21'; + + prepare insert_cvl_username_password_mapping_override as + insert into credential_vault_library_username_password_domain_mapping_ovrd + (library_id,username_attribute, password_attribute, domain_attribute) + values + ('vl______wvl21', 'my_username', 'my_password', 'my_domain'); + select lives_ok('insert_cvl_username_password_mapping_override'); + + + select is(count(*), 1::bigint) from credential_vault_library_username_password_domain_mapping_ovrd where library_id = 'vl______wvl21'; + select is(count(*), 1::bigint) from credential_vault_library_mapping_override where library_id = 'vl______wvl21'; + + -- validate delete triggers + prepare delete_cvl_username_password_domain_mapping_ovrd as + delete + from credential_vault_library_username_password_domain_mapping_ovrd + where library_id = 'vl______wvl21'; + select lives_ok('delete_cvl_username_password_domain_mapping_ovrd'); + + + select is(count(*), 0::bigint) from credential_vault_library_username_password_domain_mapping_ovrd where library_id = 'vl______wvl21'; + select is(count(*), 0::bigint) from credential_vault_library_mapping_override where library_id = 'vl______wvl21'; + + select * from finish(); + +rollback; \ No newline at end of file diff --git a/internal/db/sqltest/tests/history/static_credentials.sql b/internal/db/sqltest/tests/history/static_credentials.sql index 8d1f27a6a..2e7ae0104 100644 --- a/internal/db/sqltest/tests/history/static_credentials.sql +++ b/internal/db/sqltest/tests/history/static_credentials.sql @@ -2,7 +2,7 @@ -- SPDX-License-Identifier: BUSL-1.1 begin; - select plan(16); + select plan(19); -- Verify the trigger functions exist and are declared properly select has_function('insert_credential_static_history_subtype'); @@ -21,6 +21,10 @@ begin; select has_trigger('credential_static_username_password_credential_hst', 'delete_credential_static_history_subtype'); select fk_ok('credential_static_username_password_credential_hst', 'history_id', 'credential_static_history_base' , 'history_id'); + select has_trigger('credential_static_username_password_domain_credential_hst', 'insert_credential_static_history_subtype'); + select has_trigger('credential_static_username_password_domain_credential_hst', 'delete_credential_static_history_subtype'); + select fk_ok('credential_static_username_password_domain_credential_hst', 'history_id', 'credential_static_history_base' , 'history_id'); + select has_trigger('credential_static_ssh_private_key_credential_hst', 'insert_credential_static_history_subtype'); select has_trigger('credential_static_ssh_private_key_credential_hst', 'delete_credential_static_history_subtype'); select fk_ok('credential_static_ssh_private_key_credential_hst', 'history_id', 'credential_static_history_base' , 'history_id'); @@ -29,6 +33,7 @@ begin; 'select ' '(select count(*) from credential_static_json_credential_hst) + ' '(select count(*) from credential_static_username_password_credential_hst) + ' + '(select count(*) from credential_static_username_password_domain_credential_hst) + ' '(select count(*) from credential_static_ssh_private_key_credential_hst)', 'select count(*) from credential_static_history_base' ); diff --git a/internal/db/sqltest/tests/pagination/credential.sql b/internal/db/sqltest/tests/pagination/credential.sql index d6728c2d8..ec2b007e4 100644 --- a/internal/db/sqltest/tests/pagination/credential.sql +++ b/internal/db/sqltest/tests/pagination/credential.sql @@ -2,7 +2,7 @@ -- SPDX-License-Identifier: BUSL-1.1 begin; - select plan(10); + select plan(11); -- Verify the trigger functions exist and are declared properly select has_function('update_credential_static_table_update_time'); @@ -11,6 +11,7 @@ begin; select has_trigger('credential_static_json_credential', 'update_credential_static_table_update_time'); select has_trigger('credential_static_ssh_private_key_credential', 'update_credential_static_table_update_time'); select has_trigger('credential_static_username_password_credential', 'update_credential_static_table_update_time'); + select has_trigger('credential_static_username_password_domain_credential', 'update_credential_static_table_update_time'); select has_index('credential_static', 'credential_static_create_time_public_id_idx', array['create_time', 'public_id']); select has_index('credential_static', 'credential_static_update_time_public_id_idx', array['update_time', 'public_id']); diff --git a/internal/db/sqltest/tests/recording/recording_static_credentials.sql b/internal/db/sqltest/tests/recording/recording_static_credentials.sql index 12a6689a2..5d58d446e 100644 --- a/internal/db/sqltest/tests/recording/recording_static_credentials.sql +++ b/internal/db/sqltest/tests/recording/recording_static_credentials.sql @@ -2,11 +2,12 @@ -- SPDX-License-Identifier: BUSL-1.1 begin; - select plan(33); + select plan(35); select has_table('recording_static_credential'); select has_view('credential_static_json_credential_hst_aggregate', 'view for aggregate static json credential history info does not exist'); select has_view('credential_static_username_password_credential_hst_aggregate', 'view for aggregate static username password credential history info does not exist'); +select has_view('credential_static_username_password_domain_credential_hst_agg', 'view for aggregate static username password domain credential history info does not exist'); select has_view('credential_static_ssh_private_key_credential_hst_aggregate', 'view for aggregate static ssh private key credential history info does not exist'); -- tests a fk column referencing a history table @@ -79,6 +80,18 @@ select has_view('credential_static_ssh_private_key_credential_hst_aggregate', 'v ('sr1_____cora', 'csu__gcolors', 'css__gcolors', 'brokered')$$ ); + prepare select_recording_static_username_password_domain_credentials as + select recording_id::text, public_id::text, store_public_id::text, purposes::text + from credential_static_username_password_domain_credential_hst_agg + where recording_id = 'sr1_____cora' + order by public_id; + + select results_eq( + 'select_recording_static_username_password_domain_credentials', + $$VALUES + ('sr1_____cora', 'csud_gcolors', 'css__gcolors', 'brokered')$$ + ); + prepare select_recording_static_ssh_private_key_credentials as select recording_id::text, public_id::text, store_public_id::text, purposes::text from credential_static_ssh_private_key_credential_hst_aggregate @@ -91,11 +104,11 @@ select has_view('credential_static_ssh_private_key_credential_hst_aggregate', 'v ('sr1_____cora', 'cspk_gcolors', 'css__gcolors', 'injected_application')$$ ); - select is(count(*), 3::bigint) + select is(count(*), 4::bigint) from target_static_credential where target_id = 'tssh______cg'; - select is(count(*), 3::bigint) + select is(count(*), 4::bigint) from session_credential_static where session_id = 's1______cora'; @@ -104,7 +117,7 @@ select has_view('credential_static_ssh_private_key_credential_hst_aggregate', 'v where session_id = 's1______cora' and public_id = 'sr1_____cora'; - select is(count(*), 3::bigint) + select is(count(*), 4::bigint) from recording_static_credential where recording_id = 'sr1_____cora';