security.rb 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class Setting::Validation::Saml::Security < Setting::Validation::Base
  3. def run
  4. return result_success if value.blank? || disabled_security?
  5. %w[check_security_prerequisites check_private_key].each do |method|
  6. msg = send(method)
  7. next if msg.nil?
  8. return result_failed(msg)
  9. end
  10. cert = read_certificate
  11. return result_failed(__('The certificate could not be parsed.')) if cert.nil?
  12. msg = check_certificate(cert)
  13. {
  14. success: msg.nil?,
  15. message: msg,
  16. }
  17. end
  18. private
  19. def disabled_security?
  20. value.fetch('security', 'off').eql?('off')
  21. end
  22. def check_security_prerequisites
  23. return __('No certificate found.') if certificate_pem.blank?
  24. return __('No private key found.') if private_key_pem.blank?
  25. nil
  26. end
  27. def check_private_key
  28. begin
  29. private_key = OpenSSL::PKey.read(private_key_pem, private_key_secret)
  30. return __('The type of the private key is wrong.') if !private_key.class.name.end_with?('RSA')
  31. return __('The length of the private key is too short.') if private_key.n.num_bits < 2048
  32. rescue => e
  33. return e.message
  34. end
  35. nil
  36. end
  37. def read_certificate
  38. begin
  39. cert = Certificate::X509.new(certificate_pem)
  40. rescue
  41. return nil
  42. end
  43. cert
  44. end
  45. def check_certificate(cert)
  46. return __('The certificate is not usable due to being a CA certificate.') if cert.ca?
  47. return __('The certificate is not usable (e.g. expired).') if !cert.usable?
  48. return __('The certificate is not usable for signing and encryption.') if !cert.signature? || !cert.encryption?
  49. msg = check_cert_key_match(cert)
  50. return msg if !msg.nil?
  51. nil
  52. end
  53. def check_cert_key_match(cert)
  54. begin
  55. return __('The certificate does not match the given private key.') if !cert.key_match?(private_key_pem, private_key_secret)
  56. rescue => e
  57. return e.message
  58. end
  59. nil
  60. end
  61. def certificate_pem
  62. @certificate_pem ||= value.fetch('certificate', '')
  63. end
  64. def private_key_pem
  65. @private_key_pem ||= value.fetch('private_key', '')
  66. end
  67. def private_key_secret
  68. @private_key_secret ||= value.fetch('private_key_secret', '')
  69. end
  70. end