Skip to content

Commit

Permalink
add support for SSL peer verification in EventMachine
Browse files Browse the repository at this point in the history
Prior to this EM was happily making HTTPS requests while ignoring server
certificate info. Shocking, I know.
  • Loading branch information
mislav committed Jul 27, 2013
1 parent 5b6f89d commit 63cf47c
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
24 changes: 24 additions & 0 deletions lib/faraday/adapter/em_http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def connection_config(env)
configure_proxy(options, env)
configure_timeout(options, env)
configure_socket(options, env)
configure_ssl(options, env)
options
end

Expand Down Expand Up @@ -48,6 +49,15 @@ def configure_socket(options, env)
end
end

def configure_ssl(options, env)
if env[:url].scheme == 'https' && env[:ssl]
options[:ssl] = {
:cert_chain_file => env[:ssl][:ca_file],
:verify_peer => env[:ssl].fetch(:verify, true)
}
end
end

def configure_timeout(options, env)
timeout, open_timeout = request_options(env).values_at(:timeout, :open_timeout)
options[:connect_timeout] = options[:inactivity_timeout] = timeout
Expand Down Expand Up @@ -118,6 +128,12 @@ def perform_request(env)
else
raise Error::ConnectionFailed, err
end
rescue => err
if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
raise Faraday::SSLError, err
else
raise
end
end

# TODO: reuse the connection to support pipelining
Expand Down Expand Up @@ -211,3 +227,11 @@ def check_finished
end
end
end

begin
require 'openssl'
rescue LoadError
warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support"
else
require 'faraday/adapter/em_http_ssl_patch'
end if Faraday::Adapter::EMHttp.loaded?
56 changes: 56 additions & 0 deletions lib/faraday/adapter/em_http_ssl_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require 'openssl'
require 'em-http'

module EmHttpSslPatch
def ssl_verify_peer(cert_string)
cert = nil
begin
cert = OpenSSL::X509::Certificate.new(cert_string)
rescue OpenSSL::X509::CertificateError
return false
end

@last_seen_cert = cert

if certificate_store.verify(@last_seen_cert)
begin
certificate_store.add_cert(@last_seen_cert)
rescue OpenSSL::X509::StoreError => e
raise e unless e.message == 'cert already in hash table'
end
true
else
raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}"))
end
end

def ssl_handshake_completed
return true unless verify_peer?

unless OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
raise OpenSSL::SSL::SSLError.new(%(host "#{host}" does not match the server certificate))
else
true
end
end

def verify_peer?
parent.connopts.tls[:verify_peer]
end

def host
parent.connopts.host
end

def certificate_store
@certificate_store ||= begin
store = OpenSSL::X509::Store.new
store.set_default_paths
ca_file = parent.connopts.tls[:cert_chain_file]
store.add_file(ca_file) if ca_file
store
end
end
end

EventMachine::HttpStubConnection.send(:include, EmHttpSslPatch)
14 changes: 14 additions & 0 deletions lib/faraday/adapter/em_synchrony.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,23 @@ def call(env)
else
raise Error::ConnectionFailed, err
end
rescue => err
if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
raise Faraday::SSLError, err
else
raise
end
end
end
end
end

require 'faraday/adapter/em_synchrony/parallel_manager'

begin
require 'openssl'
rescue LoadError
warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support"
else
require 'faraday/adapter/em_http_ssl_patch'
end if Faraday::Adapter::EMSynchrony.loaded?

0 comments on commit 63cf47c

Please sign in to comment.