OpenSSL::SSL::SSLError on Heroku [duplicate] - ruby-on-rails

This question already has answers here:
SSL Error When installing rubygems, Unable to pull data from 'https://rubygems.org/
(26 answers)
Closed 8 years ago.
I'm trying to authenticate a user via Facebook or Twitter, get them to fill out their information, and then click save (thus creating a user record). I'm getting an OpenSSL error on that final step -- after clicking save. This happens at the Devise RegistrationsController#create method.
So I'm getting this error in my Rails application, hosted on Heroku:
2012-07-28T18:25:13+00:00 app[web.1]: OpenSSL::SSL::SSLError (SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed)
I've seen plenty of solutions, none of them work. Here are some things I've tried:
1) Installing the certified gem
2) Upgrading the Heroku gem to v2.30, pushing again
3) This:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, TWITTER_KEY, TWITTER_SECRET, {:client_options => {:ssl => {:ca_file => "/usr/lib/ssl/certs/ca-certificates.crt"}}}
provider :facebook, FACEBOOK_KEY, FACEBOOK_SECRET, {:scope => "publish_actions,user_location,email", :client_options => {:ssl => {:ca_file => "/usr/lib/ssl/certs/ca-certificates.crt"}}}
end
It seems like one problem could be that this cert file doesn't actually exist -- I've seen it in several places, and it seems like that is the default path to the ca_cert file for Heroku, but I could be wrong.
Oddly enough, this is happening after I've already authenticated via FB/Twitter, and am trying to create a user's account. Why would this be, and how can I solve/debug this? Sincerely confused.
Update: I added this line to the Omniauth initializer, and now it "works". Thus I've diagnosed the problem is with Omniauth. However, I'd like to still have the SSL verification... this obviously leaves a security gap.
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

After some searching here is what I found:
If you’re using Ruby to open connections to an external server over https, eg. the Facebook Graph API, you may run into the following error:
OpenSSL::SSL::SSLError:SSL_connectreturned=1errno=0state=SSLv3readservercertificateB:certificateverifyfailed
This error is due to Ruby not being able to find the certification authority certificates (CA Certs) used to verify the authenticity of secured web servers. The solution is to download the this ca-bundle.crt into your application’s lib/ directory:
Then add the following code to config/initializers/fix_ssl.rb:
require 'open-uri'
require 'net/https'
module Net
class HTTP
alias_method :original_use_ssl=, :use_ssl=
def use_ssl=(flag)
self.ca_file = Rails.root.join('lib/ca-bundle.crt').to_s
self.verify_mode = OpenSSL::SSL::VERIFY_PEER
self.original_use_ssl = flag
end
end
end
This should force ruby to use the CA bundle from your application’s lib/ directory.
Taken from: http://jimneath.org/2011/10/19/ruby-ssl-certificate-verify-failed.html
UPDATE:
You may need to use self.ca_path= instead of self.ca_file= depending on your system.

It sounds like you've got the right openssl configuration in OmniAuth, but perhaps your CA certs path isn't correct?
You can check that on your heroku servers by running:
heroku run bash
... and then running openssl to display the proper path:
$ openssl version -a
OpenSSL 1.0.0e 6 Sep 2011
OPENSSLDIR: "/usr/lib/ssl"
... You should find the ca_certificates.crt file at $OPENSSLDIR/certs/ca-certificates.crt
I would confirm that path an update your code to match.

Related

Rails/Ubuntu: SSLv3 read server certificate B: certificate verify failed

Two days ago, I started seeing this error on the production server of my app (on staging everything works fine). I found a lot of topics here on SO, but none of them solved this issue for me.
Here's the piece of code that's causing this error message:
#client = Savon.client(wsdl: wsdl_url)
##client = Savon.client(wsdl: wsdl_url, ssl_verify_mode: :none) # this sovles the problem, but I don't want to skip the verification
On SO, I also found that a possible solution might be to create an initializer file and put there the following:
require 'open-uri'
require 'net/https'
module Net
class HTTP
alias_method :original_use_ssl=, :use_ssl=
def use_ssl=(flag)
#self.ca_path = Rails.root.join('lib/ca-bundle.crt').to_s
self.ssl_version = :TLSv1_2 # added
self.ca_file = '/etc/ssl/certs/ca-certificates.crt' # the file exists
self.verify_mode = OpenSSL::SSL::VERIFY_PEER
self.original_use_ssl = flag
end
end
end
But this, unfortunately, didn't solve the error. I also tried to reinstall the certificate on the production Ubuntu (14.04) server
sudo apt-get install openssl ca-certificates
The package has been upgraded, but the error is unfortunately still here.
Any tips what could I do yet and get rid of the error?
EDIT: How or where should I start debugging?
Run openssl s_client -showcerts -connect server_you_are_connecting_to.com:443 and examine the certificate. After this you should find yourself in one of the following situations:
The certificate is valid (has valid expiry date and common name), but it is signed by the certificate authority (CA) that isn't trusted by your system. If that's the case, you would need to add the CA's certificate to the trusted store or update the ca-bundle package on your system.
The certificate is invalid (is expired or has the wrong common name). If disabling peer SSL certificate verification isn't an option for you, then you can implement your own certificate verification callback, for example as described here -- in this case the code wouldn't be relying on system's trusted store, but rather check that the peer server uses a specific certificate.
Hope this helps.
I also started getting this error a few days ago.
Removing geocoder fixed the issue.
Per Heroku support, sometimes these errors occur when an external provider changes their SSL configuration.
Reply to comment:
Nothing in logs specifically saying geocoder, but I saw in my error reports (via exception notifier gem) that the app crashed, with this error, on lines making a request to geocoder.
I also had a callback on the users model, and noticed the app crashed anytime a user was saved/updated.
Lucky guess I suppose.

Write a custom OmniAuth strategy

I've got a Rail 4 app with Devise.
I'm trying to configure OmniAuth to use our corporate Ping OpenID Connect IdP.
It appears that I have to write an OmniAuth strategy in Rack Middleware.
I took the 'omniauth-digitalocean' gem (which has their strategy) and carefully replaced all references of 'digitalocean' with another name. I was careful to respect all case to conform to convention.
The problem I'm having now is that I appear to have a private gem.
I added it to my Gemfile with:
gem 'omniauth-private', :path => "/var/lib/gems/2.0.0/gems/omniauth-private-0.1.0"
I get no errors when I run 'bundle install'.
I was getting this error with 'rake db:migrate':
fatal: Not a git repository (or any of the parent directories): .git
I believe this was caused by a .gitignore file in my custom gem.
I deleted the .gitignore file and now I'm getting:
Devise::OmniAuth::StrategyNotFound: Could not find a strategy with name `Private'. Please ensure it is required or explicitly set it using the :strategy_class option.
This is the same error message I was getting before I figure out I needed to write n Omniuth strategy, so I think it means my gem is not being recognized.
So I'm not sure exactly what's going on. I think I'm struggling with this private gem. But it could be an OmniAuth problem too.
Anyone ever gotten a private OpenID Connect IdP working with OmniAuth?
I had the same "Could not find a strategy with the name..." with my custom Omniauth OAuth2 strategy.
I created a custom strategy as per these instructions https://github.com/intridea/omniauth-oauth2, and saved my file in config/initializers - this then loads the module on ruby boot.
I feel that I should be able to store this in the lib/ folder, but can't work out what the filename or folder structure should be!
You need to add:
require 'strategies/private'
to the top of config/devise.rb. This points to your strategy file at /lib/strategies/private.rb
The "fatal" error about "Not a git repo" comes from the fact that gems use 'git ls'. Just running "git init" should fix it. I did that and then committed to github.
"Could not find a strategy with the name..." error is fixed by loading the custom gem properly. I did that by adding this line to my Gemfile:
gem 'omniauth-private', :path => "/var/lib/gems/2.0.0/gems/omniauth-private-0.1.0
In your devise/initializers file check and make sure you have the correct name
of the auth you want to configure example:
config.omniauth :facebook, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :private, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'

How to deploy a Rails application with an internally signed SSL certificate (SSL_CERT_FILE and openssl related)

I have a few questions regarding deploying a Rails application with an SSL certificate.
Background:
Rails 3.2.16 / Ruby 1.9.3
SAN SSL certificate signed by internal Windows CA server
App deployed to Ubuntu 12.04 servers with Apache/Passenger
As per, https://gist.github.com/fnichol/867550, Windows clients using Ruby net/http do not trust the certificate on the Ubuntu severs. I assume this is becuase the SSL_CERT_FILE environment variable is not set (despite the fact the internal root certificates are installed on the Ubuntu servers and deployed to Windows clients by Group Policy..?)
I want to be able to run the following code snippet from any client of my app (Windows or Ubuntu)
require 'net/http'
uri = URI.parse('https://ubuntu-server.internal.com/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.start { |agent| agent.get(uri.path) }
Should i bundle the internal CA root certificate (and intermediate certificate, and the rest of the CURL cert bundle) with the app and then set ENV['SSL_CERT_FILE'] in code?)
Should i include only the internal CA root certificate in the app and use an initializer to setup net/http before use? This seems to be the approach of the RubyInstaller https://github.com/oneclick/rubyinstaller/blob/master/rake/contrib/uri_ext.rb#L287-295 but i don't really know how i would go about coding this?
Something else?
Option 2 seems the best to me so far, but as I say i dont know how i would go about setting
http.use_ssl = true
http.ca_file = "#{Rails.root}/config/internal-ca.crt"
in a Rails initializer.
Any help / advice would be greatly appreciated.
Thanks
So, with some further Googling i've come up with the following solution:
# /config/initializers/ssl.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
store.add_cert(OpenSSL::X509::Certificate.new(File.read("#{Rails.root}/config/ssl/root.crt")))
store.add_cert(OpenSSL::X509::Certificate.new(File.read("#{Rails.root}/config/ssl/intermediate.crt")))
self.cert_store = store
self.verify_mode = OpenSSL::SSL::VERIFY_PEER
self.original_use_ssl = flag
end
end
end
Sources
http://gistflow.com/posts/227-net-http-cheat-sheet
http://jjinux.blogspot.nl/2012/02/ruby-working-around-ssl-errors-on-os-x.html
This seems to work for me, but i am open to other suggestions.

How do I set an SSL certificate for Resque on Heroku?

I'm trying to debug a failed job on a production environment version of Resque because this is all the web interface gives me to work with:
Worker: 9c9fe9d3-8ee0-43fe-afcd-c6806fc75f0d:2 on sentiment_pull at just now
Class: SentimentJob
Arguments: [16, 17, 18]13
Exception: OpenSSL::SSL::SSLError
Error: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
This works in development and I'm not sure why I'd get an OpenSSL error on Heroku. I am also using Omniauth so in that initializer I have already set:
Rails.application.config.middleware.use OmniAuth::Builder do
provider #...
:client_options => {:ssl => {:ca_path => "/etc/ssl/certs"}}
end
I haven't found any examples of Resque requiring an SSL certificate on Heroku so I'm a bit stumped because the job is set to do requests on an HTTPS URL.
I've recently had this problem and despite there being plenty of answers out there on how to fix it, this was the only one that worked for me (I'm not on Heroku but instead a Debian VPS). This is a bad idea most of the time but is fine for my usage case where I need to accept self-signed SSL records.
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
This will cause OpenSSL to not verify SSL records and will suppress the error.

How to solve "certificate verify failed" on Windows?

I am trying to use signet for OAuth to Google services. And get this error:
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
Following these questions:
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
OmniAuth & Facebook: certificate verify failed
Seems the solution is either to fix ca_path or to set VERIFY_NONE for SSL.
The ca_path fix posted only works on Linux (port install) and the fix for VERIFY_NONE seems to be for faraday.
Is there a solution for Windows/signet gem?
Actually the best way I found to solve this in windows for Ruby itself, not just one gem, is to do the following:
Download https://curl.haxx.se/ca/cacert.pem into c:\railsinstaller\cacert.pem. Make sure you save it as a .pem file, rather than a text file.
Go to your Computer -> Advanced Settings -> Environment Variables
Create a new System Variable:
Variable: SSL_CERT_FILE
Value: C:\RailsInstaller\cacert.pem
Close all your command prompts, including your Rails server command prompt, etc.
Start a new ruby irb prompt, and try the following:
$irb>require 'open-uri'
$irb>open('https://www.gmail.com')
It should all work now just fine.
Solution for Windows, which I cobbled together from a few different answers:
Download https://curl.haxx.se/ca/cacert.pem and put it in YOUR_APP/lib/assets (or wherever)
In config/initializers/omniauth.rb:
#config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, CUSTOMER_KEY, CUSTOMER_SECRET, {client_options: {ssl: {ca_file: Rails.root.join('lib/assets/cacert.pem').to_s}}}
end
Obviously, restart your server.
Footnotes:
You might be able to cut out a lot of the unnecessary certificates in the cacert.pem file to reduce the size. If you only need this solution for development, you could save the file outside of your project and do a if Rails.env.development? _provider line with the client_options hash_ else _provider line without client_options hash_ end
After too much searching and wasted time, I found a very simple solution to fix this issue in Ruby with Windows.
Two simple steps:
In command prompt write: C:\gem install certified
In your rb file add: require 'certified'
That's it.
Updating the rubygems package management framework solved this issue for me on Windows 7.
https://rubygems.org/pages/download
gem update --system # may need to be administrator or root
yes, I've set the omniouth.rb file in the initializers folder to this:
provider :facebook, FACEBOOK_KEY, FACEBOOK_SECRET, {:client_options => {:ssl => {:verify => false}}}
and this seems to work fine now. But don't use this for production.
Using the http:// URL instead of https:// make this easier to you
Change the gem source to http://rubygems.org/ by using the following line of command on your ruby command line
gem sources -a http://rubygems.org/
Adding onto DevDude's solution, but using Windows Powershell:
Download http://curl.haxx.se/ca/cacert.pem into c:\railsinstaller\cacert.pem
At the powershell prompt:
$env:SSL_CERT_FILE = 'c:\RailsInstaller\cacert.pem'
I was then able to run gem update successfully
Note: you can simply define that environment variable in your profile notepad $profile
Go to the rubygems-update download page: https://rubygems.org/gems/rubygems-update
Click on the Download link, and you'll download a file called rubygems-update-2.6.7.gem. At the command line, navigate to the directory you downloaded the .gem file to and type:
gem install rubygems-update-2.6.7.gem
(or whatever the filename was, if a newer version)
Then type:
update_rubygems
You can verify it's updated with:
gem --version
I had this error whilst trying to setup rails 5 on a windows machine, turns out I had to update the rubygem version to 2.6.7 and then it worked.
step 1 download rubygem from below
https://rubygems.org/downloads/rubygems-update-2.6.7.gem
step 2 - install by pointing to downloaded rubygems
gem install --local C:\rubygems-update-2.6.7.gem
step 3 - check new version is 2.6.7
gem --version
step 4 - now safely un-install rubygems-update gem
gem uninstall rubygems-update -x
step 5 tried to install rails 5 again
gem install rails --version 5.0.0
worked like a charm!
I got info from:
http://guides.rubygems.org/ssl-certificate-update/#installing-using-update-packages
I was able to eliminate the PATH or SYSTEM VARIABLE setting mentioned above by importing the certificate as a Trusted Authority.
Invoke certmgr.msc
Right-click the Trusted Root Certificate Authority folder.
Select "All Tasks"
Select "Import"
Select All Files in file type dropdown and select the cacert.pem file.
You should receive a message "Import Successful"
I believe the correct answer is to update your gem installer: rubygems-update. The explanation for why this is needed is found at: Ssl Certificate Updates
save your cacert.pmp file from https://curl.haxx.se/ca/cacert.pem and then add this file to location yourruby-installation folder\lib\ruby\2.3.0\rubygems\ssl_certs
for example:C:\Ruby23\lib\ruby\2.3.0\rubygems\ssl_certs
This helped me:
https://coderwall.com/p/ubl6iw/fix-ssl_connect-returned-1-errno-0-state-sslv3-read-server-certificate-b-certificate-verify-failed-openssl-ssl-sslerror
My ruby on rails project is posting data to an api internally, and it cannot verify the internal certificate.
These lines helped:
require 'https'
http = Net::HTTP.new('example.com', 443)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.cert_store = OpenSSL::X509::Store.new
http.cert_store.set_default_paths
http.cert_store.add_file('/path/to/internal.cert.pem')
Hope this can help.
I was also facing this issue when I installed older ruby versions. When I installed the latest Ruby version this problem went away. So basically the SSL certificate needed to be updated.
For people who are using rails 4.
Add this in devise.rb
require "omniauth-google-oauth2"
config.omniauth :google_oauth2, "CLIENT_ID", "CLIENT_SECRET", { access_type: "offline", approval_prompt: "", :client_options => {:ssl => {:verify => false}} }

Resources