luci-base: use rpcd session logins
authorJo-Philipp Wich <jo@mein.io>
Sun, 9 Jul 2017 19:26:49 +0000 (21:26 +0200)
committerJo-Philipp Wich <jo@mein.io>
Sun, 9 Jul 2017 19:35:26 +0000 (21:35 +0200)
Drop the custom credentials checking in favor to perform proper session
logins via rpcd. This is needed to properly setup ACLs when spawning
rpcd sessions in order to support direct client side ubus access in the
future.

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

index 0bd1945..2b5f7b4 100644 (file)
@@ -14,8 +14,6 @@ uci = require "luci.model.uci"
 i18n = require "luci.i18n"
 _M.fs = fs
 
 i18n = require "luci.i18n"
 _M.fs = fs
 
-authenticator = {}
-
 -- Index table
 local index = nil
 
 -- Index table
 local index = nil
 
@@ -101,24 +99,6 @@ function error500(message)
        return false
 end
 
        return false
 end
 
-function authenticator.htmlauth(validator, accs, default, template)
-       local user = http.formvalue("luci_username")
-       local pass = http.formvalue("luci_password")
-
-       if user and validator(user, pass) then
-               return user
-       end
-
-       require("luci.i18n")
-       require("luci.template")
-       context.path = {}
-       http.status(403, "Forbidden")
-       luci.template.render(template or "sysauth", {duser=default, fuser=user})
-
-       return false
-
-end
-
 function httpdispatch(request, prefix)
        http.context.request = request
 
 function httpdispatch(request, prefix)
        http.context.request = request
 
@@ -188,6 +168,41 @@ function test_post_security()
        return true
 end
 
        return true
 end
 
+local function session_retrieve(sid, allowed_users)
+       local sdat = util.ubus("session", "get", { ubus_rpc_session = sid })
+
+       if type(sdat) == "table" and
+          type(sdat.values) == "table" and
+          type(sdat.values.token) == "string" and
+          util.contains(allowed_users, sdat.values.username)
+       then
+               return sid, sdat.values
+       end
+
+       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) }
+               })
+
+               return login.ubus_rpc_session
+       end
+
+       return nil
+end
+
 function dispatch(request)
        --context._disable_memtrace = require "luci.debug".trap_memtrace("l")
        local ctx = context
 function dispatch(request)
        --context._disable_memtrace = require "luci.debug".trap_memtrace("l")
        local ctx = context
@@ -332,74 +347,65 @@ function dispatch(request)
        )
 
        if track.sysauth then
        )
 
        if track.sysauth then
-               local authen = type(track.sysauth_authenticator) == "function"
-                and track.sysauth_authenticator
-                or authenticator[track.sysauth_authenticator]
-
-               local def  = (type(track.sysauth) == "string") and track.sysauth
-               local accs = def and {track.sysauth} or track.sysauth
-               local sess = ctx.authsession
-               if not sess then
-                       sess = http.getcookie("sysauth")
-                       sess = sess and sess:match("^[a-f0-9]*$")
-               end
+               local authen = track.sysauth_authenticator
+               local _, sid, sdat, default_user, allowed_users
 
 
-               local sdat = (util.ubus("session", "get", { ubus_rpc_session = sess }) or { }).values
-               local user, token
-
-               if sdat then
-                       user = sdat.user
-                       token = sdat.token
+               if type(track.sysauth) == "table" then
+                       default_user, allowed_users = nil, track.sysauth
                else
                else
-                       local eu = http.getenv("HTTP_AUTH_USER")
-                       local ep = http.getenv("HTTP_AUTH_PASS")
-                       if eu and ep and sys.user.checkpasswd(eu, ep) then
-                               authen = function() return eu end
-                       end
+                       default_user, allowed_users = track.sysauth, { track.sysauth }
                end
 
                end
 
-               if not util.contains(accs, user) then
-                       if authen then
-                               local user, sess = authen(sys.user.checkpasswd, accs, def, track.sysauth_template)
-                               local token
-                               if not user or not util.contains(accs, user) then
-                                       return
-                               else
-                                       if not sess then
-                                               local sdat = util.ubus("session", "create", { timeout = tonumber(luci.config.sauth.sessiontime) })
-                                               if sdat then
-                                                       token = sys.uniqueid(16)
-                                                       util.ubus("session", "set", {
-                                                               ubus_rpc_session = sdat.ubus_rpc_session,
-                                                               values = {
-                                                                       user = user,
-                                                                       token = token,
-                                                                       section = sys.uniqueid(16)
-                                                               }
-                                                       })
-                                                       sess = sdat.ubus_rpc_session
-                                               end
-                                       end
+               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)
 
 
-                                       if sess and token then
-                                               http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sess, build_url() })
+                       if not sid then
+                               local user = http.getenv("HTTP_AUTH_USER")
+                               local pass = http.getenv("HTTP_AUTH_PASS")
 
 
-                                               ctx.authsession = sess
-                                               ctx.authtoken = token
-                                               ctx.authuser = user
+                               if user == nil and pass == nil then
+                                       user = http.formvalue("luci_username")
+                                       pass = http.formvalue("luci_password")
+                               end
 
 
-                                               http.redirect(build_url(unpack(ctx.requestpath)))
-                                       end
+                               if util.contains(allowed_users, user) then
+                                       sid, sdat = session_setup(user, pass), nil
                                end
                                end
-                       else
-                               http.status(403, "Forbidden")
-                               return
+
+                               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
+
+                               http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sid, build_url() })
+                               http.redirect(build_url(unpack(ctx.requestpath)))
                        end
                else
                        end
                else
-                       ctx.authsession = sess
-                       ctx.authtoken = token
-                       ctx.authuser = user
+                       error500("Unsupported authenticator configured")
+                       return
+               end
+
+               if not sdat then
+                       sid, sdat = session_retrieve(sid, allowed_users)
                end
                end
+
+               if not sid or not sdat then
+                       http.status(403, "Forbidden")
+                       return
+               end
+
+               ctx.authsession = sid
+               ctx.authtoken = sdat.token
+               ctx.authuser = sdat.username
        end
 
        if c and require_post_security(c.target) then
        end
 
        if c and require_post_security(c.target) then