Added endpoints for creating and downloading api user certificates

This commit is contained in:
Sergei Tsoganov 2023-06-28 15:48:40 +03:00
parent b558c80e83
commit 47b6a1b87a
18 changed files with 377 additions and 102 deletions

View file

@ -1,10 +1,9 @@
module Admin module Admin
class CertificatesController < BaseController class CertificatesController < BaseController
load_and_authorize_resource load_and_authorize_resource
before_action :set_certificate, :set_api_user, only: [:sign, :show, :download_csr, :download_crt, :revoke, :destroy] before_action :set_certificate, :set_api_user, only: %i[sign show download_csr download_crt revoke destroy]
def show; def show; end
end
def new def new
@api_user = ApiUser.find(params[:api_user_id]) @api_user = ApiUser.find(params[:api_user_id])
@ -28,11 +27,9 @@ module Admin
end end
def destroy def destroy
if @certificate.interface == Certificate::REGISTRAR success = @certificate.revokable? ? revoke_and_destroy_certificate : @certificate.destroy
@certificate.revoke!
end
if @certificate.destroy if success
flash[:notice] = I18n.t('record_deleted') flash[:notice] = I18n.t('record_deleted')
redirect_to admin_registrar_api_user_path(@api_user.registrar, @api_user) redirect_to admin_registrar_api_user_path(@api_user.registrar, @api_user)
else else
@ -42,8 +39,9 @@ module Admin
end end
def sign def sign
if @certificate.sign! if @certificate.sign!(password: certificate_params[:password])
flash[:notice] = I18n.t('record_updated') flash[:notice] = I18n.t('record_updated')
notify_api_user
redirect_to [:admin, @api_user, @certificate] redirect_to [:admin, @api_user, @certificate]
else else
flash.now[:alert] = I18n.t('failed_to_update_record') flash.now[:alert] = I18n.t('failed_to_update_record')
@ -52,7 +50,7 @@ module Admin
end end
def revoke def revoke
if @certificate.revoke! if @certificate.revoke!(password: certificate_params[:password])
flash[:notice] = I18n.t('record_updated') flash[:notice] = I18n.t('record_updated')
else else
flash[:alert] = I18n.t('failed_to_update_record') flash[:alert] = I18n.t('failed_to_update_record')
@ -84,10 +82,22 @@ module Admin
def certificate_params def certificate_params
if params[:certificate] if params[:certificate]
params.require(:certificate).permit(:crt, :csr) params.require(:certificate).permit(:crt, :csr, :password)
else else
{} {}
end end
end end
def notify_api_user
api_user_email = @api_user.registrar.email
CertificateMailer.signed(email: api_user_email, api_user: @api_user,
crt: OpenSSL::X509::Certificate.new(@certificate.crt))
.deliver_now
end
def revoke_and_destroy_certificate
@certificate.revoke!(password: certificate_params[:password]) && @certificate.destroy
end
end end
end end

View file

@ -2,6 +2,7 @@ require 'serializers/repp/api_user'
module Repp module Repp
module V1 module V1
class ApiUsersController < BaseController class ApiUsersController < BaseController
before_action :find_api_user, only: %i[show update destroy]
load_and_authorize_resource load_and_authorize_resource
THROTTLED_ACTIONS = %i[index show create update destroy].freeze THROTTLED_ACTIONS = %i[index show create update destroy].freeze
@ -60,6 +61,10 @@ module Repp
private private
def find_api_user
@api_user = current_user.registrar.api_users.find(params[:id])
end
def api_user_params def api_user_params
params.require(:api_user).permit(:username, :plain_text_password, :active, params.require(:api_user).permit(:username, :plain_text_password, :active,
:identity_code, { roles: [] }) :identity_code, { roles: [] })

View file

@ -1,29 +1,52 @@
require 'serializers/repp/certificate'
module Repp module Repp
module V1 module V1
class CertificatesController < BaseController class CertificatesController < BaseController
THROTTLED_ACTIONS = %i[create].freeze before_action :find_certificate, only: %i[show download]
load_and_authorize_resource param_method: :cert_params
THROTTLED_ACTIONS = %i[show create download].freeze
include Shunter::Integration::Throttle include Shunter::Integration::Throttle
api :GET, '/repp/v1/api_users/:api_user_id/certificates/:id'
desc "Get a specific api user's specific certificate data"
def show
serializer = Serializers::Repp::Certificate.new(@certificate)
render_success(data: { cert: serializer.to_json })
end
api :POST, '/repp/v1/certificates' api :POST, '/repp/v1/certificates'
desc 'Submit a new api user certificate signing request' desc 'Submit a new api user certificate signing request'
def create def create
authorize! :create, Certificate
@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) @certificate = @api_user.certificates.build(csr: csr)
unless @certificate.save
handle_non_epp_errors(@certificate)
return
end
notify_admins if @certificate.save
render_success(data: { api_user: { id: @api_user.id } }) notify_admins
render_success(data: { api_user: { id: @api_user.id } })
else
handle_non_epp_errors(@certificate)
end
end
api :get, '/repp/v1/api_users/:api_user_id/certificates/:id/download'
desc "Download a specific api user's specific certificate"
param :type, String, required: true, desc: 'Type of certificate (csr or crt)'
def download
filename = "#{@api_user.username}_#{Time.zone.today.strftime('%y%m%d')}_portal.#{params[:type]}.pem"
send_data @certificate[params[:type].to_s], filename: filename
end end
private private
def find_certificate
@api_user = current_user.registrar.api_users.find(params[:api_user_id])
@certificate = @api_user.certificates.find(params[:id])
end
def cert_params def cert_params
params.require(:certificate).permit(:api_user_id, csr: %i[body type]) params.require(:certificate).permit(:api_user_id, csr: %i[body type])
end end
@ -40,9 +63,9 @@ module Repp
return if admin_users_emails.empty? return if admin_users_emails.empty?
admin_users_emails.each do |email| admin_users_emails.each do |email|
CertificateMailer.new_certificate_signing_request(email: email, CertificateMailer.certificate_signing_requested(email: email,
api_user: @api_user, api_user: @api_user,
csr: @certificate) csr: @certificate)
.deliver_now .deliver_now
end end
end end

View file

@ -2,6 +2,7 @@ require 'serializers/repp/invoice'
module Repp module Repp
module V1 module V1
class InvoicesController < BaseController # rubocop:disable Metrics/ClassLength class InvoicesController < BaseController # rubocop:disable Metrics/ClassLength
before_action :find_invoice, only: %i[show download send_to_recipient cancel]
load_and_authorize_resource load_and_authorize_resource
THROTTLED_ACTIONS = %i[download add_credit send_to_recipient cancel index show].freeze THROTTLED_ACTIONS = %i[download add_credit send_to_recipient cancel index show].freeze
@ -35,8 +36,6 @@ module Repp
desc 'Download a specific invoice as pdf file' desc 'Download a specific invoice as pdf file'
def download def download
filename = "Invoice-#{@invoice.number}.pdf" filename = "Invoice-#{@invoice.number}.pdf"
@response = { code: 1000, message: 'Command completed successfully',
data: filename }
send_data @invoice.as_pdf, filename: filename send_data @invoice.as_pdf, filename: filename
end end
@ -91,6 +90,10 @@ module Repp
private private
def find_invoice
@invoice = current_user.registrar.invoices.find(params[:id])
end
def index_params def index_params
params.permit(:id, :limit, :offset, :details, :q, :simple, params.permit(:id, :limit, :offset, :details, :q, :simple,
:page, :per_page, :page, :per_page,

View file

@ -1,6 +1,7 @@
module Repp module Repp
module V1 module V1
class WhiteIpsController < BaseController class WhiteIpsController < BaseController
before_action :find_white_ip, only: %i[show update destroy]
load_and_authorize_resource load_and_authorize_resource
THROTTLED_ACTIONS = %i[index show create update destroy].freeze THROTTLED_ACTIONS = %i[index show create update destroy].freeze
@ -57,6 +58,10 @@ module Repp
private private
def find_white_ip
@white_ip = current_user.registrar.white_ips.find(params[:id])
end
def white_ip_params def white_ip_params
params.require(:white_ip).permit(:ipv4, :ipv6, interfaces: []) params.require(:white_ip).permit(:ipv4, :ipv6, interfaces: [])
end end

View file

@ -1,8 +1,15 @@
class CertificateMailer < ApplicationMailer class CertificateMailer < ApplicationMailer
def new_certificate_signing_request(email:, api_user:, csr:) def certificate_signing_requested(email:, api_user:, csr:)
@certificate = csr @certificate = csr
@api_user = api_user @api_user = api_user
subject = 'New Certificate Signing Request Received' subject = 'New Certificate Signing Request Received'
mail(to: email, subject: subject) mail(to: email, subject: subject)
end end
def signed(email:, api_user:, crt:)
@crt = crt
@api_user = api_user
subject = "Certificate Signing Confirmation for API User '#{@api_user.username}'"
mail(to: email, subject: subject)
end
end end

View file

@ -30,7 +30,7 @@ class Ability
billing billing
can :manage, ApiUser can :manage, ApiUser
can :manage, WhiteIp can :manage, WhiteIp
can :create, Certificate can :manage, Certificate
end end
def epp # Registrar/api_user dynamic role def epp # Registrar/api_user dynamic role

View file

@ -17,6 +17,7 @@ class Certificate < ApplicationRecord
scope 'api', -> { where(interface: API) } scope 'api', -> { where(interface: API) }
scope 'registrar', -> { where(interface: REGISTRAR) } scope 'registrar', -> { where(interface: REGISTRAR) }
scope 'unrevoked', -> { where(revoked: false) }
validate :validate_csr_and_crt_presence validate :validate_csr_and_crt_presence
def validate_csr_and_crt_presence def validate_csr_and_crt_presence
@ -64,75 +65,49 @@ class Certificate < ApplicationRecord
status == REVOKED status == REVOKED
end end
def revokable?
interface == REGISTRAR && status != UNSIGNED
end
def status def status
return UNSIGNED if crt.blank? return UNSIGNED if crt.blank?
return @cached_status if @cached_status return @cached_status if @cached_status
@cached_status = SIGNED @cached_status = SIGNED
expired = parsed_crt.not_before > Time.zone.now.utc && parsed_crt.not_after < Time.zone.now.utc if certificate_expired?
@cached_status = EXPIRED if expired @cached_status = EXPIRED
elsif certificate_revoked?
crl = OpenSSL::X509::CRL.new(File.open("#{ENV['crl_dir']}/crl.pem").read)
return @cached_status unless crl.revoked.map(&:serial).include?(parsed_crt.serial)
@cached_status = REVOKED
end
def sign!
csr_file = Tempfile.new('client_csr')
csr_file.write(csr)
csr_file.rewind
crt_file = Tempfile.new('client_crt')
_out, err, _st = Open3.capture3('openssl', 'ca', '-config', ENV['openssl_config_path'],
'-keyfile', ENV['ca_key_path'], '-cert', ENV['ca_cert_path'],
'-extensions', 'usr_cert', '-notext', '-md', 'sha256',
'-in', csr_file.path, '-out', crt_file.path, '-key', ENV['ca_key_password'],
'-batch')
if err.match?(/Data Base Updated/)
crt_file.rewind
self.crt = crt_file.read
self.md5 = OpenSSL::Digest::MD5.new(parsed_crt.to_der).to_s
save!
else
logger.error('FAILED TO CREATE CLIENT CERTIFICATE')
if err.match?(/TXT_DB error number 2/)
errors.add(:base, I18n.t('failed_to_create_crt_csr_already_signed'))
logger.error('CSR ALREADY SIGNED')
else
errors.add(:base, I18n.t('failed_to_create_certificate'))
end
logger.error(err)
puts "Certificate sign issue: #{err.inspect}" if Rails.env.test?
false
end
end
def revoke!
crt_file = Tempfile.new('client_crt')
crt_file.write(crt)
crt_file.rewind
_out, err, _st = Open3.capture3("openssl ca -config #{ENV['openssl_config_path']} \
-keyfile #{ENV['ca_key_path']} \
-cert #{ENV['ca_cert_path']} \
-revoke #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch")
if err.match(/Data Base Updated/) || err.match(/ERROR:Already revoked/)
self.revoked = true
save!
@cached_status = REVOKED @cached_status = REVOKED
else
errors.add(:base, I18n.t('failed_to_revoke_certificate'))
logger.error('FAILED TO REVOKE CLIENT CERTIFICATE')
logger.error(err)
return false
end end
self.class.update_crl @cached_status
self end
def sign!(password:)
csr_file = create_tempfile('client_csr', csr)
crt_file = Tempfile.new('client_crt')
err_output = execute_openssl_sign_command(password, csr_file.path, crt_file.path)
update_certificate_details(crt_file) and return true if err_output.match?(/Data Base Updated/)
log_failed_to_create_certificate(err_output)
false
end
def revoke!(password:)
crt_file = create_tempfile('client_crt', crt)
err_output = execute_openssl_revoke_command(password, crt_file.path)
if revocation_successful?(err_output)
update_revocation_status
self.class.update_crl
return self
end
handle_revocation_failure(err_output)
end end
class << self class << self
@ -157,4 +132,89 @@ class Certificate < ApplicationRecord
OpenSSL::Digest::MD5.new(cert.to_der).to_s OpenSSL::Digest::MD5.new(cert.to_der).to_s
end end
end end
private
def create_tempfile(filename, content = '')
tempfile = Tempfile.new(filename)
tempfile.write(content)
tempfile.rewind
tempfile
end
def log_failed_to_create_certificate(err_output)
logger.error('FAILED TO CREATE CLIENT CERTIFICATE')
if err_output.match?(/TXT_DB error number 2/)
handle_csr_already_signed_error
else
errors.add(:base, I18n.t('failed_to_create_certificate'))
end
logger.error(err_output)
puts "Certificate sign issue: #{err_output.inspect}" if Rails.env.test?
end
def execute_openssl_sign_command(password, csr_path, crt_path)
openssl_command = [
'openssl', 'ca', '-config', ENV['openssl_config_path'],
'-keyfile', ENV['ca_key_path'], '-cert', ENV['ca_cert_path'],
'-extensions', 'usr_cert', '-notext', '-md', 'sha256',
'-in', csr_path, '-out', crt_path,
'-key', password,
'-batch'
]
_out, err, _st = Open3.capture3(*openssl_command)
err
end
def execute_openssl_revoke_command(password, crt_path)
openssl_command = [
'openssl', 'ca', '-config', ENV['openssl_config_path'],
'-keyfile', ENV['ca_key_path'], '-cert', ENV['ca_cert_path'],
'-revoke', crt_path,
'-key', password,
'-batch'
]
_out, err, _st = Open3.capture3(*openssl_command)
err
end
def update_certificate_details(crt_file)
crt_file.rewind
self.crt = crt_file.read
self.md5 = OpenSSL::Digest::MD5.new(parsed_crt.to_der).to_s
save!
end
def handle_csr_already_signed_error
errors.add(:base, I18n.t('failed_to_create_crt_csr_already_signed'))
logger.error('CSR ALREADY SIGNED')
end
def handle_revocation_failure(err_output)
errors.add(:base, I18n.t('failed_to_revoke_certificate'))
logger.error('FAILED TO REVOKE CLIENT CERTIFICATE')
logger.error(err_output)
false
end
def revocation_successful?(err_output)
err_output.match?(/Data Base Updated/) || err_output.match?(/ERROR:Already revoked/)
end
def update_revocation_status
self.revoked = true
save!
@cached_status = REVOKED
end
def certificate_expired?
parsed_crt.not_before > Time.zone.now.utc && parsed_crt.not_after < Time.zone.now.utc
end
def certificate_revoked?
crl = OpenSSL::X509::CRL.new(File.open("#{ENV['crl_dir']}/crl.pem").read)
crl.revoked.map(&:serial).include?(parsed_crt.serial)
end
end end

View file

@ -1,15 +1,7 @@
- content_for :actions do - content_for :actions do
= link_to(t(:delete), admin_api_user_certificate_path(@api_user, @certificate), = link_to(t(:delete), '#', "data-toggle": "modal", "data-target": "#deleteModal", class: 'btn btn-danger')
method: :delete, data: { confirm: t(:are_you_sure) }, class: 'btn btn-danger')
= render 'shared/title', name: t(:certificates) = render 'shared/title', name: t(:certificates)
- if @certificate.errors.any?
- @certificate.errors.each do |attr, err|
= err
%br
- if @certificate.errors.any?
%hr
.row .row
.col-md-12 .col-md-12
.panel.panel-default .panel.panel-default
@ -47,7 +39,8 @@
.pull-right .pull-right
= link_to(t(:download), download_csr_admin_api_user_certificate_path(@api_user, @certificate), class: 'btn btn-default btn-xs') = link_to(t(:download), download_csr_admin_api_user_certificate_path(@api_user, @certificate), class: 'btn btn-default btn-xs')
- unless @crt - unless @crt
= link_to(t(:sign_this_request), sign_admin_api_user_certificate_path(@api_user, @certificate), method: :post, class: 'btn btn-primary btn-xs') - sign_revoke_url = sign_admin_api_user_certificate_path(@api_user, @certificate)
= link_to(t(:sign_this_request), '#', "data-toggle": "modal", "data-target": "#signRevokeModal", class: 'btn btn-primary btn-xs')
.panel-body .panel-body
%dl.dl-horizontal %dl.dl-horizontal
@ -55,7 +48,7 @@
%dd= @csr.version %dd= @csr.version
%dt= CertificationRequest.human_attribute_name :subject %dt= CertificationRequest.human_attribute_name :subject
%dd= @csr.subject %dd{ style: 'word-break:break-all;' }= @csr.subject
%dt= t(:signature_algorithm) %dt= t(:signature_algorithm)
%dd= @csr.signature_algorithm %dd= @csr.signature_algorithm
@ -71,7 +64,8 @@
.pull-right .pull-right
= link_to(t(:download), download_crt_admin_api_user_certificate_path(@api_user, @certificate), class: 'btn btn-default btn-xs') = link_to(t(:download), download_crt_admin_api_user_certificate_path(@api_user, @certificate), class: 'btn btn-default btn-xs')
- if !@certificate.revoked? && @certificate.csr - if !@certificate.revoked? && @certificate.csr
= link_to(t(:revoke_this_certificate), revoke_admin_api_user_certificate_path(@api_user, @certificate), method: :post, class: 'btn btn-primary btn-xs') - sign_revoke_url = revoke_admin_api_user_certificate_path(@api_user, @certificate)
= link_to(t(:revoke_this_certificate), '#', "data-toggle": "modal", "data-target": "#signRevokeModal", class: 'btn btn-primary btn-xs')
- if @crt - if @crt
.panel-body .panel-body
%dl.dl-horizontal %dl.dl-horizontal
@ -98,3 +92,37 @@
%dt= Certificate.human_attribute_name :extensions %dt= Certificate.human_attribute_name :extensions
%dd= @crt.extensions.map(&:to_s).join('<br>').html_safe %dd= @crt.extensions.map(&:to_s).join('<br>').html_safe
.modal.fade{ id: "signRevokeModal", tabindex: "-1", role: "dialog", "aria-labelledby": "signRevokeModalLabel" }
.modal-dialog{ role: "document" }
.modal-content
= form_for(:certificate, url: sign_revoke_url) do |f|
.modal-header
%button.close{ type: "button", "data-dismiss": "modal", "aria-label": "Close" }
%span{ "aria-hidden" => "true" } &times;
%h4.modal-title{ id: "signRevokeModalLabel" }
= t(:enter_ca_key_password)
.modal-body
= f.password_field :password, required: true, class: 'form-control'
.modal-footer
%button.btn.btn-default{ type: "button", "data-dismiss": "modal" }
= t(:close)
%button.btn.btn-primary{ type: "submit" }
= @crt.nil? ? t(:sign) : t(:submit)
.modal.fade{ id: "deleteModal", tabindex: "-1", role: "dialog", "aria-labelledby": "deleteModalLabel" }
.modal-dialog{ role: "document" }
.modal-content
= form_for(:certificate, url: admin_api_user_certificate_path(@api_user, @certificate), method: :delete) do |f|
.modal-header
%button.close{ type: "button", "data-dismiss": "modal", "aria-label": "Close" }
%span{ "aria-hidden" => "true" } &times;
%h4.modal-title{ id: "deleteModalLabel" }
= t(:enter_ca_key_password)
.modal-body
= f.password_field :password, required: true, class: 'form-control'
.modal-footer
%button.btn.btn-default{ type: "button", "data-dismiss": "modal" }
= t(:close)
%button.btn.btn-primary{ type: "submit" }
= t(:delete)

View file

@ -0,0 +1,50 @@
Tere,
<br><br>
<p>
Anname teada, et API kasutaja on esitanud .ee registrisüsteemiga integreerumiseks sertifikaadi taotluse.
Oleme selle taotlusega seotud sertifikaadi edukalt töödelnud ja allkirjastanud.
</p>
<h3>API Kasutaja andmed:</h3>
<ul>
<li><strong>API Kasutaja nimi:</strong> <%= @api_user.username %></li>
<li><strong>Sertifikaadi seerianumber:</strong> <%= @crt.serial %></li>
<li><strong>Sertifikaadi aegumiskuupäev:</strong> <%= @crt.not_after %></li>
<li><strong>Sertifikaadi subjekt:</strong> <%= @crt.subject %></li>
</ul>
<p>
Allkirjastatud sertifikaat tagab turvalise suhtluse .ee registripidaja ning registri süsteemide vahel.
See toimib digitaalse identiteedikinnitusena, võimaldades autoriseeritud juurdepääsu .ee liidestele.
</p>
Kui Teil on küsimusi või vajate täiendavat teavet seoses sertifikaadi taotluse või API integratsiooniga, võtke meiega ühendust.
</p>
<p>
Parimate soovidega,
</p>
<%= render 'mailers/shared/signatures/signature.et.html' %>
<hr>
<br><br>
Hi,
<br><br>
<p>
We are writing to inform you that a certificate request has been made by an API user to integrate with our system.
We have successfully processed and signed the certificate associated with this request.
</p>
<h3>Api User Details:</h3>
<ul>
<li><strong>API User Name:</strong> <%= @api_user.username %></li>
<li><strong>Certificate Serial Number:</strong> <%= @crt.serial %></li>
<li><strong>Certificate Expiry Date:</strong> <%= @crt.not_after %></li>
<li><strong>Certificate Subject:</strong> <%= @crt.subject %></li>
</ul>
<p>
The signed certificate ensures secure communication between the API user's integration and .ee registry system.
It serves as a digital identity verification, enabling authorized access to the APIs.
</p>
<p>
If you have any questions or require further information regarding this certificate request or the API integration, please do not hesitate to reach out to us.
</p>
<p>
Best regards,
</p>
<%= render 'mailers/shared/signatures/signature.en.html' %>

View file

@ -0,0 +1,34 @@
Tere,
Anname teada, et API kasutaja on esitanud .ee registrisüsteemiga integreerumiseks sertifikaadi taotluse. Oleme selle taotlusega seotud sertifikaadi edukalt töödelnud ja allkirjastanud.
API Kasutaja andmed:
- API Kasutaja nimi: <%= @api_user.username %>
- Sertifikaadi seerianumber: <%= @crt.serial %>
- Sertifikaadi aegumiskuupäev: <%= @crt.not_after %>
- Sertifikaadi subjekt: <%= @crt.subject %>
Allkirjastatud sertifikaat tagab turvalise suhtluse .ee registripidaja ning registri süsteemide vahel. See toimib digitaalse identiteedikinnitusena, võimaldades autoriseeritud juurdepääsu .ee liidestele.
Kui Teil on küsimusi või vajate täiendavat teavet seoses sertifikaadi taotluse või API integratsiooniga, võtke meiega ühendust.
Parimate soovidega,
<%= render 'mailers/shared/signatures/signature.et.text' %>
---
Hi,
We are writing to inform you that a certificate request has been made by an API user to integrate with our system. We have successfully processed and signed the certificate associated with this request.
API User Details:
- API User Name: <%= @api_user.username %>
- Certificate Serial Number: <%= @crt.serial %>
- Certificate Expiry Date: <%= @crt.not_after %>
- Certificate Subject: <%= @crt.subject %>
The signed certificate ensures secure communication between the API user's integration and .ee registry system. It serves as a digital identity verification, enabling authorized access to the APIs.
If you have any questions or require further information regarding this certificate request or the API integration, please do not hesitate to reach out to us.
Best regards,
<%= render 'mailers/shared/signatures/signature.en.text' %>

View file

@ -36,7 +36,6 @@ crl_path: '/home/registry/registry/shared/ca/crl/crl.pem'
crl_updater_path: '/home/registry/registry/shared/ca/crl/crlupdater.sh' crl_updater_path: '/home/registry/registry/shared/ca/crl/crlupdater.sh'
ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.crt.pem' ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.crt.pem'
ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem' ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem'
ca_key_password: 'your-root-key-password'
directo_invoice_url: 'https://domain/ddddd.asp' directo_invoice_url: 'https://domain/ddddd.asp'
cdns_scanner_input_file: '/opt/cdns/input.txt' cdns_scanner_input_file: '/opt/cdns/input.txt'

View file

@ -363,7 +363,9 @@ en:
signature_algorithm: 'Signature algorithm' signature_algorithm: 'Signature algorithm'
version: 'Version' version: 'Version'
sign_this_request: 'Sign this request' sign_this_request: 'Sign this request'
sign: 'Sign'
revoke_this_certificate: 'Revoke this certificate' revoke_this_certificate: 'Revoke this certificate'
enter_ca_key_password: 'Enter passphrase for a CA key'
crt_revoked: 'CRT (revoked)' crt_revoked: 'CRT (revoked)'
contact_org_error: 'Parameter value policy error. Org must be blank' contact_org_error: 'Parameter value policy error. Org must be blank'
contact_fax_error: 'Parameter value policy error. Fax must be blank' contact_fax_error: 'Parameter value policy error. Fax must be blank'

View file

@ -92,10 +92,10 @@ Rails.application.routes.draw do
end end
resources :invoices, only: %i[index show] do resources :invoices, only: %i[index show] do
collection do collection do
get ':id/download', to: 'invoices#download'
post 'add_credit' post 'add_credit'
end end
member do member do
get 'download'
post 'send_to_recipient', to: 'invoices#send_to_recipient' post 'send_to_recipient', to: 'invoices#send_to_recipient'
put 'cancel', to: 'invoices#cancel' put 'cancel', to: 'invoices#cancel'
end end
@ -108,7 +108,13 @@ Rails.application.routes.draw do
get '/market_share_growth_rate', to: 'stats#market_share_growth_rate' get '/market_share_growth_rate', to: 'stats#market_share_growth_rate'
end end
end end
resources :api_users, only: %i[index show update create destroy] resources :api_users, only: %i[index show update create destroy] do
resources :certificates, only: %i[show] do
member do
get 'download'
end
end
end
resources :white_ips, only: %i[index show update create destroy] resources :white_ips, only: %i[index show update create destroy]
resources :certificates, only: %i[create] resources :certificates, only: %i[create]
namespace :registrar do namespace :registrar do

View file

@ -32,9 +32,9 @@ module Serializers
private private
def certificates def certificates
user.certificates.map do |x| user.certificates.unrevoked.map do |x|
subject = x.csr ? x.parsed_csr.try(:subject) : x.parsed_crt.try(:subject) subject = x.csr ? x.parsed_csr.try(:subject) : x.parsed_crt.try(:subject)
{ subject: subject.to_s, status: x.status } { id: x.id, subject: subject.to_s, status: x.status }
end end
end end
end end

View file

@ -0,0 +1,43 @@
module Serializers
module Repp
class Certificate
attr_reader :certificate
def initialize(certificate)
@certificate = certificate
end
def to_json(obj = certificate)
json = obj.as_json.except('csr', 'crt')
csr = obj.parsed_csr
crt = obj.parsed_crt
json[:csr] = csr_data(csr) if csr
json[:crt] = crt_data(crt) if crt
json
end
private
def csr_data(csr)
{
version: csr.version,
subject: csr.subject.to_s,
alg: csr.signature_algorithm.to_s,
}
end
def crt_data(crt)
{
version: crt.version,
serial: crt.serial.to_s,
alg: crt.signature_algorithm.to_s,
issuer: crt.issuer.to_s,
not_before: crt.not_before,
not_after: crt.not_after,
subject: crt.subject.to_s,
extensions: crt.extensions.map(&:to_s),
}
end
end
end
end