This commit is contained in:
OlegPhenomenon 2025-08-10 02:07:10 +00:00 committed by GitHub
commit 31a90e802e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 96 additions and 4 deletions

View file

@ -19,11 +19,14 @@ module Repp
desc 'Submit a new api user certificate signing request' desc 'Submit a new api user certificate signing request'
def create def create
@api_user = current_user.registrar.api_users.find(cert_params[:api_user_id]) @api_user = current_user.registrar.api_users.find(cert_params[:api_user_id])
csr = decode_cert_params(cert_params[:csr]) 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 if @certificate.save
notify_admins notify_admins
render_success(data: { api_user: { id: @api_user.id } }) render_success(data: { api_user: { id: @api_user.id } })
@ -69,7 +72,6 @@ module Repp
def decode_cert_params(csr_params) def decode_cert_params(csr_params)
return if csr_params.blank? return if csr_params.blank?
return nil if csr_params[:body] == 'invalid' return nil if csr_params[:body] == 'invalid'
begin begin

View file

@ -43,6 +43,23 @@ class Certificate < ApplicationRecord
errors.add(:base, I18n.t(:invalid_csr_or_crt)) errors.add(:base, I18n.t(:invalid_csr_or_crt))
end 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 validate :assign_metadata, on: :create
def assign_metadata def assign_metadata
return if errors.any? return if errors.any?

View file

@ -706,3 +706,7 @@ en:
errors: errors:
invalid_ca: "Invalid Certificate Authority for this interface" invalid_ca: "Invalid Certificate Authority for this interface"
active_certificate_exists: "Active certificate already exists for this user and 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"

View file

@ -2,6 +2,10 @@ et:
username: 'Kasutajanimi' username: 'Kasutajanimi'
password: 'Parool' 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: time:
formats: formats:
default: "%Y-%m-%d %H:%M" default: "%Y-%m-%d %H:%M"

View file

@ -10,12 +10,23 @@ class ReppV1CertificatesCreateTest < ActionDispatch::IntegrationTest
adapter = ENV['shunter_default_adapter'].constantize.new adapter = ENV['shunter_default_adapter'].constantize.new
adapter&.clear! adapter&.clear!
@user.registrar.update!(address_country_code: 'ET',vat_rate: 22)
end end
def test_creates_new_api_user_certificate_and_informs_admins 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('Certificate.count') do
assert_difference 'ActionMailer::Base.deliveries.size', +1 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
end end
json = JSON.parse(response.body, symbolize_names: true) json = JSON.parse(response.body, symbolize_names: true)
@ -23,6 +34,8 @@ class ReppV1CertificatesCreateTest < ActionDispatch::IntegrationTest
assert_response :ok assert_response :ok
assert_equal 1000, json[:code] assert_equal 1000, json[:code]
assert_equal 'Command completed successfully', json[:message] assert_equal 'Command completed successfully', json[:message]
@user.update!(username: original_username)
end end
def test_return_error_when_invalid_certificate def test_return_error_when_invalid_certificate

View file

@ -41,4 +41,56 @@ class CertificateTest < ActiveSupport::TestCase
@certificate.update!(interface: Certificate::REGISTRAR, crt: nil) @certificate.update!(interface: Certificate::REGISTRAR, crt: nil)
assert_not @certificate.revokable? assert_not @certificate.revokable?
end 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 end