foreman_x509 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +619 -0
- data/README.md +38 -0
- data/Rakefile +47 -0
- data/app/controllers/foreman_x509/api/v2/base_controller.rb +12 -0
- data/app/controllers/foreman_x509/api/v2/certificates_controller.rb +59 -0
- data/app/controllers/foreman_x509/api/v2/generations_controller.rb +58 -0
- data/app/controllers/foreman_x509/api/v2/issuers_controller.rb +41 -0
- data/app/controllers/foreman_x509/api/v2/requests_controller.rb +32 -0
- data/app/controllers/foreman_x509/certificates_controller.rb +82 -0
- data/app/controllers/foreman_x509/generations_controller.rb +71 -0
- data/app/controllers/foreman_x509/issuers_controller.rb +49 -0
- data/app/controllers/foreman_x509/requests_controller.rb +17 -0
- data/app/helpers/foreman_x509/certificates_helper.rb +49 -0
- data/app/models/concerns/foreman_x509/digest.rb +11 -0
- data/app/models/concerns/foreman_x509/extensions.rb +20 -0
- data/app/models/concerns/foreman_x509/subject.rb +23 -0
- data/app/models/foreman_x509/certificate.rb +75 -0
- data/app/models/foreman_x509/generation.rb +61 -0
- data/app/models/foreman_x509/issuer.rb +87 -0
- data/app/models/foreman_x509/request.rb +40 -0
- data/app/services/foreman_x509/builder.rb +86 -0
- data/app/services/foreman_x509/serializer/big_number.rb +13 -0
- data/app/services/foreman_x509/serializer/certificate.rb +15 -0
- data/app/services/foreman_x509/serializer/certificate_revocation_list.rb +14 -0
- data/app/services/foreman_x509/serializer/configuration.rb +13 -0
- data/app/services/foreman_x509/serializer/key.rb +13 -0
- data/app/services/foreman_x509/serializer/request.rb +13 -0
- data/app/views/foreman_x509/api/v2/certificates/base.json.rabl +3 -0
- data/app/views/foreman_x509/api/v2/certificates/index.json.rabl +3 -0
- data/app/views/foreman_x509/api/v2/certificates/show.json.rabl +9 -0
- data/app/views/foreman_x509/api/v2/generations/base.json.rabl +11 -0
- data/app/views/foreman_x509/api/v2/generations/index.json.rabl +0 -0
- data/app/views/foreman_x509/api/v2/generations/show.json.rabl +7 -0
- data/app/views/foreman_x509/api/v2/issuers/base.json.rabl +3 -0
- data/app/views/foreman_x509/api/v2/issuers/index.json.rabl +3 -0
- data/app/views/foreman_x509/api/v2/requests/show.json.rabl +16 -0
- data/app/views/foreman_x509/certificates/_form.html.erb +12 -0
- data/app/views/foreman_x509/certificates/_generations.html.erb +32 -0
- data/app/views/foreman_x509/certificates/index.html.erb +34 -0
- data/app/views/foreman_x509/certificates/new.html.erb +3 -0
- data/app/views/foreman_x509/certificates/show.html.erb +31 -0
- data/app/views/foreman_x509/generations/edit.html.erb +8 -0
- data/app/views/foreman_x509/issuers/index.html.erb +24 -0
- data/app/views/foreman_x509/issuers/new.html.erb +0 -0
- data/app/views/foreman_x509/issuers/show.html.erb +52 -0
- data/app/views/foreman_x509/requests/show.html.erb +15 -0
- data/config/routes.rb +68 -0
- data/db/migrate/20250201155706_initialize_foreman_x509_schema.rb +37 -0
- data/db/migrate/20250401083842_create_foreman_x509_requests.rb +14 -0
- data/lib/foreman_x509/engine.rb +47 -0
- data/lib/foreman_x509/plugin.rb +30 -0
- data/lib/foreman_x509/version.rb +3 -0
- data/lib/foreman_x509.rb +4 -0
- data/lib/tasks/foreman_x509_tasks.rake +31 -0
- data/locale/Makefile +73 -0
- data/locale/en/foreman_x509.po +19 -0
- data/locale/foreman_x509.pot +19 -0
- data/locale/gemspec.rb +2 -0
- data/package.json +41 -0
- data/test/factories/foreman_x509_factories.rb +5 -0
- data/test/test_plugin_helper.rb +6 -0
- data/test/unit/foreman_x509_test.rb +11 -0
- data/webpack/global_index.js +17 -0
- data/webpack/global_test_setup.js +11 -0
- data/webpack/index.js +8 -0
- data/webpack/src/Components/EmptyState/Constants.js +2 -0
- data/webpack/src/Components/EmptyState/EmptyStateReducer.js +19 -0
- data/webpack/src/Components/EmptyState/ExtendedEmptyState.js +43 -0
- data/webpack/src/Components/EmptyState/__tests__/ExtendedEmptyState.test.js +37 -0
- data/webpack/src/Extends/index.js +15 -0
- data/webpack/src/Router/WelcomePage/Welcome.js +9 -0
- data/webpack/src/Router/WelcomePage/index.js +1 -0
- data/webpack/src/Router/routes.js +12 -0
- data/webpack/src/reducers.js +10 -0
- data/webpack/test_setup.js +17 -0
- metadata +168 -0
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ForemanX509'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
task default: :test
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'rubocop/rake_task'
|
40
|
+
RuboCop::RakeTask.new
|
41
|
+
rescue LoadError
|
42
|
+
puts 'Rubocop not loaded.'
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default do
|
46
|
+
Rake::Task['rubocop'].execute
|
47
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
module Api
|
3
|
+
module V2
|
4
|
+
class CertificatesController < BaseController
|
5
|
+
resource_description do
|
6
|
+
resource_id 'certificates'
|
7
|
+
api_version 'v2'
|
8
|
+
api_base_url '/foreman_x509/api'
|
9
|
+
end
|
10
|
+
|
11
|
+
before_action :find_resource, only: [:show, :destroy]
|
12
|
+
|
13
|
+
api :GET, '/certificates', N_('List certificates')
|
14
|
+
param_group :search_and_pagination, ::Api::V2::BaseController
|
15
|
+
add_scoped_search_description_for(Certificate)
|
16
|
+
def index
|
17
|
+
@certificates = resource_scope_for_index
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
end
|
22
|
+
|
23
|
+
def show
|
24
|
+
end
|
25
|
+
|
26
|
+
def update
|
27
|
+
end
|
28
|
+
|
29
|
+
api :GET, '/certificates/:id/chain', N_('Download the PEM format chain')
|
30
|
+
param :id, Integer, desc: N_('Id of the certificate')
|
31
|
+
def chain
|
32
|
+
send_data @certificate.issuer.bundle.map(&:to_pem).join('\n'), filename: "#{@certificate.name}_ca.pem"
|
33
|
+
end
|
34
|
+
|
35
|
+
api :GET, '/certificates/:id/certificate', N_('Download the PEM format certificate')
|
36
|
+
param :id, Integer, desc: N_('Id of the certificate')
|
37
|
+
def certificate
|
38
|
+
send_data @certificate.certificate.to_pem, filename: "#{@certificate.name}_cert.pem"
|
39
|
+
end
|
40
|
+
|
41
|
+
api :GET, '/certificate/:id/key', N_('Download the PEM format key')
|
42
|
+
param :id, Integer, desc: N_('Id of the key')
|
43
|
+
def key
|
44
|
+
send_data @certificate.key.to_pem, filename: "#{@certificate.name}_key.pem"
|
45
|
+
end
|
46
|
+
|
47
|
+
api :DELETE, '/certificates/:id', N_('Destroy a certificate')
|
48
|
+
param :id, Integer, desc: N_('Id of the certificate')
|
49
|
+
def destroy
|
50
|
+
process_response @certificate.destroy
|
51
|
+
end
|
52
|
+
|
53
|
+
def resource_class
|
54
|
+
ForemanX509::Certificate
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
module Api
|
3
|
+
module V2
|
4
|
+
class GenerationsController < BaseController
|
5
|
+
before_action :find_owner
|
6
|
+
before_action :find_generation, except: [:index, :create]
|
7
|
+
|
8
|
+
api :GET, '/certificates/:owner_id/generations', N_('List certificate generations')
|
9
|
+
param :certificate_id, Integer, desc: N_('ID of the owning certificate')
|
10
|
+
param_group :search_and_pagination, ::Api::V2::BaseController
|
11
|
+
def index
|
12
|
+
@generations = resource_scope_for_index
|
13
|
+
end
|
14
|
+
|
15
|
+
api :GET, '/certificates/:owner_id/generations/:id', N_('Get generation details')
|
16
|
+
param :certificate_id, Integer, desc: N_('ID of the owning certificate')
|
17
|
+
param :id, Integer, desc: N_('ID of the generation')
|
18
|
+
def show
|
19
|
+
end
|
20
|
+
|
21
|
+
api :GET, '/certificates/:owner_id/generations/:id/certificate', N_('Download the generation certificate')
|
22
|
+
param :certificate_id, Integer, desc: N_('ID of the owning certificate')
|
23
|
+
param :id, Integer, desc: N_('ID of the generation')
|
24
|
+
def certificate
|
25
|
+
end
|
26
|
+
|
27
|
+
api :GET, '/certificates/:owner_id/generations/:id/key', N_('Download the generation key')
|
28
|
+
param :certificate_id, Integer, desc: N_('ID of the owning certificate')
|
29
|
+
param :id, Integer, desc: N_('ID of the generation')
|
30
|
+
def key
|
31
|
+
send_data @generation.key.to_pem, filename: "#{@generation.owner.name}-#{@generation.id}_key.pem"
|
32
|
+
end
|
33
|
+
|
34
|
+
api :POST, '/certificates/:owner_id/generations/:id', N_('Activate certificate generation')
|
35
|
+
param :certificate_id, Integer, desc: N_('ID of the owning certificate')
|
36
|
+
param :id, Integer, desc: N_('ID of the generation')
|
37
|
+
def activate
|
38
|
+
@generation.activate!
|
39
|
+
end
|
40
|
+
|
41
|
+
api :DELETE, '/certificates/:owner_id/generations/:id', N_('Delete certificate generation')
|
42
|
+
def destroy
|
43
|
+
@generation.destroy
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def find_owner
|
49
|
+
@owner ||= ForemanX509::Certificate.find(params[:owner_id])
|
50
|
+
end
|
51
|
+
|
52
|
+
def find_generation
|
53
|
+
@generation ||= find_certificate.generations.find_by(id: params[:id])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
module Api
|
3
|
+
module V2
|
4
|
+
class IssuersController < BaseController
|
5
|
+
resource_description do
|
6
|
+
resource_id 'issuer'
|
7
|
+
api_version 'v2'
|
8
|
+
api_base_url '/foreman_x509/api'
|
9
|
+
end
|
10
|
+
|
11
|
+
before_action :find_resource, only: [:show, :destroy]
|
12
|
+
|
13
|
+
api :GET, '/issuers', N_('List issuers')
|
14
|
+
param_group :search_and_pagination, ::Api::V2::BaseController
|
15
|
+
add_scoped_search_description_for(ForemanX509::Issuer)
|
16
|
+
def index
|
17
|
+
@issuers = resource_scope_for_index
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
end
|
22
|
+
|
23
|
+
def show
|
24
|
+
end
|
25
|
+
|
26
|
+
def update
|
27
|
+
end
|
28
|
+
|
29
|
+
api :DELETE, '/issuer/:id', N_('Destroy an issuer')
|
30
|
+
param :id, Integer, desc: N_('Id of the issuer')
|
31
|
+
def destroy
|
32
|
+
process_response @issuer.destroy
|
33
|
+
end
|
34
|
+
|
35
|
+
def resource_class
|
36
|
+
ForemanX509::Issuer
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
module Api
|
3
|
+
module V2
|
4
|
+
class RequestsController < BaseController
|
5
|
+
resource_description do
|
6
|
+
resource_id 'requests'
|
7
|
+
api_version 'v2'
|
8
|
+
api_base_url '/foreman_x509/api'
|
9
|
+
end
|
10
|
+
|
11
|
+
before_action :find_resource, only: [:show, :download]
|
12
|
+
|
13
|
+
def index
|
14
|
+
@requests = resource_scope_for_index
|
15
|
+
end
|
16
|
+
|
17
|
+
def show
|
18
|
+
respond_to do |format|
|
19
|
+
format.der { send_data @request.to_der, filename: "#{@request.name}_req.der" }
|
20
|
+
format.pem { send_data @request.to_pem, filename: "#{@request.name}_req.pem" }
|
21
|
+
format.json
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def resource_class
|
26
|
+
ForemanX509::Request
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
class CertificatesController < ::ApplicationController
|
3
|
+
before_action :upload_certificate_file, only: [:create, :update]
|
4
|
+
before_action :upload_key_file, only: [:create, :update]
|
5
|
+
before_action :upload_configuration_file, only: [:create, :update]
|
6
|
+
before_action :find_resource, except: [:index, :new, :create]
|
7
|
+
|
8
|
+
def index
|
9
|
+
@certificates = resource_base_search_and_page
|
10
|
+
end
|
11
|
+
|
12
|
+
def new
|
13
|
+
@certificate = Certificate.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def create
|
17
|
+
@certificate = Certificate.new(certificate_params)
|
18
|
+
if @certificate.save
|
19
|
+
process_success object: @certificate
|
20
|
+
else
|
21
|
+
process_error object: @certificate
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def show
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
if @certificate.update(certificate_params)
|
30
|
+
process_success object: @certificate
|
31
|
+
else
|
32
|
+
process_error object: @certificate
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def chain
|
37
|
+
send_date @certificate.issuer.bundle.map(&:to_pem).join('\n'), filename: "#{@certificate.name}_ca.pem"
|
38
|
+
end
|
39
|
+
|
40
|
+
def certificate
|
41
|
+
send_data @certificate.certificate.to_pem, filename: "#{@certificate.name}_cert.pem"
|
42
|
+
end
|
43
|
+
|
44
|
+
def key
|
45
|
+
send_data @certificate.key.to_pem, filename: "#{@certificate.name}_key.pem"
|
46
|
+
end
|
47
|
+
|
48
|
+
def destroy
|
49
|
+
if @certificate.destroy
|
50
|
+
process_success object: @certificate
|
51
|
+
else
|
52
|
+
process_error object: @certificate
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def resource_class
|
57
|
+
ForemanX509::Certificate
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def upload_configuration_file
|
63
|
+
return if (configuration = params.dig(:certificate, :configuration_file)).nil?
|
64
|
+
params[:certificate][:configuration] = configuration.read if configuration.respond_to?(:read)
|
65
|
+
end
|
66
|
+
|
67
|
+
def upload_certificate_file
|
68
|
+
return if (certificate = params.dig(:certificate, :generation_attributes, :certificate_file)).nil?
|
69
|
+
params[:certificate][:generation_attributes][:certificate] = certificate.read if certificate.respond_to?(:read)
|
70
|
+
end
|
71
|
+
|
72
|
+
def upload_key_file
|
73
|
+
return if (key = params.dig(:certificate, :generation_attributes, :key_file)).nil?
|
74
|
+
params[:certificate][:generation_attributes][:key] = key.read if key.respond_to?(:read)
|
75
|
+
end
|
76
|
+
|
77
|
+
def certificate_params
|
78
|
+
params.require(:certificate).permit(:name, :description, :issuer_id, :configuration, generation_attributes: [:certificate, :key])
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
class GenerationsController < ::ApplicationController
|
3
|
+
|
4
|
+
before_action :find_owner
|
5
|
+
before_action :find_generation, except: [:new, :create]
|
6
|
+
before_action :upload_certificate_file, only: [:create, :update]
|
7
|
+
|
8
|
+
def new
|
9
|
+
@generation = ForemanX509::Generation.new(owner: @owner)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
@generation = ForemanX509::Builder.create(@owner) if generation_params.empty?
|
14
|
+
@generation = @owner.generations.create(generation_params) unless generation_params.empty?
|
15
|
+
if @generation
|
16
|
+
process_success object: @generation, success_redirect: certificate_path(@owner)
|
17
|
+
else
|
18
|
+
process_error object: @generation, redirect: certificate_path(@owner)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def update
|
23
|
+
if @generation.update(generation_params)
|
24
|
+
process_success object: @generation, success_redirect: certificate_path(@owner)
|
25
|
+
else
|
26
|
+
process_error object: @generation, redirect: request_path(@generation.request)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def activate
|
31
|
+
@generation.activate!
|
32
|
+
|
33
|
+
redirect_to certificate_path(@owner)
|
34
|
+
end
|
35
|
+
|
36
|
+
def certificate
|
37
|
+
send_data @generation.certificate.to_pem, filename: "#{@generation.owner.name}-#{@generation.id}_cert.pem"
|
38
|
+
end
|
39
|
+
|
40
|
+
def key
|
41
|
+
send_data @generation.key.to_pem, filename: "#{@generation.owner.name}-#{@generation.id}_key.pem"
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy
|
45
|
+
if @generation.destroy
|
46
|
+
process_success object: @generation, success_redirect: certificate_path(@owner)
|
47
|
+
else
|
48
|
+
process_error object: @generation, redirect: certificate_path(@owner)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def find_owner
|
55
|
+
@owner ||= ForemanX509::Certificate.friendly.find(params[:owner_id])
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_generation
|
59
|
+
@generation ||= ForemanX509::Generation.find_by(owner: find_owner, id: params[:id])
|
60
|
+
end
|
61
|
+
|
62
|
+
def upload_certificate_file
|
63
|
+
return if (certificate = params.dig(:generation, :certificate_file)).nil?
|
64
|
+
params[:generation][:certificate] = certificate.read if certificate.respond_to?(:read)
|
65
|
+
end
|
66
|
+
|
67
|
+
def generation_params
|
68
|
+
params.require(:generation).permit(:certificate, :active)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
class IssuersController < ::ApplicationController
|
3
|
+
|
4
|
+
before_action :find_resource, only: [:show, :destroy]
|
5
|
+
|
6
|
+
def index
|
7
|
+
@issuers = resource_base_search_and_page
|
8
|
+
end
|
9
|
+
|
10
|
+
def new
|
11
|
+
@issuer = Issuer.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def create
|
15
|
+
if @issuer.create(issuer_params)
|
16
|
+
process_success object: @issuer
|
17
|
+
else
|
18
|
+
process_error object: @issuer
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def show
|
23
|
+
end
|
24
|
+
|
25
|
+
def bundle
|
26
|
+
send_data @issuer.bundle.map(&:to_pem).join('\n'), filename: "#{@issuer.name}_bundle.pem"
|
27
|
+
end
|
28
|
+
|
29
|
+
def destroy
|
30
|
+
if @issuer.destroy
|
31
|
+
process_success object: @issuer
|
32
|
+
else
|
33
|
+
process_error object: @issuer
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def resource_class
|
38
|
+
ForemanX509::Issuer
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def issuer_params_for_create
|
44
|
+
params.require(:issuer).permit(:certificate_id, :serial, :crl_number, :certificate_revocation_list,
|
45
|
+
certificate_attributes: [:name, :issuer_id, :description, :configuration, generation_attributes: [:certificate, :key]])
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
class RequestsController < ::ApplicationController
|
3
|
+
before_action :find_resource
|
4
|
+
|
5
|
+
def show
|
6
|
+
respond_to do |format|
|
7
|
+
format.der { send_data @request.to_der, filename: "#{@request.name}_req.der" }
|
8
|
+
format.pem { send_data @request.to_pem, filename: "#{@request.name}_req.pem" }
|
9
|
+
format.html
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def resource_class
|
14
|
+
ForemanX509::Request
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
module CertificatesHelper
|
3
|
+
def certificate_details
|
4
|
+
if @certificate.certificate.present?
|
5
|
+
@certificate.certificate.to_text
|
6
|
+
else
|
7
|
+
@certificate.subject.to_s(OpenSSL::X509::Name::MULTILINE)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def issuer_link(certificate)
|
12
|
+
return if certificate.issuer.nil?
|
13
|
+
link_to certificate.issuer.name, issuer_path(certificate.issuer)
|
14
|
+
end
|
15
|
+
|
16
|
+
def certificate_download_links
|
17
|
+
links = []
|
18
|
+
|
19
|
+
links << link_to(_('Download Certificate'), certificate_certificate_path(@certificate),
|
20
|
+
class: 'btn btn-default',
|
21
|
+
title: _('Download the PEM format certificate')) unless @certificate.certificate.nil?
|
22
|
+
|
23
|
+
links << link_to(_('Sign Request'), request_path(@certificate.request),
|
24
|
+
class: 'btn btn-default',
|
25
|
+
title: _('Upload the signed certificate')) unless @certificate.request.nil?
|
26
|
+
|
27
|
+
links << link_to(_('Download Key'), key_certificate_path(@certificate),
|
28
|
+
class: 'btn btn-default',
|
29
|
+
title: _('Download the PEM format private key')) unless @certificate.key.nil?
|
30
|
+
|
31
|
+
links
|
32
|
+
end
|
33
|
+
|
34
|
+
def generation_actions(generation)
|
35
|
+
buttons = []
|
36
|
+
|
37
|
+
params = [generation.owner, generation]
|
38
|
+
|
39
|
+
buttons << link_to(_('Activate'), generation_path(*params, generation: { active: true }), method: :put) if generation.status == 'inactive'
|
40
|
+
buttons << link_to(_('Download Certificate'), certificate_generation_path(*params)) unless generation.status == 'pending'
|
41
|
+
buttons << link_to(_('Upload Certificate'), request_path(generation.request)) if generation.status == 'pending'
|
42
|
+
buttons << link_to(_('Download Request'), request_path(generation.request, format: :pem)) if generation.status == 'pending'
|
43
|
+
buttons << link_to(_('Download Key'), key_generation_path(*params)) unless generation.key.nil?
|
44
|
+
buttons << link_to(_('Delete'), generation_path(*params), method: :delete, data: { confirm: _("Are you sure?") }) unless generation.active?
|
45
|
+
|
46
|
+
action_buttons(buttons)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
module Digest
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def digest
|
6
|
+
algorithm = configuration.get_value(authority_section, 'default_md') if respond_to?(:authority_section)
|
7
|
+
algorithm ||= configuration.get_value('req', 'default_md')
|
8
|
+
OpenSSL::Digest.new(algorithm || 'sha256') # TODO: make Setting[:default_digest_algorithm]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
module Extensions
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
EXTENSION_ENTRY_FORMAT = /\A(?<critical>critical,)?\s*(?:@(?<section>[a-zA-Z_]+)|(?<value>[^@].*))\Z/.freeze
|
6
|
+
|
7
|
+
def extensions_from_section(section)
|
8
|
+
return {} if section.nil?
|
9
|
+
|
10
|
+
configuration[section].transform_values do |value|
|
11
|
+
data = EXTENSION_ENTRY_FORMAT.match(value)
|
12
|
+
data[:critical].to_s + (data[:value] || extension_value_from_section(data[:section])).to_s
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def extension_value_from_section(section)
|
17
|
+
configuration[section].entries.map { |entry| entry.join(':') }.join(',')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
module Subject
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def subject
|
6
|
+
@subject ||= subject_from_certificate
|
7
|
+
@subject ||= subject_from_configuration
|
8
|
+
end
|
9
|
+
|
10
|
+
def subject_from_certificate
|
11
|
+
certificate.subject unless certificate.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def subject_from_configuration
|
15
|
+
return if configuration.blank?
|
16
|
+
|
17
|
+
section = configuration.get_value('req', 'distinguished_name')
|
18
|
+
|
19
|
+
OpenSSL::X509::Name.new(configuration[section].to_a) unless section.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module ForemanX509
|
2
|
+
class Certificate < ::ApplicationRecord
|
3
|
+
include ForemanX509::Subject
|
4
|
+
include ForemanX509::Extensions
|
5
|
+
include ForemanX509::Digest
|
6
|
+
extend FriendlyId
|
7
|
+
friendly_id :name
|
8
|
+
|
9
|
+
belongs_to :issuer, class_name: 'ForemanX509::Issuer', inverse_of: :certificates
|
10
|
+
|
11
|
+
has_many :generations, class_name: 'ForemanX509::Generation', foreign_key: :owner_id, inverse_of: :owner
|
12
|
+
has_one :generation, -> { where(foreman_x509_generations: { active: true }) }, class_name: 'ForemanX509::Generation', foreign_key: :owner_id
|
13
|
+
accepts_nested_attributes_for :generation
|
14
|
+
|
15
|
+
delegate :certificate, :key, to: :generation, allow_nil: true
|
16
|
+
|
17
|
+
has_one :request, class_name: 'ForemanX509::Request', inverse_of: :certificate
|
18
|
+
|
19
|
+
serialize :configuration, ForemanX509::Serializer::Configuration
|
20
|
+
|
21
|
+
validates :name, format: { with: /\A[a-z][a-z0-9.-]*(?<!-)\z/, message: _("Invalid name format!") }
|
22
|
+
validates :certificate, presence: true, if: -> { configuration.nil? }
|
23
|
+
validate :configuration_has_required_fields, unless: -> { configuration.nil? }
|
24
|
+
|
25
|
+
after_save :ensure_active_generation, if: -> { generations.empty? }
|
26
|
+
|
27
|
+
scoped_search on: :name, complete_value: true
|
28
|
+
|
29
|
+
def can_self_sign?
|
30
|
+
return false if configuration.nil?
|
31
|
+
|
32
|
+
section = configuration.get_value('req', 'x509_extensions')
|
33
|
+
configuration[section].present?
|
34
|
+
end
|
35
|
+
|
36
|
+
def active?
|
37
|
+
return false if certificate.nil?
|
38
|
+
|
39
|
+
(not_before..not_after).include? Time.now
|
40
|
+
end
|
41
|
+
|
42
|
+
def not_before
|
43
|
+
certificate.not_before unless certificate.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
def not_after
|
47
|
+
certificate.not_after unless certificate.nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
def requested_extensions
|
51
|
+
extensions_from_section(configuration.get_value('req', 'req_extensions'))
|
52
|
+
end
|
53
|
+
|
54
|
+
def certificate_extensions_section
|
55
|
+
configuration.get_value('req', 'x509_extensions')
|
56
|
+
end
|
57
|
+
|
58
|
+
def key_bits
|
59
|
+
return 4096 if configuration.get_value('req', 'default_bits').nil?
|
60
|
+
configuration.get_value('req', 'default_bits').to_i
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def configuration_has_required_fields
|
66
|
+
errors.add("Configuration missing distinguished name definition") if subject_from_configuration.nil?
|
67
|
+
end
|
68
|
+
|
69
|
+
def ensure_active_generation
|
70
|
+
return if configuration.blank?
|
71
|
+
|
72
|
+
ForemanX509::Builder.create(self)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|