commit 57d396e8e86200fe1a4bd92b1c092b7e2149d356 Author: root Date: Tue Jul 13 12:54:28 2021 +0000 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07ec58a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/luarocks +/lua +/lua_modules +/.luarocks +/.vscode \ No newline at end of file diff --git a/contrib/ldap-auth-request.ini b/contrib/ldap-auth-request.ini new file mode 100644 index 0000000..3d49130 --- /dev/null +++ b/contrib/ldap-auth-request.ini @@ -0,0 +1,10 @@ +[uwsgi] +plugins = http,ugreen,lua +http-socket = :8080 +http-socket-modifier1 = 6 +chdir = /srv/%n +lua = contrib/uwsgi.lua +lua-gc-freq = 1 +async = 8 +ugreen = true +thunder-lock = true diff --git a/contrib/nginx.conf b/contrib/nginx.conf new file mode 100644 index 0000000..29c1f65 --- /dev/null +++ b/contrib/nginx.conf @@ -0,0 +1,14 @@ + location / { + auth_request /auth; + # ... + } + + location = /auth { + proxy_pass http://127.0.0.1:8080/auth; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-LDAP-Auth-Server "dc_server_list"; + proxy_set_header X-LDAP-Auth-Prefix ""; + proxy_set_header X-LDAP-Auth-Suffix "@DOMAIN.local"; + } + diff --git a/contrib/uwsgi.lua b/contrib/uwsgi.lua new file mode 100644 index 0000000..7d50f97 --- /dev/null +++ b/contrib/uwsgi.lua @@ -0,0 +1,7 @@ +local _VERSION, package, require = _VERSION, package, require + +local version = _VERSION:match("%d+%.%d+") +package.path = "src/?.lua;src/?/init.lua;lua_modules/share/lua/" .. version .. "/?.lua;lua_modules/share/lua/" .. version .. "/?/init.lua;" .. package.path +package.cpath = "lua_modules/lib/lua/" .. version .. "/?.so;" .. package.cpath + +return require("ldap-auth-request") diff --git a/rockspec/ldap-auth-request-0.0.1-1.rockspec b/rockspec/ldap-auth-request-0.0.1-1.rockspec new file mode 100644 index 0000000..f5ec0be --- /dev/null +++ b/rockspec/ldap-auth-request-0.0.1-1.rockspec @@ -0,0 +1,23 @@ +package = "ldap-auth-request" +version = "0.0.1-1" +source = { + url = "*** please add URL for source tarball, zip or repository here ***" +} +description = { + summary = "summary", + detailed = "detailed", + homepage = "*** please enter a project homepage ***", + license = "MIT/X11" +} +-- luarocks install --only-deps +dependencies = { + "lua >= 5.1, < 5.2", + "bit32 >= 5.3.5", + "lualdap >= 1.3.0", + "luasocket >= 2.0.2", + "penlight >= 1.10.0" +} +build = { + type = "builtin", + modules = {} +} diff --git a/src/ldap-auth-request.lua b/src/ldap-auth-request.lua new file mode 100644 index 0000000..d28f024 --- /dev/null +++ b/src/ldap-auth-request.lua @@ -0,0 +1,72 @@ +local require, type, io, tostring, string, assert, pcall = require, type, io, tostring, string, assert, pcall + +local pretty = require("pl.pretty") +local mime = require("mime") +local lualdap = require("lualdap") + +local _M = {} + +-- print message to stderr +local log = function(msg) + if type(msg) == "table" then + io.stderr:write("LOG: " .. pretty.write(msg) .. "\n") + else + io.stderr:write("LOG: " .. tostring(msg) .. "\n") + end +end + +-- decode HTTP_AUTHORIZATION header and split to login/password +local decode_authorization = function(header) + local auth_string_b64 = string.match(header, "^Basic%s([^%s]+)$") + local auth_string, _ = mime.unb64(auth_string_b64) + local login, password = string.match(auth_string, "^([^:]+)[:](.+)$") + return login, password +end + +-- try connect and bind to ADSI/LDAP +local bind = function(dc, username, password) + local conn = assert(lualdap.open(dc)) + local _, err = conn:bind_simple(username, password) + conn:close() + assert(err == nil, err) +end + +-- main +function _M.run(wsapi_env) + local path = wsapi_env.PATH_INFO + local authorization = wsapi_env.HTTP_AUTHORIZATION or "" + local dc = wsapi_env.HTTP_X_LDAP_AUTH_SERVER or "localhost" + local login_prefix = wsapi_env.HTTP_X_LDAP_AUTH_PREFIX or "" + local login_suffix = wsapi_env.HTTP_X_LDAP_AUTH_SUFFIX or "" + + -- debug only + -- log(wsapi_env) + + -- test auth url + if path ~= "/auth" then + return 404, {}, "" + end + + -- test auth header + if authorization == "" then + return 401, {["WWW-Authenticate"] = [[Basic realm="realm", charset="UTF-8"]]}, "" + end + + local status, login, password = pcall(decode_authorization, authorization) + if (not status) then + return 403, {}, "" + end + + -- make normal username + local username = string.format("%s%s%s", login_prefix, login, login_suffix) + + local status, err = pcall(bind, dc, username, password) + if (not status) then + log(err) + return 403, {}, "" + end + + return 200, {}, "" +end + +return _M