Skip to content

Commit

Permalink
Merge pull request #1 from rgacogne/tls
Browse files Browse the repository at this point in the history
Add TLS support
  • Loading branch information
rgacogne authored Sep 30, 2024
2 parents 980da7a + 748c53e commit 2485b1d
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 9 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ deps:
luarocks install luasocket
luarocks install lua-cjson
luarocks install uuid
luarocks install luasec

.PHONY: test test-deps deps
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Requirements
* [lua-cjson](https://github.com/mpx/lua-cjson)
* [uuid](https://github.com/Tieske/uuid)
* [nats](https://github.com/derekcollison/nats) or [gnatsd](https://github.com/apcera/gnatsd)
* [luasec](https://github.com/lunarmodules/luasec) if TLS support is needed

This is a NATS Lua library for Lua 5.1, 5.2 and 5.3. The
libraries are copyright by their author 2015 (see the Creators
Expand Down Expand Up @@ -94,6 +95,22 @@ client:set_auth(user, password)
client:connect()
```

### Basic usage: TLS connection

```lua
local nats = require 'nats'

local client = nats.connect({
host = '127.0.0.1',
port = 4222,
tls = true,
tls_ca_path = '/etc/ssl/certs',
})

-- connect to the server using TLS and validating the server certificate
client:connect()
```

Developer's Information
-----------------------

Expand Down
56 changes: 47 additions & 9 deletions src/nats.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ local defaults = {
port = 4222,
tcp_nodelay = true,
path = nil,
tls = false,
tls_ca_path = nil,
tls_ca_file = nil,
tls_cert = nil,
tls_key = nil,
}

-- ### Create a properly formatted inbox subject.
Expand Down Expand Up @@ -76,10 +81,12 @@ local function load_methods(proto, commands)
return client
end

local function create_client(client_proto, client_socket, commands)
local function create_client(client_proto, client_socket, commands, parameters)
local client = load_methods(client_proto, commands)
-- assign client error handler
client.error = nats.error
-- keep parameters around, for TLS
client.parameters = parameters
-- assign client network methods
client.network = {
socket = client_socket,
Expand Down Expand Up @@ -224,6 +231,26 @@ client_prototype.get_server_info = function(client)
return client.information
end

client_prototype.upgrade_to_tls = function(client)
local status, luasec = pcall(require, 'ssl')
if not status then
nats.error('TLS is required but the luasec library is not available')
end
local params = {
capath = client.parameters.tls_ca_path,
cafile = client.parameters.tls_ca_file,
certificate = client.parameters.tls_cert,
key = client.parameters.tls_key,
mode = "client",
options = {"all", "no_sslv3"},
protocol = "tlsv1_2",
verify = "peer",
}

client.network.socket = luasec.wrap(client.network.socket, params)
client.network.socket:dohandshake()
end

client_prototype.shutdown = function(client)
client.network.socket:shutdown()
end
Expand Down Expand Up @@ -265,7 +292,10 @@ local function create_connection(parameters)
else
if parameters.scheme then
local scheme = parameters.scheme
assert(scheme == 'nats' or scheme == 'tcp', 'invalid scheme: '..scheme)
assert(scheme == 'nats' or scheme == 'tcp' or scheme == 'tls', 'invalid scheme: '..scheme)
if scheme == 'tls' then
parameters.tls = true
end
end
perform_connection, socket = connect_tcp, require('socket').tcp
end
Expand Down Expand Up @@ -295,7 +325,7 @@ function nats.connect(...)
end

local socket = create_connection(merge_defaults(parameters))
local client = create_client(client_prototype, socket, commands)
local client = create_client(client_prototype, socket, commands, parameters)

return client
end
Expand All @@ -308,24 +338,32 @@ end

function command.connect(client)
local config = {
lang = client.lang,
version = client.version,
verbose = client.verbose,
pedantic = client.pedantic,
lang = client.lang,
version = client.version,
verbose = client.verbose,
pedantic = client.pedantic,
tls_required = client.parameters.tls,
}

if client.user ~= nil and client.pass ~= nil then
config.user = client.user
config.pass = client.pass
end

request.raw(client, 'CONNECT '..cjson.encode(config)..'\r\n')

-- gather the server information
local data = response.read(client)
if data.action == 'INFO' then
client.information = cjson.decode(data.content)
if client.parameters.tls then
if (client.information['tls_available'] or client.information['tls_required']) then
client:upgrade_to_tls()
else
nats.error('TLS is required but not offered by the server')
end
end
end

request.raw(client, 'CONNECT '..cjson.encode(config)..'\r\n')
end

function command.ping(client)
Expand Down

0 comments on commit 2485b1d

Please sign in to comment.