luci-base: remove security token from urls

Now that sensitive urls require post requests and only accept them if a valid
security token is sent along the request, we can drop the global random url
token to improve LuCI usability.

The main improvement is the ability to use multiple tabs with the same login
session, but also deep linking to specific urls without the need for another
login becomes feasible, e.g. for documentation purposes.

Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
This commit is contained in:
Jo-Philipp Wich 2015-10-21 00:31:27 +02:00
parent f23f7b8751
commit 86326e0def

View file

@ -113,24 +113,11 @@ function authenticator.htmlauth(validator, accs, default)
return user return user
end end
if context.urltoken.stok then
context.urltoken.stok = nil
local cookie = 'sysauth=%s; expires=%s; path=%s/' %{
http.getcookie('sysauth') or 'x',
'Thu, 01 Jan 1970 01:00:00 GMT',
build_url()
}
http.header("Set-Cookie", cookie)
http.redirect(build_url())
else
require("luci.i18n") require("luci.i18n")
require("luci.template") require("luci.template")
context.path = {} context.path = {}
http.status(403, "Forbidden") http.status(403, "Forbidden")
luci.template.render("sysauth", {duser=default, fuser=user}) luci.template.render("sysauth", {duser=default, fuser=user})
end
return false return false
@ -151,19 +138,9 @@ function httpdispatch(request, prefix)
end end
end end
local tokensok = true
for node in pathinfo:gmatch("[^/]+") do for node in pathinfo:gmatch("[^/]+") do
local tkey, tval
if tokensok then
tkey, tval = node:match(";(%w+)=([a-fA-F0-9]*)")
end
if tkey then
context.urltoken[tkey] = tval
else
tokensok = false
r[#r+1] = node r[#r+1] = node
end end
end
local stat, err = util.coxpcall(function() local stat, err = util.coxpcall(function()
dispatch(context.request) dispatch(context.request)
@ -311,13 +288,14 @@ function dispatch(request)
resource = luci.config.main.resourcebase; resource = luci.config.main.resourcebase;
ifattr = function(...) return _ifattr(...) end; ifattr = function(...) return _ifattr(...) end;
attr = function(...) return _ifattr(true, ...) end; attr = function(...) return _ifattr(true, ...) end;
token = ctx.urltoken.stok;
url = build_url; url = build_url;
}, {__index=function(table, key) }, {__index=function(table, key)
if key == "controller" then if key == "controller" then
return build_url() return build_url()
elseif key == "REQUEST_URI" then elseif key == "REQUEST_URI" then
return build_url(unpack(ctx.requestpath)) return build_url(unpack(ctx.requestpath))
elseif key == "token" then
return ctx.authtoken
else else
return rawget(table, key) or _G[key] return rawget(table, key) or _G[key]
end end
@ -340,20 +318,17 @@ function dispatch(request)
local def = (type(track.sysauth) == "string") and track.sysauth local def = (type(track.sysauth) == "string") and track.sysauth
local accs = def and {track.sysauth} or track.sysauth local accs = def and {track.sysauth} or track.sysauth
local sess = ctx.authsession local sess = ctx.authsession
local verifytoken = false
if not sess then if not sess then
sess = http.getcookie("sysauth") sess = http.getcookie("sysauth")
sess = sess and sess:match("^[a-f0-9]*$") sess = sess and sess:match("^[a-f0-9]*$")
verifytoken = true
end end
local sdat = (util.ubus("session", "get", { ubus_rpc_session = sess }) or { }).values local sdat = (util.ubus("session", "get", { ubus_rpc_session = sess }) or { }).values
local user local user, token
if sdat then if sdat then
if not verifytoken or ctx.urltoken.stok == sdat.token then
user = sdat.user user = sdat.user
end token = sdat.token
else else
local eu = http.getenv("HTTP_AUTH_USER") local eu = http.getenv("HTTP_AUTH_USER")
local ep = http.getenv("HTTP_AUTH_PASS") local ep = http.getenv("HTTP_AUTH_PASS")
@ -390,8 +365,8 @@ function dispatch(request)
sess, build_url() sess, build_url()
}) })
ctx.urltoken.stok = token
ctx.authsession = sess ctx.authsession = sess
ctx.authtoken = token
ctx.authuser = user ctx.authuser = user
http.redirect(build_url(unpack(ctx.requestpath))) http.redirect(build_url(unpack(ctx.requestpath)))
@ -403,6 +378,7 @@ function dispatch(request)
end end
else else
ctx.authsession = sess ctx.authsession = sess
ctx.authtoken = token
ctx.authuser = user ctx.authuser = user
end end
end end
@ -414,7 +390,7 @@ function dispatch(request)
return return
end end
if http.formvalue("token") ~= ctx.urltoken.stok then if http.formvalue("token") ~= ctx.authtoken then
http.status(403, "Forbidden") http.status(403, "Forbidden")
luci.template.render("csrftoken") luci.template.render("csrftoken")
return return