app/models/endpoint.rb
require 'openssl'
class Endpoint < ApplicationRecord
belongs_to :resource, :polymorphic => true
default_value_for :verify_ssl, OpenSSL::SSL::VERIFY_PEER
validates :verify_ssl, :inclusion => {:in => [OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER]}
validates :port, :numericality => {:only_integer => true, :allow_nil => true, :greater_than => 0}
validates :url, :uniqueness_when_changed => true, :allow_blank => true, :unless => :allow_duplicate_url?
validate :validate_certificate_authority
after_create :endpoint_created
after_destroy :endpoint_destroyed
delegate :to_s, :to => :url, :allow_nil => true
def endpoint_created
resource.endpoint_created(role) if resource.respond_to?(:endpoint_created)
end
def endpoint_destroyed
resource.endpoint_destroyed(role) if resource.respond_to?(:endpoint_destroyed)
end
def verify_ssl=(val)
val = resolve_verify_ssl_value(val)
super
end
def verify_ssl?
verify_ssl != OpenSSL::SSL::VERIFY_NONE
end
# From endpoint, falling back to Settings, then to system CA bundle
def ssl_cert_store
certs = parse_certificate_authority
if certs.present?
store = OpenSSL::X509::Store.new
certs.each do |cert|
store.add_cert(cert)
end
return store
end
file = Settings.ssl.ssl_ca_file
path = Settings.ssl.ssl_ca_path
if file.present? || path.present?
store = OpenSSL::X509::Store.new
store.add_file(file) if file.present?
store.add_path(path) if path.present?
return store
end
nil # use system defaults
end
private
def resolve_verify_ssl_value(val)
case val
when true then OpenSSL::SSL::VERIFY_PEER
when false then OpenSSL::SSL::VERIFY_NONE
else val
end
end
# Returns a list, to support concatenated PEM certs.
def parse_certificate_authority
return [] if certificate_authority.blank?
certificate_authority.split(/(?=-----BEGIN)/).reject(&:blank?).collect do |pem_fragment|
OpenSSL::X509::Certificate.new(pem_fragment)
end
end
def validate_certificate_authority
parse_certificate_authority
rescue OpenSSL::OpenSSLError => err
errors.add(:certificate_authority, err.to_s)
end
def allow_duplicate_url?
resource.try(:allow_duplicate_endpoint_url?)
end
end