Skip to content

Commit

Permalink
Support setting SSL client cert as a an array, to configure extra_cha…
Browse files Browse the repository at this point in the history
…in_cert (#42)

* fix test: tap into SSLOptions setting client_cert

Tested locally using 3.1.4 and got:
warning: Passing only keyword arguments to Struct#initialize will behave differently from Ruby 3.2. Please use a Hash literal like .new({k: v}) instead of .new(k: v).

Checked the keyword vs literal on 3.3.4, Yes it behaves differently.

irb(main):008> ssl_options_without_literal_hash = Faraday::SSLOptions.new(client_cert: "this is my string")
=> #<struct Faraday::SSLOptions verify=nil, verify_hostname=nil, ca_file=nil, ca_path=nil, verify_mode=nil, cert_store=nil, client_cert="this is my string", client_key=nil, certificate=nil, private_key=nil, verify_depth=nil, version=nil, min_version=nil, max_version=...
irb(main):009> ssl_options_with_literal_hash = Faraday::SSLOptions.new({client_cert: "this is my string"})
=>
...
irb(main):010> ssl_options_with_literal_hash
=>
 verify={:client_cert=>"this is my string"},
 verify_hostname=nil,
 ca_file=nil,
 ca_path=nil,
 verify_mode=nil,
 cert_store=nil,
 client_cert=nil,
 client_key=nil,
 certificate=nil,
 private_key=nil,
 verify_depth=nil,
 version=nil,
 min_version=nil,
 max_version=nil>

Looked closer at other tests.
Thanks for all the good examples.
Found a way that should be more compatible: (Well, it worked on my machine with 3.1.4 and 3.3.4 :-D )

  let(:ssl_options) do
    Faraday::SSLOptions.new.tap do |ssl_options|
      ssl_options.client_cert = cert
    end
  end

---------

Co-authored-by: Lars Kronfält <[email protected]>
  • Loading branch information
olleolleolle and larkro authored Aug 1, 2024
1 parent c1cdf44 commit 1dd1e64
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 1 deletion.
5 changes: 4 additions & 1 deletion lib/faraday/adapter/net_http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ def configure_ssl(http, ssl)
http.verify_mode = ssl_verify_mode(ssl)
http.cert_store = ssl_cert_store(ssl)

http.cert = ssl[:client_cert] if ssl[:client_cert]
cert, *extra_chain_cert = ssl[:client_cert]
http.cert = cert if cert
http.extra_chain_cert = extra_chain_cert if extra_chain_cert.any?

http.key = ssl[:client_key] if ssl[:client_key]
http.ca_file = ssl[:ca_file] if ssl[:ca_file]
http.ca_path = ssl[:ca_path] if ssl[:ca_path]
Expand Down
44 changes: 44 additions & 0 deletions spec/faraday/adapter/net_http_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,48 @@
it { expect(response.body.encoding).to eq(::Encoding::UTF_8) }
end
end

context 'client certificate' do
let(:adapter) { described_class.new }
let(:url) { URI('https://example.com') }
let(:http) { adapter.send(:connection, url: url, request: {}, ssl: ssl_options) }

before do
stub_request(:any, 'https://example.com')
end

context 'when client_cert is provided as an array' do
let(:cert_array) { [OpenSSL::X509::Certificate.new, OpenSSL::X509::Certificate.new] }
let(:ssl_options) do
Faraday::SSLOptions.new.tap do |ssl_options|
ssl_options.client_cert = cert_array
end
end

it 'sets the first cert as cert and the rest as extra_chain_cert' do
adapter.send(:configure_ssl, http, ssl_options)
end

it { expect(http.cert).to eq(cert_array.first) }

it { expect(http.extra_chain_cert).to eq(cert_array[1..]) }
end

context 'when client_cert is provided as a single cert' do
let(:cert) { OpenSSL::X509::Certificate.new }
let(:ssl_options) do
Faraday::SSLOptions.new.tap do |ssl_options|
ssl_options.client_cert = cert
end
end

it 'sets the cert as cert' do
adapter.send(:configure_ssl, http, ssl_options)
end

it { expect(http.cert).to eq(cert) }

it { expect(http.extra_chain_cert).to be_nil }
end
end
end

0 comments on commit 1dd1e64

Please sign in to comment.