luci-base: properly handle authentication without authenticator
authorJo-Philipp Wich <jo@mein.io>
Tue, 11 Jul 2017 12:12:50 +0000 (14:12 +0200)
committerJo-Philipp Wich <jo@mein.io>
Tue, 11 Jul 2017 12:12:50 +0000 (14:12 +0200)
Some controller actions like the ones in "servicectl" require authentication
but are not meant to provide an authenticator because they're only invoked
by scripts.

Rework the dispatcher logic to handle this situation and only bail out if
an authenticator name other than "htmlauth" is set.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/luasrc/dispatcher.lua

index 2b5f7b4929b979583942c3f3f45203e4977d0e33..1b684aa79c93271fca9a0f02511451d6af212d88 100644 (file)
@@ -174,7 +174,8 @@ local function session_retrieve(sid, allowed_users)
        if type(sdat) == "table" and
           type(sdat.values) == "table" and
           type(sdat.values.token) == "string" and
-          util.contains(allowed_users, sdat.values.username)
+          (not allowed_users or
+           util.contains(allowed_users, sdat.values.username))
        then
                return sid, sdat.values
        end
@@ -182,25 +183,27 @@ local function session_retrieve(sid, allowed_users)
        return nil, nil
 end
 
-local function session_setup(user, pass)
-       local login = util.ubus("session", "login", {
-               username = user,
-               password = pass,
-               timeout  = tonumber(luci.config.sauth.sessiontime)
-       })
-
-       if type(login) == "table" and
-          type(login.ubus_rpc_session) == "string"
-       then
-               util.ubus("session", "set", {
-                       ubus_rpc_session = login.ubus_rpc_session,
-                       values = { token = sys.uniqueid(16) }
+local function session_setup(user, pass, allowed_users)
+       if util.contains(allowed_users, user) then
+               local login = util.ubus("session", "login", {
+                       username = user,
+                       password = pass,
+                       timeout  = tonumber(luci.config.sauth.sessiontime)
                })
 
-               return login.ubus_rpc_session
+               if type(login) == "table" and
+                  type(login.ubus_rpc_session) == "string"
+               then
+                       util.ubus("session", "set", {
+                               ubus_rpc_session = login.ubus_rpc_session,
+                               values = { token = sys.uniqueid(16) }
+                       })
+
+                       return session_retrieve(login.ubus_rpc_session)
+               end
        end
 
-       return nil
+       return nil, nil
 end
 
 function dispatch(request)
@@ -350,6 +353,11 @@ function dispatch(request)
                local authen = track.sysauth_authenticator
                local _, sid, sdat, default_user, allowed_users
 
+               if type(authen) == "string" and authen ~= "htmlauth" then
+                       error500("Unsupported authenticator %q configured" % authen)
+                       return
+               end
+
                if type(track.sysauth) == "table" then
                        default_user, allowed_users = nil, track.sysauth
                else
@@ -358,44 +366,39 @@ function dispatch(request)
 
                if type(authen) == "function" then
                        _, sid = authen(sys.user.checkpasswd, allowed_users)
-               elseif authen == "htmlauth" then
-                       sid, sdat = session_retrieve(http.getcookie("sysauth"), allowed_users)
+               else
+                       sid = http.getcookie("sysauth")
+               end
 
-                       if not sid then
-                               local user = http.getenv("HTTP_AUTH_USER")
-                               local pass = http.getenv("HTTP_AUTH_PASS")
+               sid, sdat = session_retrieve(sid, allowed_users)
 
-                               if user == nil and pass == nil then
-                                       user = http.formvalue("luci_username")
-                                       pass = http.formvalue("luci_password")
-                               end
+               if not (sid and sdat) and authen == "htmlauth" then
+                       local user = http.getenv("HTTP_AUTH_USER")
+                       local pass = http.getenv("HTTP_AUTH_PASS")
 
-                               if util.contains(allowed_users, user) then
-                                       sid, sdat = session_setup(user, pass), nil
-                               end
+                       if user == nil and pass == nil then
+                               user = http.formvalue("luci_username")
+                               pass = http.formvalue("luci_password")
+                       end
 
-                               if not sid then
-                                       require("luci.i18n")
-                                       require("luci.template")
-                                       context.path = {}
-                                       http.status(403, "Forbidden")
-                                       luci.template.render(track.sysauth_template or "sysauth", {
-                                               duser = default_user,
-                                               fuser = user
-                                       })
-                                       return
-                               end
+                       sid, sdat = session_setup(user, pass, allowed_users)
+
+                       if not sid then
+                               local tmpl = require "luci.template"
 
-                               http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sid, build_url() })
-                               http.redirect(build_url(unpack(ctx.requestpath)))
+                               context.path = {}
+
+                               http.status(403, "Forbidden")
+                               tmpl.render(track.sysauth_template or "sysauth", {
+                                       duser = default_user,
+                                       fuser = user
+                               })
+
+                               return
                        end
-               else
-                       error500("Unsupported authenticator configured")
-                       return
-               end
 
-               if not sdat then
-                       sid, sdat = session_retrieve(sid, allowed_users)
+                       http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sid, build_url() })
+                       http.redirect(build_url(unpack(ctx.requestpath)))
                end
 
                if not sid or not sdat then