diff --git a/app/controllers/repp/v1/certificates_controller.rb b/app/controllers/repp/v1/certificates_controller.rb index 632bff615..b4b7aeda5 100644 --- a/app/controllers/repp/v1/certificates_controller.rb +++ b/app/controllers/repp/v1/certificates_controller.rb @@ -19,11 +19,14 @@ module Repp desc 'Submit a new api user certificate signing request' def create @api_user = current_user.registrar.api_users.find(cert_params[:api_user_id]) - csr = decode_cert_params(cert_params[:csr]) - @certificate = @api_user.certificates.build(csr: csr) + if csr.blank? + @certificate.errors.add(:base, I18n.t(:crt_or_csr_must_be_present)) + return handle_non_epp_errors(@certificate) + end + @certificate = @api_user.certificates.build(csr: csr) if @certificate.save notify_admins render_success(data: { api_user: { id: @api_user.id } }) @@ -69,7 +72,6 @@ module Repp def decode_cert_params(csr_params) return if csr_params.blank? - return nil if csr_params[:body] == 'invalid' begin diff --git a/app/models/certificate.rb b/app/models/certificate.rb index 6ff032c4b..62c0a0a2e 100644 --- a/app/models/certificate.rb +++ b/app/models/certificate.rb @@ -43,6 +43,23 @@ class Certificate < ApplicationRecord errors.add(:base, I18n.t(:invalid_csr_or_crt)) end + validate :validate_csr_parameters, if: -> { new_record? && csr.present? && parsed_csr.present? } + def validate_csr_parameters + subject = parsed_csr.subject.to_s + common_name = subject.scan(%r{/CN=([^/]+)}).flatten.first + country = subject.scan(%r{/C=([^/]+)}).flatten.first + + unless common_name == api_user.username + errors.add(:base, I18n.t(:csr_common_name_must_match_username)) + end + + if country.present? && api_user.registrar.address_country_code.present? + unless country == api_user.registrar.address_country_code + errors.add(:base, I18n.t(:csr_country_must_match_registrar_country)) + end + end + end + validate :assign_metadata, on: :create def assign_metadata return if errors.any? diff --git a/config/locales/en.yml b/config/locales/en.yml index fe98336f3..e7c32a745 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -706,3 +706,7 @@ en: errors: invalid_ca: "Invalid Certificate Authority for this interface" active_certificate_exists: "Active certificate already exists for this user and interface" + + # Adding translation keys for certificate CSR validation + csr_common_name_must_match_username: "Certificate CN (common name) must match the username of the account" + csr_country_must_match_registrar_country: "Certificate C (country) must match the country of the registrar" diff --git a/config/locales/et.yml b/config/locales/et.yml index 51192c708..00cc7e11f 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -2,6 +2,10 @@ et: username: 'Kasutajanimi' password: 'Parool' + # Adding translation keys for certificate CSR validation + csr_common_name_must_match_username: "Sertifikaadi CN (üldine nimi) peab vastama konto kasutajanimele" + csr_country_must_match_registrar_country: "Sertifikaadi C (riik) peab vastama registripidaja riigile" + time: formats: default: "%Y-%m-%d %H:%M" diff --git a/test/integration/repp/v1/certificates/create_test.rb b/test/integration/repp/v1/certificates/create_test.rb index 7ead82706..97813391b 100644 --- a/test/integration/repp/v1/certificates/create_test.rb +++ b/test/integration/repp/v1/certificates/create_test.rb @@ -10,12 +10,23 @@ class ReppV1CertificatesCreateTest < ActionDispatch::IntegrationTest adapter = ENV['shunter_default_adapter'].constantize.new adapter&.clear! + + @user.registrar.update!(address_country_code: 'ET',vat_rate: 22) end def test_creates_new_api_user_certificate_and_informs_admins + original_username = @user.username + @user.update!(username: 'host.ee') && @user.reload + + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + headers = { 'Authorization' => "Basic #{token}" } + assert_difference('Certificate.count') do assert_difference 'ActionMailer::Base.deliveries.size', +1 do - post repp_v1_certificates_path, headers: @auth_headers, params: request_body + post repp_v1_certificates_path, headers: headers, params: request_body + + puts "Response status: #{response.status}" + puts "Response body: #{response.body}" end end json = JSON.parse(response.body, symbolize_names: true) @@ -23,6 +34,8 @@ class ReppV1CertificatesCreateTest < ActionDispatch::IntegrationTest assert_response :ok assert_equal 1000, json[:code] assert_equal 'Command completed successfully', json[:message] + + @user.update!(username: original_username) end def test_return_error_when_invalid_certificate diff --git a/test/models/certificate_test.rb b/test/models/certificate_test.rb index 08a0dac3d..b6ba7a1bc 100644 --- a/test/models/certificate_test.rb +++ b/test/models/certificate_test.rb @@ -41,4 +41,56 @@ class CertificateTest < ActiveSupport::TestCase @certificate.update!(interface: Certificate::REGISTRAR, crt: nil) assert_not @certificate.revokable? end + + def test_csr_common_name_must_match_username + api_user = @certificate.api_user + + new_cert = Certificate.new( + api_user: api_user, + csr: @certificate.csr + ) + api_user.update!(username: 'different_username') + + new_cert.send(:validate_csr_parameters) + + assert_includes new_cert.errors.full_messages, I18n.t(:csr_common_name_must_match_username) + end + + def test_csr_country_validation + api_user = @certificate.api_user + csr_content = @certificate.csr + + new_cert = Certificate.new( + api_user: api_user, + csr: csr_content + ) + api_user.registrar.update!(address_country_code: 'EE', vat_rate: 22) + + new_cert.send(:validate_csr_parameters) + + assert_not_includes new_cert.errors.full_messages, I18n.t(:csr_country_must_match_registrar_country) + + new_cert.errors.clear + api_user.registrar.update!(address_country_code: 'US', vat_rate: nil) + new_cert.send(:validate_csr_parameters) + + assert_includes new_cert.errors.full_messages, I18n.t(:csr_country_must_match_registrar_country) + end + + def test_validation_in_controller_context + api_user = @certificate.api_user + api_user.update!(username: 'different_username') + + cert = Certificate.new( + api_user: api_user, + csr: @certificate.csr + ) + + Rails.env.stub :test?, false do + assert_not cert.save + assert_includes cert.errors.full_messages, I18n.t(:csr_common_name_must_match_username) + end + + assert cert.save(validate: false) + end end