From 271c53a4af7a79414a440b3a4d90ef7dbc48fd77 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Sun, 14 Dec 2008 21:43:10 +0000 Subject: [PATCH] Implement URL tokens Add basic XSRF protection --- libs/web/luasrc/dispatcher.lua | 80 ++++++++++++++++++++++++++++------- modules/rpc/luasrc/controller/rpc.lua | 23 +++++++--- 2 files changed, 83 insertions(+), 20 deletions(-) diff --git a/libs/web/luasrc/dispatcher.lua b/libs/web/luasrc/dispatcher.lua index d3daa46a6..1fbdb7150 100644 --- a/libs/web/luasrc/dispatcher.lua +++ b/libs/web/luasrc/dispatcher.lua @@ -47,7 +47,7 @@ local fi -- @param ... Virtual path -- @return Relative URL function build_url(...) - return luci.http.getenv("SCRIPT_NAME") .. "/" .. table.concat(arg, "/") + return context.scriptname .. "/" .. table.concat(arg, "/") end --- Send a 404 error code and render the "error404" template if available. @@ -123,6 +123,8 @@ function dispatch(request) --context._disable_memtrace = require "luci.debug".trap_memtrace() local ctx = context ctx.path = request + ctx.scriptname = luci.http.getenv("SCRIPT_NAME") or "" + ctx.urltoken = ctx.urltoken or {} require "luci.i18n".setlanguage(require "luci.config".main.lang) @@ -137,18 +139,32 @@ function dispatch(request) ctx.args = args ctx.requestargs = ctx.requestargs or args local n + local t = true + local token = ctx.urltoken + local preq = {} for i, s in ipairs(request) do - c = c.nodes[s] - n = i - if not c then - break + local tkey, tval + if t then + tkey, tval = s:match(";(%w+)=(.*)") end - util.update(track, c) + if tkey then + token[tkey] = tval + else + t = false + preq[#preq+1] = s + c = c.nodes[s] + n = i + if not c then + break + end - if c.leaf then - break + util.update(track, c) + + if c.leaf then + break + end end end @@ -158,6 +174,13 @@ function dispatch(request) end end + for k, v in pairs(token) do + ctx.scriptname = ctx.scriptname .. "/;" .. k .. "=" .. + http.urlencode(v) + end + + ctx.path = preq + if track.i18n then require("luci.i18n").loadc(track.i18n) end @@ -177,17 +200,23 @@ function dispatch(request) assert(media, "No valid theme found") end - local viewns = setmetatable({}, {__index=_G}) + local viewns = setmetatable({}, {__index=function(table, key) + if key == "controller" then + return ctx.scriptname + elseif key == "REQUEST_URI" then + return ctx.scriptname .. "/" .. table.concat(ctx.requested, "/") + else + return rawget(table, key) or _G[key] + end + end}) tpl.context.viewns = viewns viewns.write = luci.http.write viewns.include = function(name) tpl.Template(name):render(getfenv(2)) end viewns.translate = function(...) return require("luci.i18n").translate(...) end viewns.striptags = util.striptags - viewns.controller = luci.http.getenv("SCRIPT_NAME") viewns.media = media viewns.theme = fs.basename(media) viewns.resource = luci.config.main.resourcebase - viewns.REQUEST_URI = (luci.http.getenv("SCRIPT_NAME") or "") .. (luci.http.getenv("PATH_INFO") or "") end track.dependent = (track.dependent ~= false) @@ -202,9 +231,22 @@ function dispatch(request) local def = (type(track.sysauth) == "string") and track.sysauth local accs = def and {track.sysauth} or track.sysauth - local sess = ctx.authsession or luci.http.getcookie("sysauth") - sess = sess and sess:match("^[A-F0-9]+$") - local user = sauth.read(sess) + local sess = ctx.authsession + local verifytoken = true + if not sess then + sess = luci.http.getcookie("sysauth") + sess = sess and sess:match("^[A-F0-9]+$") + end + + local sdat = sauth.read(sess) + local user + + if sdat then + sdat = loadstring(sdat)() + if not verifytoken or ctx.urltoken.stok == sdat.token then + user = sdat.user + end + end if not util.contains(accs, user) then if authen then @@ -215,7 +257,13 @@ function dispatch(request) local sid = sess or luci.sys.uniqueid(16) luci.http.header("Set-Cookie", "sysauth=" .. sid.."; path=/") if not sess then - sauth.write(sid, user) + local token = luci.sys.uniqueid(16) + sauth.write(sid, util.get_bytecode({ + user=user, + token=token, + secret=luci.sys.uniqueid(16) + })) + ctx.scriptname = ctx.scriptname .. "/;stok="..token end ctx.authsession = sid end @@ -223,6 +271,8 @@ function dispatch(request) luci.http.status(403, "Forbidden") return end + else + ctx.authsession = sess end end diff --git a/modules/rpc/luasrc/controller/rpc.lua b/modules/rpc/luasrc/controller/rpc.lua index 2eef7a0eb..d83c26d45 100644 --- a/modules/rpc/luasrc/controller/rpc.lua +++ b/modules/rpc/luasrc/controller/rpc.lua @@ -52,20 +52,33 @@ function rpc_auth() local http = require "luci.http" local sys = require "luci.sys" local ltn12 = require "luci.ltn12" + local util = require "luci.util" local loginstat local server = {} - server.login = function(user, pass) - local sid - + server.challenge = function(user, pass) + local sid, token, secret + if sys.user.checkpasswd(user, pass) then sid = sys.uniqueid(16) + token = sys.uniqueid(16) + secret = sys.uniqueid(16) + http.header("Set-Cookie", "sysauth=" .. sid.."; path=/") - sauth.write(sid, user) + sauth.write(sid, util.get_bytecode({ + user=user, + token=token, + secret=secret + })) end - return sid + return sid and {sid=sid, token=token, secret=secret} + end + + server.login = function(...) + local challenge = server.challenge(...) + return challenge and challenge.sid end http.prepare_content("application/json") -- 2.11.0