Browse Source

Added basic auth. Added static settings file

Samuel A. Dieck 5 years ago
parent
commit
be63ee0093
8 changed files with 81 additions and 13 deletions
  1. 1 0
      .gitignore
  2. 2 2
      Makefile
  3. 5 1
      README.md
  4. 29 0
      httpserver-basicauth.lua
  5. 20 0
      httpserver-conf.lua
  6. 8 3
      httpserver-error.lua
  7. 12 3
      httpserver.lua
  8. 4 4
      init.lua

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+*.swp

+ 2 - 2
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:

+ 5 - 1
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.

+ 29 - 0
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

+ 20 - 0
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

+ 8 - 3
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("<html><head><title>" .. args.code .. " - " .. args.errorString .. "</title></head><body><h1>" .. args.code .. " - " .. args.errorString .. "</h1></body></html>\r\n")
 end

+ 12 - 3
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"}

+ 4 - 4
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