Reputation: 6280
I am a newbie on SSL concept, I am trying to connect to API which has x509 mutual auth using HTTParty.
I got client cert, client key and server cert (all are pem files).
I got it working with client cert and key and with verify: false
.
Now next step is how to verify server cert also?
HTTParty documentation link https://github.com/jnunemaker/httparty/tree/master/docs#working-with-ssl
class ServiceClient
include HTTParty
DEFAULT_HEADERS = {
'Content-Type' => 'application/json'
}.freeze
base_uri 'https://example.com'
pem File.read("#{File.expand_path('.')}/path/to/certs/cert.pem")
def self.iframe_url(**payload)
post(
'/test/create',
body: payload.to_json,
headers: DEFAULT_HEADERS,
verify: false
)
end
end
Call to service client
payload = {user_id: "100", account_id: "1234"}
ServiceClient.iframe_url(payload)
Edit:
HTTParty is not a hard requirement so solution with any http client would work for me.
If I remove verify: false
I get below error.
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=error: certificate verify failed
Upvotes: 7
Views: 6108
Reputation: 2313
By default, the TLS protocol only proves the identity of the server to the client, leaving the authentication of the client to the server to the application layer, e.g., HTTP Basic authentication.
Mutual TLS authentication refers to the client and server authenticating each other at the same time. It can be used as an alternative to HTTP Basic authentication. It's also often called certificate-based authentication.
Looks like you're getting this error (but works with verify: false
) because
the server certificate isn't trusted. Is it self-signed? Or perhaps the
certificate authority (CA) who issued the certificate isn't trusted in your system.
HTTParty is built on top of Net::HTTP
, which uses OpenSSL
, which gets the
trusted CA certificates from the system, e.g. /etc/ssl/cert.pem
. Although you
could override the SSL_CERT_FILE
environment variable, I don't think it's a
good idea because it might impact other parts of your application. A better
solution would be to pass the CA certificates to HTTParty only.
I've never used HTTParty, so bear with me. But taking a quick look at the
code
and assuming you're using the default ConnectionAdapter
, looks like you need
to define both pem
and ssl_ca_file
options, which will define the client
and CA certificate files, respectively. Also note that by doing it so, it will
turn certificate verification
on.
class ServiceClient
include HTTParty
pem "path/to/client_cert_and_key.pem"
ssl_ca_file "path/to/ca_certificates.pem"
end
I don't think it's related to your issue, but if your client key has a
passphrase, make sure to pass it on pem(pem_contents, password)
.
HTH. Best.
Upvotes: 4
Reputation: 1459
This should solve the problem:
RestClient::Resource.new(
'https://example.com',
:ssl_client_cert => OpenSSL::X509::Certificate.new(File.read("cert.pem")),
:ssl_client_key => OpenSSL::PKey::RSA.new(File.read("key.pem"), "passphrase, if any"),
:ssl_ca_file => "ca_certificate.pem",
:verify_ssl => OpenSSL::SSL::VERIFY_PEER
).get
Ref: https://github.com/rest-client/rest-client
Upvotes: 1
Reputation: 357
Try as you I suppose you are using ssl certificate that you want to verify. Also it's quite easier in RestClient, I am adding snippet at the end.
class ServiceClient
include HTTParty
DEFAULT_HEADERS = {
'Content-Type' => 'application/json'
}.freeze
base_uri 'https://example.com'
ssl_ca_file "#{File.expand_path('.')}/path/to/certs/cert.pem"
def self.iframe_url(**payload)
post(
'/test/create',
body: payload.to_json,
headers: DEFAULT_HEADERS,
)
end
end
Rest Client solution:
client = RestClient::Resource.new('https://example.com/',
:ssl_client_cert => p12.certificate,
:ssl_client_key => p12.key,
:verify_ssl => OpenSSL::SSL::VERIFY_NONE)
Upvotes: 1
Reputation: 1
Use " OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE"
In your code , maybe look like to:
class ServiceClient
include HTTParty
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
{...your code...}
end
Upvotes: -1