diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 934a316..c6c8e75 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -3,34 +3,5 @@ class ApplicationController < ActionController::Base # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception - def check_cert - @cert = Certificate.find_by active: true - unless @cert - @cert = Certificate.create - @cert.save - end - - # update cert on all hosts if close to end. - # This will never fail as lxd is very lax with its certificates. - # It accepts certificates even behind the not_after date. - # As a result a password is only required when a new host is added - # or we remove the current cert completely. - if (@cert.cert.not_after - 1.day + 300) < Time.now - @new_cert = @cert.update - Host.all.each { |host| - host.cert = @cert - # add new certificate - cert = Lxd::Certificate.new( - api: host.api, - certificate: @new_cert.cert.to_pem.split("\n")[1...-1].join) - cert.add - # delete old certificate / we don't want this to be used - # any more. - Lxd::Certificate.new( - api: host.api, fingerprint: @cert.cert_fpr).delete - } - @cert = @new_cert - end - end end # vim: set et ts=2 sw=2: diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index cab303c..21e702e 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,18 +1,14 @@ class DashboardController < ApplicationController def index - check_cert @hosts = Host.all @hosts.map { |host| - host.cert = @cert - if host.config.auth == 'untrusted' + if host.lxd_config.auth == 'untrusted' session[:return_to] = request.env["REQUEST_URI"] redirect_to controller: 'hosts', action: 'auth', id: host.id return end } - - @certificates = Lxd::Certificate.all @hosts.first.api end end # vim: set et ts=2 sw=2: diff --git a/app/controllers/hosts_controller.rb b/app/controllers/hosts_controller.rb index 00c3df8..d3ce002 100644 --- a/app/controllers/hosts_controller.rb +++ b/app/controllers/hosts_controller.rb @@ -28,8 +28,7 @@ class HostsController < ApplicationController # PATCH/PUT /hosts/1/add_key def add_key - cert = Lxd::Certificate.new api: @host.api - cert.add params[:hosts][:password] + @host.lxd_authenticate params[:hosts][:password] redirect_to session.delete(:return_to) end @@ -76,9 +75,7 @@ class HostsController < ApplicationController private # Use callbacks to share common setup or constraints between actions. def set_host - check_cert @host = Host.find(params[:id]) - @host.cert = @cert end # Never trust parameters from the scary internet, only allow the white list through. diff --git a/app/models/certificate.rb b/app/models/certificate.rb index d4fdaac..229532e 100644 --- a/app/models/certificate.rb +++ b/app/models/certificate.rb @@ -2,28 +2,49 @@ require "openssl" require 'digest/md5' class Certificate < ActiveRecord::Base + private_class_method :new + + def self.get + @@cert ||= find_by active: true + @@cert ||= create + if @@cert.is_expired? + @@cert = @@cert.update + end + @@cert + end + def self.create(old=nil) key = if old then old.key else OpenSSL::PKey::RSA.new 4096 end cert = OpenSSL::X509::Certificate.new cert.version = if old then old.cert.version else 2 end cert.serial = if old then old.cert.serial+1 else 0 end cert.not_before = Time.now - #cert.not_after = Time.now + 1.year - cert.not_after = Time.now + 1.day + #cert.not_after = Time.now + 3.months + cert.not_after = Time.now + 1.day + 5.minutes cert.public_key = key.public_key cert.subject = OpenSSL::X509::Name.parse( 'CN=lex-deeit/' + Rails.configuration.x.certificate['x509_base']) cert.sign key, OpenSSL::Digest::SHA256.new - Certificate.new key: key.to_pem, cert: cert.to_pem, active: true + certificate = new(key: key.to_pem, cert: cert.to_pem, active: true) + certificate.save + certificate end def update self.active = false self.save - cert = Certificate.create(self) - cert.save - cert + Certificate.create(self) + end + + def is_expired? + # The cert is already expired + self.cert.not_after < Time.now + end + + def expires_soon? + # The cert will expire within the next day or is alreay expired + (self.cert.not_after - 1.day) < Time.now end def key @@ -43,5 +64,13 @@ class Certificate < ActiveRecord::Base def cert_fpr Digest::SHA256.hexdigest(cert.to_der).upcase end + + def to_s + cert.to_pem.split("\n")[1...-1].join + end + + def to_str + to_s + end end # vim: set et ts=2 sw=2: diff --git a/app/models/host.rb b/app/models/host.rb index 1f1920e..207233c 100644 --- a/app/models/host.rb +++ b/app/models/host.rb @@ -1,14 +1,43 @@ class Host < ActiveRecord::Base - def cert=(cert) - @cert = cert - end + belongs_to :certificate - def api - Lxd::API.get self, @cert + def certificate + # ensure that we always use a current, working non expired certificate. + case + when super.nil? + self.certificate_id = Certificate.get.id + self.save + super(true) + when super.expires_soon? + old = super + new = Certificate.get.update + Lxd::Certificate.new(api: api(old), certificate: new.to_s).add + self.certificate_id = new.id + self.save + @api = nil # enforce new api to get the new certificate used. + # finally remove the old certificate from lxd + Lxd::Certificate.new(api: api(new), fingerprint: old.cert_fpr).delete + super(true) + else + super + end end - def config + def lxd_config Lxd::Config.get api end + + def lxd_certificates + Lxd::Certificate.all api + end + + def lxd_authenticate password + Lxd::Certificate.new(api: api).add password + end + + private + def api certificate = nil + @api ||= Lxd::API.get self, certificate + end end # vim: ts=2 sw=2: diff --git a/app/models/lxd/api.rb b/app/models/lxd/api.rb index 0f06f8d..f8a5ae1 100644 --- a/app/models/lxd/api.rb +++ b/app/models/lxd/api.rb @@ -1,9 +1,7 @@ module Lxd::API - def self.get host, certificate - begin - uri = URI.parse host.uri - rescue - end + def self.get host, certificate = nil + certificate ||= host.certificate + uri = URI.parse host.uri con = Net::HTTP.new uri.host, uri.port ? uri.port : 8443 con.use_ssl = true con.cert = OpenSSL::X509::Certificate.new certificate.cert diff --git a/app/views/dashboard/index.html.erb b/app/views/dashboard/index.html.erb index 955a357..c295325 100644 --- a/app/views/dashboard/index.html.erb +++ b/app/views/dashboard/index.html.erb @@ -1,9 +1,12 @@

Dashboard#index

-

<%= @cert.cert_fpr %>

-

Serial: <%= @cert.cert.serial %>

+<% Certificate.all.each do |cert| -%> +

Fingerprint: <%= cert.cert_fpr %>  +Serial: <%= cert.cert.serial %>

+<% end -%> +
<% @hosts.each do |host| -%> -

<%= host.config.inspect %>

+

<%= host.lxd_config.inspect %>

+<% host.lxd_certificates.each do |certificate| -%> +

<%= certificate.fingerprint %>

<% end -%> -<% @certificates.each do |cert| -%> -

<%= cert.fingerprint %>

<% end -%>