OmniAuth & Facebook: проверка сертификата не выполнена

Я следил за Railscast # 235, чтобы попытаться установить минимальную аутентификацию Facebook.

Сначала я настроил аутентификацию Twitter, как это сделал сам Райан. Это работало безупречно.

Затем я перешел к добавлению входа в Facebook. Однако после авторизации приложения перенаправление на /auth/facebook/callback не выполняется:

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

Я работаю над localhost. Я не установил SSL в приложении. Что я делаю неправильно?

Ответ 1

Реальная проблема заключается в том, что Faraday (который использует Omniauth/Oauth для своих HTTP-вызовов) is not не задавал переменную ca_path для OpenSSL. По крайней мере, на Ubuntu большинство корневых сертификатов хранятся в "/etc/ssl/certs". Поскольку Faraday не не устанавливал эту переменную (и в настоящее время не имеет метода для этого), OpenSSL не wasn 't найти корневой сертификат для SSL-сертификата Facebook.

Я отправил запрос на передачу в Faraday, который добавит поддержку этой переменной, и, надеюсь, они скоро потянут это изменение, До тех пор вы можете monkeypatch faraday выглядеть как this или использовать мою вилку Фарадей. После этого вы должны указать версию 0.3.0 из OAuth2 gem в Gemspec, которая поддерживает передачу опций SSL до Faraday. Теперь вам нужно обновить до Faraday 0.6.1, который поддерживает передачу переменную ca_path и обновление до OmniAuth 0.2.2, которая имеет соответствующие зависимости для OAuth2. Затем вы сможете правильно исправить эту проблему, просто добавив следующее в свой инициализатор Omniauth:

Rails.application.config.middleware.use OmniAuth::Builder do
    provider :facebook, FACEBOOK_KEY, FACEBOOK_SECRET, {:client_options => {:ssl => {:ca_path => "/etc/ssl/certs"}}}
end

Итак, чтобы повторить:

  • Faraday необходимо обновить, чтобы поддерживать SSL ca_path. Установить Faraday 0.6.1
  • Ваше приложение должно использовать OAuth2 версии 0.3.0. Возможно, вам понадобится fork omniauth, так как в настоящее время он имеет незначительную версию зависимости в дереве 0.2.x. Обновление до OmniAuth 0.2.2
  • Измените инициализатор поставщика, чтобы указать путь к вашему системному сертификату ( "/etc/ssl/certs" в Ubuntu и др.)

Будем надеяться, что в следующих версиях как Faraday, так и Omniauth будет включено это решение.

Спасибо KirylP выше, чтобы установить меня на правильный путь.

Ответ 2

У меня возникла эта проблема и я попытался использовать аргумент: ca_path без успеха. Посмотрев через Github некоторое время, я наткнулся на предложение, которое упоминалось с использованием: ca_file и прямо указывает на сертификацию.

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :facebook, 'secret_key', 'secret_key',
   :client_options => {:ssl => {:ca_file => '/etc/pki/tls/certs/ca-bundle.crt'}}}
end

Если вам нужно получить путь к файлам системной сертификации (и вашему использованию linux), просто введите из терминала. Это даст вам кучу информации о вашей настройке SSL, включая путь (см. OPENSSLDIR). Вам нужно добавить certs/ca-bundle.crt к предоставленному пути.

open-ssl version -a

Ответ 3

Я на ubuntu 10.10 (Maverick)... боролся около 6 часов, прежде чем я получил его на работу, поделился своим опытом

  • не пробовал патч обезьяны
  • try {: client_options = > {: ssl = > {: ca_path = > "/etc/ssl/certs" }}, но все еще не работает
  • попробовал ruby ​​1.8.7 все еще не работал
  • попробовал разные версии omniauth и faraday, до сих пор не повезло.

Единственное, что заставило его работать, было следующее (спасибо Alex)

if Rails.env.development? 
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE 
end

Ответ 4

Удалось пройти проверку SSL-сертификата, как и должно быть. Мой проект использует идентификатор 37signals для интеграции Basecamp (Ruby 1.9.2-p130, Rails 3.0.4).

RAILS_ROOT/конфигурации/Инициализаторы/omniauth.rb

require 'omniauth/oauth'

Rails.application.config.middleware.use OmniAuth::Strategies::ThirtySevenSignals,
    'CLIENT_ID', 'CLIENT_SECRET', {client_options: {ssl: {ca_file: Rails.root.join('gd_bundle.crt').to_s}}}

module OAuth2
  class Client
    def initialize(client_id, client_secret, opts = {})
      adapter = opts.delete(:adapter)
      self.id = client_id
      self.secret = client_secret
      self.site = opts.delete(:site) if opts[:site]
      self.options = opts
      self.connection = Faraday::Connection.new(site, {ssl: opts.delete(:ssl)})
      self.json = opts.delete(:parse_json)        # ^ my code starts here

      if adapter && adapter != :test
        connection.build { |b| b.adapter(adapter) }
      end
    end
  end
end

Где 'CLIENT_ID', 'CLIENT_SECRET' вы можете получить 37signals.com и файл пакета сертификатов gd_bundle.crt из GoDaddy, поскольку 37signals используют свой CA.

Ответ 5

Если вы развертываете в Heroku, вы хотите указать на конкретное расположение файла. Это работает для меня (в config/initializers/omniauth.rb):

Rails.application.config.middleware.use OmniAuth::Builder do
  # This cert location is only for Heroku
  provider :facebook, APP_ID, APP_SECRET, {:client_options => {:ssl => {:ca_file => "/usr/lib/ssl/certs/ca-certificates.crt"}}}
end

Ответ 6

Я решил это с помощью пакета CA из: http://certifie.com/ca-bundle/

И в моем инициализаторе Devise:

:client_options => { :ssl => { :ca_file => "#{Rails.root}/config/ca-bundle.crt" } } }

Ответ 7

Похоже, Omniauth теперь использует более новую версию Faraday, которая объясняет, почему надпись на обезьяне выше не работала для меня. Я согласен, что должен быть лучший способ, но для тех, кому просто нужно заставить его работать, чтобы проверить, здесь обновленная версия:

(создайте файл в каталоге инициализаций со следующим кодом)

require 'faraday'
module Faraday
class Adapter
 class NetHttp < Faraday::Adapter
  def call(env)
  super
  url = env[:url]
  req = env[:request]

  http = net_http_class(env).new(url.host, url.inferred_port)

  if http.use_ssl = (url.scheme == 'https' && env[:ssl])
    ssl = env[:ssl]
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    http.cert        = ssl[:client_cert] if ssl[:client_cert]
    http.key         = ssl[:client_key]  if ssl[:client_key]
    http.ca_file     = ssl[:ca_file]     if ssl[:ca_file]
    http.cert_store  = ssl[:cert_store]  if ssl[:cert_store]
  end

  http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
  http.open_timeout = req[:open_timeout]                if req[:open_timeout]

  if :get != env[:method]
    http_request = Net::HTTPGenericRequest.new \
      env[:method].to_s.upcase,    # request method
      !!env[:body],                # is there data
      true,                        # does net/http love you, true or false?
      url.request_uri,             # request uri path
      env[:request_headers]        # request headers

    if env[:body].respond_to?(:read)
      http_request.body_stream = env[:body]
      env[:body] = nil
    end
  end

  begin
    http_response = if :get == env[:method]
      # prefer `get` to `request` because the former handles gzip (ruby 1.9)
      http.get url.request_uri, env[:request_headers]
    else
      http.request http_request, env[:body]
    end
  rescue Errno::ECONNREFUSED
    raise Error::ConnectionFailed, $!
  end

  http_response.each_header do |key, value|
    response_headers(env)[key] = value
  end
  env.update :status => http_response.code.to_i, :body => http_response.body

  @app.call env
end
end
end
end

Ответ 9

Изменить: проверьте ответ ниже, поскольку он более релевантен

Это сработало для меня (исправить любезно https://github.com/jspooner):

Создайте файл в каталоге инициализатора со следующим патчем обезьяны:

require 'faraday'
module Faraday
class Adapter
 class NetHttp < Faraday::Adapter
  def call(env)
    super

    is_ssl = env[:url].scheme == 'https'

    http = net_http_class(env).new(env[:url].host, env[:url].port || (is_ssl ? 443 : 80))
    if http.use_ssl = is_ssl
      ssl = env[:ssl]
      if ssl[:verify] == false
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      else
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE # <= PATCH or HACK ssl[:verify]
      end
      http.cert    = ssl[:client_cert] if ssl[:client_cert]
      http.key     = ssl[:client_key]  if ssl[:client_key]
      http.ca_file = ssl[:ca_file]     if ssl[:ca_file]
    end
    req = env[:request]
    http.read_timeout = net.open_timeout = req[:timeout] if req[:timeout]
    http.open_timeout = req[:open_timeout]               if req[:open_timeout]

    full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
    http_req  = Net::HTTPGenericRequest.new(
      env[:method].to_s.upcase,    # request method
      (env[:body] ? true : false), # is there data
      true,                        # does net/http love you, true or false?
      full_path,                   # request uri path
    env[:request_headers])       # request headers

    if env[:body].respond_to?(:read)
      http_req.body_stream = env[:body]
      env[:body] = nil
    end

    http_resp = http.request http_req, env[:body]

    resp_headers = {}
    http_resp.each_header do |key, value|
      resp_headers[key] = value
    end

    env.update \
      :status           => http_resp.code.to_i,
      :response_headers => resp_headers,
      :body             => http_resp.body

    @app.call env
  rescue Errno::ECONNREFUSED
    raise Error::ConnectionFailed.new(Errno::ECONNREFUSED)
  end

  def net_http_class(env)
    if proxy = env[:request][:proxy]
      Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
    else
      Net::HTTP
    end
  end
 end
end
end

Ответ 10

Я использую Faraday 0.6.1 и OAUTH2 (один, не обернутый чем-либо). Этого было достаточно, чтобы решить эту проблему для меня (на Gentoo, должен работать на Ubunto)

Поверните это

  client = OAuth2::Client.new(FACEBOOK_API_KEY, FACEBOOK_API_SECRET, :site => FACEBOOK_API_SITE)

В этот

  client = OAuth2::Client.new(FACEBOOK_API_KEY, FACEBOOK_API_SECRET, :site => FACEBOOK_API_SITE, :ssl => {:ca_path => '/etc/ssl/certs' })

Ответ 11

Моя проблема была решена путем обеспечения того, чтобы openSSL использовал правильный каталог сертификата:

Для моей системы (ubuntu64) это было: ENV ['SSL_CERT_DIR'] = '/usr/share/ca-certificates/'

Это использовало jruby-openssl с JRuby 1.6.0

Я добавил этот параметр в development.rb

Ответ 12

Я знаю, что это звучит тривиально, но убедитесь, что вы используете правильный протокол. Я продолжал получать эту ошибку, а затем понял, что пытаюсь подключиться через http. 1,5 часа впустую, потому что я идиот.

Ответ 13

Кажется, это проблема 1.9.x. Возврат к 1.8.7 исправил проблему.

Ответ 14

Вот что я сделал, что помогло, если у вас есть проблема с Leopard.

Мой сертификат был старым и нуждался в обновлении. Я скачал это:

http://curl.haxx.se/ca/cacert.pem

Затем заменил мой сертификат, который был найден здесь на Leopard:

/usr/share/curl/curl-ca-bundle.crt

Перезагрузите все, что у вас есть, и вы должны быть добрыми!

Ответ 15

Просто потому, что инструкции были немного разными для того, что сработало для меня, я думал, что добавляю свои 2 цента:

Я нахожусь в OS X Lion и использую macports и rvm

Я установил curl-ca-bundle:

sudo port install curl-ca-bundle

Затем я скорректировал свою конфигурацию omniauth следующим образом:

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, APP_CONFIG['CONSUMER_KEY'], APP_CONFIG['CONSUMER_SECRET'],
           :scope => 'https://www.google.com/m8/feeds https://www.googleapis.com/auth/userinfo.profile',
           :ssl => {:ca_path => "/share/curl/curl-ca-bundle.crt"}
end

Ответ 16

В Ubuntu все, что мне нужно было сделать, это update/environments/development.rb:

Rails.application.config.middleware.use OmniAuth::Builder do
    provider :facebook, FACEBOOK_KEY, FACEBOOK_SECRET, {:client_options => {:ssl => {:ca_path => "/etc/ssl/certs"}}}
end

а затем:

cd /etc/ssl/certs
sudo wget http://curl.haxx.se/ca/cacert.pem

Wola!

Ответ 17

Наконец-то я нашел исправление для Mountain Lion. См.: http://coderwall.com/p/f4hyqw

rvm pkg install openssl
rvm reinstall 1.9.3 --with-openssl-dir=$rvm_path/usr

Ответ 18

Я столкнулся с аналогичной ошибкой, используя RVM на Mountain Lion. Кажется, что Ruby не может найти сертификат CA, которому необходимо разрешить SSL-соединение. Вам нужно установить его. Это решение выполнило трюк:

http://fredwu.me/post/28834446907/fix-openssl-error-on-mountain-lion-and-rvm

(Хотя я не мог загрузить эту страницу в своем браузере, мне пришлось найти ее в кеше Google.)

Вот короткий ответ:

curl http://curl.haxx.se/ca/cacert.pem -o ~/.rvm/usr/ssl/cert.pem

И все готово.