Skip to content

Commit 21d27be

Browse files
authored
feat: new rust decoder (#17)
1 parent 479e491 commit 21d27be

File tree

15 files changed

+281
-45
lines changed

15 files changed

+281
-45
lines changed

.github/workflows/ci.yml

+5-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,12 @@ jobs:
3737
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
3838
sudo docker run hello-world
3939
40+
# rust
41+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
42+
43+
# luarocks
4044
sudo apt -y install lua5.1 luarocks
41-
sudo luarocks install lua_pack
42-
sudo luarocks install lpeg
45+
luarocks make rockspec/lua-resty-ldap-local-0.rockspec --local --tree ./deps # install deps to local
4346
4447
- name: script
4548
run: |

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
# dev
22
t/servroot
3+
4+
5+
# Added by cargo
6+
7+
/target
8+
/Cargo.lock

Cargo.toml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "lua-resty-ldap"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
name = "rasn"
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]
11+
mlua = { version = "0.8.6", features = ["module", "send", "luajit"] }
12+
rasn = "0.6.1"
13+
rasn-ldap = "0.6.0"
14+
bytes = "1.4.0"
15+
16+
[profile.release]
17+
strip = true

Makefile

+25-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,37 @@
1-
PREFIX ?= /usr/local/openresty
2-
LUA_LIB_DIR ?= $(PREFIX)/lualib/$(LUA_VERSION)
31
INSTALL ?= install
2+
ECHO ?= echo
3+
4+
all:
5+
@echo --- Build
6+
@echo CFLAGS: $(CFLAGS)
7+
@echo LIBFLAG: $(LIBFLAG)
8+
@echo LUA_LIBDIR: $(LUA_LIBDIR)
9+
@echo LUA_BINDIR: $(LUA_BINDIR)
10+
@echo LUA_INCDIR: $(LUA_INCDIR)
11+
12+
@echo --- Check Rust toolchain
13+
@utils/check-rust.sh
14+
15+
@echo --- Build Rust cdylib
16+
cargo build --release
417

518
### install: Install the library to runtime
619
.PHONY: install
720
install:
8-
$(INSTALL) -d $(DESTDIR)/$(LUA_LIB_DIR)/resty/ldap/
9-
$(INSTALL) lib/resty/*.lua $(DESTDIR)/$(LUA_LIB_DIR)/resty/ldap/
21+
@echo --- Install
22+
@echo INST_PREFIX: $(INST_PREFIX)
23+
@echo INST_BINDIR: $(INST_BINDIR)
24+
@echo INST_LIBDIR: $(INST_LIBDIR)
25+
@echo INST_LUADIR: $(INST_LUADIR)
26+
@echo INST_CONFDIR: $(INST_CONFDIR)
27+
$(INSTALL) -d $(INST_LUADIR)/resty/ldap/
28+
$(INSTALL) lib/resty/ldap/*.lua $(INST_LUADIR)/resty/ldap/
29+
$(INSTALL) target/release/librasn.so $(INST_LIBDIR)/rasn.so
1030

1131
### dev: Create a development ENV
1232
.PHONY: dev
1333
dev:
14-
luarocks install rockspec/lua-resty-ldap-main-0.1-0.rockspec --only-deps --local
34+
luarocks install rockspec/lua-resty-ldap-main-0.rockspec --only-deps --local
1535

1636
### help: Show Makefile rules
1737
.PHONY: help

lib/resty/ldap/client.lua

+14-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ local bunpack = require("lua_pack").unpack
22
local protocol = require("resty.ldap.protocol")
33
local asn1 = require("resty.ldap.asn1")
44
local to_hex = require("resty.string").to_hex
5+
local rasn = require("rasn")
56

67
local tostring = tostring
78
local fmt = string.format
@@ -11,6 +12,7 @@ local DEBUG = ngx.DEBUG
1112
local tcp = ngx.socket.tcp
1213
local table_insert = table.insert
1314
local string_char = string.char
15+
local rasn_decode = rasn.decode_ldap
1416

1517
local asn1_parse_ldap_result = asn1.parse_ldap_result
1618

@@ -38,7 +40,7 @@ local function calculate_payload_length(encStr, pos, socket)
3840
elen = elenCalc
3941
end
4042

41-
return pos, elen
43+
return pos, elen, encStr
4244
end
4345

4446
local function _start_tls(sock, host, port)
@@ -173,7 +175,7 @@ local function _send_recieve(cli, request, multi_resp_hint)
173175
end
174176
break -- read done, data has been taken to the end
175177
end
176-
local _, packet_len = calculate_payload_length(len, 2, socket)
178+
local _, packet_len, packet_header = calculate_payload_length(len, 2, socket)
177179

178180
-- Get the data of the specified length
179181
local packet, err = socket:receive(packet_len)
@@ -184,10 +186,17 @@ local function _send_recieve(cli, request, multi_resp_hint)
184186
socket:close()
185187
return nil, err
186188
end
187-
local res, err = asn1_parse_ldap_result(packet)
188-
if err then
189-
return nil, fmt("invalid ldap message encoding: %s, message: %s", err, to_hex(packet))
189+
190+
local packet = packet_header .. packet
191+
local ok, res, err = pcall(rasn_decode, packet)
192+
if not ok or err then
193+
return nil, fmt(
194+
"failed to decode ldap message: %s, message: %s",
195+
not ok and res or err, -- error returned in second value by pcall
196+
to_hex(packet)
197+
)
190198
end
199+
191200
table_insert(result, res)
192201

193202
-- This is an ugly patch to actively stop continuous reading. When a search
@@ -297,8 +306,6 @@ function _M.search(self, base_dn, scope, deref_aliases, size_limit, time_limit,
297306
item.diagnostic_msg or "")
298307
end
299308
res[index] = nil
300-
else
301-
res[index] = item.search_entries
302309
end
303310
end
304311

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package = "lua-resty-ldap"
2+
version = "local-0"
3+
source = {
4+
url = "file://."
5+
}
6+
7+
description = {
8+
summary = "Nonblocking Lua ldap driver library for OpenResty",
9+
homepage = "https://github.com/api7/lua-resty-ldap",
10+
license = "Apache License 2.0",
11+
maintainer = "Yuansheng Wang <[email protected]>"
12+
}
13+
14+
dependencies = {
15+
"lua_pack = 2.0.0-0",
16+
"lpeg = 1.0.2-1",
17+
}
18+
19+
build = {
20+
type = "make",
21+
build_variables = {
22+
CFLAGS="$(CFLAGS)",
23+
LIBFLAG="$(LIBFLAG)",
24+
LUA_LIBDIR="$(LUA_LIBDIR)",
25+
LUA_BINDIR="$(LUA_BINDIR)",
26+
LUA_INCDIR="$(LUA_INCDIR)",
27+
LUA="$(LUA)",
28+
},
29+
install_variables = {
30+
INST_PREFIX="$(PREFIX)",
31+
INST_BINDIR="$(BINDIR)",
32+
INST_LIBDIR="$(LIBDIR)",
33+
INST_LUADIR="$(LUADIR)",
34+
INST_CONFDIR="$(CONFDIR)",
35+
},
36+
}

rockspec/lua-resty-ldap-main-0.rockspec

+17-8
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,24 @@ description = {
1414

1515
dependencies = {
1616
"lua_pack = 2.0.0-0",
17-
"lpeg = 1.0.2-1"
17+
"lpeg = 1.0.2-1",
1818
}
1919

2020
build = {
21-
type = "builtin",
22-
modules = {
23-
["resty.ldap.client"] = "lib/resty/ldap/client.lua",
24-
["resty.ldap.protocol"] = "lib/resty/ldap/protocol.lua",
25-
["resty.ldap.filter"] = "lib/resty/ldap/filter.lua",
26-
["resty.ldap.asn1"] = "lib/resty/ldap/asn1.lua",
27-
}
21+
type = "make",
22+
build_variables = {
23+
CFLAGS="$(CFLAGS)",
24+
LIBFLAG="$(LIBFLAG)",
25+
LUA_LIBDIR="$(LUA_LIBDIR)",
26+
LUA_BINDIR="$(LUA_BINDIR)",
27+
LUA_INCDIR="$(LUA_INCDIR)",
28+
LUA="$(LUA)",
29+
},
30+
install_variables = {
31+
INST_PREFIX="$(PREFIX)",
32+
INST_BINDIR="$(BINDIR)",
33+
INST_LIBDIR="$(LIBDIR)",
34+
INST_LUADIR="$(LUADIR)",
35+
INST_CONFDIR="$(CONFDIR)",
36+
},
2837
}

src/ldap_codec/decoder.rs

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use mlua::prelude::{Lua, LuaResult, LuaValue};
2+
use bytes::Bytes;
3+
use rasn::der;
4+
use rasn_ldap::{LdapMessage, ProtocolOp};
5+
6+
fn bytes_to_string(b: Bytes) -> Result<String, std::string::FromUtf8Error> {
7+
return String::from_utf8(b.to_vec());
8+
}
9+
10+
pub fn decode<'lua>(
11+
lua: &'lua Lua,
12+
v: LuaValue<'lua>,
13+
) -> LuaResult<(LuaValue<'lua>, LuaValue<'lua>)> {
14+
let der = match v {
15+
LuaValue::String(v) => v,
16+
_ => {
17+
return Ok((
18+
LuaValue::Nil,
19+
LuaValue::String(lua.create_string("wrong format on input data")?),
20+
))
21+
}
22+
};
23+
24+
let lm = match der::decode::<LdapMessage>(der.as_bytes()) {
25+
Ok(lm) => lm,
26+
Err(err) => {
27+
let err_str = format!("{}", err.to_string());
28+
29+
return Ok((
30+
LuaValue::Nil,
31+
LuaValue::String(lua.create_string(err_str.as_bytes())?),
32+
));
33+
}
34+
};
35+
36+
let result = lua.create_table()?;
37+
match lm.protocol_op {
38+
ProtocolOp::BindResponse(resp) => {
39+
result.set("protocol_op", 1)?;
40+
result.set("result_code", resp.result_code as i64)?;
41+
result.set("matched_dn", bytes_to_string(resp.matched_dn).unwrap())?;
42+
result.set(
43+
"diagnostic_msg",
44+
bytes_to_string(resp.diagnostic_message).unwrap(),
45+
)?;
46+
return Ok((LuaValue::Table(result), LuaValue::Nil));
47+
}
48+
ProtocolOp::SearchResEntry(entry) => {
49+
result.set("protocol_op", 4)?;
50+
result.set("entry_dn", bytes_to_string(entry.object_name).unwrap())?;
51+
52+
let attributes = lua.create_table()?;
53+
for attribute in entry.attributes.into_iter() {
54+
let attribute_vals = lua.create_table()?;
55+
for val in attribute.vals.into_iter() {
56+
attribute_vals.push(bytes_to_string(val).unwrap())?
57+
}
58+
attributes.set(bytes_to_string(attribute.r#type).unwrap(), attribute_vals)?;
59+
}
60+
61+
result.set("attributes", attributes)?;
62+
return Ok((LuaValue::Table(result), LuaValue::Nil));
63+
}
64+
ProtocolOp::SearchResDone(done) => {
65+
let resp = done.0;
66+
result.set("protocol_op", 5)?;
67+
result.set("result_code", resp.result_code as i64)?;
68+
result.set("matched_dn", bytes_to_string(resp.matched_dn).unwrap())?;
69+
result.set(
70+
"diagnostic_msg",
71+
bytes_to_string(resp.diagnostic_message).unwrap(),
72+
)?;
73+
return Ok((LuaValue::Table(result), LuaValue::Nil));
74+
}
75+
ProtocolOp::ModifyResponse(resp0) => {
76+
let resp = resp0.0;
77+
result.set("protocol_op", 7)?;
78+
result.set("result_code", resp.result_code as i64)?;
79+
result.set("matched_dn", bytes_to_string(resp.matched_dn).unwrap())?;
80+
result.set(
81+
"diagnostic_msg",
82+
bytes_to_string(resp.diagnostic_message).unwrap(),
83+
)?;
84+
return Ok((LuaValue::Table(result), LuaValue::Nil));
85+
}
86+
ProtocolOp::SearchResRef(_) => {
87+
return Ok((
88+
LuaValue::Nil,
89+
LuaValue::String(
90+
lua.create_string("decoder not yet implement: search result reference")?,
91+
),
92+
))
93+
}
94+
_ => {
95+
return Ok((
96+
LuaValue::Nil,
97+
LuaValue::String(lua.create_string("decoder not yet implement")?),
98+
))
99+
}
100+
}
101+
}

src/ldap_codec/encoder.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use mlua::prelude::{Lua, LuaResult, LuaValue};
2+
3+
pub fn encode<'lua>(
4+
lua: &'lua Lua,
5+
_: LuaValue<'lua>,
6+
) -> LuaResult<(LuaValue<'lua>, LuaValue<'lua>)> {
7+
Ok((
8+
LuaValue::Nil,
9+
LuaValue::String(lua.create_string("not yet implement")?),
10+
))
11+
}

src/ldap_codec/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod encoder;
2+
pub mod decoder;

src/lib.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use ldap_codec::{decoder::decode, encoder::encode};
2+
use mlua::prelude::{Lua, LuaResult, LuaTable};
3+
4+
mod ldap_codec;
5+
6+
#[mlua::lua_module]
7+
fn rasn(lua: &Lua) -> LuaResult<LuaTable> {
8+
let exports = lua.create_table()?;
9+
10+
exports.set("encode_ldap", lua.create_function(encode)?)?;
11+
exports.set("decode_ldap", lua.create_function(decode)?)?;
12+
13+
Ok(exports)
14+
}

t/client.t

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ repeat_each(1);
77
plan 'no_plan';
88

99
our $HttpConfig = <<'_EOC_';
10-
lua_package_path 'lib/?.lua;lib/?/init.lua;/usr/local/share/lua/5.3/?.lua;/usr/share/lua/5.1/?.lua;;';
10+
lua_package_path 'lib/?.lua;/usr/share/lua/5.1/?.lua;;';
11+
lua_package_cpath 'deps/lib/lua/5.1/?.so;;';
1112
resolver 127.0.0.53;
1213
_EOC_
1314

t/filter.t

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ repeat_each(1);
77
plan 'no_plan';
88

99
our $HttpConfig = <<'_EOC_';
10-
lua_package_path 'lib/?.lua;lib/?/init.lua;/usr/local/share/lua/5.3/?.lua;/usr/share/lua/5.1/?.lua;;';
10+
lua_package_path 'lib/?.lua;/usr/share/lua/5.1/?.lua;;';
11+
lua_package_cpath 'deps/lib/lua/5.1/?.so;;';
1112
resolver 127.0.0.53;
1213
_EOC_
1314

0 commit comments

Comments
 (0)