2

I'm running a ruby on rails application (rails 4.x) and I have a protected resource that needs authentication using a client certificate. I need to force the client to authenticate with its certifcate. Is that even possible from a rails controller or is this handled in an upper layer that has my server cert?

I'm able to do requests from rails to another server and authenticate with my rails certificate, however the other way around doesn't seem possible.

This is how I authenticate from my rails app to another server

# Example usage:
req = HttpsReq.new
response = req.http.request Net::HTTP::Get.new "/api/users"
require 'openssl'
require 'net/http'
require 'json'

class HttpsReq

  DEFAULT_OPTIONS = {
    use_ssl: true,
    verify_mode: OpenSSL::SSL::VERIFY_PEER,
    keep_alive_timeout: 30,
    ssl_version: :TLSv1_2,
    ca_file: File.join(File.dirname(__FILE__), "cacert.pem"),
    cert: OpenSSL::X509::Certificate.new(Base64.decode64(ENV['CLIENT_CERT_PEM'])),
    key: OpenSSL::PKey::RSA.new(Base64.decode64(ENV['CLIENT_KEY_PEM']), ENV['CLIENT_KEY_PASSWORD'])
  }

  def initialize(http = nil)
    if http
      @http = http
    else
      @http = Net::HTTP.start(ENV['SECURE_SERVER'], 8080, DEFAULT_OPTIONS)
    end
  end

end
vato
  • 409
  • 1
  • 3
  • 15

1 Answers1

2

It's kind of possible, but you need to do some trick. Because it's only possible to acquire a client certificate during the TLS handshake process.

I think most of a Rails web app designed to run behind proxy servers or load balancers. And this case TLS handshake process already done before web request come to your Rails controller.

So, there are several tricks you can use.

  1. Run separated endpoint with Ruby HTTP client and provide all required root certificate and private key. From rails controller, you need force to redirect to that Ruby HTTP client's endpoint, until your client (browser) successfully authenticates with client certificate.
  2. Configure NGINX that require Mutual TLS Authentication then pass actual raw client certificate from the HTTP request to your Rails controller. So, this way you need setup special url or special port for Nginx configuration and from Rails controller you need force to redirect that endpoint. And that special endpoint can proxy your actual Rails controller with HTTP parameters (X-SSL-CERT $ssl_client_raw_cert). So, from there you can read actual client certificate and validate it with a Ruby OpenSSL library.

If you need more info, please check this article

Zogoo
  • 43
  • 8