mirror of
https://github.com/rest-client/rest-client.git
synced 2022-11-09 13:49:40 -05:00
Refactor SSL options for better default handling.
Move SSL options into their own hash so we can handle defaults in a more sane way. This also makes it much clearer to the user what's happening when defaults are used for SSL parameters.
This commit is contained in:
parent
1d0f0d9fa3
commit
d7ddc7e928
2 changed files with 85 additions and 41 deletions
|
@ -34,9 +34,8 @@ module RestClient
|
|||
|
||||
attr_reader :method, :url, :headers, :cookies,
|
||||
:payload, :user, :password, :timeout, :max_redirects,
|
||||
:open_timeout, :raw_response, :verify_ssl, :ssl_client_cert,
|
||||
:ssl_client_key, :ssl_ca_file, :ssl_ca_path, :ssl_cert_store,
|
||||
:processed_headers, :args, :ssl_version, :ssl_ciphers
|
||||
:open_timeout, :raw_response, :processed_headers, :args,
|
||||
:ssl_opts
|
||||
|
||||
def self.execute(args, & block)
|
||||
new(args).execute(& block)
|
||||
|
@ -100,6 +99,9 @@ module RestClient
|
|||
"ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
|
||||
])
|
||||
|
||||
SSLOptionList = %w{client_cert client_key ca_file ca_path cert_store
|
||||
version ciphers}
|
||||
|
||||
def initialize args
|
||||
@method = args[:method] or raise ArgumentError, "must pass :method"
|
||||
@headers = args[:headers] || {}
|
||||
|
@ -120,28 +122,53 @@ module RestClient
|
|||
end
|
||||
@block_response = args[:block_response]
|
||||
@raw_response = args[:raw_response] || false
|
||||
@verify_ssl = args.fetch(:verify_ssl, OpenSSL::SSL::VERIFY_PEER)
|
||||
@ssl_client_cert = args[:ssl_client_cert] || nil
|
||||
@ssl_client_key = args[:ssl_client_key] || nil
|
||||
@ssl_ca_file = args[:ssl_ca_file] || nil
|
||||
@ssl_ca_path = args[:ssl_ca_path] || nil
|
||||
@ssl_cert_store = args[:ssl_cert_store] || nil
|
||||
@ssl_version = args[:ssl_version]
|
||||
@tf = nil # If you are a raw request, this is your tempfile
|
||||
@max_redirects = args[:max_redirects] || 10
|
||||
@processed_headers = make_headers headers
|
||||
@args = args
|
||||
|
||||
if args.include?(:ssl_ciphers)
|
||||
@ssl_ciphers = args.fetch(:ssl_ciphers)
|
||||
@ssl_opts = {}
|
||||
|
||||
if args.include?(:verify_ssl)
|
||||
v_ssl = args.fetch(:verify_ssl)
|
||||
if v_ssl
|
||||
if v_ssl == true
|
||||
# interpret :verify_ssl => true as VERIFY_PEER
|
||||
@ssl_opts[:verify_ssl] = OpenSSL::SSL::VERIFY_PEER
|
||||
else
|
||||
# otherwise pass through any truthy values
|
||||
@ssl_opts[:verify_ssl] = v_ssl
|
||||
end
|
||||
else
|
||||
# interpret all falsy :verify_ssl values as VERIFY_NONE
|
||||
@ssl_opts[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE
|
||||
end
|
||||
else
|
||||
# if :verify_ssl was not passed, default to VERIFY_PEER
|
||||
@ssl_opts[:verify_ssl] = OpenSSL::SSL::VERIFY_PEER
|
||||
end
|
||||
|
||||
SSLOptionList.each do |key|
|
||||
source_key = ('ssl_' + key).to_sym
|
||||
if args.has_key?(source_key)
|
||||
@ssl_opts[key.to_sym] = args.fetch(source_key)
|
||||
end
|
||||
end
|
||||
|
||||
# If there's no CA file, CA path, or cert store provided, use default
|
||||
if !ssl_ca_file && !ssl_ca_path && !@ssl_opts.include?(:cert_store)
|
||||
@ssl_opts[:cert_store] = self.class.default_ssl_cert_store
|
||||
end
|
||||
|
||||
unless @ssl_opts.include?(:ciphers)
|
||||
# If we're on a Ruby version that has insecure default ciphers,
|
||||
# override it with our default list.
|
||||
if WeakDefaultCiphers.include?(
|
||||
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.fetch(:ciphers))
|
||||
@ssl_ciphers = DefaultCiphers
|
||||
@ssl_opts[:ciphers] = DefaultCiphers
|
||||
end
|
||||
end
|
||||
|
||||
@tf = nil # If you are a raw request, this is your tempfile
|
||||
@max_redirects = args[:max_redirects] || 10
|
||||
@processed_headers = make_headers headers
|
||||
@args = args
|
||||
end
|
||||
|
||||
def execute & block
|
||||
|
@ -151,6 +178,16 @@ module RestClient
|
|||
payload.close if payload
|
||||
end
|
||||
|
||||
# SSL-related options
|
||||
def verify_ssl
|
||||
@ssl_opts.fetch(:verify_ssl)
|
||||
end
|
||||
SSLOptionList.each do |key|
|
||||
define_method('ssl_' + key) do
|
||||
@ssl_opts[key.to_sym]
|
||||
end
|
||||
end
|
||||
|
||||
# Extract the query parameters and append them to the url
|
||||
def process_url_params url, headers
|
||||
url_params = {}
|
||||
|
@ -268,14 +305,11 @@ module RestClient
|
|||
|
||||
net = net_http_class.new(uri.host, uri.port)
|
||||
net.use_ssl = uri.is_a?(URI::HTTPS)
|
||||
net.ssl_version = @ssl_version if @ssl_version
|
||||
net.ciphers = @ssl_ciphers if @ssl_ciphers
|
||||
net.ssl_version = ssl_version if ssl_version
|
||||
net.ciphers = ssl_ciphers if ssl_ciphers
|
||||
err_msg = nil
|
||||
if @verify_ssl
|
||||
if @verify_ssl == true
|
||||
@verify_ssl = OpenSSL::SSL::VERIFY_PEER
|
||||
end
|
||||
net.verify_mode = @verify_ssl
|
||||
if verify_ssl
|
||||
net.verify_mode = verify_ssl
|
||||
net.verify_callback = lambda do |preverify_ok, ssl_context|
|
||||
if (!preverify_ok) || ssl_context.error != 0
|
||||
err_msg = "SSL Verification failed -- Preverify: #{preverify_ok}, Error: #{ssl_context.error_string} (#{ssl_context.error})"
|
||||
|
@ -284,20 +318,14 @@ module RestClient
|
|||
true
|
||||
end
|
||||
else
|
||||
net.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
net.verify_mode = verify_ssl
|
||||
end
|
||||
|
||||
# if no CA information of any kind was specified, supply our own default
|
||||
# cert store using system default CA locations
|
||||
if !@ssl_ca_file && !@ssl_ca_path && !@ssl_cert_store
|
||||
@ssl_cert_store = self.class.default_ssl_cert_store
|
||||
end
|
||||
|
||||
net.cert = @ssl_client_cert if @ssl_client_cert
|
||||
net.key = @ssl_client_key if @ssl_client_key
|
||||
net.ca_file = @ssl_ca_file if @ssl_ca_file
|
||||
net.ca_path = @ssl_ca_path if @ssl_ca_path
|
||||
net.cert_store = @ssl_cert_store if @ssl_cert_store
|
||||
net.cert = ssl_client_cert if ssl_client_cert
|
||||
net.key = ssl_client_key if ssl_client_key
|
||||
net.ca_file = ssl_ca_file if ssl_ca_file
|
||||
net.ca_path = ssl_ca_path if ssl_ca_path
|
||||
net.cert_store = ssl_cert_store if ssl_cert_store
|
||||
|
||||
if OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE
|
||||
warn('WARNING: OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE')
|
||||
|
|
|
@ -736,6 +736,7 @@ describe RestClient::Request do
|
|||
:ssl_ca_file => "Certificate Authority File"
|
||||
)
|
||||
@net.should_receive(:ca_file=).with("Certificate Authority File")
|
||||
@net.should_not_receive(:cert_store=)
|
||||
@http.stub(:request)
|
||||
@request.stub(:process_result)
|
||||
@request.stub(:response_log)
|
||||
|
@ -767,6 +768,7 @@ describe RestClient::Request do
|
|||
:ssl_ca_path => "Certificate Authority Path"
|
||||
)
|
||||
@net.should_receive(:ca_path=).with("Certificate Authority Path")
|
||||
@net.should_not_receive(:cert_store=)
|
||||
@http.stub(:request)
|
||||
@request.stub(:process_result)
|
||||
@request.stub(:response_log)
|
||||
|
@ -797,28 +799,42 @@ describe RestClient::Request do
|
|||
:ssl_cert_store => store
|
||||
)
|
||||
@net.should_receive(:cert_store=).with(store)
|
||||
@net.should_not_receive(:ca_path=)
|
||||
@net.should_not_receive(:ca_file=)
|
||||
@http.stub(:request)
|
||||
@request.stub(:process_result)
|
||||
@request.stub(:response_log)
|
||||
@request.transmit(@uri, 'req', 'payload')
|
||||
end
|
||||
|
||||
it "should not set the ssl_cert_store if it is not provided" do
|
||||
it "should by default set the ssl_cert_store if no CA info is provided" do
|
||||
@request = RestClient::Request.new(
|
||||
:method => :put,
|
||||
:url => 'https://some/resource',
|
||||
:payload => 'payload'
|
||||
)
|
||||
@net.should_receive(:cert_store=)
|
||||
@net.should_not_receive(:ca_path=)
|
||||
@net.should_not_receive(:ca_file=)
|
||||
@http.stub(:request)
|
||||
@request.stub(:process_result)
|
||||
@request.stub(:response_log)
|
||||
@request.transmit(@uri, 'req', 'payload')
|
||||
end
|
||||
|
||||
it "should not set the ssl_cert_store if it is set falsy" do
|
||||
@request = RestClient::Request.new(
|
||||
:method => :put,
|
||||
:url => 'https://some/resource',
|
||||
:payload => 'payload',
|
||||
:ssl_cert_store => nil,
|
||||
)
|
||||
@net.should_not_receive(:cert_store=)
|
||||
@http.stub(:request)
|
||||
@request.stub(:process_result)
|
||||
@request.stub(:response_log)
|
||||
@request.transmit(@uri, 'req', 'payload')
|
||||
end
|
||||
|
||||
it "should default to not having an ssl_cert_store" do
|
||||
@request.ssl_cert_store.should be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
it "should still return a response object for 204 No Content responses" do
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue