66

我已经按照Railscast #235尝试设置最小的 Facebook 身份验证。

我首先设置了一个 Twitter 身份验证,正如 Ryan 自己所做的那样。那工作完美无缺。

然后我继续添加 Facebook 登录。但是,在授权应用程序后,重定向/auth/facebook/callback失败并显示:

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

我正在本地主机上工作。我没有在应用程序中设置任何 SSL。我究竟做错了什么?

4

18 回答 18

74

真正的问题是法拉第(Omniauth/Oauth 用于他们的 HTTP 调用)没有为 OpenSSL 设置 ca_path 变量。至少在 Ubuntu 上,大多数根证书都存储在“/etc/ssl/certs”中。由于 Faraday不是没有设置这个变量(并且目前没有这样做的方法),因此 OpenSSL不是没有找到 Facebook 的 SSL 证书的根证书。

我已经向 Faraday 提交了一个拉取请求,它将增加对这个变量的支持,希望他们能尽快引入这个变化。在那之前,你可以猴子补丁法拉第看起来像这样或使用我的法拉第叉。之后,您应该在 Gemspec 中指定 OAuth2 gem 的 0.3.0 版本,它支持将 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

所以,回顾一下:

  1. Faraday 需要更新以支持 SSL ca_path。安装法拉第 0.6.1
  2. 您的应用需要使用 OAuth2 版本 0.3.0。您可能需要 fork omniauth,因为它目前在 0.2.x 树中具有次要版本依赖关系。升级到 OmniAuth 0.2.2
  3. 修改您的提供程序初始化程序以指向您系统的证书路径(Ubuntu 等上的“/etc/ssl/certs”)

希望 Faraday 和 Omniauth 的下一个版本将包含此解决方案。

感谢上面的 KirylP 让我走上了正确的道路。

于 2011-04-11T07:23:22.017 回答
18

我遇到了这个问题并尝试使用 :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
于 2011-04-30T06:01:35.013 回答
13

I am on ubuntu 10.10 (Maverick)... struggled about 6 hours before I got it to work, sharing my experience

  1. did not try monkey patch
  2. tried {:client_options => {:ssl => {:ca_path => "/etc/ssl/certs"}} but still not worked
  3. tried ruby 1.8.7 still not worked
  4. tried different versions of omniauth & faraday, still no luck.

The only thing that made it to work was following (thanks Alex)

if Rails.env.development? 
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE 
end
于 2011-04-23T17:41:56.240 回答
7

Managed to go through SSL Certificate Verification like it has to be. My project is using 37signals ID for Basecamp integration (Ruby 1.9.2-p130, Rails 3.0.4).

RAILS_ROOT/config/initializers/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

Where 'CLIENT_ID', 'CLIENT_SECRET' you can get at 37signals.com and certificates bundle file gd_bundle.crt from GoDaddy because 37signals are using their CA.

于 2011-02-11T15:02:52.483 回答
6

如果要部署到 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
于 2011-05-24T15:00:20.503 回答
5

我用 CA 包解决了这个问题:http: //certifie.com/ca-bundle/

在我的设计初始化程序中:

:client_options => { :ssl => { :ca_file => "#{Rails.root}/config/ca-bundle.crt" } } }
于 2011-06-28T12:49:07.773 回答
4

看起来 Omniauth 现在使用较新版本的法拉第,这就解释了为什么上面的猴子补丁对我不起作用。我同意必须有更好的方法,但对于只需要让它工作进行测试的其他人,这里有一个更新的版本:

(使用以下代码在您的初始化程序目录中创建一个文件)

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
于 2011-04-07T17:40:41.687 回答
4

所有的解决方案都对我不起作用,然后我发现了这个

http://railsapps.github.io/openssl-certificate-verify-failed.html

rvm osx-ssl-certs update all

osx 10.8 ruby​​ 2.0.0 通过 rvm

于 2013-08-13T18:38:35.390 回答
2

编辑:检查下面的答案,因为它更相关

这对我有用(修复由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
于 2010-12-07T17:07:49.283 回答
2

我正在使用 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' })
于 2011-05-08T02:29:59.347 回答
1

我知道这听起来微不足道,但请确保您使用的是正确的协议。我不断收到此错误,然后意识到我正在尝试通过 http 连接。浪费了1.5个小时,因为我是个白痴。

于 2012-12-04T11:33:57.210 回答
1

通过确保 openSSL 使用正确的证书目录解决了我的问题:

对于我的系统(ubuntu64),这是:ENV['SSL_CERT_DIR'] = '/usr/share/ca-certificates/'

这是在 JRuby 1.6.0 中使用 jruby-openssl

我刚刚将此设置添加到 development.rb

于 2011-04-24T01:27:27.787 回答
0

Just because instructions were a slight bit different for what worked for me, I thought I add my 2 cents:

I'm on OS X Lion and using macports and rvm

I installed curl-ca-bundle:

sudo port install curl-ca-bundle

Then I adjusted my omniauth config to be this:

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
于 2012-03-24T16:58:37.157 回答
0

我在 Mountain Lion 上使用 RVM 遇到了类似的错误。似乎 Ruby 找不到授权 SSL 连接所需的 CA 证书。你需要安装一个。这个解决方案成功了:

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

你完成了。

于 2012-09-13T21:04:30.853 回答
0

我终于找到了解决山狮的方法。见:http ://coderwall.com/p/f4hyqw

rvm pkg install openssl
rvm reinstall 1.9.3 --with-openssl-dir=$rvm_path/usr
于 2012-08-22T06:53:22.310 回答
0

这似乎是 1.9.x 的问题。恢复到 1.8.7 解决了这个问题。

于 2010-10-20T14:51:32.170 回答
0

如果您在 Leopard 上遇到具体问题,这就是我所做的帮助。

我的证书很旧,需要更新。我下载了这个:

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

然后替换了我在 Leopard 上找到的证书:

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

重新加载任何可以访问它的内容,您应该一切顺利!

于 2011-08-25T04:06:21.810 回答
0

On Ubuntu, all I had to do was update /environments/development.rb to:

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

and then:

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

wola!

于 2012-04-14T20:19:49.273 回答