ruby-on-rails - 猴子修补 use_ssl= 方法适用于 Net :HTTP but not for OpenURI in Ruby 1. 9.3?

标签 ruby-on-rails ruby ssl net-http open-uri

背景:

  • ruby 1.9.3
  • rails 3.2.16
  • Windows 7 x64

问题

我正在努力解决臭名昭著的问题

SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

在我执行的每个 HTTP 请求中包含我的证书时出错。为此,我猴子修补 Net::HTTP#use_ssl=:

# lib/gem_ext/net_http.rb
require 'open-uri'
require 'net/https'

module Net
  class HTTP
    alias_method :original_use_ssl=, :use_ssl=

    def use_ssl=(flag)
      store = OpenSSL::X509::Store.new
      store.set_default_paths # Auto-include the system CAs.

      Dir[Rails.root + 'config/certificates/*'].each do |cert|
        puts "Adding cert: #{cert}"
        store.add_cert(OpenSSL::X509::Certificate.new(File.read(cert)))
      end

      self.cert_store = store
      self.verify_mode = OpenSSL::SSL::VERIFY_PEER
      self.original_use_ssl = flag
    end
  end
end

现在,使用 Net::HTTP 执行请求,例如:

> uri = URI.parse('https://internal-app/secure_url.json?foo=bar')
> Net::HTTP.start(uri.host, uri.port, :read_timeout => 10.minutes, :use_ssl => uri.scheme == 'https') do |http|
>  http.request Net::HTTP::Get.new(uri.request_uri)
> end
Adding cert: config/certificates/cert1.cer
Adding cert: config/certificates/cert2.cer
=> #<Net::HTTPOK 200 OK readbody=true>

完美运行。

但是,当我尝试使用 OpenURI 时,我认为它只是 Net::HTTP(和其他 IO 操作)的包装器,例如:

> require 'open-uri'    
> open('https://our-all/secure_url.json?foo=bar', 'r', :read_timeout => 10.minutes)
Adding cert: config/certificates/cert1.cer
Adding cert: config/certificates/cert2.cer
#<Class:0x870e2e0>: SSL_connect returned=1 errno=0 state=SSLv3 read server certi
  from D:/Ruby/Ruby193/lib/ruby/1.9.1/net/http.rb:800:in `connect'
  from D:/Ruby/Ruby193/lib/ruby/1.9.1/net/http.rb:800:in `block in connect

所以我可以看到我的猴子修补方法被击中(“添加证书..”),但我仍然收到错误。似乎有别的东西在压倒它。有什么想法吗?

谢谢

最佳答案

我设法想出了一个解决方案(前一段时间,所以我希望它仍然适用)。

根据我的代码中的评论,我需要猴子补丁 cert_store= 以及“as use_ssl= as Net::HTTPOpenURI.open_http以不同的顺序调用这些方法,因此我们需要确保一致地添加证书。”

所以,这是我的解决方案:

module Net
  class HTTP

    alias_method :original_use_ssl=, :use_ssl=
    def use_ssl=(flag)
      store = OpenSSL::X509::Store.new
      store.set_default_paths # Auto-include the system CAs.
      self.cert_store = store # Now include internal certificates.
      self.verify_mode = OpenSSL::SSL::VERIFY_PEER # Force verification.
      self.original_use_ssl = flag
    end

    alias_method :original_cert_store=, :cert_store=
    def cert_store=(store)
      Dir[Rails.root + 'config/certificates/*'].each do |cert|
        store.add_cert(OpenSSL::X509::Certificate.new(File.read(cert)))
      end

      self.original_cert_store = store
    end
  end
end

希望对你有帮助

关于ruby-on-rails - 猴子修补 use_ssl= 方法适用于 Net :HTTP but not for OpenURI in Ruby 1. 9.3?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21599821/

相关文章:

ruby-on-rails - nokogiri gem 安装错误

android - RUBYMOTION_ANDROID_SDK 不正确

ruby-on-rails - 如何通过助手名称获取路线?

ssl - 更新 SSL 证书的 PKI 最佳实践

c++ - 为什么没有 asio::ssl::iostream? (以及如何实现)

ruby-on-rails - 在 Rails 中,数据库锁定是否会确保只有进程一次检查属性值而不会成为巨大的瓶颈?

ruby-on-rails - 在网络应用程序中使用开源代码/软件

ruby-on-rails - 为什么要使用相互的 has_one 关系?

ruby-on-rails - rails,将未定义的属性添加到 form_tag

ssl - 是否可以在不需要 native 库和 APR 的情况下使用 OpenSSL 为 Tomcat 启用 HTTPS/TLS?