1
0
Fork 0
mirror of https://github.com/rest-client/rest-client.git synced 2022-11-09 13:49:40 -05:00

Merge pull request #277 from ab/ab-ssl-verify-callback

Expose verify_callback to users
This commit is contained in:
Andy Brody 2014-04-09 22:22:13 -07:00
commit e7592a65e3
4 changed files with 122 additions and 6 deletions

View file

@ -17,5 +17,14 @@ module RestClient
# library uses that to test what platform it's on.
!!File::ALT_SEPARATOR
end
# Return true if we are running on jruby.
#
# @return [Boolean]
#
def self.jruby?
# defined on mri >= 1.9
RUBY_ENGINE == 'jruby'
end
end
end

View file

@ -26,7 +26,7 @@ module RestClient
# * :timeout and :open_timeout are how long to wait for a response and to
# open a connection, in seconds. Pass nil to disable the timeout.
# * :ssl_client_cert, :ssl_client_key, :ssl_ca_file, :ssl_ca_path,
# :ssl_cert_store
# :ssl_cert_store, :ssl_verify_callback, :ssl_verify_callback_warnings
# * :ssl_version specifies the SSL version for the underlying Net::HTTP connection
# * :ssl_ciphers sets SSL ciphers for the connection. See
# OpenSSL::SSL::SSLContext#ciphers=
@ -100,7 +100,7 @@ module RestClient
])
SSLOptionList = %w{client_cert client_key ca_file ca_path cert_store
version ciphers}
version ciphers verify_callback verify_callback_warnings}
def initialize args
@method = args[:method] or raise ArgumentError, "must pass :method"
@ -327,6 +327,20 @@ module RestClient
cert_store
end
def print_verify_callback_warnings
warned = false
if RestClient::Platform.mac?
warn('warning: ssl_verify_callback return code is ignored on OS X')
warned = true
end
if RestClient::Platform.jruby?
warn('warning: SSL verify_callback may not work correctly in jruby')
warn('see https://github.com/jruby/jruby/issues/597')
warned = true
end
warned
end
def transmit uri, req, payload, & block
setup_credentials req
@ -335,8 +349,6 @@ module RestClient
net.ssl_version = ssl_version if ssl_version
net.ciphers = ssl_ciphers if ssl_ciphers
# we no longer set net.verify_callback because it's not well supported on
# all platforms (see comments below)
net.verify_mode = verify_ssl
net.cert = ssl_client_cert if ssl_client_cert
@ -345,6 +357,26 @@ module RestClient
net.ca_path = ssl_ca_path if ssl_ca_path
net.cert_store = ssl_cert_store if ssl_cert_store
# We no longer rely on net.verify_callback for the main SSL verification
# because it's not well supported on all platforms (see comments below).
# But do allow users to set one if they want.
if ssl_verify_callback
net.verify_callback = ssl_verify_callback
# Hilariously, jruby only calls the callback when cert_store is set to
# something, so make sure to set one.
# https://github.com/jruby/jruby/issues/597
if RestClient::Platform.jruby?
net.cert_store ||= OpenSSL::X509::Store.new
end
if ssl_verify_callback_warnings != false
if print_verify_callback_warnings
warn('pass :ssl_verify_callback_warnings => false to silence this')
end
end
end
if OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE
warn('WARNING: OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE')
warn('This dangerous monkey patch leaves you open to MITM attacks!')

View file

@ -37,7 +37,7 @@ describe RestClient::Request do
it "is unsuccessful with an incorrect ca_file", :unless => RestClient::Platform.mac? do
request = RestClient::Request.new(
:method => :get,
:url => 'https://www.mozilla.com',
:url => 'https://www.mozilla.org',
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt")
)
expect { request.execute }.to raise_error(RestClient::SSLCertificateNotVerified)
@ -48,7 +48,7 @@ describe RestClient::Request do
it "is unsuccessful with an incorrect ca_path", :unless => RestClient::Platform.mac? do
request = RestClient::Request.new(
:method => :get,
:url => 'https://www.mozilla.com',
:url => 'https://www.mozilla.org',
:ssl_ca_path => File.join(File.dirname(__FILE__), "capath_verisign")
)
expect { request.execute }.to raise_error(RestClient::SSLCertificateNotVerified)
@ -62,5 +62,43 @@ describe RestClient::Request do
)
expect {request.execute }.to_not raise_error
end
it "executes the verify_callack" do
ran_callback = false
request = RestClient::Request.new(
:method => :get,
:url => 'https://www.mozilla.org',
:verify_ssl => true,
:ssl_verify_callback => lambda { |preverify_ok, store_ctx|
ran_callback = true
preverify_ok
},
)
expect {request.execute }.to_not raise_error
ran_callback.should eq(true)
end
it "fails verification when the callback returns false",
:unless => RestClient::Platform.mac? do
request = RestClient::Request.new(
:method => :get,
:url => 'https://www.mozilla.org',
:verify_ssl => true,
:ssl_verify_callback => lambda { |preverify_ok, store_ctx| false },
)
expect { request.execute }.to raise_error(RestClient::SSLCertificateNotVerified)
end
it "succeeds verification when the callback returns true",
:unless => RestClient::Platform.mac? do
request = RestClient::Request.new(
:method => :get,
:url => 'https://www.mozilla.org',
:verify_ssl => true,
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt"),
:ssl_verify_callback => lambda { |preverify_ok, store_ctx| true },
)
expect { request.execute }.to_not raise_error
end
end
end

View file

@ -834,6 +834,43 @@ describe RestClient::Request do
@request.stub(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should not set the ssl_verify_callback by default" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload',
)
@net.should_not_receive(:verify_callback=)
@http.stub(:request)
@request.stub(:process_result)
@request.stub(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should set the ssl_verify_callback if passed" do
callback = lambda {}
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:ssl_verify_callback => callback,
)
@net.should_receive(:verify_callback=).with(callback)
# we'll read cert_store on jruby
# https://github.com/jruby/jruby/issues/597
if RestClient::Platform.jruby?
allow(@net).to receive(:cert_store)
end
@http.stub(:request)
@request.stub(:process_result)
@request.stub(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
# </ssl>
end
it "should still return a response object for 204 No Content responses" do