luci-mod-rpc: rework authentication and session handling

- Use the ubus session.login procedure to authenticate credentials
 - Fix testing of allowed usernames
 - Support authentication via sysauth cookie

Fixes #1300, #1700, #1711

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2018-04-06 07:56:56 +02:00
parent d6b4a3d45a
commit feefc600ed

View file

@ -7,23 +7,45 @@ local pairs = pairs
local print = print local print = print
local pcall = pcall local pcall = pcall
local table = table local table = table
local type = type
local tonumber = tonumber
module "luci.controller.rpc" module "luci.controller.rpc"
function index()
local function authenticator(validator, accs) local function session_retrieve(sid, allowed_users)
local util = require "luci.util"
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
type(sdat.values.secret) == "string" and
type(sdat.values.username) == "string" and
util.contains(allowed_users, sdat.values.username)
then
return sid, sdat.values
end
return nil
end
local function authenticator(validator, accs)
local auth = luci.http.formvalue("auth", true) local auth = luci.http.formvalue("auth", true)
or luci.http.getcookie("sysauth")
if auth then -- if authentication token was given if auth then -- if authentication token was given
local sdat = (luci.util.ubus("session", "get", { ubus_rpc_session = auth }) or { }).values local sid, sdat = session_retrieve(auth, accs)
if sdat then -- if given token is valid if sdat then -- if given token is valid
if sdat.user and luci.util.contains(accs, sdat.user) then return sdat.username, sid
return sdat.user, auth
end
end
end end
luci.http.status(403, "Forbidden") luci.http.status(403, "Forbidden")
end end
end
function index()
local rpc = node("rpc") local rpc = node("rpc")
rpc.sysauth = "root" rpc.sysauth = "root"
rpc.sysauth_authenticator = authenticator rpc.sysauth_authenticator = authenticator
@ -43,39 +65,48 @@ function rpc_auth()
local ltn12 = require "luci.ltn12" local ltn12 = require "luci.ltn12"
local util = require "luci.util" local util = require "luci.util"
local loginstat
local server = {} local server = {}
server.challenge = function(user, pass) server.challenge = function(user, pass)
local sid, token, secret
local config = require "luci.config" local config = require "luci.config"
local login = util.ubus("session", "login", {
username = user,
password = pass,
timeout = tonumber(config.sauth.sessiontime)
})
if sys.user.checkpasswd(user, pass) then if type(login) == "table" and
local sdat = util.ubus("session", "create", { timeout = config.sauth.sessiontime }) type(login.ubus_rpc_session) == "string"
if sdat then then
sid = sdat.ubus_rpc_session
token = sys.uniqueid(16)
secret = sys.uniqueid(16)
http.header("Set-Cookie", "sysauth="..sid.."; path=/")
util.ubus("session", "set", { util.ubus("session", "set", {
ubus_rpc_session = sid, ubus_rpc_session = login.ubus_rpc_session,
values = { values = {
user = user, token = sys.uniqueid(16),
token = token, secret = sys.uniqueid(16)
secret = secret
} }
}) })
local sid, sdat = session_retrieve(login.ubus_rpc_session, { user })
if sdat then
return {
sid = sid,
token = sdat.token,
secret = sdat.secret
}
end end
end end
return sid and {sid=sid, token=token, secret=secret} return nil
end end
server.login = function(...) server.login = function(...)
local challenge = server.challenge(...) local challenge = server.challenge(...)
return challenge and challenge.sid if challenge then
http.header("Set-Cookie", 'sysauth=%s; path=%s' %{
challenge.sid,
http.getenv("SCRIPT_NAME")
})
return challenge.sid
end
end end
http.prepare_content("application/json") http.prepare_content("application/json")