From be63ee00930a5fe65404d307a8f24594bc63a0e4 Mon Sep 17 00:00:00 2001 From: "Samuel A. Dieck" Date: Sat, 18 Jul 2015 23:17:14 -0500 Subject: [PATCH] Added basic auth. Added static settings file --- .gitignore | 1 + Makefile | 4 ++-- README.md | 6 +++++- httpserver-basicauth.lua | 29 +++++++++++++++++++++++++++++ httpserver-conf.lua | 20 ++++++++++++++++++++ httpserver-error.lua | 11 ++++++++--- httpserver.lua | 15 ++++++++++++--- init.lua | 8 ++++---- 8 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 .gitignore create mode 100644 httpserver-basicauth.lua create mode 100644 httpserver-conf.lua diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/Makefile b/Makefile index 10c6c27..ca0612f 100644 --- a/Makefile +++ b/Makefile @@ -4,14 +4,14 @@ # Path to nodemcu-uploader (https://github.com/kmpm/nodemcu-uploader) NODEMCU-UPLOADER=../nodemcu-uploader/nodemcu-uploader.py # Serial port -PORT=/dev/cu.usbserial-A602HRAZ +PORT=/dev/ttyUSB0 SPEED=9600 ###################################################################### # End of user config ###################################################################### HTTP_FILES := $(wildcard http/*) -LUA_FILES := init.lua httpserver.lua httpserver-request.lua httpserver-static.lua httpserver-header.lua httpserver-error.lua +LUA_FILES := init.lua httpserver.lua httpserver-request.lua httpserver-basicauth.lua httpserver-conf.lua httpserver-static.lua httpserver-header.lua httpserver-error.lua # Print usage usage: diff --git a/README.md b/README.md index 79ee6e8..93ddb99 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ A (very) simple web server written in Lua for the ESP8266 firmware NodeMCU. * Server-side execution of Lua scripts * Query string argument parsing * Serving .gz compressed files +* HTTP basic authentication ## How to use @@ -49,6 +50,10 @@ A (very) simple web server written in Lua for the ESP8266 firmware NodeMCU. then index.html is served. By the way, unlike most HTTP servers, nodemcu_httpserver treats the URLs in a case-sensitive manner. +4. Enable http basic authentication. + + Enable and configure http basic authentication in "httpserver-conf.lua" file. + ## How to create dynamic Lua scripts Similar to static files, upload a Lua script called "http/[name].lua where you replace [name] with your script's name. @@ -123,7 +128,6 @@ A (very) simple web server written in Lua for the ESP8266 firmware NodeMCU. ## Not supported * Other methods: HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH -* HTTP authentication * Encryption ## Notes on memory usage. diff --git a/httpserver-basicauth.lua b/httpserver-basicauth.lua new file mode 100644 index 0000000..fc295bd --- /dev/null +++ b/httpserver-basicauth.lua @@ -0,0 +1,29 @@ +-- httpserver-basicauth.lua +-- Part of nodemcu-httpserver, authenticates a user using http basic auth. +-- Author: Sam Dieck + +basicAuth = {} + +function basicAuth.authenticate(header) + conf = dofile("httpserver-conf.lc") + -- Parse basic auth http header. + -- Returns the username if header contains valid credentials, + -- nil otherwise. + local credentials_enc = header:match("Authorization: Basic ([A-Za-z0-9+/=]+)") + if not credentials_enc then + return nil + end + local credentials = dofile("b64.lc").decode(credentials_enc) + local user, pwd = credentials:match("^(.*):(.*)$") + if user ~= conf.auth.user or pwd ~= conf.auth.password then + return nil + end + print("httpserver-basicauth: User " .. user .. " authenticated.") + return user +end + +function basicAuth.authErrorHeader() + return "WWW-Authenticate: Basic realm=\"nodemcu-httpserver\"" +end + +return basicAuth diff --git a/httpserver-conf.lua b/httpserver-conf.lua new file mode 100644 index 0000000..d9e70e8 --- /dev/null +++ b/httpserver-conf.lua @@ -0,0 +1,20 @@ +-- httpserver-conf.lua +-- Part of nodemcu-httpserver, contains static configuration for httpserver. +-- Author: Sam Dieck + +conf = {} + +-- WIFI +-- FIXME use these +--wifi = {} +--wifi.essid = "Internet" +--wifi.password = "" + +-- Basic Authentication Conf +auth = {} +auth.enabled = false +auth.user = "user" +auth.password = "password" +conf.auth = auth + +return conf diff --git a/httpserver-error.lua b/httpserver-error.lua index a8dfe84..00e6bd8 100644 --- a/httpserver-error.lua +++ b/httpserver-error.lua @@ -4,11 +4,16 @@ return function (connection, args) - local function sendHeader(connection, code, errorString, mimeType) - connection:send("HTTP/1.0 " .. code .. " " .. errorString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\nConnection: close\r\n\r\n") + local function sendHeader(connection, code, errorString, extraHeaders, mimeType) + connection:send("HTTP/1.0 " .. code .. " " .. errorString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\n") + for i, header in ipairs(extraHeaders) do + connection:send(header .. "\r\n") + end + connection:send("connection: close\r\n\r\n") end print("Error " .. args.code .. ": " .. args.errorString) - sendHeader(connection, args.code, args.errorString, "text/html") + args.headers = args.headers or {} + sendHeader(connection, args.code, args.errorString, args.headers, "text/html") connection:send("" .. args.code .. " - " .. args.errorString .. "

" .. args.code .. " - " .. args.errorString .. "

\r\n") end diff --git a/httpserver.lua b/httpserver.lua index f2e5210..ecfe4c9 100644 --- a/httpserver.lua +++ b/httpserver.lua @@ -40,16 +40,25 @@ return function (port) local function onReceive(connection, payload) collectgarbage() - -- print(payload) -- for debugging + local conf = dofile("httpserver-conf.lc") + local auth + local user = "Anonymous" + -- parse payload and decide what to serve. local req = dofile("httpserver-request.lc")(payload) print("Requested URI: " .. req.request) - if req.methodIsValid and req.method == "GET" then + if conf.auth.enabled then + auth = dofile("httpserver-basicauth.lc") + user = auth.authenticate(payload) -- authenticate returns nil on failed auth + end + if user and req.methodIsValid and req.method == "GET" then onGet(connection, req.uri) else local args = {} local fileServeFunction = dofile("httpserver-error.lc") - if req.methodIsValid then + if not user then + args = {code = 401, errorString = "Not Authorized", headers = {auth.authErrorHeader()}} + elseif req.methodIsValid then args = {code = 501, errorString = "Not Implemented"} else args = {code = 400, errorString = "Bad Request"} diff --git a/init.lua b/init.lua index 1d8957f..ccad8fb 100644 --- a/init.lua +++ b/init.lua @@ -12,8 +12,8 @@ wifiConfig.accessPointConfig.ssid = "ESP-"..node.chipid() -- Name of the SSID wifiConfig.accessPointConfig.pwd = "ESP-"..node.chipid() -- WiFi password - at least 8 characters wifiConfig.stationPointConfig = {} -wifiConfig.stationPointConfig.ssid = "Internet" -- Name of the WiFi network you want to join -wifiConfig.stationPointConfig.pwd = "" -- Password for the WiFi network +wifiConfig.stationPointConfig.ssid = "Internet" -- Name of the WiFi network you want to join +wifiConfig.stationPointConfig.pwd = "" -- Password for the WiFi network -- Tell the chip to connect to the access point @@ -43,7 +43,7 @@ local compileAndRemoveIfNeeded = function(f) end end -local serverFiles = {'httpserver.lua', 'httpserver-request.lua', 'httpserver-static.lua', 'httpserver-header.lua', 'httpserver-error.lua'} +local serverFiles = {'httpserver.lua', 'httpserver-basicauth.lua', 'httpserver-conf.lua', 'b64.lua', 'httpserver-request.lua', 'httpserver-static.lua', 'httpserver-header.lua', 'httpserver-error.lua'} for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end compileAndRemoveIfNeeded = nil @@ -66,7 +66,7 @@ tmr.alarm(0, 3000, 1, function() else print('IP: ',ip) -- Uncomment to automatically start the server in port 80 - --dofile("httpserver.lc")(80) + dofile("httpserver.lc")(80) end tmr.stop(0) joinCounter = nil