mirror of
https://github.com/internetee/registry.git
synced 2025-05-17 01:47:18 +02:00
Add new resource for certs
This commit is contained in:
parent
143fb7eb1b
commit
5319db16b4
12 changed files with 310 additions and 33 deletions
|
@ -53,14 +53,6 @@ class Admin::ApiUsersController < AdminController
|
|||
end
|
||||
end
|
||||
|
||||
def download_csr
|
||||
send_data @api_user.csr, filename: "#{@api_user.username}.csr.pem"
|
||||
end
|
||||
|
||||
def download_crt
|
||||
send_data @api_user.crt, filename: "#{@api_user.username}.crt.pem"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_api_user
|
||||
|
|
68
app/controllers/admin/certificates_controller.rb
Normal file
68
app/controllers/admin/certificates_controller.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
class Admin::CertificatesController < AdminController
|
||||
load_and_authorize_resource
|
||||
before_action :set_certificate, :set_api_user, only: [:sign, :show, :download_csr, :download_crt, :revoke]
|
||||
|
||||
def show
|
||||
@csr = OpenSSL::X509::Request.new(@certificate.csr) if @certificate.csr
|
||||
@crt = OpenSSL::X509::Certificate.new(@certificate.crt) if @certificate.crt
|
||||
end
|
||||
|
||||
def new
|
||||
set_api_user
|
||||
@certificate = Certificate.new
|
||||
end
|
||||
|
||||
def create
|
||||
@api_user = ApiUser.find(params[:api_user_id])
|
||||
csr = certificate_params[:csr].open.read if certificate_params[:csr]
|
||||
|
||||
@certificate = @api_user.certificates.build(csr: csr)
|
||||
if @api_user.save
|
||||
flash[:notice] = I18n.t('record_created')
|
||||
redirect_to [:admin, @api_user, @certificate]
|
||||
else
|
||||
flash.now[:alert] = I18n.t('failed_to_create_record')
|
||||
render 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def sign
|
||||
if @certificate.sign!
|
||||
flash[:notice] = I18n.t('record_updated')
|
||||
else
|
||||
flash[:alert] = I18n.t('failed_to_update_record')
|
||||
end
|
||||
redirect_to [:admin, @api_user, @certificate]
|
||||
end
|
||||
|
||||
def revoke
|
||||
if @certificate.revoke!
|
||||
flash[:notice] = I18n.t('record_updated')
|
||||
else
|
||||
flash[:alert] = I18n.t('failed_to_update_record')
|
||||
end
|
||||
redirect_to [:admin, @api_user, @certificate]
|
||||
end
|
||||
|
||||
def download_csr
|
||||
send_data @certificate.csr, filename: "#{@api_user.username}.csr.pem"
|
||||
end
|
||||
|
||||
def download_crt
|
||||
send_data @certificate.crt, filename: "#{@api_user.username}.crt.pem"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_certificate
|
||||
@certificate = Certificate.find(params[:id])
|
||||
end
|
||||
|
||||
def set_api_user
|
||||
@api_user = ApiUser.find(params[:api_user_id])
|
||||
end
|
||||
|
||||
def certificate_params
|
||||
params.require(:certificate).permit(:csr)
|
||||
end
|
||||
end
|
|
@ -45,6 +45,7 @@ class Ability
|
|||
can :manage, DomainVersion
|
||||
can :manage, User
|
||||
can :manage, ApiUser
|
||||
can :manage, Certificate
|
||||
can :manage, Keyrelay
|
||||
can :manage, LegalDocument
|
||||
can :read, ApiLog::EppLog
|
||||
|
|
|
@ -5,6 +5,7 @@ class ApiUser < User
|
|||
# TODO: should have max request limit per day
|
||||
belongs_to :registrar
|
||||
has_many :contacts
|
||||
has_many :certificates
|
||||
|
||||
validates :username, :password, :registrar, presence: true
|
||||
validates :username, uniqueness: true
|
||||
|
|
83
app/models/certificate.rb
Normal file
83
app/models/certificate.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
class Certificate < ActiveRecord::Base
|
||||
SIGNED = 'signed'
|
||||
UNSIGNED = 'unsigned'
|
||||
EXPIRED = 'expired'
|
||||
REVOKED = 'revoked'
|
||||
VALID = 'valid'
|
||||
|
||||
validates :csr, presence: true
|
||||
|
||||
def parsed_crt
|
||||
@p_crt ||= OpenSSL::X509::Certificate.new(crt) if crt
|
||||
end
|
||||
|
||||
def parsed_csr
|
||||
@p_csr ||= OpenSSL::X509::Request.new(csr) if csr
|
||||
end
|
||||
|
||||
def revoked?
|
||||
status == REVOKED
|
||||
end
|
||||
|
||||
def status
|
||||
return UNSIGNED if crt.blank?
|
||||
return @cached_status if @cached_status
|
||||
|
||||
@cached_status = SIGNED
|
||||
|
||||
if parsed_crt.not_before > Time.now.utc && parsed_crt.not_after < Time.now.utc
|
||||
@cached_status = EXPIRED
|
||||
end
|
||||
|
||||
crl = OpenSSL::X509::CRL.new(File.open(APP_CONFIG['crl_path']).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 -keyfile #{APP_CONFIG['ca_key_path']} \
|
||||
-cert #{APP_CONFIG['ca_cert_path']} \
|
||||
-extensions usr_cert -notext -md sha256 \
|
||||
-in #{csr_file.path} -out #{crt_file.path} -key '#{APP_CONFIG['ca_key_password']}' -batch")
|
||||
|
||||
if err.match(/Data Base Updated/)
|
||||
crt_file.rewind
|
||||
self.crt = crt_file.read
|
||||
save!
|
||||
else
|
||||
errors.add(:base, I18n.t('failed_to_create_certificate'))
|
||||
logger.error('FAILED TO CREATE CLIENT CERTIFICATE')
|
||||
logger.error(err)
|
||||
return 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 -keyfile #{APP_CONFIG['ca_key_path']} \
|
||||
-cert #{APP_CONFIG['ca_cert_path']} \
|
||||
-revoke #{crt_file.path} -key '#{APP_CONFIG['ca_key_password']}' -batch")
|
||||
|
||||
if err.match(/Data Base Updated/) || err.match(/ERROR:Already revoked/)
|
||||
save!
|
||||
else
|
||||
errors.add(:base, I18n.t('failed_to_revoke_certificate'))
|
||||
logger.error('FAILED TO REVOKE CLIENT CERTIFICATE')
|
||||
logger.error(err)
|
||||
return false
|
||||
end
|
||||
|
||||
_out, _err, _st = Open3.capture3("openssl ca -keyfile #{APP_CONFIG['ca_key_path']} \
|
||||
-cert #{APP_CONFIG['ca_cert_path']} \
|
||||
-gencrl -out #{APP_CONFIG['crl_path']} -key '#{APP_CONFIG['ca_key_password']}' -batch")
|
||||
end
|
||||
end
|
|
@ -15,7 +15,7 @@
|
|||
- if @api_user.errors.any?
|
||||
%hr
|
||||
.row
|
||||
.col-md-6
|
||||
.col-md-12
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%h3.panel-title= t('general')
|
||||
|
@ -29,21 +29,24 @@
|
|||
|
||||
%dt= t('active')
|
||||
%dd= @api_user.active
|
||||
|
||||
.col-md-6
|
||||
.row
|
||||
.col-md-12
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%h3.panel-title= t('certificates')
|
||||
.panel-body
|
||||
%dl.dl-horizontal
|
||||
%dt= t('csr')
|
||||
- if @api_user.csr
|
||||
%dd= link_to(t('download'), download_csr_admin_api_user_path)
|
||||
- else
|
||||
%dd -
|
||||
.panel-heading.clearfix
|
||||
.pull-left
|
||||
= t('certificates')
|
||||
.pull-right
|
||||
= link_to(t('upload_csr'), new_admin_api_user_certificate_path(@api_user), class: 'btn btn-primary btn-xs')
|
||||
|
||||
%dt= t('crt')
|
||||
- if @api_user.csr
|
||||
%dd= link_to(t('download'), download_crt_admin_api_user_path)
|
||||
- else
|
||||
%dd -
|
||||
.table-responsive
|
||||
%table.table.table-hover.table-bordered.table-condensed
|
||||
%thead
|
||||
%tr
|
||||
%th{class: 'col-xs-10'}= t('subject')
|
||||
%th{class: 'col-xs-2'}= t('status')
|
||||
%tbody
|
||||
- @api_user.certificates.each do |x|
|
||||
- if x.csr
|
||||
%tr
|
||||
%td= link_to(x.parsed_csr.try(:subject), admin_api_user_certificate_path(@api_user, x))
|
||||
%td= x.status
|
||||
|
|
20
app/views/admin/certificates/new.haml
Normal file
20
app/views/admin/certificates/new.haml
Normal file
|
@ -0,0 +1,20 @@
|
|||
%h2= t('upload_csr')
|
||||
%hr
|
||||
= form_for([:admin, @api_user, @certificate], multipart: true) do |f|
|
||||
- if @certificate.errors.any?
|
||||
- @certificate.errors.each do |attr, err|
|
||||
= err
|
||||
%br
|
||||
- if @certificate.errors.any?
|
||||
%hr
|
||||
|
||||
.row
|
||||
.col-md-12.text-left
|
||||
.form-group
|
||||
= f.label :csr, t('certificate_signing_req')
|
||||
= f.file_field :csr
|
||||
%hr
|
||||
.row
|
||||
.col-md-12.text-right
|
||||
= button_tag(t('save'), class: 'btn btn-primary')
|
||||
|
75
app/views/admin/certificates/show.haml
Normal file
75
app/views/admin/certificates/show.haml
Normal file
|
@ -0,0 +1,75 @@
|
|||
.row
|
||||
.col-sm-6
|
||||
%h2.text-center-xs
|
||||
= t('certificates')
|
||||
.col-sm-6
|
||||
%h2.text-right.text-center-xs
|
||||
= link_to(t('back_to_api_user'), [:admin, @api_user], class: 'btn btn-default')
|
||||
|
||||
%hr
|
||||
- if @certificate.errors.any?
|
||||
- @certificate.errors.each do |attr, err|
|
||||
= err
|
||||
%br
|
||||
- if @certificate.errors.any?
|
||||
%hr
|
||||
.row
|
||||
.col-md-12
|
||||
.panel.panel-default
|
||||
.panel-heading.clearfix
|
||||
.pull-left
|
||||
= t('csr')
|
||||
.pull-right
|
||||
= link_to(t('download'), download_csr_admin_api_user_certificate_path(@api_user, @certificate), class: 'btn btn-default btn-xs')
|
||||
- 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')
|
||||
|
||||
.panel-body
|
||||
%dl.dl-horizontal
|
||||
%dt= t('version')
|
||||
%dd= @csr.version
|
||||
|
||||
%dt= t('subject')
|
||||
%dd= @csr.subject
|
||||
|
||||
%dt= t('signature_algorithm')
|
||||
%dd= @csr.signature_algorithm
|
||||
|
||||
- if @crt
|
||||
.row
|
||||
.col-md-12
|
||||
.panel.panel-default
|
||||
.panel-heading.clearfix
|
||||
.pull-left
|
||||
= t('crt') unless @certificate.revoked?
|
||||
= t('crt_revoked') if @certificate.revoked?
|
||||
.pull-right
|
||||
= link_to(t('download'), download_crt_admin_api_user_certificate_path(@api_user, @certificate), class: 'btn btn-default btn-xs')
|
||||
- unless @certificate.revoked?
|
||||
= link_to(t('revoke_this_certificate'), revoke_admin_api_user_certificate_path(@api_user, @certificate), method: :post, class: 'btn btn-primary btn-xs')
|
||||
- if @crt
|
||||
.panel-body
|
||||
%dl.dl-horizontal
|
||||
%dt= t('version')
|
||||
%dd= @crt.version
|
||||
|
||||
%dt= t('serial_number')
|
||||
%dd= @crt.serial
|
||||
|
||||
%dt= t('signature_algorithm')
|
||||
%dd= @crt.signature_algorithm
|
||||
|
||||
%dt= t('issuer')
|
||||
%dd= @crt.issuer
|
||||
|
||||
%dt= t('valid_from')
|
||||
%dd= @crt.not_before
|
||||
|
||||
%dt= t('valid_to')
|
||||
%dd= @crt.not_after
|
||||
|
||||
%dt= t('subject')
|
||||
%dd= @crt.subject
|
||||
|
||||
%dt= t('extensions')
|
||||
%dd= @crt.extensions.map(&:to_s).join('<br>').html_safe
|
|
@ -481,4 +481,11 @@ en:
|
|||
address_help: 'Street name, house no - apartment no, city, county, country, zip'
|
||||
download: 'Download'
|
||||
failed_to_create_certificate: 'Failed to create certificate!'
|
||||
failed_to_revoke_certificate: 'Failed to revoke certificate!'
|
||||
contact_code: Contact code
|
||||
upload_csr: 'Upload CSR'
|
||||
signature_algorithm: 'Signature algorithm'
|
||||
version: 'Version'
|
||||
sign_this_request: 'Sign this request'
|
||||
revoke_this_certificate: 'Revoke this certificate'
|
||||
crt_revoked: 'CRT (revoked)'
|
||||
|
|
|
@ -48,11 +48,15 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :admin_users
|
||||
resources :api_users do
|
||||
resources :certificates do
|
||||
member do
|
||||
post 'sign'
|
||||
post 'revoke'
|
||||
get 'download_csr'
|
||||
get 'download_crt'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
resources :delayed_jobs
|
||||
|
||||
|
|
15
db/migrate/20150223104842_create_certificates.rb
Normal file
15
db/migrate/20150223104842_create_certificates.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class CreateCertificates < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :certificates do |t|
|
||||
t.integer :api_user_id
|
||||
t.text :csr
|
||||
t.text :crt
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
ApiUser.all.each do |x|
|
||||
x.certificates << Certificate.new(crt: x.crt, csr: x.csr)
|
||||
end
|
||||
end
|
||||
end
|
10
db/schema.rb
10
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150217133937) do
|
||||
ActiveRecord::Schema.define(version: 20150223104842) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -53,6 +53,14 @@ ActiveRecord::Schema.define(version: 20150217133937) do
|
|||
|
||||
add_index "cached_nameservers", ["hostname", "ipv4", "ipv6"], name: "index_cached_nameservers_on_hostname_and_ipv4_and_ipv6", unique: true, using: :btree
|
||||
|
||||
create_table "certificates", force: :cascade do |t|
|
||||
t.integer "api_user_id"
|
||||
t.text "csr"
|
||||
t.text "crt"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "contact_disclosures", force: :cascade do |t|
|
||||
t.integer "contact_id"
|
||||
t.boolean "phone"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue