zammad/app/models/setting/validation/saml/security.rb
2026-01-02 15:41:09 +02:00

94 lines
2.2 KiB
Ruby

# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
class Setting::Validation::Saml::Security < Setting::Validation::Base
def run
return result_success if value.blank? || disabled_security?
%w[check_security_prerequisites check_private_key].each do |method|
msg = send(method)
next if msg.nil?
return result_failed(msg)
end
cert = read_certificate
return result_failed(__('The certificate could not be parsed.')) if cert.nil?
msg = check_certificate(cert)
{
success: msg.nil?,
message: msg,
}
end
private
def disabled_security?
value.fetch('security', 'off').eql?('off')
end
def check_security_prerequisites
return __('No certificate found.') if certificate_pem.blank?
return __('No private key found.') if private_key_pem.blank?
nil
end
def check_private_key
begin
private_key = OpenSSL::PKey.read(private_key_pem, private_key_secret)
return __('The type of the private key is wrong.') if !private_key.class.name.end_with?('RSA')
return __('The length of the private key is too short.') if private_key.n.num_bits < 2048
rescue => e
return e.message
end
nil
end
def read_certificate
begin
cert = Certificate::X509.new(certificate_pem)
rescue
return nil
end
cert
end
def check_certificate(cert)
return __('The certificate is not usable due to being a CA certificate.') if cert.ca?
return __('The certificate is not usable (e.g. expired).') if !cert.usable?
return __('The certificate is not usable for signing and encryption.') if !cert.signature? || !cert.encryption?
msg = check_cert_key_match(cert)
return msg if !msg.nil?
nil
end
def check_cert_key_match(cert)
begin
return __('The certificate does not match the given private key.') if !cert.key_match?(private_key_pem, private_key_secret)
rescue => e
return e.message
end
nil
end
def certificate_pem
@certificate_pem ||= value.fetch('certificate', '')
end
def private_key_pem
@private_key_pem ||= value.fetch('private_key', '')
end
def private_key_secret
@private_key_secret ||= value.fetch('private_key_secret', '')
end
end