Исправление обезьяны методом use_ssl= работает для Net: HTTP, но не для OpenURI в Ruby 1.9.3?

Общие сведения:

  • Руби 1.9.3
  • Рельсы 3.2.16
  • виндовс 7 х64

Проблема

Я пытаюсь исправить печально известный

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 (и других операций ввода-вывода), например:

> 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

Итак, я вижу, что мой исправленный метод обезьяны срабатывает («Добавление сертификата ..»), но все же я получаю сообщение об ошибке. Кажется, что что-то другое перевешивает его. Любые идеи?

Спасибо


person rwb    schedule 06.02.2014    source источник
comment
ты когда-нибудь это понял?   -  person azurewraith    schedule 05.06.2015


Ответы (1)


Мне удалось найти решение (некоторое время назад, поэтому я надеюсь, что оно все еще применимо).

Согласно комментариям в моем коде, мне нужно было исправить cert_store=, а также «а также use_ssl=, Net::HTTP и OpenURI.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

надеюсь, это поможет

person rwb    schedule 08.06.2015