From e339762f9be24ee071116040b22cd44d302e442f Mon Sep 17 00:00:00 2001 From: Adam Grare Date: Thu, 3 Aug 2023 13:19:57 -0400 Subject: [PATCH] Add auths to script payload join table Automatically add authentications referenced in the credentials payload to the authentications_configuration_script_payload join table --- ...onfiguration_script_payloads_controller.rb | 21 ++++++++++ .../configuration_script_payloads_spec.rb | 39 ++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/configuration_script_payloads_controller.rb b/app/controllers/api/configuration_script_payloads_controller.rb index 52eb4d8871..a825a46209 100644 --- a/app/controllers/api/configuration_script_payloads_controller.rb +++ b/app/controllers/api/configuration_script_payloads_controller.rb @@ -11,6 +11,27 @@ def edit_resource(type, id, data) unpermitted_params = data.keys.map(&:to_s) - allowed_params raise BadRequestError, _("Invalid parameters: %{params}" % {:params => unpermitted_params.join(", ")}) if unpermitted_params.any? + # If a credentials payload is provided, map any requested authentication + # records to the configuration_script_payload via the + # authentications_configuration_script_payloads join table. + unless data["credentials"].nil? + # Credentials can be a static string or a payload with an external + # Authentication record referenced by credential_ref and credential_field. + credential_refs = data["credentials"].values.select { |val| val.kind_of?(Hash) }.map { |val| val["credential_ref"] } + # Lookup the Authentication record by ems_ref in the parent manager's + # list of authentications. + credentials = resource.manager&.authentications&.where(:ems_ref => credential_refs) || [] + # Filter the collection based on the current user's RBAC roles. + credentials, _ = collection_filterer(credentials, "authentications", ::Authentication) + # If any requested authentications were unable to be found, either due + # to a bad credential_ref or due to RBAC then raise a 400 BadRequestError. + missing_credential_refs = credential_refs - credentials.pluck(:ems_ref) + raise BadRequestError, _("Could not find credentials %{missing_credential_refs}") % {:missing_credential_refs => missing_credential_refs} if missing_credential_refs.any? + # Reset the authentications collection with the current set of credentials. + # This will also remove any credential references not in the new payload. + resource.authentications = credentials + end + resource.update!(data.except(*ID_ATTRS)) resource end diff --git a/spec/requests/configuration_script_payloads_spec.rb b/spec/requests/configuration_script_payloads_spec.rb index 93a836bed7..747377cb58 100644 --- a/spec/requests/configuration_script_payloads_spec.rb +++ b/spec/requests/configuration_script_payloads_spec.rb @@ -50,7 +50,8 @@ end describe 'POST /api/configuration_script_payloads' do - let(:script_payload) { FactoryBot.create(:configuration_script_payload) } + let(:manager) { FactoryBot.create(:ext_management_system) } + let(:script_payload) { FactoryBot.create(:configuration_script_payload, :manager => manager) } context "edit" do it 'forbids edit of a configuration_script_payload without an appropriate role' do @@ -71,6 +72,42 @@ expect(script_payload.credentials).to include("my-cred" => "credential123") end + it "fails if the credential can't be found" do + api_basic_authorize collection_action_identifier(:configuration_script_payloads, :edit, :post) + + post(api_configuration_script_payloads_url, :params => {:action => 'edit', :resources => [{:id => script_payload.id, :name => 'foo', :credentials => {"my-cred" => {"credential_ref" => "my-credential", "credential_field" => "userid"}}}]}) + expect(response).to have_http_status(:bad_request) + end + + context "with an authentication reference in credentials" do + let!(:authentication) { FactoryBot.create(:authentication, :ems_ref => "my-credential", :resource => manager) } + + it "adds the authentication to the configuration_script_payload.authentications" do + api_basic_authorize collection_action_identifier(:configuration_script_payloads, :edit, :post) + + post(api_configuration_script_payloads_url, :params => {:action => 'edit', :resources => [{:id => script_payload.id, :name => 'foo', :credentials => {"my-cred" => {"credential_ref" => "my-credential", "credential_field" => "userid"}}}]}) + expect(script_payload.reload.authentications).to include(authentication) + end + + context "with an existing associated authentication record" do + before { script_payload.authentications << authentication } + + it "doesn't duplicate records" do + api_basic_authorize collection_action_identifier(:configuration_script_payloads, :edit, :post) + + post(api_configuration_script_payloads_url, :params => {:action => 'edit', :resources => [{:id => script_payload.id, :name => 'foo', :credentials => {"my-cred" => {"credential_ref" => "my-credential", "credential_field" => "userid"}}}]}) + expect(script_payload.reload.authentications.count).to eq(1) + end + + it "removes associated authentications" do + api_basic_authorize collection_action_identifier(:configuration_script_payloads, :edit, :post) + + post(api_configuration_script_payloads_url, :params => {:action => 'edit', :resources => [{:id => script_payload.id, :name => 'foo', :credentials => {}}]}) + expect(script_payload.reload.authentications.count).to be_zero + end + end + end + context "with a configuration_script_source" do let(:script_source) { FactoryBot.create(:configuration_script_source) } let(:script_payload) { FactoryBot.create(:configuration_script_payload, :configuration_script_source => script_source) }