mamantoha / crest

HTTP and REST client for Crystal
https://mamantoha.github.io/crest/
MIT License
235 stars 14 forks source link

Unable to connect to host due to OpenSSL Issue #118

Closed elaine-jackson closed 5 years ago

elaine-jackson commented 5 years ago

When attempting to contact a JSON API over HTTPS I get an OpenSSL Error. I'm able to access the website in Safari without an issue so I know it's not a server issue. Could the developers please advise on this?

System information: macOS 10.12.6 (16G1918) ASDF Version Manager Crystal 0.27.2 Crest installs as dependency from github: mamantoha/crest

Example code:

require "crest"
require "json"

# TODO: Write documentation for `CrystalProxmox`
module CrystalProxmox
  VERSION = "0.1.0"

  class Proxmox
    @auth_params : Hash(String, String)

    def initialize(pve_cluster : String, node : String, username : String, password : String, realm : String)
      @pve_cluster = pve_cluster # https://your-proxmox-server.local:8006/api2/json/
      @node = node               # node
      @username = username       # root
      @password = password       # password
      @realm = realm             # pve
      @connection_status = "error"
      @site = Crest::Resource.new(@pve_cluster)
      @auth_params = create_ticket()
    end

    def get(path, args = Hash.new)
      @site.get(path, args)
    end

    def post(path, args = Hash.new)
      @site.post(path, args)
    end

    def put(path, args = Hash.new)
      @site.put(path, args)
    end

    def delete(path, args = Hash.new)
      @site.delete(path, args)
    end

    def show_ticket
      @auth_params["cookie"]
    end

    def create_ticket : Hash(String, String)
      response = @site["access/ticket"].post(
        headers: {
          "Content-Type" => "application/json",
        },
        params: {
          "username" => @username,
          "password" => @password,
          "realm"    => @realm,
        }
      )
      extract_ticket(response)
    end

    def extract_ticket(response : Object) : Hash(String, String)
      data = JSON.parse(response.body)
      ticket = data["data"]["ticket"]
      csrf_prevention_token = data["data"]["CSRFPreventionToken"]
      token = "PVEAuthCookie=" + ticket.as_s.gsub(/:/, "%3A").gsub(/=/, "%3D")
      @connection_status = "connected"
      return {
        "CSRFPreventionToken" => csrf_prevention_token.as_s,
        "cookie"              => token,
      }
    end
  end
end

my_proxmox_host = CrystalProxmox::Proxmox.new("https://hypervisor-cust-01.bhs-ca.ulayer.net:8006/api2/json/", "hypervisor-cust-01", "username", "password", "pve")
puts my_proxmox_host.show_ticket

Log output:

Nathaniels-MBP% crystal run src/CrystalProxmox.cr
Unhandled exception: SSL_connect: Unexpected EOF (OpenSSL::SSL::Error)
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/openssl/ssl/socket.cr:34:9 in 'initialize'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/openssl/ssl/socket.cr:3:5 in 'new:context:sync_close:hostname'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/http/client.cr:680:5 in 'socket'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/http/client.cr:572:5 in 'send_request'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/http/client.cr:511:5 in 'exec_internal_single'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/http/client.cr:498:5 in 'exec_internal'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/http/client.cr:494:5 in 'exec'
  from lib/crest/src/crest/request.cr:177:7 in 'execute'
  from lib/crest/src/crest/request.cr:79:7 in 'execute:method:form:url:params:headers:tls:user:password:p_addr:p_port:p_user:p_pass:logging:logger:handle_errors:http_client'
  from lib/crest/src/crest/resource.cr:137:7 in 'execute_request'
  from lib/crest/src/crest/resource.cr:92:5 in 'post:headers:params'
  from src/CrystalProxmox.cr:43:7 in 'create_ticket'
  from src/CrystalProxmox.cr:19:7 in 'initialize'
  from src/CrystalProxmox.cr:11:5 in 'new'
  from src/CrystalProxmox.cr:70:1 in '__crystal_main'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/crystal/main.cr:97:5 in 'main_user_code'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/crystal/main.cr:86:7 in 'main'
  from /Users/nathanielsuchy/.asdf/installs/crystal/0.27.2/src/crystal/main.cr:106:3 in 'main'
elaine-jackson commented 5 years ago

The same issue can actually be reproduced with the standard library (See: https://github.com/ulayer/CrystalProxmox/blob/master/src/CrystalProxmox.cr for an example). I question whether this is an issue Crest can address. Perhaps the issue should be closed, I'll leave that decision to whomever triages issues.

mamantoha commented 5 years ago

Hi. Definitely, this is Crystal issue.

But, can you try:

Crest::Resource.new(@pve_cluster,  tls: OpenSSL::SSL::Context::Client.insecure)

or

HTTP::Client.new(URI.parse(@pve_cluster), tls: OpenSSL::SSL::Context::Client.insecure)
elaine-jackson commented 5 years ago

Exporting OpenSSL from Homebrew’s pkg-config fixes part of the issue. Sending an invalid content type header to the server can also trigger a similar error with OpenSSL. This is really a two part issue if you think about it some more. More graceful error handing with more descriptive exception messages would be nice for Crystal to implement. I ended up using HTTP::Client from the standard library for my project however I’ll consider Crest for future projects :)

Cordially, Nathaniel Suchy

On Apr 15, 2019, at 5:02 AM, Anton Maminov notifications@github.com wrote:

Hi. Definitely, this is Crystal issue.

But, can you try:

Crest::Resource.new(@pve_cluster, tls: OpenSSL::SSL::Context::Client.insecure) or

HTTP::Client.new(URI.parse(@pve_cluster), tls: OpenSSL::SSL::Context::Client.insecure) — You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub, or mute the thread.